Fixed some bad interaction between variable and data sheets.
[pspp-builds.git] / lib / gtksheet / gtksheet.c
1 /* This version of GtkSheet has been *heavily* modified, for the specific 
2    requirements of PSPPIRE. */
3
4 /* GtkSheet widget for Gtk+.
5  * Copyright (C) 1999-2001 Adrian E. Feiguin <adrian@ifir.ifir.edu.ar>
6  *
7  * Based on GtkClist widget by Jay Painter, but major changes.
8  * Memory allocation routines inspired on SC (Spreadsheet Calculator)
9  *
10  * This library is free software; you can redistribute it and/or
11  * modify it under the terms of the GNU Lesser General Public
12  * License as published by the Free Software Foundation; either
13  * version 2.1 of the License, or (at your option) any later version.
14  *
15  * This library is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
18  * Lesser General Public License for more details.
19  * 
20  * You should have received a copy of the GNU Lesser General Public
21  * License along with this library; if not, write to the Free Software
22  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
23  */
24 /**
25  * SECTION:gtksheet
26  * @short_description: spreadsheet widget for gtk2
27  *
28  * GtkSheet is a matrix widget for GTK+. It consists of an scrollable grid of 
29  * cells where you can allocate text. Cell contents can be edited interactively
30  * through a specially designed entry, GtkItemEntry. It is also a container
31  * subclass, allowing you to display buttons, curves, pixmaps and any other 
32  * widgets in it.
33  *
34  * You can also set many attributes as: border, foreground and background color,
35  * text justification, and more.
36  *
37  * The testgtksheet program shows how easy is to create a spreadsheet-like GUI
38  * using this widget.
39  */
40 #include <string.h>
41 #include <stdio.h>
42 #include <stdlib.h>
43 #include <glib.h>
44 #include <gdk/gdk.h>
45 #include <gdk/gdkkeysyms.h>
46 #include <gtk/gtksignal.h>
47 #include <gtk/gtklabel.h>
48 #include <gtk/gtkbutton.h>
49 #include <gtk/gtkadjustment.h>
50 #include <gtk/gtktable.h>
51 #include <gtk/gtkbox.h>
52 #include <gtk/gtkmain.h>
53 #include <gtk/gtktypeutils.h>
54 #include <gtk/gtkentry.h>
55 #include <gtk/gtkcontainer.h>
56 #include <gtk/gtkpixmap.h>
57 #include <pango/pango.h>
58 #include "gtkitementry.h"
59 #include "gtksheet.h"
60 #include "gtkextra-marshal.h"
61 #include "gsheetmodel.h"
62
63
64 /* sheet flags */
65 enum
66
67   GTK_SHEET_IS_LOCKED       = 1 << 0,
68   GTK_SHEET_IS_FROZEN       = 1 << 1,
69   GTK_SHEET_IN_XDRAG        = 1 << 2,
70   GTK_SHEET_IN_YDRAG        = 1 << 3,
71   GTK_SHEET_IN_DRAG         = 1 << 4,
72   GTK_SHEET_IN_SELECTION    = 1 << 5,
73   GTK_SHEET_IN_RESIZE       = 1 << 6,
74   GTK_SHEET_IN_CLIP         = 1 << 7,
75   GTK_SHEET_REDRAW_PENDING  = 1 << 8,
76 };
77
78 #define GTK_SHEET_FLAGS(sheet)             (GTK_SHEET (sheet)->flags)
79 #define GTK_SHEET_SET_FLAGS(sheet,flag)    (GTK_SHEET_FLAGS (sheet) |= (flag))
80 #define GTK_SHEET_UNSET_FLAGS(sheet,flag)  (GTK_SHEET_FLAGS (sheet) &= ~(flag))
81
82 #define GTK_SHEET_IS_LOCKED(sheet)   (GTK_SHEET_FLAGS (sheet) & GTK_SHEET_IS_LOCKED)
83
84
85 #define GTK_SHEET_IS_FROZEN(sheet)   (GTK_SHEET_FLAGS (sheet) & GTK_SHEET_IS_FROZEN)
86 #define GTK_SHEET_IN_XDRAG(sheet)    (GTK_SHEET_FLAGS (sheet) & GTK_SHEET_IN_XDRAG)
87 #define GTK_SHEET_IN_YDRAG(sheet)    (GTK_SHEET_FLAGS (sheet) & GTK_SHEET_IN_YDRAG)
88 #define GTK_SHEET_IN_DRAG(sheet)     (GTK_SHEET_FLAGS (sheet) & GTK_SHEET_IN_DRAG)
89 #define GTK_SHEET_IN_SELECTION(sheet) (GTK_SHEET_FLAGS (sheet) & GTK_SHEET_IN_SELECTION)
90 #define GTK_SHEET_IN_RESIZE(sheet) (GTK_SHEET_FLAGS (sheet) & GTK_SHEET_IN_RESIZE)
91 #define GTK_SHEET_IN_CLIP(sheet) (GTK_SHEET_FLAGS (sheet) & GTK_SHEET_IN_CLIP)
92 #define GTK_SHEET_REDRAW_PENDING(sheet)   (GTK_SHEET_FLAGS (sheet) & GTK_SHEET_REDRAW_PENDING)
93  
94 #define CELL_SPACING 1
95 #define DRAG_WIDTH 6
96 #define TIMEOUT_SCROLL 20
97 #define TIMEOUT_FLASH 200
98 #define TIME_INTERVAL 8
99 #define COLUMN_MIN_WIDTH 10
100 #define MINROWS 1
101 #define MINCOLS 1
102 #define MAXLENGTH 30
103 #define CELLOFFSET 4
104 #define DEFAULT_COLUMN_WIDTH 80
105
106
107 static gboolean gtk_sheet_cell_empty (const GtkSheet *sheet, gint row, gint col);
108
109 static inline
110 void dispose_string (const GtkSheet *sheet, gchar *text)
111 {
112   GSheetModel *model  = gtk_sheet_get_model(sheet);
113
114   if ( ! model ) 
115     return;
116
117   if (g_sheet_model_free_strings(model))
118     g_free(text);
119 }
120
121 static inline 
122 guint DEFAULT_ROW_HEIGHT(GtkWidget *widget) 
123
124   if(!widget->style->font_desc) return 24;
125   else {
126     PangoContext *context = gtk_widget_get_pango_context(widget); 
127     PangoFontMetrics *metrics = pango_context_get_metrics(context,
128                                   widget->style->font_desc,
129                                   pango_context_get_language(context)); 
130     guint val = pango_font_metrics_get_descent(metrics) + 
131                 pango_font_metrics_get_ascent(metrics);
132     pango_font_metrics_unref(metrics);
133     return PANGO_PIXELS(val)+2*CELLOFFSET;
134   }
135 }
136 static inline guint DEFAULT_FONT_ASCENT(GtkWidget *widget) 
137
138   if(!widget->style->font_desc) return 12;
139   else {
140     PangoContext *context = gtk_widget_get_pango_context(widget); 
141     PangoFontMetrics *metrics = pango_context_get_metrics(context,
142                                   widget->style->font_desc,
143                                   pango_context_get_language(context)); 
144     guint val = pango_font_metrics_get_ascent(metrics);
145     pango_font_metrics_unref(metrics);
146     return PANGO_PIXELS(val);
147   }
148 }
149 static inline guint STRING_WIDTH(GtkWidget *widget,
150                                  const PangoFontDescription *font, const gchar *text)
151 {
152   PangoRectangle rect;
153   PangoLayout *layout;
154
155   layout = gtk_widget_create_pango_layout (widget, text);
156   pango_layout_set_font_description (layout, font);
157
158   pango_layout_get_extents (layout, NULL, &rect);
159
160   g_object_unref(G_OBJECT(layout));
161   return PANGO_PIXELS(rect.width);
162 }
163
164 static inline guint DEFAULT_FONT_DESCENT(GtkWidget *widget) 
165
166   if(!widget->style->font_desc) return 12;
167   else {
168     PangoContext *context = gtk_widget_get_pango_context(widget); 
169     PangoFontMetrics *metrics = pango_context_get_metrics(context,
170                                   widget->style->font_desc,
171                                   pango_context_get_language(context)); 
172     guint val =  pango_font_metrics_get_descent(metrics);
173     pango_font_metrics_unref(metrics);
174     return PANGO_PIXELS(val);
175   }
176 }
177
178
179 static gint
180 yyy_row_is_visible(GtkSheet *sheet, gint row)
181 {
182   GSheetRow *row_geo = sheet->row_geometry;
183
184   return g_sheet_row_get_visibility(row_geo, row, sheet);
185 }
186
187
188 static gint
189 yyy_row_is_sensitive(GtkSheet *sheet, gint row)
190 {
191   GSheetRow *row_geo = sheet->row_geometry;
192
193   return g_sheet_row_get_sensitivity(row_geo, row, sheet);
194 }
195
196
197
198 static inline gint
199 yyy_row_count(const GtkSheet *sheet)
200 {
201   GSheetRow *row_geo = sheet->row_geometry;
202
203   return g_sheet_row_get_row_count(row_geo, sheet);
204 }
205
206 static inline gint
207 yyy_row_height(const GtkSheet *sheet, gint row)
208 {
209   GSheetRow *row_geo = sheet->row_geometry;
210
211   return g_sheet_row_get_height(row_geo, row, sheet);
212 }
213
214 static gint
215 yyy_row_top_ypixel(GtkSheet *sheet, gint row)
216 {
217   GSheetRow *geo = sheet->row_geometry;
218
219   gint y = g_sheet_row_start_pixel(geo, row, sheet);
220
221   if ( sheet->column_titles_visible ) 
222     y += sheet->column_title_area.height;
223
224   return y;
225 }
226
227
228 /* Return the row containing pixel Y */
229 static gint
230 yyy_row_ypixel_to_row(GtkSheet *sheet, gint y)
231 {
232   GSheetRow *geo = sheet->row_geometry;
233
234   gint cy = sheet->voffset;
235
236   if(sheet->column_titles_visible) 
237     cy += sheet->column_title_area.height;
238   
239   if(y < cy) return 0;
240
241
242   return g_sheet_row_pixel_to_row(geo, y - cy, sheet);
243 }
244
245
246 /* gives the top pixel of the given row in context of
247  * the sheet's voffset */
248 static inline gint
249 ROW_TOP_YPIXEL(GtkSheet *sheet, gint row)
250 {
251   return (sheet->voffset + yyy_row_top_ypixel(sheet, row));
252 }
253
254
255 /* returns the row index from a y pixel location in the 
256  * context of the sheet's voffset */
257 static inline gint 
258 ROW_FROM_YPIXEL(GtkSheet *sheet, gint y)
259 {
260   return (yyy_row_ypixel_to_row(sheet, y));
261 }
262
263 static inline const GtkSheetButton *
264 xxx_column_button(GtkSheet *sheet, gint col)
265 {
266   GSheetColumn *col_geo = sheet->column_geometry;
267
268   return g_sheet_column_get_button(col_geo, col, sheet);
269 }
270
271
272 static inline gint
273 xxx_column_left_xpixel(GtkSheet *sheet, gint col)
274 {
275   GSheetColumn *geo = sheet->column_geometry;
276
277   gint x = g_sheet_column_start_pixel(geo, col, sheet);
278
279   if ( sheet->row_titles_visible ) 
280     x += sheet->row_title_area.width;
281
282   return x;
283 }
284
285 static inline gint
286 xxx_column_width(const GtkSheet *sheet, gint col)
287 {
288   GSheetColumn *col_geo = sheet->column_geometry;
289
290   return g_sheet_column_get_width(col_geo, col, sheet);
291 }
292
293
294 static inline void
295 xxx_set_column_width(GtkSheet *sheet, gint col, gint width)
296 {
297   if ( sheet->column_geometry ) 
298     g_sheet_column_set_width(sheet->column_geometry, col, width, sheet);
299 }
300
301 static inline void
302 xxx_column_set_left_column(GtkSheet *sheet, gint col, gint i)
303 {
304   GSheetColumn *col_geo = sheet->column_geometry;
305
306   g_sheet_column_set_left_text_column(col_geo, col, i, sheet);
307 }
308
309 static inline gint
310 xxx_column_left_column(const GtkSheet *sheet, gint col)
311 {
312   GSheetColumn *col_geo = sheet->column_geometry;
313
314   return g_sheet_column_get_left_text_column(col_geo, col, sheet);
315 }
316
317 static inline void
318 xxx_column_set_right_column(GtkSheet *sheet, gint col, gint i)
319 {
320   GSheetColumn *col_geo = sheet->column_geometry;
321
322   g_sheet_column_set_right_text_column(col_geo, col, i, sheet);
323 }
324
325 static inline gint
326 xxx_column_right_column(const GtkSheet *sheet, gint col)
327 {
328   GSheetColumn *col_geo = sheet->column_geometry;
329
330   return g_sheet_column_get_right_text_column(col_geo, col, sheet);
331 }
332
333 static inline GtkJustification
334 xxx_column_justification(const GtkSheet *sheet, gint col)
335 {
336   GSheetColumn *col_geo = sheet->column_geometry;
337
338   return g_sheet_column_get_justification(col_geo, col, sheet);
339 }
340
341 static inline gint
342 xxx_column_is_visible(GtkSheet *sheet, gint col)
343 {
344   GSheetColumn *col_geo = sheet->column_geometry;
345
346   return g_sheet_column_get_visibility(col_geo, col, sheet);
347 }
348
349
350 static inline gint
351 xxx_column_is_sensitive(GtkSheet *sheet, gint col)
352 {
353   GSheetColumn *col_geo = sheet->column_geometry;
354
355   return g_sheet_column_get_sensitivity(col_geo, col, sheet);
356 }
357
358
359 /* gives the left pixel of the given column in context of
360  * the sheet's hoffset */
361 static inline gint
362 COLUMN_LEFT_XPIXEL(GtkSheet *sheet, gint ncol)
363 {
364   return (sheet->hoffset + xxx_column_left_xpixel(sheet, ncol));
365 }
366
367 static inline gint
368 xxx_column_count(const GtkSheet *sheet)
369 {
370   GSheetColumn *col_geo = sheet->column_geometry;
371
372   return g_sheet_column_get_column_count(col_geo, sheet);
373 }
374
375 /* returns the column index from a x pixel location in the 
376  * context of the sheet's hoffset */
377 static inline gint
378 COLUMN_FROM_XPIXEL (GtkSheet * sheet,
379                     gint x)
380 {
381   gint i, cx;
382
383   cx = sheet->hoffset;
384   if( sheet->row_titles_visible ) 
385     cx += sheet->row_title_area.width;
386
387   if(x < cx) return 0;
388   for (i = 0; i < xxx_column_count(sheet); i++)
389     {
390       if (x >= cx  && x <= (cx + xxx_column_width(sheet, i)) && 
391           xxx_column_is_visible(sheet, i))
392         return i;
393       if( xxx_column_is_visible(sheet, i))
394         cx += xxx_column_width(sheet, i);
395     }
396
397   /* no match */
398   return xxx_column_count(sheet) - 1;
399 }
400
401 /* returns the total height of the sheet */
402 static inline gint SHEET_HEIGHT(GtkSheet *sheet)
403 {
404   const gint n_rows = yyy_row_count(sheet);
405
406   return yyy_row_top_ypixel(sheet, n_rows - 1) + 
407     yyy_row_height(sheet, n_rows - 1);
408 }
409
410
411 static inline const GtkSheetButton *
412 yyy_row_button(GtkSheet *sheet, gint row)
413 {
414   GSheetRow *row_geo = sheet->row_geometry;
415
416   return g_sheet_row_get_button(row_geo, row, sheet);
417 }
418
419
420
421
422 static inline void
423 yyy_set_row_height(GtkSheet *sheet, gint row, gint height)
424 {
425   if ( sheet->row_geometry ) 
426     g_sheet_row_set_height(sheet->row_geometry, row, height, sheet);
427 }
428
429
430
431 /* returns the total width of the sheet */
432 static inline gint SHEET_WIDTH(GtkSheet *sheet)
433 {
434   gint i,cx;
435
436   cx = ( sheet->row_titles_visible ? sheet->row_title_area.width : 0);
437  
438   for (i=0; i < xxx_column_count(sheet); i++)
439     if(xxx_column_is_visible(sheet, i)) cx += xxx_column_width(sheet, i);
440   
441   return cx;
442 }
443
444 #define MIN_VISIBLE_ROW(sheet) sheet->view.row0
445 #define MAX_VISIBLE_ROW(sheet) sheet->view.rowi
446 #define MIN_VISIBLE_COLUMN(sheet) sheet->view.col0
447 #define MAX_VISIBLE_COLUMN(sheet) sheet->view.coli
448
449
450 static inline gint
451 POSSIBLE_XDRAG(GtkSheet *sheet, gint x, gint *drag_column)
452 {
453  gint column, xdrag;
454
455  column=COLUMN_FROM_XPIXEL(sheet, x);
456  *drag_column=column;
457
458  xdrag=COLUMN_LEFT_XPIXEL(sheet,column)+CELL_SPACING;
459  if(x <= xdrag+DRAG_WIDTH/2 && column != 0){
460    while(! xxx_column_is_visible(sheet, column-1) && column>0) column--;
461    *drag_column=column-1;
462    return xxx_column_is_sensitive(sheet, column-1);
463  }
464
465  xdrag+= xxx_column_width(sheet, column);
466  if(x >= xdrag-DRAG_WIDTH/2 && x <= xdrag+DRAG_WIDTH/2)
467    return xxx_column_is_sensitive(sheet, column);
468
469  return FALSE;
470
471
472 static inline gint
473 POSSIBLE_YDRAG(GtkSheet *sheet, gint y, gint *drag_row)
474 {
475  gint row, ydrag;
476
477  row=ROW_FROM_YPIXEL(sheet, y);
478  *drag_row=row;
479
480  ydrag=ROW_TOP_YPIXEL(sheet,row)+CELL_SPACING;
481  if(y <= ydrag+DRAG_WIDTH/2 && row != 0){
482    while(!yyy_row_is_visible(sheet, row-1) && row>0) row--;
483    *drag_row=row-1;
484    return yyy_row_is_sensitive(sheet, row-1);
485  }
486
487  ydrag+=yyy_row_height(sheet, row);
488
489  if(y >= ydrag-DRAG_WIDTH/2 && y <= ydrag+DRAG_WIDTH/2)
490    return yyy_row_is_sensitive(sheet, row);
491  
492  
493  return FALSE;
494 }        
495
496 static inline gint POSSIBLE_DRAG(GtkSheet *sheet, gint x, gint y,
497                             gint *drag_row, gint *drag_column)
498 {
499   gint ydrag, xdrag;
500
501   *drag_column=COLUMN_FROM_XPIXEL(sheet,x);
502   *drag_row=ROW_FROM_YPIXEL(sheet,y);
503
504   if(x>=COLUMN_LEFT_XPIXEL(sheet,sheet->range.col0)-DRAG_WIDTH/2 &&
505      x<=COLUMN_LEFT_XPIXEL(sheet,sheet->range.coli)+
506      xxx_column_width(sheet, sheet->range.coli) + DRAG_WIDTH/2){
507     ydrag=ROW_TOP_YPIXEL(sheet,sheet->range.row0);
508      if(y>=ydrag-DRAG_WIDTH/2 && y<=ydrag+DRAG_WIDTH/2){
509         *drag_row=sheet->range.row0;
510         return TRUE;
511      }
512      ydrag=ROW_TOP_YPIXEL(sheet,sheet->range.rowi)+
513            yyy_row_height(sheet, sheet->range.rowi);
514      if(y>=ydrag-DRAG_WIDTH/2 && y<=ydrag+DRAG_WIDTH/2){
515         *drag_row=sheet->range.rowi;
516         return TRUE;
517      }
518   }
519
520   if(y>=ROW_TOP_YPIXEL(sheet,sheet->range.row0)-DRAG_WIDTH/2 &&
521      y<=ROW_TOP_YPIXEL(sheet,sheet->range.rowi)+
522         yyy_row_height(sheet, sheet->range.rowi)+DRAG_WIDTH/2){
523      xdrag=COLUMN_LEFT_XPIXEL(sheet,sheet->range.col0);
524      if(x>=xdrag-DRAG_WIDTH/2 && x<=xdrag+DRAG_WIDTH/2){
525         *drag_column=sheet->range.col0;
526         return TRUE;
527      }
528      xdrag=COLUMN_LEFT_XPIXEL(sheet,sheet->range.coli)+
529            xxx_column_width(sheet, sheet->range.coli);
530      if(x>=xdrag-DRAG_WIDTH/2 && x<=xdrag+DRAG_WIDTH/2){
531         *drag_column=sheet->range.coli;
532         return TRUE;
533      }
534   }
535   return FALSE;
536 }
537
538 static inline gint POSSIBLE_RESIZE(GtkSheet *sheet, gint x, gint y,
539                             gint *drag_row, gint *drag_column)
540 {
541   gint xdrag, ydrag;
542   
543   xdrag=COLUMN_LEFT_XPIXEL(sheet,sheet->range.coli)+
544     xxx_column_width(sheet, sheet->range.coli);
545
546   ydrag=ROW_TOP_YPIXEL(sheet,sheet->range.rowi)+
547            yyy_row_height(sheet, sheet->range.rowi);
548
549   if(sheet->state == GTK_SHEET_COLUMN_SELECTED) 
550         ydrag = ROW_TOP_YPIXEL(sheet, sheet->view.row0);
551
552   if(sheet->state == GTK_SHEET_ROW_SELECTED)
553         xdrag = COLUMN_LEFT_XPIXEL(sheet, sheet->view.col0);
554
555   *drag_column=COLUMN_FROM_XPIXEL(sheet,x);
556   *drag_row=ROW_FROM_YPIXEL(sheet,y);
557
558   if(x>=xdrag-DRAG_WIDTH/2 && x<=xdrag+DRAG_WIDTH/2 &&
559      y>=ydrag-DRAG_WIDTH/2 && y<=ydrag+DRAG_WIDTH/2) return TRUE;
560
561   return FALSE;  
562 }
563
564 static void gtk_sheet_class_init                (GtkSheetClass * klass);
565 static void gtk_sheet_init                      (GtkSheet * sheet);
566 static void gtk_sheet_destroy                   (GtkObject * object);
567 static void gtk_sheet_finalize                  (GObject * object);
568 static void gtk_sheet_style_set                 (GtkWidget *widget,
569                                                  GtkStyle  *previous_style);
570 static void gtk_sheet_realize                   (GtkWidget * widget);
571 static void gtk_sheet_unrealize                 (GtkWidget * widget);
572 static void gtk_sheet_map                       (GtkWidget * widget);
573 static void gtk_sheet_unmap                     (GtkWidget * widget);
574 static gint gtk_sheet_expose                    (GtkWidget * widget,
575                                                  GdkEventExpose * event);
576 static void gtk_sheet_forall                    (GtkContainer *container,
577                                                  gboolean include_internals,
578                                                  GtkCallback  callback, 
579                                                  gpointer  callback_data); 
580
581 static void gtk_sheet_set_scroll_adjustments    (GtkSheet *sheet,
582                                                  GtkAdjustment *hadjustment,
583                                                  GtkAdjustment *vadjustment);
584
585 static gint gtk_sheet_button_press              (GtkWidget * widget,
586                                                  GdkEventButton * event);
587 static gint gtk_sheet_button_release            (GtkWidget * widget,
588                                                  GdkEventButton * event);
589 static gint gtk_sheet_motion                    (GtkWidget * widget,
590                                                  GdkEventMotion * event);
591 static gint gtk_sheet_entry_key_press           (GtkWidget *widget,
592                                                  GdkEventKey *key);
593 static gint gtk_sheet_key_press                 (GtkWidget *widget,
594                                                  GdkEventKey *key);
595 static void gtk_sheet_size_request              (GtkWidget * widget,
596                                                  GtkRequisition * requisition);
597 static void gtk_sheet_size_allocate             (GtkWidget * widget,
598                                                  GtkAllocation * allocation);
599
600 /* Sheet queries */
601
602 static gint gtk_sheet_range_isvisible           (GtkSheet * sheet,
603                                                  GtkSheetRange range);
604 static gint gtk_sheet_cell_isvisible            (GtkSheet * sheet,
605                                                  gint row, gint column);
606 /* Clipped Range */
607
608 static gint gtk_sheet_scroll                    (gpointer data);
609 static gint gtk_sheet_flash                     (gpointer data);
610
611 /* Drawing Routines */
612
613 /* draw cell background and frame */
614 static void gtk_sheet_cell_draw_default         (GtkSheet *sheet, 
615                                                  gint row, gint column);
616
617 /* draw cell border */
618 static void gtk_sheet_cell_draw_border          (GtkSheet *sheet, 
619                                                  gint row, gint column, 
620                                                  gint mask);
621
622 /* draw cell contents */
623 static void gtk_sheet_cell_draw_label           (GtkSheet *sheet, 
624                                                  gint row, gint column);
625
626 /* draw visible part of range. If range==NULL then draw the whole screen */
627 static void gtk_sheet_range_draw                (GtkSheet *sheet, 
628                                                  const GtkSheetRange *range);
629
630 /* highlight the visible part of the selected range */
631 static void gtk_sheet_range_draw_selection      (GtkSheet *sheet, 
632                                                  GtkSheetRange range);
633
634 /* Selection */
635
636 static gint gtk_sheet_move_query                (GtkSheet *sheet, 
637                                                  gint row, gint column);
638 static void gtk_sheet_real_select_range         (GtkSheet * sheet,
639                                                  GtkSheetRange * range);
640 static void gtk_sheet_real_unselect_range       (GtkSheet * sheet,
641                                                  const GtkSheetRange * range);
642 static void gtk_sheet_extend_selection          (GtkSheet *sheet, 
643                                                  gint row, gint column);
644 static void gtk_sheet_new_selection             (GtkSheet *sheet, 
645                                                  GtkSheetRange *range);
646 static void gtk_sheet_draw_border               (GtkSheet *sheet, 
647                                                  GtkSheetRange range);
648 static void gtk_sheet_draw_corners              (GtkSheet *sheet,
649                                                  GtkSheetRange range);
650
651
652 /* Active Cell handling */
653
654 static void gtk_sheet_entry_changed             (GtkWidget *widget, 
655                                                  gpointer data);
656 static gboolean gtk_sheet_deactivate_cell       (GtkSheet *sheet);
657 static void gtk_sheet_hide_active_cell          (GtkSheet *sheet);
658 static gboolean gtk_sheet_activate_cell         (GtkSheet *sheet, 
659                                                  gint row, gint col);
660 static void gtk_sheet_draw_active_cell          (GtkSheet *sheet);
661 static void gtk_sheet_show_active_cell          (GtkSheet *sheet);
662 static void gtk_sheet_click_cell                (GtkSheet *sheet, 
663                                                  gint row, 
664                                                  gint column,
665                                                  gboolean *veto);
666
667 /* Backing Pixmap */
668
669 static void gtk_sheet_make_backing_pixmap       (GtkSheet *sheet, 
670                                                  guint width, guint height);
671 static void gtk_sheet_draw_backing_pixmap       (GtkSheet *sheet, 
672                                                  GtkSheetRange range);
673 /* Scrollbars */
674
675 static void adjust_scrollbars                   (GtkSheet * sheet);
676 static void vadjustment_changed                 (GtkAdjustment * adjustment,
677                                                  gpointer data);
678 static void hadjustment_changed                 (GtkAdjustment * adjustment,
679                                                  gpointer data);
680 static void vadjustment_value_changed           (GtkAdjustment * adjustment,
681                                                  gpointer data);
682 static void hadjustment_value_changed           (GtkAdjustment * adjustment,
683                                                  gpointer data);
684
685
686 static void draw_xor_vline                      (GtkSheet * sheet);
687 static void draw_xor_hline                      (GtkSheet * sheet);
688 static void draw_xor_rectangle                  (GtkSheet *sheet, 
689                                                  GtkSheetRange range);
690 static void gtk_sheet_draw_flashing_range       (GtkSheet *sheet, 
691                                                  GtkSheetRange range);
692 static guint new_column_width                   (GtkSheet * sheet,
693                                                  gint column,
694                                                  gint * x);
695 static guint new_row_height                     (GtkSheet * sheet,
696                                                  gint row,
697                                                  gint * y);
698 /* Sheet Button */
699
700 static void create_global_button                (GtkSheet *sheet);
701 static void global_button_clicked               (GtkWidget *widget, 
702                                                  gpointer data);
703 /* Sheet Entry */
704
705 static void create_sheet_entry                  (GtkSheet *sheet);
706 static void gtk_sheet_size_allocate_entry       (GtkSheet *sheet);
707 static void gtk_sheet_entry_set_max_size        (GtkSheet *sheet);
708
709 /* Sheet button gadgets */
710
711 static void size_allocate_column_title_buttons  (GtkSheet * sheet);
712 static void size_allocate_row_title_buttons     (GtkSheet * sheet);
713
714
715 static void gtk_sheet_button_draw               (GtkSheet *sheet, 
716                                                  gint row, gint column);
717 static void size_allocate_global_button         (GtkSheet *sheet);
718 static void gtk_sheet_button_size_request       (GtkSheet *sheet,
719                                                  const GtkSheetButton *button, 
720                                                  GtkRequisition *requisition);
721
722 /* Attributes routines */
723 static void init_attributes                     (GtkSheet *sheet, gint col,  
724                                                  GtkSheetCellAttr *attributes);
725
726
727 /* Memory allocation routines */
728 static void gtk_sheet_real_range_clear          (GtkSheet *sheet, 
729                                                  const GtkSheetRange *range, 
730                                                  gboolean delete);
731 static void gtk_sheet_real_cell_clear           (GtkSheet *sheet, 
732                                                  gint row,
733                                                  gint column,
734                                                  gboolean delete);
735
736
737 /* Container Functions */
738 static void gtk_sheet_remove                    (GtkContainer *container,
739                                                  GtkWidget *widget);
740 static void gtk_sheet_realize_child             (GtkSheet *sheet,
741                                                  GtkSheetChild *child);
742 static void gtk_sheet_position_child            (GtkSheet *sheet,
743                                                  GtkSheetChild *child);
744 static void gtk_sheet_position_children         (GtkSheet *sheet);
745 static void gtk_sheet_child_show                (GtkSheetChild *child); 
746 static void gtk_sheet_child_hide                (GtkSheetChild *child); 
747 static void gtk_sheet_column_size_request       (GtkSheet *sheet,
748                                                  gint col,
749                                                  guint *requisition);
750 static void gtk_sheet_row_size_request          (GtkSheet *sheet,
751                                                  gint row,
752                                                  guint *requisition);
753
754
755 /* Signals */
756
757 extern void 
758 _gtkextra_signal_emit(GtkObject *object, guint signal_id, ...);
759
760 enum {
761       SELECT_ROW, 
762       SELECT_COLUMN, 
763       DOUBLE_CLICK_ROW,
764       DOUBLE_CLICK_COLUMN,
765       SELECT_RANGE,
766       CLIP_RANGE,
767       RESIZE_RANGE,
768       MOVE_RANGE,
769       TRAVERSE, 
770       DEACTIVATE, 
771       ACTIVATE,
772       SET_CELL,
773       CLEAR_CELL,
774       CHANGED,
775       NEW_COL_WIDTH,
776       NEW_ROW_HEIGHT,
777       LAST_SIGNAL
778 };
779
780 static GtkContainerClass *parent_class = NULL;
781 static guint sheet_signals[LAST_SIGNAL] = {0};
782
783
784 GType
785 gtk_sheet_get_type ()
786 {
787   static GType sheet_type = 0;
788                                                                                 
789   if (!sheet_type)
790     {
791       static const GTypeInfo sheet_info =
792       {
793         sizeof (GtkSheetClass),
794         NULL,
795         NULL,
796         (GClassInitFunc) gtk_sheet_class_init,
797         NULL,        
798         NULL,       
799         sizeof (GtkSheet),
800         0,         
801         (GInstanceInitFunc) gtk_sheet_init,
802         NULL,
803       };
804       sheet_type =
805         g_type_register_static (GTK_TYPE_CONTAINER, "GtkSheet",
806                                 &sheet_info, 0);
807     }
808   return sheet_type;
809 }
810
811 static GtkSheetRange*
812 gtk_sheet_range_copy (const GtkSheetRange *range)
813 {
814   GtkSheetRange *new_range;
815
816   g_return_val_if_fail (range != NULL, NULL);
817
818   new_range = g_new (GtkSheetRange, 1);
819
820   *new_range = *range;
821
822   return new_range;
823 }
824
825 static void
826 gtk_sheet_range_free (GtkSheetRange *range)
827 {
828   g_return_if_fail (range != NULL);
829
830   g_free (range);
831 }
832
833 GType
834 gtk_sheet_range_get_type (void)
835 {
836   static GType sheet_range_type=0;
837
838   if(!sheet_range_type)
839   {
840     sheet_range_type = g_boxed_type_register_static("GtkSheetRange", (GBoxedCopyFunc)gtk_sheet_range_copy, (GBoxedFreeFunc)gtk_sheet_range_free);
841   }
842   return sheet_range_type;
843
844 }
845
846 static void
847 gtk_sheet_class_init (GtkSheetClass * klass)
848 {
849   GtkObjectClass *object_class;
850   GtkWidgetClass *widget_class;
851   GtkContainerClass *container_class;
852   GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
853
854   object_class = (GtkObjectClass *) klass;
855   widget_class = (GtkWidgetClass *) klass;
856   container_class = (GtkContainerClass *) klass;
857
858   parent_class = g_type_class_peek_parent (klass);
859
860   /**
861    * GtkSheet::select-row
862    * @sheet: the sheet widget that emitted the signal
863    * @row: the newly selected row index
864    *
865    * A row has been selected.
866    */
867   sheet_signals[SELECT_ROW] =
868     gtk_signal_new ("select-row",
869                     GTK_RUN_LAST,
870                     GTK_CLASS_TYPE(object_class),
871                     GTK_SIGNAL_OFFSET (GtkSheetClass, select_row),
872                     gtkextra_VOID__INT,
873                     GTK_TYPE_NONE, 1, GTK_TYPE_INT);
874
875   /**
876    * GtkSheet::select-column
877    * @sheet: the sheet widget that emitted the signal
878    * @column: the newly selected column index
879    *
880    * A column has been selected.
881    */
882   sheet_signals[SELECT_COLUMN] =
883     gtk_signal_new ("select-column",
884                     GTK_RUN_LAST,
885                     GTK_CLASS_TYPE(object_class),
886                     GTK_SIGNAL_OFFSET (GtkSheetClass, select_column),
887                     gtkextra_VOID__INT,
888                     GTK_TYPE_NONE, 1, GTK_TYPE_INT);
889
890
891   /**
892    * GtkSheet::double-click-row
893    * @sheet: the sheet widget that emitted the signal
894    * @row: the row that was double clicked.
895    *
896    * A row's title button has been double clicked
897    */
898   sheet_signals[DOUBLE_CLICK_ROW] =
899     gtk_signal_new ("double-click-row",
900                     GTK_RUN_LAST,
901                     GTK_CLASS_TYPE(object_class),
902                     0,
903                     gtkextra_VOID__INT,
904                     GTK_TYPE_NONE, 1, GTK_TYPE_INT);
905
906
907   /**
908    * GtkSheet::double-click-column
909    * @sheet: the sheet widget that emitted the signal
910    * @column: the column that was double clicked.
911    *
912    * A column's title button has been double clicked
913    */
914   sheet_signals[DOUBLE_CLICK_COLUMN] =
915     gtk_signal_new ("double-click-column",
916                     GTK_RUN_LAST,
917                     GTK_CLASS_TYPE(object_class),
918                     0,
919                     gtkextra_VOID__INT,
920                     GTK_TYPE_NONE, 1, GTK_TYPE_INT);
921
922   sheet_signals[SELECT_RANGE] =
923     gtk_signal_new ("select-range",
924                     GTK_RUN_LAST,
925                     GTK_CLASS_TYPE(object_class),
926                     GTK_SIGNAL_OFFSET (GtkSheetClass, select_range),
927                     gtkextra_VOID__BOXED,
928                     GTK_TYPE_NONE, 1, GTK_TYPE_SHEET_RANGE);
929
930   sheet_signals[CLIP_RANGE] =
931     gtk_signal_new ("clip-range",
932                     GTK_RUN_LAST,
933                     GTK_CLASS_TYPE(object_class),
934                     GTK_SIGNAL_OFFSET (GtkSheetClass, clip_range),
935                     gtkextra_VOID__BOXED,
936                     GTK_TYPE_NONE, 1, GTK_TYPE_SHEET_RANGE);
937
938   sheet_signals[RESIZE_RANGE] =
939     gtk_signal_new ("resize-range",
940                     GTK_RUN_LAST,
941                     GTK_CLASS_TYPE(object_class),
942                     GTK_SIGNAL_OFFSET (GtkSheetClass, resize_range),
943                     gtkextra_VOID__BOXED_BOXED,
944                     GTK_TYPE_NONE, 2, GTK_TYPE_SHEET_RANGE, GTK_TYPE_SHEET_RANGE);
945   sheet_signals[MOVE_RANGE] =
946     gtk_signal_new ("move-range",
947                     GTK_RUN_LAST,
948                     GTK_CLASS_TYPE(object_class),
949                     GTK_SIGNAL_OFFSET (GtkSheetClass, move_range),
950                     gtkextra_VOID__BOXED_BOXED,
951                     GTK_TYPE_NONE, 2, GTK_TYPE_SHEET_RANGE, GTK_TYPE_SHEET_RANGE);
952   sheet_signals[TRAVERSE] =
953     gtk_signal_new ("traverse",
954                     GTK_RUN_LAST,
955                     GTK_CLASS_TYPE(object_class),
956                     GTK_SIGNAL_OFFSET (GtkSheetClass, traverse),
957                     gtkextra_BOOLEAN__INT_INT_POINTER_POINTER,
958                     GTK_TYPE_BOOL, 4, GTK_TYPE_INT, GTK_TYPE_INT,
959                                       GTK_TYPE_POINTER, GTK_TYPE_POINTER);
960
961   sheet_signals[DEACTIVATE] =
962     gtk_signal_new ("deactivate",
963                     GTK_RUN_LAST,
964                     GTK_CLASS_TYPE(object_class),
965                     GTK_SIGNAL_OFFSET (GtkSheetClass, deactivate),
966                     gtkextra_BOOLEAN__INT_INT,
967                     GTK_TYPE_BOOL, 2, GTK_TYPE_INT, GTK_TYPE_INT);
968
969   sheet_signals[ACTIVATE] =
970     gtk_signal_new ("activate",
971                     GTK_RUN_LAST,
972                     GTK_CLASS_TYPE(object_class),
973                     GTK_SIGNAL_OFFSET (GtkSheetClass, activate),
974                     gtkextra_BOOLEAN__INT_INT,
975                     GTK_TYPE_BOOL, 2, GTK_TYPE_INT, GTK_TYPE_INT);
976
977   sheet_signals[SET_CELL] =
978     gtk_signal_new ("set-cell",
979                     GTK_RUN_LAST,
980                     GTK_CLASS_TYPE(object_class),
981                     GTK_SIGNAL_OFFSET (GtkSheetClass, set_cell),
982                     gtkextra_VOID__INT_INT,
983                     GTK_TYPE_NONE, 2, GTK_TYPE_INT, GTK_TYPE_INT);
984
985   sheet_signals[CLEAR_CELL] =
986     gtk_signal_new ("clear-cell",
987                     GTK_RUN_LAST,
988                     GTK_CLASS_TYPE(object_class),
989                     GTK_SIGNAL_OFFSET (GtkSheetClass, clear_cell),
990                     gtkextra_VOID__INT_INT,
991                     GTK_TYPE_NONE, 2, GTK_TYPE_INT, GTK_TYPE_INT);
992
993   sheet_signals[CHANGED] =
994     gtk_signal_new ("changed",
995                     GTK_RUN_LAST,
996                     GTK_CLASS_TYPE(object_class),
997                     GTK_SIGNAL_OFFSET (GtkSheetClass, changed),
998                     gtkextra_VOID__INT_INT,
999                     GTK_TYPE_NONE, 2, GTK_TYPE_INT, GTK_TYPE_INT);
1000
1001   sheet_signals[NEW_COL_WIDTH] =
1002     gtk_signal_new ("new-column-width",
1003                     GTK_RUN_LAST,
1004                     GTK_CLASS_TYPE(object_class),
1005                     GTK_SIGNAL_OFFSET (GtkSheetClass, changed),
1006                     gtkextra_VOID__INT_INT,
1007                     GTK_TYPE_NONE, 2, GTK_TYPE_INT, GTK_TYPE_INT);
1008
1009   sheet_signals[NEW_ROW_HEIGHT] =
1010     gtk_signal_new ("new-row-height",
1011                     GTK_RUN_LAST,
1012                     GTK_CLASS_TYPE(object_class),
1013                     GTK_SIGNAL_OFFSET (GtkSheetClass, changed),
1014                     gtkextra_VOID__INT_INT,
1015                     GTK_TYPE_NONE, 2, GTK_TYPE_INT, GTK_TYPE_INT);
1016
1017   widget_class->set_scroll_adjustments_signal =
1018     gtk_signal_new ("set-scroll-adjustments",
1019                     GTK_RUN_LAST,
1020                     GTK_CLASS_TYPE(object_class),
1021                     GTK_SIGNAL_OFFSET (GtkSheetClass, set_scroll_adjustments),
1022                     gtkextra_VOID__OBJECT_OBJECT,
1023                     GTK_TYPE_NONE, 2, GTK_TYPE_ADJUSTMENT, GTK_TYPE_ADJUSTMENT);
1024
1025
1026   container_class->add = NULL;
1027   container_class->remove = gtk_sheet_remove;
1028   container_class->forall = gtk_sheet_forall;
1029
1030   object_class->destroy = gtk_sheet_destroy;
1031   gobject_class->finalize = gtk_sheet_finalize;
1032
1033   widget_class->realize = gtk_sheet_realize;
1034   widget_class->unrealize = gtk_sheet_unrealize;
1035   widget_class->map = gtk_sheet_map;
1036   widget_class->unmap = gtk_sheet_unmap;
1037   widget_class->style_set = gtk_sheet_style_set;
1038   widget_class->button_press_event = gtk_sheet_button_press;
1039   widget_class->button_release_event = gtk_sheet_button_release;
1040   widget_class->motion_notify_event = gtk_sheet_motion;
1041   widget_class->key_press_event = gtk_sheet_key_press;
1042   widget_class->expose_event = gtk_sheet_expose;
1043   widget_class->size_request = gtk_sheet_size_request;
1044   widget_class->size_allocate = gtk_sheet_size_allocate;
1045   widget_class->focus_in_event = NULL;
1046   widget_class->focus_out_event = NULL;
1047
1048   klass->set_scroll_adjustments = gtk_sheet_set_scroll_adjustments;
1049   klass->select_row = NULL;
1050   klass->select_column = NULL;
1051   klass->select_range = NULL;
1052   klass->clip_range = NULL;
1053   klass->resize_range = NULL;
1054   klass->move_range = NULL;
1055   klass->traverse = NULL;
1056   klass->deactivate = NULL;
1057   klass->activate = NULL;
1058   klass->set_cell = NULL;
1059   klass->clear_cell = NULL;
1060   klass->changed = NULL;
1061
1062 }
1063
1064 static void 
1065 gtk_sheet_init (GtkSheet *sheet)
1066 {
1067   sheet->column_geometry = NULL;
1068   sheet->row_geometry = NULL;
1069
1070   sheet->children = NULL;
1071
1072   sheet->flags = 0;
1073   sheet->selection_mode = GTK_SELECTION_BROWSE;
1074   sheet->freeze_count = 0;
1075   sheet->state = GTK_SHEET_NORMAL;
1076
1077   GTK_WIDGET_UNSET_FLAGS (sheet, GTK_NO_WINDOW);
1078   GTK_WIDGET_SET_FLAGS (sheet, GTK_CAN_FOCUS);
1079
1080   sheet->view.row0 = 0;
1081   sheet->view.col0 = 0;
1082   sheet->view.rowi = 0;
1083   sheet->view.coli = 0;
1084
1085   sheet->column_title_window=NULL;
1086   sheet->column_title_area.x=0;
1087   sheet->column_title_area.y=0;
1088   sheet->column_title_area.width=0;
1089   sheet->column_title_area.height=DEFAULT_ROW_HEIGHT(GTK_WIDGET(sheet));
1090  
1091   sheet->row_title_window=NULL;
1092   sheet->row_title_area.x=0;
1093   sheet->row_title_area.y=0;
1094   sheet->row_title_area.width = DEFAULT_COLUMN_WIDTH;
1095   sheet->row_title_area.height=0;
1096
1097
1098   sheet->active_cell.row=0;
1099   sheet->active_cell.col=0;
1100   sheet->selection_cell.row=0;
1101   sheet->selection_cell.col=0;
1102
1103   sheet->sheet_entry=NULL;
1104   sheet->pixmap=NULL;
1105
1106   sheet->range.row0=0;
1107   sheet->range.rowi=0;
1108   sheet->range.col0=0;
1109   sheet->range.coli=0;
1110
1111   sheet->state=GTK_SHEET_NORMAL;
1112
1113   sheet->sheet_window = NULL;
1114   sheet->sheet_window_width = 0;
1115   sheet->sheet_window_height = 0;
1116   sheet->sheet_entry = NULL;
1117   sheet->button = NULL;
1118
1119   sheet->hoffset = 0;
1120   sheet->voffset = 0;
1121
1122   sheet->hadjustment = NULL;
1123   sheet->vadjustment = NULL;
1124
1125   sheet->cursor_drag = gdk_cursor_new(GDK_PLUS);
1126   sheet->xor_gc = NULL;
1127   sheet->fg_gc = NULL;
1128   sheet->bg_gc = NULL;
1129   sheet->x_drag = 0;
1130   sheet->y_drag = 0;
1131
1132   gdk_color_parse("white", &sheet->bg_color);
1133   gdk_color_alloc(gdk_colormap_get_system(), &sheet->bg_color);
1134   gdk_color_parse("gray", &sheet->grid_color);
1135   gdk_color_alloc(gdk_colormap_get_system(), &sheet->grid_color);
1136   sheet->show_grid = TRUE;
1137 }
1138
1139
1140 /* Callback which occurs whenever columns are inserted/deleted in the model */
1141 static void 
1142 columns_inserted_deleted_callback (GSheetModel *model, gint first_column, gint n_columns,
1143                       gpointer data)
1144 {
1145   GtkSheet *sheet = GTK_SHEET(data);
1146
1147   GtkSheetRange range;
1148   gint model_columns = g_sheet_model_get_column_count(model);
1149
1150
1151   /* Need to update all the columns starting from the first column and onwards.
1152    * Previous column are unchanged, so don't need to be updated.
1153    */
1154   range.col0 = first_column;
1155   range.row0 = 0;
1156   range.coli = xxx_column_count(sheet) - 1;
1157   range.rowi = yyy_row_count(sheet) - 1;
1158
1159   if (sheet->active_cell.col >= model_columns)
1160     gtk_sheet_activate_cell(sheet, sheet->active_cell.row, model_columns - 1);
1161   
1162   gtk_sheet_range_draw(sheet, &range);
1163 }
1164
1165
1166 /* Callback which occurs whenever rows are inserted/deleted in the model */
1167 static void 
1168 rows_inserted_deleted_callback (GSheetModel *m, gint first_row, gint n_rows,
1169                       gpointer data)
1170 {
1171   GtkSheet *sheet = GTK_SHEET(data);
1172
1173   GtkSheetRange range;
1174
1175   /* Need to update all the rows starting from the first row and onwards.
1176    * Previous rows are unchanged, so don't need to be updated.
1177    */
1178   range.row0 = first_row;
1179   range.col0 = 0;
1180   range.rowi = yyy_row_count(sheet) - 1;
1181   range.coli = xxx_column_count(sheet) - 1;
1182   
1183   gtk_sheet_range_draw(sheet, &range);
1184
1185 }
1186
1187 /* 
1188    If row0 or rowi are negative, then all rows will be updated.
1189    If col0 or coli are negative, then all columns will be updated.
1190 */
1191 static void 
1192 range_update_callback (GSheetModel *m, gint row0, gint col0, 
1193      gint rowi, gint coli, gpointer data)
1194 {
1195   GtkSheet *sheet = GTK_SHEET(data);
1196
1197   GtkSheetRange range;
1198
1199   range.row0 = row0;
1200   range.col0 = col0;
1201   range.rowi = rowi;
1202   range.coli = coli;
1203
1204   if( ( row0 < 0  && col0 < 0 ) || ( rowi < 0  && coli < 0 ) )
1205     {
1206       gtk_sheet_range_draw(sheet, NULL);
1207       return;
1208     }
1209   else if ( row0 < 0 || rowi < 0 )
1210     {
1211       range.row0=MIN_VISIBLE_ROW(sheet);
1212       range.rowi=MAX_VISIBLE_ROW(sheet);
1213     }
1214   else if ( col0 < 0 || coli < 0 )
1215     {
1216       range.col0=MIN_VISIBLE_COLUMN(sheet);
1217       range.coli=MAX_VISIBLE_COLUMN(sheet);
1218     }
1219   
1220   gtk_sheet_range_draw(sheet, &range);
1221 }
1222
1223
1224 static void gtk_sheet_construct (GtkSheet *sheet,
1225                                  GSheetRow *vgeo,
1226                                  GSheetColumn *hgeo,
1227                                  const gchar *title);
1228
1229
1230 /**
1231  * gtk_sheet_new:
1232  * @rows: initial number of rows
1233  * @columns: initial number of columns
1234  * @title: sheet title
1235  * @model: the model to use for the sheet data
1236  *
1237  * Creates a new sheet widget with the given number of rows and columns.
1238  *
1239  * Returns: the new sheet widget
1240  */
1241 GtkWidget *
1242 gtk_sheet_new (GSheetRow *vgeo, GSheetColumn *hgeo, const gchar *title,
1243                GSheetModel *model)
1244 {
1245   GtkWidget *widget;
1246
1247   widget = gtk_type_new (gtk_sheet_get_type ());
1248
1249   gtk_sheet_construct(GTK_SHEET(widget), vgeo, hgeo, title);
1250
1251   if (model) 
1252     gtk_sheet_set_model(GTK_SHEET(widget), model);
1253
1254
1255   return widget;
1256 }
1257
1258
1259 /**
1260  * gtk_sheet_set_model
1261  * @sheet: the sheet to set the model for
1262  * @model: the model to use for the sheet data
1263  *
1264  * Sets the model for a GtkSheet
1265  *
1266  */
1267 void
1268 gtk_sheet_set_model(GtkSheet *sheet, GSheetModel *model)
1269 {
1270   g_return_if_fail (GTK_IS_SHEET (sheet));
1271   g_return_if_fail (G_IS_SHEET_MODEL (model));
1272
1273   sheet->model = model;
1274
1275   g_signal_connect(model, "range_changed", 
1276                    G_CALLBACK(range_update_callback), sheet);
1277
1278   g_signal_connect(model, "rows_inserted",
1279                    G_CALLBACK(rows_inserted_deleted_callback), sheet);
1280
1281   g_signal_connect(model, "rows_deleted",
1282                    G_CALLBACK(rows_inserted_deleted_callback), sheet);
1283
1284   g_signal_connect(model, "columns_inserted",
1285                    G_CALLBACK(columns_inserted_deleted_callback), sheet);
1286
1287   g_signal_connect(model, "columns_deleted",
1288                    G_CALLBACK(columns_inserted_deleted_callback), sheet);
1289
1290 }
1291
1292
1293
1294 static void
1295 column_titles_changed(GtkWidget *w, gint first, gint n_columns, gpointer data)
1296 {
1297   GtkSheet *sheet = GTK_SHEET(data);
1298
1299
1300   if(!GTK_SHEET_IS_FROZEN(sheet)){  
1301     gint i;
1302     for ( i = first ; i <= MAX_VISIBLE_COLUMN(sheet) ; ++i ) 
1303       {
1304         gtk_sheet_button_draw(sheet, -1, i);
1305         gtk_signal_emit(GTK_OBJECT(sheet), sheet_signals[CHANGED], -1, i);
1306       }
1307   }
1308 }
1309
1310 static void
1311 gtk_sheet_construct (GtkSheet *sheet, 
1312                      GSheetRow *vgeo,
1313                      GSheetColumn *hgeo,
1314                      const gchar *title)
1315 {
1316   g_return_if_fail(G_IS_SHEET_COLUMN(hgeo));
1317   g_return_if_fail(G_IS_SHEET_ROW(vgeo));
1318
1319   sheet->column_geometry = hgeo;
1320   sheet->row_geometry = vgeo;
1321   
1322
1323   sheet->columns_resizable = TRUE;
1324   sheet->rows_resizable = TRUE;
1325
1326   sheet->row_titles_visible = TRUE;
1327   sheet->row_title_area.width = DEFAULT_COLUMN_WIDTH;
1328
1329   sheet->column_titles_visible = TRUE;
1330   sheet->autoscroll = TRUE;
1331   sheet->justify_entry = TRUE;
1332
1333
1334   /* create sheet entry */
1335   sheet->entry_type = 0;
1336   create_sheet_entry (sheet);
1337
1338   /* create global selection button */
1339   create_global_button(sheet);
1340
1341   if(title)
1342      sheet->name = g_strdup(title);
1343
1344   g_signal_connect(sheet->column_geometry, "columns_changed", 
1345                    G_CALLBACK(column_titles_changed), sheet);
1346
1347 }
1348
1349
1350 GtkWidget *
1351 gtk_sheet_new_with_custom_entry (GSheetRow *rows, GSheetColumn *columns, const gchar *title,
1352                                  GtkType entry_type)
1353 {
1354   GtkWidget *widget;
1355   
1356   widget = gtk_type_new (gtk_sheet_get_type ());
1357
1358   gtk_sheet_construct_with_custom_entry(GTK_SHEET(widget), 
1359                                        rows, columns, title, entry_type);
1360  
1361   return widget;
1362 }
1363
1364 void
1365 gtk_sheet_construct_with_custom_entry (GtkSheet *sheet, 
1366                                        GSheetRow *vgeo,
1367                                        GSheetColumn *hgeo,
1368                                       const gchar *title,
1369                                       GtkType entry_type)
1370 {
1371   gtk_sheet_construct(sheet, vgeo, hgeo, title);
1372
1373   sheet->entry_type = entry_type;
1374   create_sheet_entry(sheet);
1375 }
1376
1377
1378
1379 void
1380 gtk_sheet_change_entry(GtkSheet *sheet, GtkType entry_type)
1381 {
1382   gint state;
1383
1384   g_return_if_fail (sheet != NULL);
1385   g_return_if_fail (GTK_IS_SHEET (sheet));
1386
1387   state = sheet->state;
1388
1389   if(sheet->state == GTK_SHEET_NORMAL)
1390       gtk_sheet_hide_active_cell(sheet);
1391
1392   sheet->entry_type = entry_type;
1393
1394   create_sheet_entry(sheet);
1395
1396   if(state == GTK_SHEET_NORMAL)
1397     {
1398       gtk_sheet_show_active_cell(sheet); 
1399       g_signal_connect(G_OBJECT(gtk_sheet_get_entry(sheet)),
1400                          "changed",
1401                          G_CALLBACK(gtk_sheet_entry_changed),
1402                          sheet);
1403
1404
1405     }
1406  
1407 }
1408
1409 void
1410 gtk_sheet_show_grid(GtkSheet *sheet, gboolean show)
1411 {
1412   g_return_if_fail (sheet != NULL);
1413   g_return_if_fail (GTK_IS_SHEET (sheet));
1414
1415   if(show == sheet->show_grid) return;
1416  
1417   sheet->show_grid = show;
1418
1419   if(!GTK_SHEET_IS_FROZEN(sheet)) 
1420     gtk_sheet_range_draw(sheet, NULL);
1421 }
1422
1423 gboolean
1424 gtk_sheet_grid_visible(GtkSheet *sheet)
1425 {
1426   g_return_val_if_fail (sheet != NULL, 0);
1427   g_return_val_if_fail (GTK_IS_SHEET (sheet), 0);
1428
1429   return sheet->show_grid;
1430 }
1431
1432 void
1433 gtk_sheet_set_background(GtkSheet *sheet, GdkColor *color)
1434 {
1435   g_return_if_fail (sheet != NULL);
1436   g_return_if_fail (GTK_IS_SHEET (sheet));
1437
1438   if(!color) {
1439     gdk_color_parse("white", &sheet->bg_color);
1440     gdk_color_alloc(gdk_colormap_get_system(), &sheet->bg_color);
1441   } else
1442     sheet->bg_color = *color;
1443
1444   if(!GTK_SHEET_IS_FROZEN(sheet)) 
1445     gtk_sheet_range_draw(sheet, NULL);
1446 }
1447
1448 void
1449 gtk_sheet_set_grid(GtkSheet *sheet, GdkColor *color)
1450 {
1451   g_return_if_fail (sheet != NULL);
1452   g_return_if_fail (GTK_IS_SHEET (sheet));
1453
1454   if(!color){
1455     gdk_color_parse("black", &sheet->grid_color);
1456     gdk_color_alloc(gdk_colormap_get_system(), &sheet->grid_color);
1457   }else
1458     sheet->grid_color = *color;
1459
1460   if(!GTK_SHEET_IS_FROZEN(sheet)) 
1461     gtk_sheet_range_draw(sheet, NULL);
1462 }
1463
1464 guint
1465 gtk_sheet_get_columns_count(GtkSheet *sheet)
1466 {
1467   g_return_val_if_fail (sheet != NULL, 0);
1468   g_return_val_if_fail (GTK_IS_SHEET (sheet), 0);
1469
1470   return xxx_column_count(sheet);
1471 }
1472
1473 guint
1474 gtk_sheet_get_rows_count(GtkSheet *sheet)
1475 {
1476   g_return_val_if_fail (sheet != NULL, 0);
1477   g_return_val_if_fail (GTK_IS_SHEET (sheet), 0);
1478
1479   return yyy_row_count(sheet);
1480 }
1481
1482 gint
1483 gtk_sheet_get_state(GtkSheet *sheet)
1484 {
1485   g_return_val_if_fail (sheet != NULL, 0);
1486   g_return_val_if_fail (GTK_IS_SHEET (sheet), 0);
1487
1488   return (sheet->state);
1489 }
1490
1491 void
1492 gtk_sheet_set_selection_mode(GtkSheet *sheet, gint mode)
1493 {
1494   g_return_if_fail (sheet != NULL);
1495   g_return_if_fail (GTK_IS_SHEET (sheet));
1496
1497   if(GTK_WIDGET_REALIZED(sheet))
1498    gtk_sheet_real_unselect_range(sheet, NULL);
1499
1500   sheet->selection_mode = mode;
1501 }
1502
1503 void
1504 gtk_sheet_set_autoresize                (GtkSheet *sheet, gboolean autoresize)
1505 {
1506   g_return_if_fail (sheet != NULL);
1507   g_return_if_fail (GTK_IS_SHEET (sheet));
1508
1509   sheet->autoresize = autoresize;
1510 }
1511
1512 gboolean
1513 gtk_sheet_autoresize                    (GtkSheet *sheet)
1514 {
1515   g_return_val_if_fail (sheet != NULL, FALSE);
1516   g_return_val_if_fail (GTK_IS_SHEET (sheet), FALSE);
1517
1518   return sheet->autoresize;
1519 }
1520
1521 static void
1522 gtk_sheet_set_column_width (GtkSheet * sheet,
1523                             gint column,
1524                             guint width);
1525
1526
1527 static void
1528 gtk_sheet_autoresize_column (GtkSheet *sheet, gint column)
1529 {
1530   gint text_width = 0;
1531   gint row;
1532
1533   g_return_if_fail (sheet != NULL);
1534   g_return_if_fail (GTK_IS_SHEET (sheet));
1535   if (column >= xxx_column_count(sheet) || column < 0) return;
1536
1537   for (row = 0; row < yyy_row_count(sheet); row++)
1538     {
1539       gchar *text = gtk_sheet_cell_get_text(sheet, row, column);
1540       if (text && strlen(text) > 0){
1541         GtkSheetCellAttr attributes;
1542
1543         gtk_sheet_get_attributes(sheet, row, column, &attributes);
1544         if(attributes.is_visible){
1545           gint width = STRING_WIDTH(GTK_WIDGET(sheet),
1546                                     attributes.font_desc,
1547                                     text)
1548             + 2*CELLOFFSET + attributes.border.width;
1549           text_width = MAX (text_width, width);
1550         }
1551       }
1552       dispose_string(sheet, text);
1553     }
1554
1555   if(text_width > xxx_column_width(sheet, column) )
1556     {
1557       gtk_sheet_set_column_width(sheet, column, text_width);
1558       GTK_SHEET_SET_FLAGS(sheet, GTK_SHEET_REDRAW_PENDING);
1559     }
1560 }
1561
1562
1563 void
1564 gtk_sheet_set_autoscroll                (GtkSheet *sheet, gboolean autoscroll)
1565 {
1566   g_return_if_fail (sheet != NULL);
1567   g_return_if_fail (GTK_IS_SHEET (sheet));
1568
1569   sheet->autoscroll = autoscroll;
1570 }
1571
1572 gboolean
1573 gtk_sheet_autoscroll                    (GtkSheet *sheet)
1574 {
1575   g_return_val_if_fail (sheet != NULL, FALSE);
1576   g_return_val_if_fail (GTK_IS_SHEET (sheet), FALSE);
1577
1578   return sheet->autoscroll;
1579 }
1580
1581 void
1582 gtk_sheet_set_clip_text                (GtkSheet *sheet, gboolean clip_text)
1583 {
1584   g_return_if_fail (sheet != NULL);
1585   g_return_if_fail (GTK_IS_SHEET (sheet));
1586
1587   sheet->clip_text = clip_text;
1588 }
1589
1590 gboolean
1591 gtk_sheet_clip_text                    (GtkSheet *sheet)
1592 {
1593   g_return_val_if_fail (sheet != NULL, FALSE);
1594   g_return_val_if_fail (GTK_IS_SHEET (sheet), FALSE);
1595
1596   return sheet->clip_text;
1597 }
1598
1599 void
1600 gtk_sheet_set_justify_entry             (GtkSheet *sheet, gboolean justify)
1601 {
1602   g_return_if_fail (sheet != NULL);
1603   g_return_if_fail (GTK_IS_SHEET (sheet));
1604
1605   sheet->justify_entry = justify;
1606 }
1607
1608 gboolean
1609 gtk_sheet_justify_entry                    (GtkSheet *sheet)
1610 {
1611   g_return_val_if_fail (sheet != NULL, FALSE);
1612   g_return_val_if_fail (GTK_IS_SHEET (sheet), FALSE);
1613
1614   return sheet->justify_entry;
1615 }
1616
1617 void
1618 gtk_sheet_set_locked             (GtkSheet *sheet, gboolean locked)
1619 {
1620   g_return_if_fail (sheet != NULL);
1621   g_return_if_fail (GTK_IS_SHEET (sheet));
1622
1623   if ( locked ) 
1624     {
1625       GTK_SHEET_SET_FLAGS(sheet,GTK_SHEET_IS_LOCKED);
1626       gtk_widget_hide(sheet->sheet_entry);
1627       gtk_widget_unmap(sheet->sheet_entry);
1628     }
1629   else
1630     {
1631       GTK_SHEET_UNSET_FLAGS(sheet,GTK_SHEET_IS_LOCKED);
1632       if (GTK_WIDGET_MAPPED(GTK_WIDGET(sheet)))
1633         {
1634           gtk_widget_show (sheet->sheet_entry);
1635           gtk_widget_map (sheet->sheet_entry);
1636         }
1637     }
1638
1639   gtk_entry_set_editable(GTK_ENTRY(sheet->sheet_entry), locked);
1640
1641 }
1642
1643 gboolean
1644 gtk_sheet_locked                    (const GtkSheet *sheet)
1645 {
1646   g_return_val_if_fail (sheet != NULL, FALSE);
1647   g_return_val_if_fail (GTK_IS_SHEET (sheet), FALSE);
1648
1649   return GTK_SHEET_IS_LOCKED(sheet);
1650 }
1651
1652 /* This routine has problems with gtk+-1.2 related with the
1653  * label/button drawing - I think it's a bug in gtk+-1.2 */
1654
1655 void
1656 gtk_sheet_set_title(GtkSheet *sheet, const gchar *title)
1657 {
1658 /*  GtkWidget *old_widget;
1659 */  GtkWidget *label;
1660
1661   g_return_if_fail (sheet != NULL);
1662   g_return_if_fail (title != NULL);
1663   g_return_if_fail (GTK_IS_SHEET (sheet));
1664
1665   if (sheet->name)
1666     g_free (sheet->name);
1667
1668   sheet->name = g_strdup (title);
1669
1670   if(!GTK_WIDGET_REALIZED(GTK_WIDGET(sheet)) || !title) return;
1671
1672   if(GTK_BIN(sheet->button)->child)
1673            label = GTK_BIN(sheet->button)->child;
1674 /*
1675   gtk_label_set_text(GTK_LABEL(label), title);
1676 */
1677   size_allocate_global_button(sheet);
1678
1679   /* remove and destroy the old widget */
1680 /*
1681   old_widget = GTK_BIN (sheet->button)->child;
1682   if (old_widget)
1683     {
1684       gtk_container_remove (GTK_CONTAINER (sheet->button), old_widget);
1685     }
1686
1687   label = gtk_label_new (title);
1688   gtk_misc_set_alignment(GTK_MISC(label), 0.5 , 0.5 );
1689
1690   gtk_container_add (GTK_CONTAINER (sheet->button), label);
1691   gtk_widget_show (label);
1692
1693   size_allocate_global_button(sheet);
1694
1695   gtk_signal_emit(GTK_OBJECT(sheet),sheet_signals[CHANGED], -1, -1);
1696
1697   if(old_widget)
1698       gtk_widget_destroy (old_widget);
1699 */
1700 }
1701
1702 void
1703 gtk_sheet_freeze (GtkSheet *sheet)
1704 {
1705   g_return_if_fail (sheet != NULL);
1706   g_return_if_fail (GTK_IS_SHEET (sheet));
1707
1708   sheet->freeze_count++;
1709   GTK_SHEET_SET_FLAGS(sheet, GTK_SHEET_IS_FROZEN);
1710 }
1711
1712 void
1713 gtk_sheet_thaw(GtkSheet *sheet)
1714 {
1715   g_return_if_fail (sheet != NULL);
1716   g_return_if_fail (GTK_IS_SHEET (sheet));
1717
1718   if(sheet->freeze_count == 0) return;
1719
1720   sheet->freeze_count--;
1721   if(sheet->freeze_count > 0) return;
1722
1723   adjust_scrollbars(sheet);
1724
1725   GTK_SHEET_UNSET_FLAGS(sheet, GTK_SHEET_IS_FROZEN);
1726
1727   sheet->old_vadjustment = -1.;
1728   sheet->old_hadjustment = -1.;
1729
1730   if(sheet->hadjustment)
1731       gtk_signal_emit_by_name (GTK_OBJECT (sheet->hadjustment), 
1732                               "value_changed");
1733   if(sheet->vadjustment)
1734       gtk_signal_emit_by_name (GTK_OBJECT (sheet->vadjustment), 
1735                               "value_changed");
1736
1737   if(sheet->state == GTK_STATE_NORMAL)
1738      if(sheet->sheet_entry && GTK_WIDGET_MAPPED(sheet->sheet_entry)){
1739         gtk_sheet_activate_cell(sheet, sheet->active_cell.row, sheet->active_cell.col);
1740 /*
1741         gtk_signal_connect(GTK_OBJECT(gtk_sheet_get_entry(sheet)),
1742                            "changed",
1743                            (GtkSignalFunc)gtk_sheet_entry_changed,
1744                            GTK_OBJECT(GTK_WIDGET(sheet)));
1745         gtk_sheet_show_active_cell(sheet);
1746 */
1747      }
1748
1749 }
1750
1751 void
1752 gtk_sheet_set_row_titles_width(GtkSheet *sheet, guint width)
1753 {
1754  if(width < COLUMN_MIN_WIDTH) return;
1755
1756  sheet->row_title_area.width = width;
1757  sheet->view.col0 = COLUMN_FROM_XPIXEL(sheet, sheet->row_title_area.width+1);
1758  sheet->view.coli = COLUMN_FROM_XPIXEL(sheet, sheet->sheet_window_width);
1759
1760
1761  adjust_scrollbars(sheet);
1762
1763  sheet->old_hadjustment = -1.;
1764  if(sheet->hadjustment)
1765      gtk_signal_emit_by_name (GTK_OBJECT (sheet->hadjustment), 
1766                               "value_changed");
1767  size_allocate_global_button(sheet);
1768 }
1769
1770 void
1771 gtk_sheet_set_column_titles_height(GtkSheet *sheet, guint height)
1772 {
1773  if(height < DEFAULT_ROW_HEIGHT(GTK_WIDGET(sheet))) return;
1774
1775  sheet->column_title_area.height = height;
1776  sheet->view.row0=ROW_FROM_YPIXEL(sheet, sheet->column_title_area.height+1);
1777  sheet->view.rowi=ROW_FROM_YPIXEL(sheet, sheet->sheet_window_height-1);
1778
1779  adjust_scrollbars(sheet);
1780
1781  sheet->old_vadjustment = -1.;
1782  if(sheet->vadjustment)
1783      gtk_signal_emit_by_name (GTK_OBJECT (sheet->vadjustment), 
1784                               "value_changed");
1785  size_allocate_global_button(sheet);
1786 }
1787
1788 void
1789 gtk_sheet_show_column_titles(GtkSheet *sheet)
1790 {
1791  gint col;
1792
1793  if(sheet->column_titles_visible) return;
1794
1795  sheet->column_titles_visible = TRUE;
1796
1797
1798  if(GTK_WIDGET_REALIZED(GTK_WIDGET(sheet))){
1799   gdk_window_show(sheet->column_title_window);
1800   gdk_window_move_resize (sheet->column_title_window,
1801                           sheet->column_title_area.x,
1802                           sheet->column_title_area.y,
1803                           sheet->column_title_area.width,
1804                           sheet->column_title_area.height);
1805
1806   for(col = MIN_VISIBLE_COLUMN(sheet); 
1807       col <= MAX_VISIBLE_COLUMN(sheet); 
1808       col++)
1809     {
1810       const GtkSheetButton *button = xxx_column_button(sheet, col);
1811       GtkSheetChild *child = button->child;
1812       if(child)
1813         gtk_sheet_child_show(child);
1814     }
1815   adjust_scrollbars(sheet);
1816  } 
1817
1818  sheet->old_vadjustment = -1.;
1819  if(sheet->vadjustment)
1820      gtk_signal_emit_by_name (GTK_OBJECT (sheet->vadjustment), 
1821                               "value_changed");
1822  size_allocate_global_button(sheet);
1823 }
1824
1825
1826 void
1827 gtk_sheet_show_row_titles(GtkSheet *sheet)
1828 {
1829  gint row;
1830
1831  if(sheet->row_titles_visible) return;
1832
1833  sheet->row_titles_visible = TRUE;
1834
1835
1836  if(GTK_WIDGET_REALIZED(GTK_WIDGET(sheet))){
1837   gdk_window_show(sheet->row_title_window);
1838   gdk_window_move_resize (sheet->row_title_window,
1839                           sheet->row_title_area.x,
1840                           sheet->row_title_area.y,
1841                           sheet->row_title_area.width,
1842                           sheet->row_title_area.height);
1843
1844   for(row = MIN_VISIBLE_ROW(sheet); 
1845       row <= MAX_VISIBLE_ROW(sheet); 
1846       row++)
1847     {
1848       const GtkSheetButton *button = yyy_row_button(sheet, row);
1849       GtkSheetChild *child = button->child;
1850
1851       if(child){
1852         gtk_sheet_child_show(child);
1853       }
1854   }
1855   adjust_scrollbars(sheet);
1856  }
1857
1858  sheet->old_hadjustment = -1.;
1859  if(sheet->hadjustment)
1860      gtk_signal_emit_by_name (GTK_OBJECT (sheet->hadjustment), 
1861                               "value_changed");
1862  size_allocate_global_button(sheet);
1863 }
1864
1865 void
1866 gtk_sheet_hide_column_titles(GtkSheet *sheet)
1867 {
1868  gint col;
1869
1870  if(!sheet->column_titles_visible) return;
1871
1872  sheet->column_titles_visible = FALSE;
1873
1874  if(GTK_WIDGET_REALIZED(GTK_WIDGET(sheet))){
1875   if(sheet->column_title_window) 
1876     gdk_window_hide(sheet->column_title_window);
1877   if(GTK_WIDGET_VISIBLE(sheet->button)) 
1878     gtk_widget_hide(sheet->button);
1879
1880   for(col = MIN_VISIBLE_COLUMN(sheet); 
1881       col <= MAX_VISIBLE_COLUMN(sheet); 
1882       col++)
1883     {
1884       const GtkSheetButton *button = xxx_column_button(sheet, col);
1885       GtkSheetChild *child = button->child;
1886       if(child)
1887         gtk_sheet_child_hide(child);
1888   }
1889   adjust_scrollbars(sheet);
1890  }
1891  
1892  sheet->old_vadjustment = -1.;
1893  if(sheet->vadjustment)
1894      gtk_signal_emit_by_name (GTK_OBJECT (sheet->vadjustment), 
1895                               "value_changed");
1896 }
1897
1898 void
1899 gtk_sheet_hide_row_titles(GtkSheet *sheet)
1900 {
1901  gint row;
1902
1903  if(!sheet->row_titles_visible) return;
1904
1905  sheet->row_titles_visible = FALSE;
1906
1907
1908  if(GTK_WIDGET_REALIZED(GTK_WIDGET(sheet))){
1909   if(sheet->row_title_window) 
1910     gdk_window_hide(sheet->row_title_window);
1911   if(GTK_WIDGET_VISIBLE(sheet->button)) 
1912     gtk_widget_hide(sheet->button);
1913   for(row = MIN_VISIBLE_ROW(sheet); 
1914       row <= MAX_VISIBLE_ROW(sheet); 
1915       row++)
1916     {
1917       const GtkSheetButton *button = yyy_row_button(sheet, row);
1918       GtkSheetChild *child = button->child;
1919
1920       if(child)
1921         gtk_sheet_child_hide(child);
1922     }
1923   adjust_scrollbars(sheet);
1924  }
1925
1926  sheet->old_hadjustment = -1.;
1927  if(sheet->hadjustment)
1928      gtk_signal_emit_by_name (GTK_OBJECT (sheet->hadjustment), 
1929                               "value_changed");
1930 }
1931
1932 gboolean
1933 gtk_sheet_column_titles_visible(GtkSheet *sheet)
1934 {
1935   g_return_val_if_fail (sheet != NULL, FALSE);
1936   g_return_val_if_fail (GTK_IS_SHEET (sheet), FALSE);
1937   return sheet->column_titles_visible;
1938 }
1939
1940 gboolean
1941 gtk_sheet_row_titles_visible(GtkSheet *sheet)
1942 {
1943   g_return_val_if_fail (sheet != NULL, FALSE);
1944   g_return_val_if_fail (GTK_IS_SHEET (sheet), FALSE);
1945   return sheet->row_titles_visible;
1946 }
1947
1948
1949
1950 void
1951 gtk_sheet_moveto (GtkSheet * sheet,
1952                   gint row,
1953                   gint column,
1954                   gfloat row_align,
1955                   gfloat col_align)
1956 {
1957   gint x, y;
1958   guint width, height;
1959   gint adjust;
1960   gint min_row, min_col;
1961
1962   g_return_if_fail (sheet != NULL);
1963   g_return_if_fail (GTK_IS_SHEET (sheet));
1964   g_return_if_fail (sheet->hadjustment != NULL);
1965   g_return_if_fail (sheet->vadjustment != NULL);
1966
1967   if (row < 0 || row >= yyy_row_count(sheet))
1968     return;
1969   if (column < 0 || column >= xxx_column_count(sheet))
1970     return;
1971
1972   height = sheet->sheet_window_height;
1973   width = sheet->sheet_window_width;
1974
1975   /* adjust vertical scrollbar */
1976
1977   if (row >= 0 && row_align >=0.)
1978     {
1979 /*
1980       y = ROW_TOP_YPIXEL(sheet, row) - sheet->voffset -
1981           row_align*height-
1982           (1.-row_align)*yyy_row_height(sheet, row);
1983 */
1984       y = ROW_TOP_YPIXEL (sheet, row) - sheet->voffset
1985         - (gint) ( row_align*height + (1. - row_align) * yyy_row_height(sheet, row));
1986
1987       /* This forces the sheet to scroll when you don't see the entire cell */
1988       min_row = row;
1989       adjust = 0;
1990       if(row_align == 1.){
1991         while(min_row >= 0 && min_row > MIN_VISIBLE_ROW(sheet)){
1992          if(yyy_row_is_visible(sheet, min_row))
1993                 adjust += yyy_row_height(sheet, min_row);
1994          if(adjust >= height){
1995            break;
1996          }
1997          min_row--;
1998         }
1999         min_row = MAX(min_row, 0);
2000         y = ROW_TOP_YPIXEL(sheet, min_row) - sheet->voffset +
2001             yyy_row_height(sheet, min_row) - 1;
2002       }
2003
2004       if (y < 0)
2005         sheet->vadjustment->value = 0.0;
2006       else
2007         sheet->vadjustment->value = y;
2008
2009       sheet->old_vadjustment = -1.;
2010       gtk_signal_emit_by_name (GTK_OBJECT (sheet->vadjustment), 
2011                                "value_changed");
2012
2013     } 
2014      
2015   /* adjust horizontal scrollbar */
2016   if (column >= 0 && col_align >= 0.)
2017     {
2018 /*
2019       x = COLUMN_LEFT_XPIXEL (sheet, column) - sheet->hoffset -
2020           col_align*width -
2021           (1.-col_align)*sheet->column[column].width;
2022 */
2023       x = COLUMN_LEFT_XPIXEL (sheet, column) - sheet->hoffset
2024         - (gint) ( col_align*width + (1.-col_align)*
2025                    xxx_column_width(sheet, column));
2026
2027
2028       /* This forces the sheet to scroll when you don't see the entire cell */
2029       min_col = column;
2030       adjust = 0;
2031       if(col_align == 1.){
2032         while(min_col >= 0 && min_col > MIN_VISIBLE_COLUMN(sheet)){
2033           if(xxx_column_is_visible(sheet, min_col))
2034            adjust += xxx_column_width(sheet, min_col);
2035          
2036          if(adjust >= width){
2037            break;
2038          }
2039          min_col--;
2040         }
2041         min_col = MAX(min_col, 0);
2042         x = COLUMN_LEFT_XPIXEL(sheet, min_col) - sheet->hoffset +
2043           xxx_column_width(sheet, min_col) - 1;
2044       }
2045
2046       if (x < 0)
2047         sheet->hadjustment->value = 0.0;
2048       else
2049         sheet->hadjustment->value = x;
2050
2051       sheet->old_vadjustment = -1.;
2052       gtk_signal_emit_by_name (GTK_OBJECT (sheet->hadjustment), 
2053                                "value_changed");
2054
2055     }
2056 }
2057
2058
2059 void
2060 gtk_sheet_columns_set_resizable (GtkSheet *sheet, gboolean resizable)
2061 {
2062   g_return_if_fail (sheet != NULL);
2063   g_return_if_fail (GTK_IS_SHEET (sheet));
2064
2065   sheet->columns_resizable = resizable;
2066 }
2067
2068 gboolean
2069 gtk_sheet_columns_resizable (GtkSheet *sheet)
2070 {
2071   g_return_val_if_fail (sheet != NULL, FALSE);
2072   g_return_val_if_fail (GTK_IS_SHEET (sheet), FALSE);
2073
2074   return sheet->columns_resizable;
2075 }
2076
2077
2078 void
2079 gtk_sheet_rows_set_resizable (GtkSheet *sheet, gboolean resizable)
2080 {
2081   g_return_if_fail (sheet != NULL);
2082   g_return_if_fail (GTK_IS_SHEET (sheet));
2083
2084   sheet->rows_resizable = resizable;
2085 }
2086
2087 gboolean
2088 gtk_sheet_rows_resizable (GtkSheet *sheet)
2089 {
2090   g_return_val_if_fail (sheet != NULL, FALSE);
2091   g_return_val_if_fail (GTK_IS_SHEET (sheet), FALSE);
2092
2093   return sheet->rows_resizable;
2094 }
2095
2096
2097 void
2098 gtk_sheet_select_row (GtkSheet * sheet,
2099                       gint row)
2100 {
2101   g_return_if_fail (sheet != NULL);
2102   g_return_if_fail (GTK_IS_SHEET (sheet));
2103
2104   if (row < 0 || row >= yyy_row_count(sheet))
2105     return;
2106
2107   if(sheet->state != GTK_SHEET_NORMAL) 
2108      gtk_sheet_real_unselect_range(sheet, NULL);
2109   else
2110   {
2111      gboolean veto = TRUE;
2112      veto = gtk_sheet_deactivate_cell(sheet);
2113      if(!veto) return;
2114   }
2115
2116   sheet->state=GTK_SHEET_ROW_SELECTED;                     
2117   sheet->range.row0=row;
2118   sheet->range.col0=0;
2119   sheet->range.rowi=row;
2120   sheet->range.coli = xxx_column_count(sheet) - 1;
2121   sheet->active_cell.row=row;
2122   sheet->active_cell.col=0;
2123
2124   gtk_signal_emit (GTK_OBJECT (sheet), sheet_signals[SELECT_ROW], row);
2125   gtk_sheet_real_select_range(sheet, NULL);
2126
2127 }
2128
2129
2130 void
2131 gtk_sheet_select_column (GtkSheet * sheet,
2132                          gint column)
2133 {
2134   
2135   g_return_if_fail (sheet != NULL);
2136   g_return_if_fail (GTK_IS_SHEET (sheet));
2137
2138   if (column < 0 || column >= xxx_column_count(sheet))
2139     return;
2140
2141   if(sheet->state != GTK_SHEET_NORMAL) 
2142      gtk_sheet_real_unselect_range(sheet, NULL);
2143   else
2144   {
2145      gboolean veto = TRUE;
2146      veto = gtk_sheet_deactivate_cell(sheet);
2147      if(!veto) return;
2148   }
2149
2150   sheet->state=GTK_SHEET_COLUMN_SELECTED;                     
2151   sheet->range.row0=0;
2152   sheet->range.col0=column;
2153   sheet->range.rowi= yyy_row_count(sheet) - 1;
2154   sheet->range.coli=column;
2155   sheet->active_cell.row=0;
2156   sheet->active_cell.col=column;
2157
2158   gtk_signal_emit (GTK_OBJECT (sheet), sheet_signals[SELECT_COLUMN], column);
2159   gtk_sheet_real_select_range(sheet, NULL);
2160
2161 }
2162
2163 void
2164 gtk_sheet_clip_range (GtkSheet *sheet, const GtkSheetRange *range)
2165 {
2166
2167   g_return_if_fail (sheet != NULL);
2168   g_return_if_fail (GTK_IS_SHEET (sheet));
2169
2170   if(GTK_SHEET_IN_CLIP(sheet)) return;
2171
2172   GTK_SHEET_SET_FLAGS(sheet, GTK_SHEET_IN_CLIP);
2173
2174   if(range == NULL)
2175     sheet->clip_range = sheet->range;
2176   else
2177     sheet->clip_range=*range;
2178
2179   sheet->interval=0;
2180   sheet->clip_timer=gtk_timeout_add(TIMEOUT_FLASH, gtk_sheet_flash, sheet); 
2181
2182   gtk_signal_emit(GTK_OBJECT(sheet), sheet_signals[CLIP_RANGE],
2183                                      &sheet->clip_range);
2184
2185 }
2186
2187 void
2188 gtk_sheet_unclip_range(GtkSheet *sheet)
2189 {
2190
2191   g_return_if_fail (sheet != NULL);
2192   g_return_if_fail (GTK_IS_SHEET (sheet));
2193
2194   if(!GTK_SHEET_IN_CLIP(sheet)) return;
2195
2196   GTK_SHEET_UNSET_FLAGS(sheet, GTK_SHEET_IN_CLIP);
2197   gtk_timeout_remove(sheet->clip_timer);
2198   gtk_sheet_range_draw(sheet, &sheet->clip_range);
2199
2200   if(gtk_sheet_range_isvisible(sheet, sheet->range))
2201     gtk_sheet_range_draw(sheet, &sheet->range);
2202 }
2203
2204 gboolean
2205 gtk_sheet_in_clip (GtkSheet *sheet)
2206 {
2207   g_return_val_if_fail (sheet != NULL, FALSE);
2208   g_return_val_if_fail (GTK_IS_SHEET (sheet), FALSE);
2209
2210   return GTK_SHEET_IN_CLIP(sheet);
2211 }
2212
2213 static gint
2214 gtk_sheet_flash(gpointer data)
2215 {
2216   GtkSheet *sheet;
2217   gint x,y,width,height;
2218   GdkRectangle clip_area;
2219
2220   sheet=GTK_SHEET(data);
2221
2222   if(!GTK_WIDGET_REALIZED(GTK_WIDGET(sheet))) return TRUE;
2223   if(!GTK_WIDGET_DRAWABLE(GTK_WIDGET(sheet))) return TRUE;
2224   if(!gtk_sheet_range_isvisible(sheet, sheet->clip_range)) return TRUE;
2225   if(GTK_SHEET_IN_XDRAG(sheet)) return TRUE; 
2226   if(GTK_SHEET_IN_YDRAG(sheet)) return TRUE; 
2227
2228   GDK_THREADS_ENTER();
2229  
2230   x=COLUMN_LEFT_XPIXEL(sheet,sheet->clip_range.col0)+1;
2231   y=ROW_TOP_YPIXEL(sheet,sheet->clip_range.row0)+1;
2232   width=COLUMN_LEFT_XPIXEL(sheet,sheet->clip_range.coli)-x+ 
2233     xxx_column_width(sheet, sheet->clip_range.coli) - 1;
2234   height=ROW_TOP_YPIXEL(sheet,sheet->clip_range.rowi)-y+
2235     yyy_row_height(sheet, sheet->clip_range.rowi)-1;
2236
2237   clip_area.x=COLUMN_LEFT_XPIXEL(sheet, MIN_VISIBLE_COLUMN(sheet));
2238   clip_area.y=ROW_TOP_YPIXEL(sheet, MIN_VISIBLE_ROW(sheet));
2239   clip_area.width=sheet->sheet_window_width;
2240   clip_area.height=sheet->sheet_window_height;
2241
2242   if(x<0) {
2243      width=width+x+1;
2244      x=-1;
2245   }
2246   if(width>clip_area.width) width=clip_area.width+10;
2247   if(y<0) {
2248      height=height+y+1;
2249      y=-1;
2250   }
2251   if(height>clip_area.height) height=clip_area.height+10;
2252
2253   gdk_draw_pixmap(sheet->sheet_window,
2254                   GTK_WIDGET(sheet)->style->fg_gc[GTK_STATE_NORMAL],
2255                   sheet->pixmap,
2256                   x, y,
2257                   x, y,
2258                   1, height);
2259
2260   gdk_draw_pixmap(sheet->sheet_window,
2261                   GTK_WIDGET(sheet)->style->fg_gc[GTK_STATE_NORMAL],
2262                   sheet->pixmap,
2263                   x, y,
2264                   x, y,
2265                   width, 1);
2266
2267   gdk_draw_pixmap(sheet->sheet_window,
2268                   GTK_WIDGET(sheet)->style->fg_gc[GTK_STATE_NORMAL],
2269                   sheet->pixmap,
2270                   x, y+height,
2271                   x, y+height,
2272                   width, 1);
2273
2274   gdk_draw_pixmap(sheet->sheet_window,
2275                   GTK_WIDGET(sheet)->style->fg_gc[GTK_STATE_NORMAL],
2276                   sheet->pixmap,
2277                   x+width, y,
2278                   x+width, y,
2279                   1, height);
2280
2281
2282   sheet->interval=sheet->interval+1;
2283   if(sheet->interval==TIME_INTERVAL) sheet->interval=0;
2284
2285   gdk_gc_set_dashes(sheet->xor_gc, sheet->interval, (gint8*)"\4\4", 2);
2286   gtk_sheet_draw_flashing_range(sheet,sheet->clip_range);
2287   gdk_gc_set_dashes(sheet->xor_gc, 0, (gint8*)"\4\4", 2);
2288
2289   GDK_THREADS_LEAVE();
2290
2291   return TRUE;
2292
2293 }
2294
2295 static void
2296 gtk_sheet_draw_flashing_range(GtkSheet *sheet, GtkSheetRange range)
2297 {
2298   GdkRectangle clip_area;
2299   gint x,y,width,height;
2300
2301   if(!gtk_sheet_range_isvisible(sheet, sheet->clip_range)) return;
2302   
2303   clip_area.x=COLUMN_LEFT_XPIXEL(sheet, MIN_VISIBLE_COLUMN(sheet));
2304   clip_area.y=ROW_TOP_YPIXEL(sheet, MIN_VISIBLE_ROW(sheet));
2305   clip_area.width=sheet->sheet_window_width;
2306   clip_area.height=sheet->sheet_window_height;
2307
2308   gdk_gc_set_clip_rectangle(sheet->xor_gc, &clip_area);  
2309
2310   x=COLUMN_LEFT_XPIXEL(sheet,sheet->clip_range.col0)+1;
2311   y=ROW_TOP_YPIXEL(sheet,sheet->clip_range.row0)+1;
2312   width=COLUMN_LEFT_XPIXEL(sheet,sheet->clip_range.coli)-x+ 
2313     xxx_column_width(sheet, sheet->clip_range.coli) - 1;
2314   height=ROW_TOP_YPIXEL(sheet,sheet->clip_range.rowi)-y+
2315              yyy_row_height(sheet, sheet->clip_range.rowi)-1;
2316
2317   if(x<0) {
2318      width=width+x+1;
2319      x=-1;
2320   }
2321   if(width>clip_area.width) width=clip_area.width+10;
2322   if(y<0) {
2323      height=height+y+1;
2324      y=-1;
2325   }
2326   if(height>clip_area.height) height=clip_area.height+10;
2327
2328   gdk_gc_set_line_attributes(sheet->xor_gc, 1, 1, 0 ,0 );
2329
2330   gdk_draw_rectangle(sheet->sheet_window, sheet->xor_gc, FALSE, 
2331                      x, y,
2332                      width, height);
2333
2334   gdk_gc_set_line_attributes (sheet->xor_gc, 1, 0, 0, 0);
2335
2336   gdk_gc_set_clip_rectangle(sheet->xor_gc, NULL);
2337
2338 }
2339
2340 static gint
2341 gtk_sheet_range_isvisible (GtkSheet * sheet,
2342                          GtkSheetRange range)
2343 {
2344   g_return_val_if_fail (sheet != NULL, FALSE);
2345
2346   if (range.row0 < 0 || range.row0 >= yyy_row_count(sheet))
2347     return FALSE;
2348
2349   if (range.rowi < 0 || range.rowi >= yyy_row_count(sheet))
2350     return FALSE;
2351
2352   if (range.col0 < 0 || range.col0 >= xxx_column_count(sheet))
2353     return FALSE;
2354
2355   if (range.coli < 0 || range.coli >= xxx_column_count(sheet))
2356     return FALSE;
2357
2358   if (range.rowi < MIN_VISIBLE_ROW (sheet))
2359     return FALSE;
2360
2361   if (range.row0 > MAX_VISIBLE_ROW (sheet))
2362     return FALSE;
2363
2364   if (range.coli < MIN_VISIBLE_COLUMN (sheet))
2365     return FALSE;
2366
2367   if (range.col0 > MAX_VISIBLE_COLUMN (sheet))
2368     return FALSE;
2369
2370   return TRUE;
2371 }
2372
2373 static gint
2374 gtk_sheet_cell_isvisible (GtkSheet * sheet,
2375                           gint row, gint column)
2376 {
2377   GtkSheetRange range;
2378
2379   range.row0 = row;
2380   range.col0 = column;
2381   range.rowi = row;
2382   range.coli = column;
2383
2384   return gtk_sheet_range_isvisible(sheet, range);
2385 }
2386
2387 void 
2388 gtk_sheet_get_visible_range(GtkSheet *sheet, GtkSheetRange *range)
2389 {
2390
2391   g_return_if_fail (sheet != NULL);
2392   g_return_if_fail (GTK_IS_SHEET (sheet)) ;
2393   g_return_if_fail (range != NULL);
2394
2395   range->row0 = MIN_VISIBLE_ROW(sheet);
2396   range->col0 = MIN_VISIBLE_COLUMN(sheet);
2397   range->rowi = MAX_VISIBLE_ROW(sheet);
2398   range->coli = MAX_VISIBLE_COLUMN(sheet);
2399
2400 }
2401
2402 GtkAdjustment *
2403 gtk_sheet_get_vadjustment (GtkSheet * sheet)
2404 {
2405   g_return_val_if_fail (sheet != NULL, NULL);
2406   g_return_val_if_fail (GTK_IS_SHEET (sheet), NULL);
2407
2408   return sheet->vadjustment;
2409 }
2410
2411 GtkAdjustment *
2412 gtk_sheet_get_hadjustment (GtkSheet * sheet)
2413 {
2414   g_return_val_if_fail (sheet != NULL, NULL);
2415   g_return_val_if_fail (GTK_IS_SHEET (sheet), NULL);
2416
2417   return sheet->hadjustment;
2418 }
2419
2420 void
2421 gtk_sheet_set_vadjustment (GtkSheet      *sheet,
2422                            GtkAdjustment *adjustment)
2423 {
2424   GtkAdjustment *old_adjustment;
2425
2426   g_return_if_fail (sheet != NULL);
2427   g_return_if_fail (GTK_IS_SHEET (sheet));
2428   if (adjustment)
2429     g_return_if_fail (GTK_IS_ADJUSTMENT (adjustment));
2430   
2431   if (sheet->vadjustment == adjustment)
2432     return;
2433   
2434   old_adjustment = sheet->vadjustment;
2435
2436   if (sheet->vadjustment)
2437     {
2438       gtk_signal_disconnect_by_data (GTK_OBJECT (sheet->vadjustment), sheet);
2439       gtk_object_unref (GTK_OBJECT (sheet->vadjustment));
2440     }
2441
2442   sheet->vadjustment = adjustment;
2443
2444   if (sheet->vadjustment)
2445     {
2446       gtk_object_ref (GTK_OBJECT (sheet->vadjustment));
2447       gtk_object_sink (GTK_OBJECT (sheet->vadjustment));
2448
2449       gtk_signal_connect (GTK_OBJECT (sheet->vadjustment), "changed",
2450                           (GtkSignalFunc) vadjustment_changed,
2451                           (gpointer) sheet);
2452       gtk_signal_connect (GTK_OBJECT (sheet->vadjustment), "value_changed",
2453                           (GtkSignalFunc) vadjustment_value_changed,
2454                           (gpointer) sheet);
2455     }
2456
2457   if (!sheet->vadjustment || !old_adjustment)
2458      {
2459        gtk_widget_queue_resize (GTK_WIDGET (sheet));
2460        return;
2461      }
2462
2463   sheet->old_vadjustment = sheet->vadjustment->value;
2464 }
2465
2466 void
2467 gtk_sheet_set_hadjustment (GtkSheet      *sheet,
2468                            GtkAdjustment *adjustment)
2469 {
2470   GtkAdjustment *old_adjustment;
2471
2472   g_return_if_fail (sheet != NULL);
2473   g_return_if_fail (GTK_IS_SHEET (sheet));
2474   if (adjustment)
2475     g_return_if_fail (GTK_IS_ADJUSTMENT (adjustment));
2476   
2477   if (sheet->hadjustment == adjustment)
2478     return;
2479   
2480   old_adjustment = sheet->hadjustment;
2481
2482   if (sheet->hadjustment)
2483     {
2484       gtk_signal_disconnect_by_data (GTK_OBJECT (sheet->hadjustment), sheet);
2485       gtk_object_unref (GTK_OBJECT (sheet->hadjustment));
2486     }
2487
2488   sheet->hadjustment = adjustment;
2489
2490   if (sheet->hadjustment)
2491     {
2492       gtk_object_ref (GTK_OBJECT (sheet->hadjustment));
2493       gtk_object_sink (GTK_OBJECT (sheet->hadjustment));
2494
2495       gtk_signal_connect (GTK_OBJECT (sheet->hadjustment), "changed",
2496                           (GtkSignalFunc) hadjustment_changed,
2497                           (gpointer) sheet);
2498       gtk_signal_connect (GTK_OBJECT (sheet->hadjustment), "value_changed",
2499                           (GtkSignalFunc) hadjustment_value_changed,
2500                           (gpointer) sheet);
2501     }
2502
2503   if (!sheet->hadjustment || !old_adjustment)
2504      {
2505        gtk_widget_queue_resize (GTK_WIDGET (sheet));
2506        return;
2507      }
2508
2509   sheet->old_hadjustment = sheet->hadjustment->value;
2510 }
2511
2512 static void
2513 gtk_sheet_set_scroll_adjustments (GtkSheet *sheet,
2514                                   GtkAdjustment *hadjustment,
2515                                   GtkAdjustment *vadjustment)
2516 {
2517    if(sheet->hadjustment != hadjustment)
2518          gtk_sheet_set_hadjustment (sheet, hadjustment);
2519    if(sheet->vadjustment != vadjustment)
2520          gtk_sheet_set_vadjustment (sheet, vadjustment);
2521 }
2522
2523 static void
2524 gtk_sheet_finalize (GObject * object)
2525 {
2526   GtkSheet *sheet;
2527
2528   g_return_if_fail (object != NULL);
2529   g_return_if_fail (GTK_IS_SHEET (object));
2530
2531   sheet = GTK_SHEET (object);
2532
2533   /* get rid of all the cells */
2534   gtk_sheet_range_clear (sheet, NULL);
2535   gtk_sheet_range_delete(sheet, NULL);
2536
2537   if(sheet->name){
2538       g_free(sheet->name);
2539       sheet->name = NULL;
2540   }
2541
2542   if (G_OBJECT_CLASS (parent_class)->finalize)
2543     (*G_OBJECT_CLASS (parent_class)->finalize) (object);
2544 }
2545
2546 static void
2547 gtk_sheet_destroy (GtkObject * object)
2548 {
2549   GtkSheet *sheet;
2550   GList *children;
2551
2552   g_return_if_fail (object != NULL);
2553   g_return_if_fail (GTK_IS_SHEET (object));
2554
2555   sheet = GTK_SHEET (object);
2556
2557   /* destroy the entry */
2558   if(sheet->sheet_entry && GTK_IS_WIDGET(sheet->sheet_entry)){
2559     gtk_widget_destroy (sheet->sheet_entry);
2560     sheet->sheet_entry = NULL;
2561   }
2562
2563   /* destroy the global selection button */
2564   if(sheet->button && GTK_IS_WIDGET(sheet->button)){
2565     gtk_widget_destroy (sheet->button);
2566     sheet->button = NULL;
2567   }
2568
2569   if(sheet->timer){
2570      gtk_timeout_remove(sheet->timer);
2571      sheet->timer = 0;
2572   }
2573
2574   if(sheet->clip_timer){
2575      gtk_timeout_remove(sheet->clip_timer);
2576      sheet->clip_timer = 0;
2577   }
2578
2579   /* unref adjustments */
2580   if (sheet->hadjustment)
2581     {
2582       gtk_signal_disconnect_by_data (GTK_OBJECT (sheet->hadjustment), sheet);
2583       gtk_object_unref (GTK_OBJECT (sheet->hadjustment));
2584       sheet->hadjustment = NULL;
2585     }
2586   if (sheet->vadjustment)
2587     {
2588       gtk_signal_disconnect_by_data (GTK_OBJECT (sheet->vadjustment), sheet);
2589       gtk_object_unref (GTK_OBJECT (sheet->vadjustment));
2590       sheet->vadjustment = NULL;
2591     }
2592
2593   children = sheet->children;
2594   while(children){
2595     GtkSheetChild *child = (GtkSheetChild *)children->data;
2596     if(child && child->widget) 
2597       gtk_sheet_remove(GTK_CONTAINER(sheet), child->widget);
2598     children = sheet->children;
2599   }  
2600   sheet->children = NULL;
2601
2602   if (GTK_OBJECT_CLASS (parent_class)->destroy)
2603     (*GTK_OBJECT_CLASS (parent_class)->destroy) (object);
2604 }
2605
2606 static void
2607 gtk_sheet_style_set (GtkWidget *widget,
2608                      GtkStyle  *previous_style)
2609 {
2610   GtkSheet *sheet;
2611
2612   g_return_if_fail (widget != NULL);
2613   g_return_if_fail (GTK_IS_SHEET (widget));
2614
2615   if (GTK_WIDGET_CLASS (parent_class)->style_set)
2616     (*GTK_WIDGET_CLASS (parent_class)->style_set) (widget, previous_style);
2617
2618   sheet = GTK_SHEET (widget);
2619
2620   if(GTK_WIDGET_REALIZED(widget))
2621      {
2622        gtk_style_set_background (widget->style, widget->window, widget->state);
2623      }
2624
2625 }
2626
2627 static void
2628 gtk_sheet_realize (GtkWidget * widget)
2629 {
2630   GtkSheet *sheet;
2631   GdkWindowAttr attributes;
2632   gint attributes_mask;
2633   GdkGCValues values, auxvalues;
2634   GdkColormap *colormap;
2635   gchar *name;
2636   GtkSheetChild *child;
2637   GList *children;
2638
2639   g_return_if_fail (widget != NULL);
2640   g_return_if_fail (GTK_IS_SHEET (widget));
2641
2642   sheet = GTK_SHEET (widget);
2643
2644   GTK_WIDGET_SET_FLAGS (widget, GTK_REALIZED);
2645
2646   attributes.window_type = GDK_WINDOW_CHILD;
2647   attributes.x = widget->allocation.x;
2648   attributes.y = widget->allocation.y;
2649   attributes.width = widget->allocation.width;
2650   attributes.height = widget->allocation.height;
2651   attributes.wclass = GDK_INPUT_OUTPUT;
2652
2653   attributes.visual = gtk_widget_get_visual (widget);
2654   attributes.colormap = gtk_widget_get_colormap (widget);
2655
2656   attributes.event_mask = gtk_widget_get_events (widget);
2657   attributes.event_mask |= (GDK_EXPOSURE_MASK |
2658                             GDK_BUTTON_PRESS_MASK |
2659                             GDK_BUTTON_RELEASE_MASK |
2660                             GDK_KEY_PRESS_MASK |
2661                             GDK_POINTER_MOTION_MASK |
2662                             GDK_POINTER_MOTION_HINT_MASK);
2663   attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL | GDK_WA_COLORMAP |
2664                     GDK_WA_CURSOR;
2665
2666   attributes.cursor = gdk_cursor_new(GDK_TOP_LEFT_ARROW);
2667
2668   /* main window */
2669   widget->window = gdk_window_new (gtk_widget_get_parent_window (widget), &attributes, attributes_mask);
2670
2671   gdk_window_set_user_data (widget->window, sheet);
2672
2673   widget->style = gtk_style_attach (widget->style, widget->window);
2674
2675   gtk_style_set_background (widget->style, widget->window, GTK_STATE_NORMAL);
2676
2677   attributes.x = 0;
2678   if(sheet->row_titles_visible)
2679        attributes.x = sheet->row_title_area.width;
2680   attributes.y = 0;
2681   attributes.width = sheet->column_title_area.width;
2682   attributes.height = sheet->column_title_area.height;
2683
2684   /* column-title window */
2685   sheet->column_title_window = gdk_window_new (widget->window, &attributes, attributes_mask);
2686   gdk_window_set_user_data (sheet->column_title_window, sheet);
2687   gtk_style_set_background (widget->style, sheet->column_title_window, GTK_STATE_NORMAL);
2688
2689   attributes.x = 0;
2690   attributes.y = 0;
2691   if(sheet->column_titles_visible)
2692        attributes.y = sheet->column_title_area.height;
2693   attributes.width = sheet->row_title_area.width;
2694   attributes.height = sheet->row_title_area.height;
2695
2696   /* row-title window */
2697   sheet->row_title_window = gdk_window_new (widget->window, &attributes, attributes_mask);
2698   gdk_window_set_user_data (sheet->row_title_window, sheet);
2699   gtk_style_set_background (widget->style, sheet->row_title_window, GTK_STATE_NORMAL);
2700
2701   /* sheet-window */
2702   attributes.cursor = gdk_cursor_new(GDK_PLUS);
2703
2704   attributes.x = 0;
2705   attributes.y = 0;
2706   attributes.width = sheet->sheet_window_width, 
2707   attributes.height = sheet->sheet_window_height;
2708
2709   sheet->sheet_window = gdk_window_new (widget->window, &attributes, attributes_mask);
2710   gdk_window_set_user_data (sheet->sheet_window, sheet);
2711
2712   gdk_cursor_unref(attributes.cursor);
2713
2714   gdk_window_set_background (sheet->sheet_window, &widget->style->white);
2715   gdk_window_show (sheet->sheet_window);
2716
2717   /* backing_pixmap */
2718   gtk_sheet_make_backing_pixmap(sheet, 0, 0);  
2719
2720   /* GCs */
2721   if(sheet->fg_gc) 
2722       gdk_gc_unref(sheet->fg_gc);
2723   if(sheet->bg_gc) 
2724       gdk_gc_unref(sheet->bg_gc);
2725   sheet->fg_gc = gdk_gc_new (widget->window);
2726   sheet->bg_gc = gdk_gc_new (widget->window);
2727
2728   colormap = gtk_widget_get_colormap(widget);
2729
2730   gdk_color_white(colormap, &widget->style->white);
2731   gdk_color_black(colormap, &widget->style->black);
2732
2733   gdk_gc_get_values(sheet->fg_gc, &auxvalues);
2734
2735   values.foreground = widget->style->white;
2736   values.function = GDK_INVERT;
2737   values.subwindow_mode = GDK_INCLUDE_INFERIORS;
2738   if(sheet->xor_gc)
2739     gdk_gc_unref(sheet->xor_gc);
2740   sheet->xor_gc = gdk_gc_new_with_values (widget->window,
2741                                           &values,
2742                                           GDK_GC_FOREGROUND |
2743                                           GDK_GC_FUNCTION |
2744                                           GDK_GC_SUBWINDOW);
2745
2746   if(sheet->sheet_entry->parent){
2747           gtk_widget_ref(sheet->sheet_entry);
2748           gtk_widget_unparent(sheet->sheet_entry);
2749   }
2750   gtk_widget_set_parent_window (sheet->sheet_entry, sheet->sheet_window);
2751   gtk_widget_set_parent(sheet->sheet_entry, GTK_WIDGET(sheet));
2752
2753   if(sheet->button && sheet->button->parent){
2754           gtk_widget_ref(sheet->button);
2755           gtk_widget_unparent(sheet->button);
2756   }
2757   gtk_widget_set_parent_window(sheet->button, sheet->sheet_window);
2758   gtk_widget_set_parent(sheet->button, GTK_WIDGET(sheet));
2759
2760 /*
2761   gtk_sheet_activate_cell(sheet, sheet->active_cell.row, sheet->active_cell.col);
2762 */
2763   if(!sheet->cursor_drag)
2764        sheet->cursor_drag = gdk_cursor_new(GDK_PLUS);
2765  
2766   if(sheet->column_titles_visible)
2767      gdk_window_show(sheet->column_title_window);
2768   if(sheet->row_titles_visible)
2769      gdk_window_show(sheet->row_title_window);
2770
2771   size_allocate_row_title_buttons(sheet);
2772   size_allocate_column_title_buttons(sheet);
2773
2774   name = g_strdup(sheet->name);
2775   gtk_sheet_set_title(sheet, name);
2776
2777   g_free(name);
2778
2779   children = sheet->children;
2780   while(children)
2781     {
2782       child = children->data;
2783       children = children->next;
2784  
2785       gtk_sheet_realize_child(sheet, child);
2786     }
2787 }
2788
2789 static void
2790 create_global_button(GtkSheet *sheet)
2791 {
2792    sheet->button = gtk_button_new_with_label(" ");
2793
2794    gtk_signal_connect (GTK_OBJECT (sheet->button),
2795                       "pressed",
2796                       (GtkSignalFunc) global_button_clicked,
2797                       (gpointer) sheet);
2798 }
2799
2800 static void
2801 size_allocate_global_button(GtkSheet *sheet)
2802 {
2803   GtkAllocation allocation;
2804
2805   if(!sheet->column_titles_visible) return;
2806   if(!sheet->row_titles_visible) return;
2807
2808   gtk_widget_size_request(sheet->button, NULL);
2809
2810   allocation.x=0;
2811   allocation.y=0;
2812   allocation.width=sheet->row_title_area.width;
2813   allocation.height=sheet->column_title_area.height;
2814
2815   gtk_widget_size_allocate(sheet->button, &allocation);
2816   gtk_widget_show(sheet->button);
2817 }
2818
2819 static void
2820 global_button_clicked(GtkWidget *widget, gpointer data)
2821 {
2822   gboolean veto;
2823
2824   gtk_sheet_click_cell(GTK_SHEET(data), -1, -1, &veto);
2825   gtk_widget_grab_focus(GTK_WIDGET(data));
2826 }
2827
2828
2829 static void
2830 gtk_sheet_unrealize (GtkWidget * widget)
2831 {
2832   GtkSheet *sheet;
2833
2834   g_return_if_fail (widget != NULL);
2835   g_return_if_fail (GTK_IS_SHEET (widget));
2836
2837   sheet = GTK_SHEET (widget);
2838
2839   gdk_cursor_destroy (sheet->cursor_drag);
2840
2841   gdk_gc_destroy (sheet->xor_gc);
2842   gdk_gc_destroy (sheet->fg_gc);
2843   gdk_gc_destroy (sheet->bg_gc);
2844
2845   gdk_window_destroy (sheet->sheet_window);
2846   gdk_window_destroy (sheet->column_title_window);
2847   gdk_window_destroy (sheet->row_title_window);
2848
2849   if (sheet->pixmap){
2850     g_object_unref(sheet->pixmap);
2851     sheet->pixmap = NULL;
2852   }
2853
2854   sheet->column_title_window=NULL;
2855   sheet->sheet_window = NULL;
2856   sheet->cursor_drag = NULL;
2857   sheet->xor_gc = NULL;
2858   sheet->fg_gc = NULL;
2859   sheet->bg_gc = NULL;
2860
2861   if (GTK_WIDGET_CLASS (parent_class)->unrealize)
2862     (* GTK_WIDGET_CLASS (parent_class)->unrealize) (widget);
2863 }
2864
2865 static void
2866 gtk_sheet_map (GtkWidget * widget)
2867 {
2868   GtkSheet *sheet;
2869   GtkSheetChild *child;
2870   GList *children;
2871
2872   g_return_if_fail (widget != NULL);
2873   g_return_if_fail (GTK_IS_SHEET (widget));
2874
2875   sheet = GTK_SHEET (widget);
2876
2877   if (!GTK_WIDGET_MAPPED (widget))
2878     {
2879       GTK_WIDGET_SET_FLAGS (widget, GTK_MAPPED);
2880
2881       if(!sheet->cursor_drag) sheet->cursor_drag=gdk_cursor_new(GDK_PLUS);
2882
2883       gdk_window_show (widget->window);
2884
2885       gdk_window_show (sheet->sheet_window);
2886
2887       if(sheet->column_titles_visible){
2888            size_allocate_column_title_buttons(sheet);
2889            gdk_window_show (sheet->column_title_window);
2890       }
2891       if(sheet->row_titles_visible){
2892            size_allocate_row_title_buttons(sheet);
2893            gdk_window_show (sheet->row_title_window);
2894       }
2895
2896       if(!GTK_WIDGET_MAPPED (sheet->sheet_entry)
2897          && ! gtk_sheet_locked(sheet)
2898          && sheet->active_cell.row  >=0
2899          && sheet->active_cell.col  >=0 )
2900         {
2901           gtk_widget_show (sheet->sheet_entry);
2902           gtk_widget_map (sheet->sheet_entry);
2903         }
2904
2905       if (GTK_WIDGET_VISIBLE (sheet->button) &&
2906           !GTK_WIDGET_MAPPED (sheet->button)){
2907                   gtk_widget_show(sheet->button);
2908                   gtk_widget_map (sheet->button);
2909       }
2910
2911       if(GTK_BIN(sheet->button)->child)
2912         if (GTK_WIDGET_VISIBLE (GTK_BIN(sheet->button)->child) &&
2913            !GTK_WIDGET_MAPPED (GTK_BIN(sheet->button)->child))
2914                   gtk_widget_map (GTK_BIN(sheet->button)->child);
2915
2916       gtk_sheet_range_draw(sheet, NULL);
2917       gtk_sheet_activate_cell(sheet, 
2918                               sheet->active_cell.row, 
2919                               sheet->active_cell.col);
2920
2921       children = sheet->children;
2922       while (children)
2923       {
2924         child = children->data;
2925         children = children->next;
2926
2927         if (GTK_WIDGET_VISIBLE (child->widget) &&
2928             !GTK_WIDGET_MAPPED (child->widget)){
2929           gtk_widget_map (child->widget);
2930           gtk_sheet_position_child(sheet, child);
2931         }
2932       }
2933
2934     }
2935 }
2936
2937 static void
2938 gtk_sheet_unmap (GtkWidget * widget)
2939 {
2940   GtkSheet *sheet;
2941   GtkSheetChild *child;
2942   GList *children;
2943
2944   g_return_if_fail (widget != NULL);
2945   g_return_if_fail (GTK_IS_SHEET (widget));
2946
2947   sheet = GTK_SHEET (widget);
2948
2949   if (GTK_WIDGET_MAPPED (widget))
2950     {
2951       GTK_WIDGET_UNSET_FLAGS (widget, GTK_MAPPED);
2952
2953       gdk_window_hide (sheet->sheet_window);
2954       if(sheet->column_titles_visible)
2955           gdk_window_hide (sheet->column_title_window);
2956       if(sheet->row_titles_visible)
2957           gdk_window_hide (sheet->row_title_window);
2958       gdk_window_hide (widget->window);
2959
2960       if (GTK_WIDGET_MAPPED (sheet->sheet_entry))
2961         gtk_widget_unmap (sheet->sheet_entry);
2962
2963       if (GTK_WIDGET_MAPPED (sheet->button))
2964         gtk_widget_unmap (sheet->button);
2965
2966       children = sheet->children;
2967       while (children)
2968         {
2969           child = children->data;
2970           children = children->next;
2971
2972           if (GTK_WIDGET_VISIBLE (child->widget) &&
2973               GTK_WIDGET_MAPPED (child->widget))
2974                 {
2975                      gtk_widget_unmap (child->widget);
2976                 }
2977         }
2978
2979     }
2980 }
2981
2982
2983 static void
2984 gtk_sheet_cell_draw_default (GtkSheet *sheet, gint row, gint col)
2985 {
2986   GtkWidget *widget;
2987   GdkGC *fg_gc, *bg_gc;
2988   GtkSheetCellAttr attributes;
2989   GdkRectangle area;
2990
2991   g_return_if_fail (sheet != NULL);
2992
2993   /* bail now if we arn't drawable yet */
2994   if (!GTK_WIDGET_DRAWABLE (sheet)) return;
2995
2996   if (row < 0 || row >= yyy_row_count(sheet)) return;
2997   if (col < 0 || col >= xxx_column_count(sheet)) return;
2998   if (! xxx_column_is_visible(sheet, col)) return;
2999   if (! yyy_row_is_visible(sheet, row)) return;
3000
3001   widget = GTK_WIDGET (sheet);
3002
3003   gtk_sheet_get_attributes(sheet, row, col, &attributes);
3004  
3005   /* select GC for background rectangle */
3006   gdk_gc_set_foreground (sheet->fg_gc, &attributes.foreground);
3007   gdk_gc_set_foreground (sheet->bg_gc, &attributes.background);
3008
3009   fg_gc = sheet->fg_gc;
3010   bg_gc = sheet->bg_gc;
3011
3012   area.x=COLUMN_LEFT_XPIXEL(sheet,col);
3013   area.y=ROW_TOP_YPIXEL(sheet,row);
3014   area.width= xxx_column_width(sheet, col);
3015   area.height=yyy_row_height(sheet, row);
3016
3017   gdk_draw_rectangle (sheet->pixmap,
3018                       bg_gc,
3019                       TRUE,
3020                       area.x,
3021                       area.y,
3022                       area.width,
3023                       area.height);
3024
3025   gdk_gc_set_line_attributes (sheet->fg_gc, 1, 0, 0, 0);
3026
3027   if(sheet->show_grid){
3028     gdk_gc_set_foreground (sheet->bg_gc, &sheet->grid_color);
3029
3030     gdk_draw_rectangle (sheet->pixmap,
3031                         sheet->bg_gc,
3032                         FALSE,
3033                         area.x, area.y,
3034                         area.width, area.height);
3035   }
3036 }
3037
3038 static void
3039 gtk_sheet_cell_draw_border (GtkSheet *sheet, gint row, gint col, gint mask)
3040 {
3041   GtkWidget *widget;
3042   GdkGC *fg_gc, *bg_gc;
3043   GtkSheetCellAttr attributes;
3044   GdkRectangle area;
3045   guint width;
3046
3047   g_return_if_fail (sheet != NULL);
3048
3049   /* bail now if we arn't drawable yet */
3050   if (!GTK_WIDGET_DRAWABLE (sheet)) return;
3051
3052   if (row < 0 || row >= yyy_row_count(sheet)) return;
3053   if (col < 0 || col >= xxx_column_count(sheet)) return;
3054   if (!xxx_column_is_visible(sheet, col)) return;
3055   if (!yyy_row_is_visible(sheet, row)) return;
3056
3057   widget = GTK_WIDGET (sheet);
3058
3059   gtk_sheet_get_attributes(sheet, row, col, &attributes);
3060
3061   /* select GC for background rectangle */
3062   gdk_gc_set_foreground (sheet->fg_gc, &attributes.border.color);
3063   gdk_gc_set_foreground (sheet->bg_gc, &attributes.background);
3064
3065   fg_gc = sheet->fg_gc;
3066   bg_gc = sheet->bg_gc;
3067
3068   area.x=COLUMN_LEFT_XPIXEL(sheet,col);
3069   area.y=ROW_TOP_YPIXEL(sheet,row);
3070   area.width=xxx_column_width(sheet, col);
3071   area.height=yyy_row_height(sheet, row);
3072
3073   width = attributes.border.width;
3074   gdk_gc_set_line_attributes(sheet->fg_gc, attributes.border.width,
3075                                            attributes.border.line_style,
3076                                            attributes.border.cap_style,
3077                                            attributes.border.join_style);
3078   if(width>0){
3079
3080    if(attributes.border.mask & GTK_SHEET_LEFT_BORDER & mask)
3081       gdk_draw_line(sheet->pixmap, sheet->fg_gc,
3082                     area.x, area.y-width/2,
3083                     area.x, area.y+area.height+width/2+1);
3084
3085    if(attributes.border.mask & GTK_SHEET_RIGHT_BORDER & mask)
3086       gdk_draw_line(sheet->pixmap, sheet->fg_gc,
3087                     area.x+area.width, area.y-width/2,
3088                     area.x+area.width, 
3089                     area.y+area.height+width/2+1);
3090
3091    if(attributes.border.mask & GTK_SHEET_TOP_BORDER & mask)
3092       gdk_draw_line(sheet->pixmap, sheet->fg_gc,
3093                     area.x-width/2,area.y,
3094                     area.x+area.width+width/2+1, 
3095                     area.y);
3096
3097    if(attributes.border.mask & GTK_SHEET_BOTTOM_BORDER & mask)
3098       gdk_draw_line(sheet->pixmap, sheet->fg_gc,
3099                     area.x-width/2, area.y+area.height,
3100                     area.x+area.width+width/2+1, 
3101                     area.y+area.height);
3102   }
3103
3104 }
3105
3106
3107 static void
3108 gtk_sheet_cell_draw_label (GtkSheet *sheet, gint row, gint col)
3109 {
3110   GtkWidget *widget;
3111   GdkRectangle area, clip_area;
3112   gint i;
3113   gint text_width, text_height, y;
3114   gint xoffset=0;  
3115   gint size, sizel, sizer;
3116   GdkGC *fg_gc, *bg_gc;
3117   GtkSheetCellAttr attributes;
3118   PangoLayout *layout;
3119   PangoRectangle rect;
3120   PangoRectangle logical_rect;
3121   PangoLayoutLine *line;
3122   PangoFontMetrics *metrics;
3123   PangoContext *context = gtk_widget_get_pango_context(GTK_WIDGET(sheet)); 
3124   gint ascent, descent, y_pos;
3125
3126   gchar *label;
3127
3128   g_return_if_fail (sheet != NULL);
3129
3130    /* bail now if we aren't drawable yet */
3131    if (!GTK_WIDGET_DRAWABLE (sheet))
3132     return;
3133
3134   label = gtk_sheet_cell_get_text(sheet, row, col);
3135   if (!label)
3136       return;
3137
3138   if (row < 0 || row >= yyy_row_count(sheet)) return;
3139   if (col < 0 || col >= xxx_column_count(sheet)) return;
3140   if (! xxx_column_is_visible(sheet, col)) return;
3141   if (!yyy_row_is_visible(sheet, row)) return;
3142
3143
3144   widget = GTK_WIDGET(sheet);
3145
3146   gtk_sheet_get_attributes(sheet, row, col, &attributes);
3147
3148   /* select GC for background rectangle */
3149   gdk_gc_set_foreground (sheet->fg_gc, &attributes.foreground);
3150   gdk_gc_set_foreground (sheet->bg_gc, &attributes.background);
3151
3152   fg_gc = sheet->fg_gc;
3153   bg_gc = sheet->bg_gc;
3154
3155   area.x=COLUMN_LEFT_XPIXEL(sheet,col);
3156   area.y=ROW_TOP_YPIXEL(sheet,row);
3157   area.width  = xxx_column_width(sheet, col);
3158   area.height = yyy_row_height(sheet, row);
3159
3160   clip_area = area;
3161
3162   layout = gtk_widget_create_pango_layout (GTK_WIDGET(sheet), label);
3163   dispose_string(sheet, label);
3164   pango_layout_set_font_description (layout, attributes.font_desc);
3165
3166   pango_layout_get_pixel_extents (layout, NULL, &rect);
3167
3168   line = pango_layout_get_lines (layout)->data;
3169   pango_layout_line_get_extents (line, NULL, &logical_rect);
3170
3171   metrics = pango_context_get_metrics(context,
3172                                   attributes.font_desc,
3173                                   pango_context_get_language(context)); 
3174
3175   ascent = pango_font_metrics_get_ascent(metrics) / PANGO_SCALE;
3176   descent = pango_font_metrics_get_descent(metrics) / PANGO_SCALE;
3177
3178   pango_font_metrics_unref(metrics);
3179
3180   /* Align primarily for locale's ascent/descent */
3181
3182   logical_rect.height /= PANGO_SCALE;
3183   logical_rect.y /= PANGO_SCALE;
3184   y_pos =  area.height - logical_rect.height;
3185
3186   if (logical_rect.height > area.height)
3187     y_pos = (logical_rect.height - area.height - 2*CELLOFFSET) / 2;
3188   else if (y_pos < 0)
3189     y_pos = 0;
3190   else if (y_pos + logical_rect.height > area.height)
3191     y_pos = area.height - logical_rect.height;
3192
3193   text_width = rect.width;
3194   text_height = rect.height;
3195   y = area.y + y_pos - CELLOFFSET;
3196
3197   switch(attributes.justification){
3198     case GTK_JUSTIFY_RIGHT:
3199           size=area.width;
3200           area.x+=area.width;
3201           if(!gtk_sheet_clip_text(sheet)){          
3202            for(i=col-1; i>=MIN_VISIBLE_COLUMN(sheet); i--){
3203              if( !gtk_sheet_cell_empty(sheet, row, i)) break;
3204              if(size>=text_width+CELLOFFSET) break;
3205              size+=xxx_column_width(sheet, i);
3206              xxx_column_set_right_column(sheet, i, 
3207                                          MAX(col,
3208                                              xxx_column_right_column(sheet, i)));
3209            }
3210            area.width=size;
3211           }
3212           area.x-=size;
3213           xoffset+=area.width-text_width - 2 * CELLOFFSET -
3214                    attributes.border.width/2;
3215           break;
3216      case GTK_JUSTIFY_CENTER:
3217           sizel=area.width/2;
3218           sizer=area.width/2;
3219           area.x+=area.width/2;
3220           if(!gtk_sheet_clip_text(sheet)){          
3221            for(i=col+1; i<=MAX_VISIBLE_COLUMN(sheet); i++){
3222              if( ! gtk_sheet_cell_empty(sheet, row, i)) break;
3223              if(sizer>=text_width/2) break;
3224              sizer+= xxx_column_width(sheet, i);
3225              xxx_column_set_left_column(sheet, i, 
3226                                         MIN(
3227                                             col, 
3228                                             xxx_column_left_column(sheet, i)));
3229            }
3230            for(i=col-1; i>=MIN_VISIBLE_COLUMN(sheet); i--){
3231              if( ! gtk_sheet_cell_empty(sheet, row, i)) break;
3232              if(sizel>=text_width/2) break;
3233              sizel+=xxx_column_width(sheet, i);
3234              xxx_column_set_right_column(sheet, i, 
3235                                          MAX(col,
3236                                              xxx_column_right_column(sheet, i)));
3237            }
3238            size=MIN(sizel, sizer);
3239           }
3240           area.x-=sizel;
3241           xoffset+= sizel - text_width/2 - CELLOFFSET;
3242           area.width=sizel+sizer;
3243           break;
3244       case GTK_JUSTIFY_LEFT:
3245       default:
3246           size=area.width;
3247           if(!gtk_sheet_clip_text(sheet)){          
3248            for(i=col+1; i<=MAX_VISIBLE_COLUMN(sheet); i++){
3249              if(! gtk_sheet_cell_empty(sheet, row, i)) break;
3250              if(size>=text_width+CELLOFFSET) break;
3251              size+=xxx_column_width(sheet, i);
3252              xxx_column_set_left_column(sheet, i, 
3253                                         MIN(
3254                                             col, 
3255                                             xxx_column_left_column(sheet, i)));
3256
3257            }
3258            area.width=size;
3259           }
3260           xoffset += attributes.border.width/2;
3261           break;
3262    }
3263
3264   if(!gtk_sheet_clip_text(sheet)) clip_area = area;
3265   gdk_gc_set_clip_rectangle(fg_gc, &clip_area);
3266
3267
3268   gdk_draw_layout (sheet->pixmap, fg_gc,
3269                    area.x + xoffset + CELLOFFSET,
3270                    y,
3271                    layout);
3272
3273   gdk_gc_set_clip_rectangle(fg_gc, NULL);
3274   g_object_unref(G_OBJECT(layout));
3275
3276   gdk_draw_pixmap(sheet->sheet_window,
3277                   GTK_WIDGET(sheet)->style->fg_gc[GTK_STATE_NORMAL],
3278                   sheet->pixmap,
3279                   area.x,
3280                   area.y,
3281                   area.x,
3282                   area.y,
3283                   area.width,
3284                   area.height);      
3285
3286 }
3287
3288
3289
3290 static void
3291 gtk_sheet_range_draw(GtkSheet *sheet, const GtkSheetRange *range)
3292 {
3293  gint i,j;
3294  GtkSheetRange drawing_range;
3295  GdkRectangle area;
3296
3297  g_return_if_fail(sheet != NULL);
3298  g_return_if_fail(GTK_SHEET(sheet));
3299  
3300  if(!GTK_WIDGET_DRAWABLE(GTK_WIDGET(sheet))) return;
3301  if(!GTK_WIDGET_REALIZED(GTK_WIDGET(sheet))) return;
3302  if(!GTK_WIDGET_MAPPED(GTK_WIDGET(sheet))) return;
3303
3304  if(range == NULL)
3305  {
3306    drawing_range.row0=MIN_VISIBLE_ROW(sheet);
3307    drawing_range.col0=MIN_VISIBLE_COLUMN(sheet);
3308    drawing_range.rowi=MAX_VISIBLE_ROW(sheet);
3309    drawing_range.coli=MAX_VISIBLE_COLUMN(sheet);
3310 /*
3311    gdk_draw_rectangle (sheet->pixmap,
3312                        GTK_WIDGET(sheet)->style->white_gc,
3313                        TRUE,
3314                        0,0,
3315                        sheet->sheet_window_width,sheet->sheet_window_height);
3316 */
3317  }
3318  else
3319  {
3320    drawing_range.row0=MAX(range->row0, MIN_VISIBLE_ROW(sheet));
3321    drawing_range.col0=MAX(range->col0, MIN_VISIBLE_COLUMN(sheet));
3322    drawing_range.rowi=MIN(range->rowi, MAX_VISIBLE_ROW(sheet));
3323    drawing_range.coli=MIN(range->coli, MAX_VISIBLE_COLUMN(sheet));
3324  }
3325
3326
3327  if(drawing_range.coli == xxx_column_count(sheet) - 1)
3328    {
3329      area.x=COLUMN_LEFT_XPIXEL(sheet,
3330                                xxx_column_count(sheet) - 1) +
3331        xxx_column_width(sheet, xxx_column_count(sheet) - 1) + 1;
3332
3333      area.y=0;
3334
3335      gdk_gc_set_foreground(sheet->fg_gc, &sheet->bg_color);
3336
3337      gdk_draw_rectangle (sheet->pixmap,
3338                          sheet->fg_gc,
3339                          TRUE,
3340                          area.x,area.y,
3341                          sheet->sheet_window_width - area.x, 
3342                          sheet->sheet_window_height);
3343
3344      gdk_draw_pixmap(sheet->sheet_window,
3345                      GTK_WIDGET(sheet)->style->fg_gc[GTK_STATE_NORMAL],
3346                      sheet->pixmap,
3347                      area.x,
3348                      area.y,
3349                      area.x,
3350                      area.y,
3351                      sheet->sheet_window_width - area.x, 
3352                      sheet->sheet_window_height);                  
3353    }
3354  
3355  if(drawing_range.rowi == yyy_row_count(sheet) - 1){
3356   area.x=0;
3357   area.y=ROW_TOP_YPIXEL(sheet,
3358                         yyy_row_count(sheet) - 1) + 
3359     yyy_row_height(sheet, yyy_row_count(sheet) - 1) + 1;
3360
3361   gdk_gc_set_foreground(sheet->fg_gc, &sheet->bg_color);
3362
3363   gdk_draw_rectangle (sheet->pixmap,
3364                       sheet->fg_gc,
3365                       TRUE,
3366                       area.x,area.y,
3367                       sheet->sheet_window_width,
3368                       sheet->sheet_window_height - area.y);
3369
3370   gdk_draw_pixmap(sheet->sheet_window,
3371                   GTK_WIDGET(sheet)->style->fg_gc[GTK_STATE_NORMAL],
3372                   sheet->pixmap,
3373                   area.x,
3374                   area.y,
3375                   area.x,
3376                   area.y,
3377                   sheet->sheet_window_width,
3378                   sheet->sheet_window_height - area.y);
3379  }
3380
3381  for(i=drawing_range.row0; i<=drawing_range.rowi; i++)
3382   for(j=drawing_range.col0; j<=drawing_range.coli; j++){
3383      gtk_sheet_cell_draw_default(sheet, i, j);
3384   }
3385
3386  for(i=drawing_range.row0; i<=drawing_range.rowi; i++)
3387   for(j=drawing_range.col0; j<=drawing_range.coli; j++){
3388      gtk_sheet_cell_draw_border(sheet, i-1, j, GTK_SHEET_BOTTOM_BORDER);
3389      gtk_sheet_cell_draw_border(sheet, i+1, j, GTK_SHEET_TOP_BORDER);
3390      gtk_sheet_cell_draw_border(sheet, i, j-1, GTK_SHEET_RIGHT_BORDER);
3391      gtk_sheet_cell_draw_border(sheet, i, j+1, GTK_SHEET_LEFT_BORDER);
3392      gtk_sheet_cell_draw_border(sheet, i, j, 15);
3393   }
3394
3395  for(i=drawing_range.row0; i<=drawing_range.rowi; i++)
3396   for(j=drawing_range.col0; j<=drawing_range.coli; j++)
3397                   gtk_sheet_cell_draw_label (sheet, i, j);
3398      
3399  for(i=drawing_range.row0; i<=drawing_range.rowi; i++)
3400    for(j= xxx_column_left_column(sheet, drawing_range.col0);
3401        j<drawing_range.col0; j++)
3402      gtk_sheet_cell_draw_label (sheet, i, j);
3403     
3404  for(i=drawing_range.row0; i<=drawing_range.rowi; i++)
3405    for(j = drawing_range.coli+1; 
3406        j <= xxx_column_right_column(sheet, drawing_range.coli);
3407        j++)
3408      gtk_sheet_cell_draw_label (sheet, i, j); 
3409
3410   gtk_sheet_draw_backing_pixmap(sheet, drawing_range);
3411
3412   if(sheet->state != GTK_SHEET_NORMAL && gtk_sheet_range_isvisible(sheet, sheet->range))
3413        gtk_sheet_range_draw_selection(sheet, drawing_range);
3414   
3415   if(sheet->state == GTK_STATE_NORMAL && 
3416      sheet->active_cell.row >= drawing_range.row0 &&
3417      sheet->active_cell.row <= drawing_range.rowi &&
3418      sheet->active_cell.col >= drawing_range.col0 &&
3419      sheet->active_cell.col <= drawing_range.coli)    
3420                             gtk_sheet_show_active_cell(sheet);
3421
3422 }
3423
3424 static void
3425 gtk_sheet_range_draw_selection(GtkSheet *sheet, GtkSheetRange range)
3426 {
3427   GdkRectangle area;
3428   gint i,j;
3429   GtkSheetRange aux;
3430
3431   if(range.col0 > sheet->range.coli || range.coli < sheet->range.col0 ||
3432      range.row0 > sheet->range.rowi || range.rowi < sheet->range.row0)
3433      return;
3434
3435   if(!gtk_sheet_range_isvisible(sheet, range)) return;
3436   if(!GTK_WIDGET_REALIZED(GTK_WIDGET(sheet))) return;
3437
3438   aux=range;
3439
3440   range.col0=MAX(sheet->range.col0, range.col0);
3441   range.coli=MIN(sheet->range.coli, range.coli);
3442   range.row0=MAX(sheet->range.row0, range.row0);
3443   range.rowi=MIN(sheet->range.rowi, range.rowi);
3444
3445   range.col0=MAX(range.col0, MIN_VISIBLE_COLUMN(sheet));
3446   range.coli=MIN(range.coli, MAX_VISIBLE_COLUMN(sheet));
3447   range.row0=MAX(range.row0, MIN_VISIBLE_ROW(sheet));
3448   range.rowi=MIN(range.rowi, MAX_VISIBLE_ROW(sheet));
3449
3450   for(i=range.row0; i<=range.rowi; i++){
3451    for(j=range.col0; j<=range.coli; j++){
3452
3453     if(gtk_sheet_cell_get_state(sheet, i, j)==GTK_STATE_SELECTED && 
3454        xxx_column_is_visible(sheet, j) && yyy_row_is_visible(sheet, i)){
3455
3456 #if 0
3457       row_button_set(sheet, i);
3458       column_button_set(sheet, j);
3459 #endif
3460
3461       area.x=COLUMN_LEFT_XPIXEL(sheet,j);
3462       area.y=ROW_TOP_YPIXEL(sheet,i);
3463       area.width= xxx_column_width(sheet, j);
3464       area.height=yyy_row_height(sheet, i);
3465
3466       if(i==sheet->range.row0){
3467             area.y=area.y+2;
3468             area.height=area.height-2;
3469       }
3470       if(i==sheet->range.rowi) area.height=area.height-3;
3471       if(j==sheet->range.col0){
3472             area.x=area.x+2;
3473             area.width=area.width-2;
3474       }
3475       if(j==sheet->range.coli) area.width=area.width-3;
3476
3477       if(i!=sheet->active_cell.row || j!=sheet->active_cell.col){
3478        gdk_draw_rectangle (sheet->sheet_window,
3479                            sheet->xor_gc,
3480                            TRUE,
3481                            area.x+1,area.y+1,
3482                            area.width,area.height);
3483       }
3484     }
3485
3486    }
3487   }
3488
3489   gtk_sheet_draw_border(sheet, sheet->range);
3490
3491 }
3492
3493 static void
3494 gtk_sheet_draw_backing_pixmap(GtkSheet *sheet, GtkSheetRange range)
3495 {
3496   gint x,y,width,height;
3497   
3498   if(!GTK_WIDGET_REALIZED(GTK_WIDGET(sheet))) return;
3499  
3500   x = COLUMN_LEFT_XPIXEL(sheet,range.col0);
3501   y = ROW_TOP_YPIXEL(sheet, range.row0);  
3502   width = COLUMN_LEFT_XPIXEL(sheet, range.coli) - x +
3503     xxx_column_width(sheet, range.coli);
3504
3505   height=ROW_TOP_YPIXEL(sheet, range.rowi)-y+yyy_row_height(sheet, range.rowi);
3506
3507   if(range.row0==sheet->range.row0){
3508           y=y-5;
3509           height=height+5;
3510   }
3511   if(range.rowi==sheet->range.rowi) height=height+5;
3512   if(range.col0==sheet->range.col0){
3513             x=x-5;
3514             width=width+5;
3515   }
3516   if(range.coli==sheet->range.coli) width=width+5;
3517
3518   
3519   width=MIN(width, sheet->sheet_window_width-x);
3520   height=MIN(height, sheet->sheet_window_height-y);
3521
3522   x--; 
3523   y--;
3524   width+=2;
3525   height+=2;
3526
3527   x = (sheet->row_titles_visible)
3528        ? MAX(x, sheet->row_title_area.width) : MAX(x, 0);
3529   y = (sheet->column_titles_visible)
3530        ? MAX(y, sheet->column_title_area.height) : MAX(y, 0);
3531
3532   if(range.coli == xxx_column_count(sheet) - 1) 
3533     width = sheet->sheet_window_width - x; 
3534   if(range.rowi == yyy_row_count(sheet)    - 1) 
3535     height=sheet->sheet_window_height - y;
3536
3537   gdk_draw_pixmap(sheet->sheet_window,
3538                   GTK_WIDGET(sheet)->style->fg_gc[GTK_STATE_NORMAL],
3539                   sheet->pixmap,
3540                   x,
3541                   y,
3542                   x,
3543                   y,
3544                   width+1,
3545                   height+1);                  
3546 }
3547
3548
3549 void 
3550 gtk_sheet_set_cell_text(GtkSheet *sheet, gint row, gint col, const gchar *text)
3551 {
3552  GtkSheetCellAttr attributes;
3553
3554  g_return_if_fail (sheet != NULL);
3555  g_return_if_fail (GTK_IS_SHEET (sheet));
3556  if (col >= xxx_column_count(sheet) || row >= yyy_row_count(sheet)) return;
3557  if (col < 0 || row < 0) return;
3558
3559  gtk_sheet_get_attributes(sheet, row, col, &attributes);
3560  gtk_sheet_set_cell(sheet, row, col, attributes.justification, text);
3561 }
3562
3563 static inline gint 
3564 safe_strcmp(const gchar *s1, const gchar *s2)
3565 {
3566   if ( !s1 && !s2) return 0;
3567   if ( !s1) return -1;
3568   if ( !s2) return +1;
3569   return strcmp(s1, s2);
3570 }
3571
3572 void 
3573 gtk_sheet_set_cell(GtkSheet *sheet, gint row, gint col, 
3574                    GtkJustification justification,
3575                    const gchar *text)
3576 {
3577   GSheetModel *model ;
3578   gboolean changed ;
3579   gchar *old_text ; 
3580
3581   GtkSheetRange range;
3582   gint text_width;
3583   GtkSheetCellAttr attributes;
3584
3585   g_return_if_fail (sheet != NULL);
3586   g_return_if_fail (GTK_IS_SHEET (sheet));
3587   if (col >= xxx_column_count(sheet) || row >= yyy_row_count(sheet)) return;
3588   if (col < 0 || row < 0) return;
3589
3590   gtk_sheet_get_attributes(sheet, row, col, &attributes);
3591
3592   attributes.justification = justification;
3593
3594   model =  gtk_sheet_get_model(sheet);
3595
3596   old_text = g_sheet_model_get_string(model, row, col);
3597
3598   changed = FALSE;
3599
3600   if (0 != safe_strcmp(old_text, text))
3601     changed = g_sheet_model_set_string(model, text, row, col);
3602
3603   if ( g_sheet_model_free_strings(model))
3604     g_free(old_text);
3605
3606
3607   if(changed && attributes.is_visible)
3608     {
3609       gchar *s = gtk_sheet_cell_get_text(sheet, row, col);
3610       text_width = 0;
3611       if(s && strlen(s) > 0) {
3612         text_width = STRING_WIDTH(GTK_WIDGET(sheet), 
3613                                   attributes.font_desc, text);
3614       }
3615       dispose_string(sheet, s);
3616
3617     range.row0 = row;
3618     range.rowi = row;
3619     range.col0 = sheet->view.col0;
3620     range.coli = sheet->view.coli;
3621
3622     if(gtk_sheet_autoresize(sheet) &&
3623        text_width > xxx_column_width(sheet, col) - 2*CELLOFFSET-attributes.border.width){
3624       gtk_sheet_set_column_width(sheet, col, text_width+2*CELLOFFSET+attributes.border.width);
3625       GTK_SHEET_SET_FLAGS(sheet, GTK_SHEET_REDRAW_PENDING);
3626     }
3627     else
3628       if(!GTK_SHEET_IS_FROZEN(sheet))
3629         gtk_sheet_range_draw(sheet, &range);
3630   }
3631
3632   if ( changed ) 
3633     gtk_signal_emit(GTK_OBJECT(sheet),sheet_signals[CHANGED], row, col);
3634
3635 }
3636
3637
3638 void
3639 gtk_sheet_cell_clear (GtkSheet *sheet, gint row, gint column)
3640 {
3641   GtkSheetRange range;
3642
3643   g_return_if_fail (sheet != NULL);
3644   g_return_if_fail (GTK_IS_SHEET (sheet));
3645   if (column >= xxx_column_count(sheet) || row >= yyy_row_count(sheet)) return;
3646   if (column < 0 || row < 0) return;
3647
3648   range.row0 = row;
3649   range.rowi = row;
3650   range.col0 = sheet->view.col0;
3651   range.coli = sheet->view.coli;
3652
3653   gtk_sheet_real_cell_clear(sheet, row, column, FALSE);
3654
3655   if(!GTK_SHEET_IS_FROZEN(sheet)){
3656      gtk_sheet_range_draw(sheet, &range);
3657   }
3658 }
3659
3660 void
3661 gtk_sheet_cell_delete (GtkSheet *sheet, gint row, gint column)
3662 {
3663   GtkSheetRange range;
3664
3665   g_return_if_fail (sheet != NULL);
3666   g_return_if_fail (GTK_IS_SHEET (sheet));
3667   if (column >= xxx_column_count(sheet) || row >= yyy_row_count(sheet)) return;
3668   if (column < 0 || row < 0) return;
3669
3670   range.row0 = row;
3671   range.rowi = row;
3672   range.col0 = sheet->view.col0;
3673   range.coli = sheet->view.coli;
3674
3675   gtk_sheet_real_cell_clear(sheet, row, column, TRUE);
3676
3677   if(!GTK_SHEET_IS_FROZEN(sheet)){
3678      gtk_sheet_range_draw(sheet, &range);
3679   }
3680 }
3681
3682 static void
3683 gtk_sheet_real_cell_clear (GtkSheet *sheet, gint row, gint column, gboolean delete)
3684 {
3685   GSheetModel *model =  gtk_sheet_get_model(sheet);
3686
3687   gchar *old_text = gtk_sheet_cell_get_text(sheet, row, column); 
3688  
3689   if (old_text && strlen(old_text) > 0 )
3690     {
3691       g_sheet_model_datum_clear(model, row, column);
3692       
3693       if(GTK_IS_OBJECT(sheet) && G_OBJECT(sheet)->ref_count > 0)
3694         gtk_signal_emit(GTK_OBJECT(sheet),sheet_signals[CLEAR_CELL], 
3695                         row, column);
3696     }  
3697
3698   dispose_string (sheet, old_text);
3699 }
3700     
3701 void
3702 gtk_sheet_range_clear (GtkSheet *sheet, const GtkSheetRange *range)
3703 {
3704   g_return_if_fail (sheet != NULL);
3705   g_return_if_fail (GTK_IS_SHEET (sheet));
3706
3707   gtk_sheet_real_range_clear(sheet, range, FALSE);
3708 }
3709
3710 void
3711 gtk_sheet_range_delete (GtkSheet *sheet, const GtkSheetRange *range)
3712 {
3713   g_return_if_fail (sheet != NULL);
3714   g_return_if_fail (GTK_IS_SHEET (sheet));
3715
3716   gtk_sheet_real_range_clear(sheet, range, TRUE);
3717 }
3718  
3719
3720 static void
3721 gtk_sheet_real_range_clear (GtkSheet *sheet, const GtkSheetRange *range, 
3722                             gboolean delete)
3723 {
3724   gint i, j;
3725   GtkSheetRange clear;
3726
3727   if(!range){
3728     clear.row0=0;
3729     clear.rowi = yyy_row_count(sheet) - 1;
3730     clear.col0=0;
3731     clear.coli = xxx_column_count(sheet) - 1;
3732   }else
3733     clear=*range;  
3734
3735   clear.row0=MAX(clear.row0, 0);
3736   clear.col0=MAX(clear.col0, 0);
3737   clear.rowi=MIN(clear.rowi, yyy_row_count(sheet) - 1 );
3738   clear.coli=MIN(clear.coli, xxx_column_count(sheet) - 1 );
3739
3740   for(i=clear.row0; i<=clear.rowi; i++)
3741     for(j=clear.col0; j<=clear.coli; j++){
3742       gtk_sheet_real_cell_clear(sheet, i, j, delete);
3743     }
3744
3745   gtk_sheet_range_draw(sheet, NULL);
3746 }
3747
3748
3749 static gboolean
3750 gtk_sheet_cell_empty (const GtkSheet *sheet, gint row, gint col)
3751 {
3752   gboolean empty;
3753   char *text = gtk_sheet_cell_get_text(sheet, row, col);
3754   empty = (text == NULL );
3755  
3756   dispose_string(sheet, text);
3757
3758   return empty;
3759 }
3760
3761
3762 gchar *     
3763 gtk_sheet_cell_get_text (const GtkSheet *sheet, gint row, gint col)
3764 {
3765   GSheetModel *model;
3766   g_return_val_if_fail (sheet != NULL, NULL);
3767   g_return_val_if_fail (GTK_IS_SHEET (sheet), NULL);
3768
3769   if(col >= xxx_column_count(sheet) || row >= yyy_row_count(sheet)) 
3770     return NULL;
3771   if(col < 0 || row < 0) return NULL;
3772
3773   model =  gtk_sheet_get_model(sheet);
3774
3775   if ( !model ) 
3776     return NULL;
3777
3778   return g_sheet_model_get_string(model, row, col);
3779 }
3780
3781
3782 GtkStateType
3783 gtk_sheet_cell_get_state (GtkSheet *sheet, gint row, gint col)
3784 {
3785  gint state;
3786  GtkSheetRange *range;
3787
3788  g_return_val_if_fail (sheet != NULL, 0);
3789  g_return_val_if_fail (GTK_IS_SHEET (sheet), 0);
3790  if(col >= xxx_column_count(sheet) || row >= yyy_row_count(sheet)) return 0;
3791  if(col < 0 || row < 0) return 0;
3792
3793  state = sheet->state;
3794  range = &sheet->range;
3795
3796  switch (state)
3797    {
3798    case GTK_SHEET_NORMAL:
3799      return GTK_STATE_NORMAL;
3800      break;
3801    case GTK_SHEET_ROW_SELECTED:
3802      if(row>=range->row0 && row<=range->rowi) 
3803        return GTK_STATE_SELECTED;
3804      break;
3805    case GTK_SHEET_COLUMN_SELECTED:
3806      if(col>=range->col0 && col<=range->coli) 
3807        return GTK_STATE_SELECTED;
3808      break;
3809    case GTK_SHEET_RANGE_SELECTED:
3810      if(row >= range->row0 && row <= range->rowi && \
3811         col >= range->col0 && col <= range->coli)
3812        return GTK_STATE_SELECTED;
3813      break;
3814    }
3815  return GTK_STATE_NORMAL;
3816 }
3817
3818 gboolean
3819 gtk_sheet_get_pixel_info (GtkSheet * sheet,
3820                           gint x,
3821                           gint y,
3822                           gint * row,
3823                           gint * column)
3824 {
3825   gint trow, tcol;
3826
3827   g_return_val_if_fail (sheet != NULL, 0);
3828   g_return_val_if_fail (GTK_IS_SHEET (sheet), 0);
3829
3830   /* bounds checking, return false if the user clicked 
3831    * on a blank area */
3832   trow = ROW_FROM_YPIXEL (sheet, y);
3833   if (trow >= yyy_row_count(sheet))
3834     return FALSE;
3835
3836   *row = trow;
3837
3838   tcol = COLUMN_FROM_XPIXEL (sheet, x);
3839   if (tcol >= xxx_column_count(sheet))
3840     return FALSE;
3841
3842  *column = tcol;
3843
3844   return TRUE;
3845 }
3846
3847 gboolean
3848 gtk_sheet_get_cell_area  (GtkSheet * sheet,
3849                           gint row,
3850                           gint column,
3851                           GdkRectangle *area)
3852 {
3853   g_return_val_if_fail (sheet != NULL, 0);
3854   g_return_val_if_fail (GTK_IS_SHEET (sheet), 0);
3855
3856   if(row >= yyy_row_count(sheet) || column >= xxx_column_count(sheet)) 
3857     return FALSE;
3858
3859   area->x = (column == -1) ? 0 : (COLUMN_LEFT_XPIXEL(sheet, column) -
3860                                  (sheet->row_titles_visible
3861                                    ? sheet->row_title_area.width
3862                                    : 0));
3863   area->y = (row == -1) ? 0 : (ROW_TOP_YPIXEL(sheet, row) -
3864                               (sheet->column_titles_visible
3865                                ? sheet->column_title_area.height
3866                                : 0));
3867   area->width= (column == -1) ? sheet->row_title_area.width
3868     : xxx_column_width(sheet, column);
3869
3870   area->height= (row == -1) ? sheet->column_title_area.height
3871                             : yyy_row_height(sheet, row);
3872
3873 /*
3874   if(row < 0 || column < 0) return FALSE;
3875
3876   area->x = COLUMN_LEFT_XPIXEL(sheet, column);
3877   area->y = ROW_TOP_YPIXEL(sheet, row);
3878   if(sheet->row_titles_visible)
3879            area->x -= sheet->row_title_area.width;
3880   if(sheet->column_titles_visible)
3881            area->y -= sheet->column_title_area.height;
3882
3883   area->width=sheet->column[column].width;
3884   area->height=yyy_row_height(sheet, row);  
3885 */
3886   return TRUE;
3887 }
3888
3889 gboolean 
3890 gtk_sheet_set_active_cell (GtkSheet *sheet, gint row, gint column)
3891 {
3892  g_return_val_if_fail (sheet != NULL, 0);
3893  g_return_val_if_fail (GTK_IS_SHEET (sheet), 0);
3894
3895  if(row < -1 || column < -1) return FALSE;
3896  if(row >= yyy_row_count(sheet) || column >= xxx_column_count(sheet)) 
3897    return FALSE;
3898
3899  if(GTK_WIDGET_REALIZED(GTK_WIDGET(sheet)))
3900    {
3901        if(!gtk_sheet_deactivate_cell(sheet)) return FALSE;
3902    }
3903
3904  sheet->active_cell.row = row;
3905  sheet->active_cell.col = column;
3906  
3907  if ( row == -1 || column == -1)
3908    {
3909      gtk_sheet_hide_active_cell(sheet);
3910      return TRUE;
3911    }
3912
3913  if(!gtk_sheet_activate_cell(sheet, row, column)) return FALSE;
3914  
3915  if(gtk_sheet_autoscroll(sheet))
3916    gtk_sheet_move_query(sheet, row, column);
3917
3918  return TRUE;
3919 }
3920
3921 void
3922 gtk_sheet_get_active_cell (GtkSheet *sheet, gint *row, gint *column)
3923 {
3924   g_return_if_fail (sheet != NULL);
3925   g_return_if_fail (GTK_IS_SHEET (sheet));
3926
3927   *row = sheet->active_cell.row;
3928   *column = sheet->active_cell.col;
3929 }
3930
3931 static void
3932 gtk_sheet_entry_changed(GtkWidget *widget, gpointer data)
3933 {
3934  GtkSheet *sheet;
3935  gint row,col;
3936  const char *text;
3937  GtkJustification justification;
3938  GtkSheetCellAttr attributes;
3939
3940  g_return_if_fail (data != NULL);
3941  g_return_if_fail (GTK_IS_SHEET (data));
3942
3943  sheet=GTK_SHEET(data);
3944
3945  if(!GTK_WIDGET_VISIBLE(widget)) return;
3946  if(sheet->state != GTK_STATE_NORMAL) return;
3947
3948  row=sheet->active_cell.row;
3949  col=sheet->active_cell.col;
3950
3951  if(row<0 || col<0) return;
3952
3953  sheet->active_cell.row=-1;
3954  sheet->active_cell.col=-1;
3955
3956  text = gtk_entry_get_text(GTK_ENTRY(gtk_sheet_get_entry(sheet)));
3957
3958  GTK_SHEET_SET_FLAGS(sheet, GTK_SHEET_IS_FROZEN);
3959
3960  if(text && strlen(text) > 0){
3961       gtk_sheet_get_attributes(sheet, row, col, &attributes); 
3962       justification=attributes.justification;
3963       gtk_sheet_set_cell(sheet, row, col, justification, text);
3964  }
3965
3966  if(sheet->freeze_count == 0)
3967         GTK_SHEET_UNSET_FLAGS(sheet, GTK_SHEET_IS_FROZEN);
3968  
3969  sheet->active_cell.row=row;;
3970  sheet->active_cell.col=col;
3971 }
3972
3973
3974 static gboolean 
3975 gtk_sheet_deactivate_cell(GtkSheet *sheet)
3976 {
3977  gboolean veto = TRUE;
3978
3979  g_return_val_if_fail (sheet != NULL, FALSE);
3980  g_return_val_if_fail (GTK_IS_SHEET (sheet), FALSE);
3981
3982  if(!GTK_WIDGET_REALIZED(GTK_WIDGET(sheet))) return FALSE;
3983  if(sheet->state != GTK_SHEET_NORMAL) return FALSE;
3984
3985  _gtkextra_signal_emit(GTK_OBJECT(sheet),sheet_signals[DEACTIVATE], 
3986                                    sheet->active_cell.row,
3987                                    sheet->active_cell.col, &veto);
3988
3989  if(!veto) return FALSE;
3990
3991  if ( sheet->active_cell.row == -1 || sheet->active_cell.col == -1 )
3992    return TRUE;
3993
3994  gtk_signal_disconnect_by_func(GTK_OBJECT(gtk_sheet_get_entry(sheet)),
3995                                (GtkSignalFunc) gtk_sheet_entry_changed,
3996                                GTK_OBJECT(GTK_WIDGET(sheet)));
3997
3998  gtk_sheet_hide_active_cell(sheet);
3999  sheet->active_cell.row = -1;
4000  sheet->active_cell.col = -1;
4001  
4002  if(GTK_SHEET_REDRAW_PENDING(sheet)){
4003    GTK_SHEET_UNSET_FLAGS(sheet, GTK_SHEET_REDRAW_PENDING);
4004    gtk_sheet_range_draw(sheet, NULL);
4005  }
4006
4007  return TRUE;
4008 }       
4009
4010 static void
4011 gtk_sheet_hide_active_cell(GtkSheet *sheet)
4012 {
4013  const char *text;
4014  gint row,col;
4015  GtkJustification justification;
4016  GtkSheetCellAttr attributes;
4017
4018  if(!GTK_WIDGET_REALIZED(GTK_WIDGET(sheet))) return;
4019
4020  row=sheet->active_cell.row;
4021  col=sheet->active_cell.col;
4022
4023  if(row < 0 || col < 0) return;
4024
4025  if(sheet->freeze_count == 0)
4026      GTK_SHEET_UNSET_FLAGS(sheet, GTK_SHEET_IS_FROZEN);
4027
4028  text=gtk_entry_get_text(GTK_ENTRY(gtk_sheet_get_entry(sheet)));
4029
4030  gtk_sheet_get_attributes(sheet, row, col, &attributes); 
4031  justification=attributes.justification;
4032
4033  if(text && strlen(text)!=0){
4034       gtk_sheet_set_cell(sheet, row, col, justification, text);
4035       gtk_signal_emit(GTK_OBJECT(sheet),sheet_signals[SET_CELL], row, col);
4036       gtk_entry_set_text(GTK_ENTRY(sheet->sheet_entry), "");
4037  }
4038  else
4039  {
4040       gtk_sheet_cell_clear(sheet, row, col);
4041  }
4042
4043  row=sheet->active_cell.row;
4044  col=sheet->active_cell.col;
4045
4046 #if 0
4047  column_button_release(sheet, col);
4048  row_button_release(sheet, row);
4049 #endif
4050
4051  gtk_widget_hide(sheet->sheet_entry);
4052  gtk_widget_unmap(sheet->sheet_entry);
4053
4054  if(row != -1 && col != -1)
4055    gdk_draw_pixmap(sheet->sheet_window,
4056                    GTK_WIDGET(sheet)->style->fg_gc[GTK_STATE_NORMAL],
4057                    sheet->pixmap,
4058                    COLUMN_LEFT_XPIXEL(sheet,col)-1,
4059                    ROW_TOP_YPIXEL(sheet,row)-1,
4060                    COLUMN_LEFT_XPIXEL(sheet,col)-1,
4061                    ROW_TOP_YPIXEL(sheet,row)-1,
4062                    xxx_column_width(sheet, col) + 4,
4063                    yyy_row_height(sheet, row)+4);   
4064
4065  gtk_widget_grab_focus(GTK_WIDGET(sheet));
4066
4067  GTK_WIDGET_UNSET_FLAGS(GTK_WIDGET(sheet->sheet_entry), GTK_VISIBLE);
4068
4069 }
4070
4071 static gboolean
4072 gtk_sheet_activate_cell(GtkSheet *sheet, gint row, gint col)
4073 {
4074  gboolean veto = TRUE;
4075
4076  g_return_val_if_fail (sheet != NULL, FALSE);
4077  g_return_val_if_fail (GTK_IS_SHEET (sheet), FALSE);
4078
4079  if(row < 0 || col < 0) return FALSE;
4080  if(row >= yyy_row_count(sheet) || col >= xxx_column_count(sheet)) 
4081    return FALSE;
4082
4083 /* _gtkextra_signal_emit(GTK_OBJECT(sheet),sheet_signals[ACTIVATE], row, col, &veto);
4084  if(!GTK_WIDGET_REALIZED(GTK_WIDGET(sheet))) return veto;
4085 */
4086
4087  if(!veto) return FALSE;
4088  if(sheet->state != GTK_SHEET_NORMAL){
4089         sheet->state=GTK_SHEET_NORMAL;
4090         gtk_sheet_real_unselect_range(sheet, NULL);
4091  }
4092
4093  sheet->range.row0=row;
4094  sheet->range.col0=col;
4095  sheet->range.rowi=row;
4096  sheet->range.coli=col;
4097  sheet->active_cell.row=row;
4098  sheet->active_cell.col=col;
4099  sheet->selection_cell.row=row;
4100  sheet->selection_cell.col=col;
4101 #if 0
4102  row_button_set(sheet, row);
4103  column_button_set(sheet, col); 
4104 #endif
4105
4106  GTK_SHEET_UNSET_FLAGS(sheet, GTK_SHEET_IN_SELECTION);
4107  gtk_sheet_show_active_cell(sheet);
4108
4109    g_signal_connect(G_OBJECT(gtk_sheet_get_entry(sheet)),
4110                     "changed",
4111                     G_CALLBACK(gtk_sheet_entry_changed),
4112                     sheet);
4113
4114  _gtkextra_signal_emit(GTK_OBJECT(sheet),sheet_signals[ACTIVATE], row, col, &veto);
4115
4116  return TRUE;
4117 }
4118
4119 static void
4120 gtk_sheet_show_active_cell(GtkSheet *sheet)
4121 {
4122  GtkEntry *sheet_entry;
4123  GtkSheetCellAttr attributes;
4124  gchar *text = NULL;
4125  const gchar *old_text;
4126  GtkJustification justification;
4127  gint row, col;
4128
4129  g_return_if_fail (sheet != NULL);
4130  g_return_if_fail (GTK_IS_SHEET (sheet));
4131
4132  row = sheet->active_cell.row;
4133  col = sheet->active_cell.col;
4134
4135  /* Don't show the active cell, if there is no active cell: */
4136  if(!(row >= 0 && col >= 0)) /* e.g row or coll == -1. */
4137    return;
4138
4139  if(!GTK_WIDGET_REALIZED(GTK_WIDGET(sheet))) return;
4140  if(sheet->state != GTK_SHEET_NORMAL) return;
4141  if(GTK_SHEET_IN_SELECTION(sheet)) return;
4142
4143  GTK_WIDGET_SET_FLAGS(GTK_WIDGET(sheet->sheet_entry), GTK_VISIBLE);
4144
4145  sheet_entry = GTK_ENTRY(gtk_sheet_get_entry(sheet));
4146
4147  gtk_sheet_get_attributes(sheet, row, col, &attributes); 
4148
4149  justification = GTK_JUSTIFY_LEFT;
4150
4151  if(gtk_sheet_justify_entry(sheet))
4152       justification = attributes.justification;
4153
4154  text = gtk_sheet_cell_get_text(sheet, row, col);
4155  if ( ! text ) 
4156          text = g_strdup("");
4157
4158  gtk_entry_set_visibility(GTK_ENTRY(sheet_entry), attributes.is_visible);
4159
4160  if(gtk_sheet_locked(sheet) || !attributes.is_editable)
4161    gtk_entry_set_editable(GTK_ENTRY(sheet_entry), FALSE);
4162  else
4163    gtk_entry_set_editable(GTK_ENTRY(sheet_entry), TRUE);
4164
4165 /*** Added by John Gotts. Mar 25, 2005 *********/
4166  old_text = gtk_entry_get_text(GTK_ENTRY(sheet_entry));
4167  if (strcmp(old_text, text) != 0) 
4168 {
4169   if(!GTK_IS_ITEM_ENTRY(sheet_entry))
4170      gtk_entry_set_text(GTK_ENTRY(sheet_entry), text);
4171   else
4172      gtk_item_entry_set_text(GTK_ITEM_ENTRY(sheet_entry), text, justification);
4173  }
4174
4175  gtk_sheet_entry_set_max_size(sheet);
4176  gtk_sheet_size_allocate_entry(sheet);
4177
4178  gtk_widget_map(sheet->sheet_entry);
4179  gtk_sheet_draw_active_cell(sheet);
4180
4181  gtk_widget_grab_focus(GTK_WIDGET(sheet_entry));
4182
4183  dispose_string(sheet, text);
4184 }
4185
4186 static void
4187 gtk_sheet_draw_active_cell(GtkSheet *sheet)
4188 {
4189     gint row, col;
4190
4191     if(!GTK_WIDGET_DRAWABLE(GTK_WIDGET(sheet))) return;
4192     if(!GTK_WIDGET_REALIZED(GTK_WIDGET(sheet))) return;
4193
4194     row = sheet->active_cell.row;
4195     col = sheet->active_cell.col;
4196  
4197     if(row < 0 || col < 0) return;
4198
4199     if(!gtk_sheet_cell_isvisible(sheet, row, col)) return;
4200 #if 0
4201     row_button_set(sheet, row);
4202     column_button_set(sheet, col);
4203 #endif
4204     gtk_sheet_draw_backing_pixmap(sheet, sheet->range);
4205     gtk_sheet_draw_border(sheet, sheet->range);
4206 }
4207
4208
4209 static void
4210 gtk_sheet_make_backing_pixmap (GtkSheet *sheet, guint width, guint height)
4211 {
4212   gint pixmap_width, pixmap_height;
4213
4214   if(!GTK_WIDGET_REALIZED(GTK_WIDGET(sheet))) return;
4215
4216   if(width == 0 && height == 0){
4217      width=sheet->sheet_window_width+80;
4218      height=sheet->sheet_window_height+80;
4219   }
4220
4221   if (!sheet->pixmap)
4222     {
4223       /* allocate */
4224       sheet->pixmap = gdk_pixmap_new (sheet->sheet_window,
4225                                       width, height,
4226                                       -1);
4227       if(!GTK_SHEET_IS_FROZEN(sheet)) gtk_sheet_range_draw(sheet, NULL);
4228     }
4229   else
4230     {
4231       /* reallocate if sizes don't match */
4232       gdk_window_get_size (sheet->pixmap,
4233                            &pixmap_width, &pixmap_height);
4234       if ((pixmap_width != width) || (pixmap_height != height))
4235         {
4236           g_object_unref(sheet->pixmap);
4237           sheet->pixmap = gdk_pixmap_new (sheet->sheet_window,
4238                                                width, height,
4239                                                -1);
4240           if(!GTK_SHEET_IS_FROZEN(sheet)) gtk_sheet_range_draw(sheet, NULL);
4241         }
4242     }
4243 }
4244
4245 static void
4246 gtk_sheet_new_selection(GtkSheet *sheet, GtkSheetRange *range)
4247 {
4248   gint i,j, mask1, mask2;
4249   gint state, selected;
4250   gint x,y,width,height;
4251   GtkSheetRange new_range, aux_range;
4252
4253   g_return_if_fail (sheet != NULL);
4254
4255   if(range==NULL) range=&sheet->range;
4256
4257   new_range=*range;
4258
4259   range->row0=MIN(range->row0, sheet->range.row0);
4260   range->rowi=MAX(range->rowi, sheet->range.rowi);
4261   range->col0=MIN(range->col0, sheet->range.col0);
4262   range->coli=MAX(range->coli, sheet->range.coli);
4263
4264   range->row0=MAX(range->row0, MIN_VISIBLE_ROW(sheet));
4265   range->rowi=MIN(range->rowi, MAX_VISIBLE_ROW(sheet));
4266   range->col0=MAX(range->col0, MIN_VISIBLE_COLUMN(sheet));
4267   range->coli=MIN(range->coli, MAX_VISIBLE_COLUMN(sheet));
4268
4269   aux_range.row0=MAX(new_range.row0, MIN_VISIBLE_ROW(sheet));
4270   aux_range.rowi=MIN(new_range.rowi, MAX_VISIBLE_ROW(sheet));
4271   aux_range.col0=MAX(new_range.col0, MIN_VISIBLE_COLUMN(sheet));
4272   aux_range.coli=MIN(new_range.coli, MAX_VISIBLE_COLUMN(sheet));
4273
4274   for(i=range->row0; i<=range->rowi; i++){
4275    for(j=range->col0; j<=range->coli; j++){     
4276
4277     state=gtk_sheet_cell_get_state(sheet, i, j);
4278     selected=(i<=new_range.rowi && i>=new_range.row0 && 
4279         j<=new_range.coli && j>=new_range.col0) ? TRUE : FALSE;
4280
4281     if(state==GTK_STATE_SELECTED && selected &&
4282        xxx_column_is_visible(sheet, j) && yyy_row_is_visible(sheet, i) &&
4283        (i==sheet->range.row0 || i==sheet->range.rowi ||
4284         j==sheet->range.col0 || j==sheet->range.coli ||
4285         i==new_range.row0 || i==new_range.rowi ||
4286         j==new_range.col0 || j==new_range.coli)){
4287
4288        mask1 = i==sheet->range.row0 ? 1 : 0;
4289        mask1 = i==sheet->range.rowi ? mask1+2 : mask1;
4290        mask1 = j==sheet->range.col0 ? mask1+4 : mask1;
4291        mask1 = j==sheet->range.coli ? mask1+8 : mask1;
4292
4293        mask2 = i==new_range.row0 ? 1 : 0;
4294        mask2 = i==new_range.rowi ? mask2+2 : mask2;
4295        mask2 = j==new_range.col0 ? mask2+4 : mask2;
4296        mask2 = j==new_range.coli ? mask2+8 : mask2;     
4297
4298        if(mask1 != mask2){
4299          x=COLUMN_LEFT_XPIXEL(sheet,j);
4300          y=ROW_TOP_YPIXEL(sheet, i);  
4301          width=COLUMN_LEFT_XPIXEL(sheet, j)-x+
4302            xxx_column_width(sheet, j);
4303          height=ROW_TOP_YPIXEL(sheet, i)-y+yyy_row_height(sheet, i);
4304
4305          if(i==sheet->range.row0){
4306             y=y-3;
4307             height=height+3;
4308          }
4309          if(i==sheet->range.rowi) height=height+3;
4310          if(j==sheet->range.col0){
4311             x=x-3;
4312             width=width+3;
4313          }
4314          if(j==sheet->range.coli) width=width+3;
4315
4316          gdk_draw_pixmap(sheet->sheet_window,
4317                   GTK_WIDGET(sheet)->style->fg_gc[GTK_STATE_NORMAL],
4318                   sheet->pixmap,
4319                   x+1,
4320                   y+1,
4321                   x+1,
4322                   y+1,
4323                   width,
4324                   height);           
4325
4326          if(i != sheet->active_cell.row || j != sheet->active_cell.col){
4327            x=COLUMN_LEFT_XPIXEL(sheet,j);
4328            y=ROW_TOP_YPIXEL(sheet, i);  
4329            width=COLUMN_LEFT_XPIXEL(sheet, j)-x+
4330              xxx_column_width(sheet, j);
4331
4332            height=ROW_TOP_YPIXEL(sheet, i)-y+yyy_row_height(sheet, i);
4333
4334            if(i==new_range.row0){
4335                y=y+2;
4336                height=height-2;
4337             }
4338             if(i==new_range.rowi) height=height-3;
4339             if(j==new_range.col0){
4340                x=x+2;
4341                width=width-2;
4342             }
4343             if(j==new_range.coli) width=width-3;
4344
4345             gdk_draw_rectangle (sheet->sheet_window,
4346                            sheet->xor_gc,
4347                            TRUE,
4348                            x+1,y+1,
4349                            width,height);
4350           }
4351        }
4352     }
4353    }
4354   }
4355
4356   for(i=range->row0; i<=range->rowi; i++){
4357    for(j=range->col0; j<=range->coli; j++){     
4358
4359     state=gtk_sheet_cell_get_state(sheet, i, j);
4360     selected=(i<=new_range.rowi && i>=new_range.row0 && 
4361         j<=new_range.coli && j>=new_range.col0) ? TRUE : FALSE;
4362
4363     if(state==GTK_STATE_SELECTED && !selected &&   
4364        xxx_column_is_visible(sheet, j) && yyy_row_is_visible(sheet, i)){
4365
4366       x=COLUMN_LEFT_XPIXEL(sheet,j);
4367       y=ROW_TOP_YPIXEL(sheet, i);  
4368       width=COLUMN_LEFT_XPIXEL(sheet, j)-x+ xxx_column_width(sheet, j);
4369       height=ROW_TOP_YPIXEL(sheet, i)-y+yyy_row_height(sheet, i);
4370
4371       if(i==sheet->range.row0){
4372             y=y-3;
4373             height=height+3;
4374       }
4375       if(i==sheet->range.rowi) height=height+3;
4376       if(j==sheet->range.col0){
4377             x=x-3;
4378             width=width+3;
4379       }
4380       if(j==sheet->range.coli) width=width+3;
4381
4382       gdk_draw_pixmap(sheet->sheet_window,
4383                   GTK_WIDGET(sheet)->style->fg_gc[GTK_STATE_NORMAL],
4384                   sheet->pixmap,
4385                   x+1,
4386                   y+1,
4387                   x+1,
4388                   y+1,
4389                   width,
4390                   height);           
4391     }
4392    }
4393   }
4394
4395   for(i=range->row0; i<=range->rowi; i++){
4396    for(j=range->col0; j<=range->coli; j++){     
4397
4398     state=gtk_sheet_cell_get_state(sheet, i, j);
4399     selected=(i<=new_range.rowi && i>=new_range.row0 && 
4400         j<=new_range.coli && j>=new_range.col0) ? TRUE : FALSE;
4401
4402     if(state!=GTK_STATE_SELECTED && selected &&
4403        xxx_column_is_visible(sheet, j) && yyy_row_is_visible(sheet, i) &&
4404        (i != sheet->active_cell.row || j != sheet->active_cell.col)){
4405
4406       x=COLUMN_LEFT_XPIXEL(sheet,j);
4407       y=ROW_TOP_YPIXEL(sheet, i);  
4408       width=COLUMN_LEFT_XPIXEL(sheet, j)-x+ xxx_column_width(sheet, j);
4409       height=ROW_TOP_YPIXEL(sheet, i)-y+yyy_row_height(sheet, i);
4410
4411       if(i==new_range.row0){
4412             y=y+2;
4413             height=height-2;
4414        }
4415        if(i==new_range.rowi) height=height-3;
4416        if(j==new_range.col0){
4417             x=x+2;
4418             width=width-2;
4419        }
4420        if(j==new_range.coli) width=width-3;
4421
4422        gdk_draw_rectangle (sheet->sheet_window,
4423                            sheet->xor_gc,
4424                            TRUE,
4425                            x+1,y+1,
4426                            width,height);
4427
4428     }   
4429
4430    }
4431   }
4432
4433   for(i=aux_range.row0; i<=aux_range.rowi; i++){
4434    for(j=aux_range.col0; j<=aux_range.coli; j++){     
4435
4436     if(xxx_column_is_visible(sheet, j) && yyy_row_is_visible(sheet, i)){
4437
4438        state=gtk_sheet_cell_get_state(sheet, i, j);
4439
4440        mask1 = i==sheet->range.row0 ? 1 : 0;
4441        mask1 = i==sheet->range.rowi ? mask1+2 : mask1;
4442        mask1 = j==sheet->range.col0 ? mask1+4 : mask1;
4443        mask1 = j==sheet->range.coli ? mask1+8 : mask1;
4444
4445        mask2 = i==new_range.row0 ? 1 : 0;
4446        mask2 = i==new_range.rowi ? mask2+2 : mask2;
4447        mask2 = j==new_range.col0 ? mask2+4 : mask2;
4448        mask2 = j==new_range.coli ? mask2+8 : mask2;    
4449        if(mask2!=mask1 || (mask2==mask1 && state!=GTK_STATE_SELECTED)){
4450          x=COLUMN_LEFT_XPIXEL(sheet,j);
4451          y=ROW_TOP_YPIXEL(sheet, i);  
4452          width=xxx_column_width(sheet, j);
4453          height=yyy_row_height(sheet, i);
4454          if(mask2 & 1)
4455                gdk_draw_rectangle (sheet->sheet_window,
4456                                    sheet->xor_gc,
4457                                    TRUE,
4458                                    x+1,y-1,
4459                                    width,3);
4460
4461            
4462          if(mask2 & 2)
4463                gdk_draw_rectangle (sheet->sheet_window,
4464                                    sheet->xor_gc,
4465                                    TRUE,
4466                                    x+1,y+height-1,
4467                                    width,3);
4468
4469          if(mask2 & 4)
4470                gdk_draw_rectangle (sheet->sheet_window,
4471                                    sheet->xor_gc,
4472                                    TRUE,
4473                                    x-1,y+1,
4474                                    3,height);
4475
4476
4477          if(mask2 & 8)
4478                gdk_draw_rectangle (sheet->sheet_window,
4479                                    sheet->xor_gc,
4480                                    TRUE,
4481                                    x+width-1,y+1,
4482                                    3,height);
4483
4484        
4485
4486        }         
4487
4488     } 
4489
4490    }
4491   } 
4492
4493
4494   *range=new_range;
4495   gtk_sheet_draw_corners(sheet, new_range);
4496
4497 }
4498
4499 static void
4500 gtk_sheet_draw_border (GtkSheet *sheet, GtkSheetRange new_range)
4501 {
4502   GtkWidget *widget;
4503   GdkRectangle area;
4504   gint i;
4505   gint x,y,width,height;
4506
4507   widget = GTK_WIDGET(sheet);
4508
4509   x=COLUMN_LEFT_XPIXEL(sheet,new_range.col0);
4510   y=ROW_TOP_YPIXEL(sheet,new_range.row0);
4511   width=COLUMN_LEFT_XPIXEL(sheet,new_range.coli)-x+ 
4512     xxx_column_width(sheet, new_range.coli);
4513
4514   height=ROW_TOP_YPIXEL(sheet,new_range.rowi)-y+
4515              yyy_row_height(sheet, new_range.rowi);
4516
4517   area.x=COLUMN_LEFT_XPIXEL(sheet, MIN_VISIBLE_COLUMN(sheet));
4518   area.y=ROW_TOP_YPIXEL(sheet, MIN_VISIBLE_ROW(sheet));
4519   area.width=sheet->sheet_window_width;
4520   area.height=sheet->sheet_window_height;
4521
4522   if(x<0) {
4523       width=width+x;
4524       x=0;
4525   }
4526   if(width>area.width) width=area.width+10;
4527   if(y<0) {
4528       height=height+y;
4529       y=0;
4530   }
4531   if(height>area.height) height=area.height+10;
4532
4533   gdk_gc_set_clip_rectangle(sheet->xor_gc, &area);
4534
4535   for(i=-1; i<=1; ++i)
4536      gdk_draw_rectangle (sheet->sheet_window,
4537                          sheet->xor_gc,
4538                          FALSE,
4539                          x+i,y+i,
4540                          width-2*i,height-2*i);
4541
4542   gdk_gc_set_clip_rectangle(sheet->xor_gc, NULL);
4543   
4544   gtk_sheet_draw_corners(sheet, new_range);
4545
4546 }
4547
4548 static void
4549 gtk_sheet_draw_corners(GtkSheet *sheet, GtkSheetRange range)
4550 {
4551   gint x,y;
4552   guint width = 1;
4553
4554   if(gtk_sheet_cell_isvisible(sheet, range.row0, range.col0)){
4555        x=COLUMN_LEFT_XPIXEL(sheet,range.col0);
4556        y=ROW_TOP_YPIXEL(sheet,range.row0);
4557        gdk_draw_pixmap(sheet->sheet_window,
4558                        GTK_WIDGET(sheet)->style->fg_gc[GTK_STATE_NORMAL],
4559                        sheet->pixmap,
4560                        x-1,
4561                        y-1,
4562                        x-1,
4563                        y-1,
4564                        3,
4565                        3);         
4566        gdk_draw_rectangle (sheet->sheet_window,
4567                            sheet->xor_gc,
4568                            TRUE,
4569                            x-1,y-1,
4570                            3,3);
4571   }
4572
4573   if(gtk_sheet_cell_isvisible(sheet, range.row0, range.coli) ||
4574      sheet->state == GTK_SHEET_COLUMN_SELECTED){
4575        x=COLUMN_LEFT_XPIXEL(sheet,range.coli)+
4576          xxx_column_width(sheet, range.coli);
4577        y=ROW_TOP_YPIXEL(sheet,range.row0);
4578        width = 1;
4579        if(sheet->state == GTK_SHEET_COLUMN_SELECTED)
4580          {
4581              y = ROW_TOP_YPIXEL(sheet, sheet->view.row0)+3;
4582              width = 3;
4583          }
4584        gdk_draw_pixmap(sheet->sheet_window,
4585                        GTK_WIDGET(sheet)->style->fg_gc[GTK_STATE_NORMAL],
4586                        sheet->pixmap,
4587                        x-width,
4588                        y-width,
4589                        x-width,
4590                        y-width,
4591                        2*width+1,
4592                        2*width+1);         
4593        gdk_draw_rectangle (sheet->sheet_window,
4594                            sheet->xor_gc,
4595                            TRUE,
4596                            x-width+width/2,y-width+width/2,
4597                            2+width,2+width);
4598   }
4599
4600   if(gtk_sheet_cell_isvisible(sheet, range.rowi, range.col0) ||
4601      sheet->state == GTK_SHEET_ROW_SELECTED){
4602        x=COLUMN_LEFT_XPIXEL(sheet,range.col0);
4603        y=ROW_TOP_YPIXEL(sheet,range.rowi)+
4604          yyy_row_height(sheet, range.rowi);
4605        width = 1;
4606        if(sheet->state == GTK_SHEET_ROW_SELECTED) 
4607          {
4608              x = COLUMN_LEFT_XPIXEL(sheet, sheet->view.col0)+3;
4609              width = 3;
4610          }
4611        gdk_draw_pixmap(sheet->sheet_window,
4612                        GTK_WIDGET(sheet)->style->fg_gc[GTK_STATE_NORMAL],
4613                        sheet->pixmap,
4614                        x-width,
4615                        y-width,
4616                        x-width,
4617                        y-width,
4618                        2*width+1,
4619                        2*width+1);         
4620        gdk_draw_rectangle (sheet->sheet_window,
4621                            sheet->xor_gc,
4622                            TRUE,
4623                            x-width+width/2,y-width+width/2,
4624                            2+width,2+width);
4625   }
4626
4627   if(gtk_sheet_cell_isvisible(sheet, range.rowi, range.coli)){
4628        x=COLUMN_LEFT_XPIXEL(sheet,range.coli)+
4629          xxx_column_width(sheet, range.coli);
4630        y=ROW_TOP_YPIXEL(sheet,range.rowi)+
4631          yyy_row_height(sheet, range.rowi);
4632        width = 1;
4633        if(sheet->state == GTK_SHEET_RANGE_SELECTED) width = 3;
4634        if(sheet->state == GTK_SHEET_NORMAL) width = 3;
4635        gdk_draw_pixmap(sheet->sheet_window,
4636                        GTK_WIDGET(sheet)->style->fg_gc[GTK_STATE_NORMAL],
4637                        sheet->pixmap,
4638                        x-width,
4639                        y-width,
4640                        x-width,
4641                        y-width,
4642                        2*width+1,
4643                        2*width+1);         
4644        gdk_draw_rectangle (sheet->sheet_window,
4645                            sheet->xor_gc,
4646                            TRUE,
4647                            x-width+width/2,y-width+width/2,
4648                            2+width,2+width);
4649
4650   }
4651
4652 }
4653
4654
4655 static void
4656 gtk_sheet_real_select_range (GtkSheet * sheet,
4657                              GtkSheetRange * range)
4658 {
4659   gint state;
4660
4661   g_return_if_fail (sheet != NULL);
4662
4663   if(range==NULL) range=&sheet->range;
4664
4665   if(range->row0 < 0 || range->rowi < 0) return;
4666   if(range->col0 < 0 || range->coli < 0) return;
4667
4668   state=sheet->state;
4669
4670 #if 0
4671   if(state==GTK_SHEET_COLUMN_SELECTED || state==GTK_SHEET_RANGE_SELECTED){
4672    for(i=sheet->range.col0; i< range->col0; i++)
4673     column_button_release(sheet, i);
4674    for(i=range->coli+1; i<= sheet->range.coli; i++)
4675     column_button_release(sheet, i);
4676    for(i=range->col0; i<=range->coli; i++){
4677     column_button_set(sheet, i);
4678    }
4679   }
4680  
4681   if(state==GTK_SHEET_ROW_SELECTED || state==GTK_SHEET_RANGE_SELECTED){
4682    for(i=sheet->range.row0; i< range->row0; i++)
4683     row_button_release(sheet, i);
4684    for(i=range->rowi+1; i<= sheet->range.rowi; i++)
4685     row_button_release(sheet, i);
4686    for(i=range->row0; i<=range->rowi; i++){
4687     row_button_set(sheet, i);
4688    }
4689   }
4690 #endif
4691
4692   if(range->coli != sheet->range.coli || range->col0 != sheet->range.col0 ||
4693      range->rowi != sheet->range.rowi || range->row0 != sheet->range.row0)
4694          {
4695
4696            gtk_sheet_new_selection(sheet, range);
4697
4698            sheet->range.col0=range->col0;
4699            sheet->range.coli=range->coli;
4700            sheet->range.row0=range->row0;
4701            sheet->range.rowi=range->rowi;
4702
4703          }
4704   else
4705          {
4706            gtk_sheet_draw_backing_pixmap(sheet, sheet->range);
4707            gtk_sheet_range_draw_selection(sheet, sheet->range);
4708          }
4709
4710   gtk_signal_emit(GTK_OBJECT(sheet), sheet_signals[SELECT_RANGE], range);
4711 }
4712
4713 void
4714 gtk_sheet_select_range(GtkSheet * sheet, const GtkSheetRange *range)
4715 {
4716   g_return_if_fail (sheet != NULL);
4717
4718   if(range==NULL) range=&sheet->range;
4719
4720   if(range->row0 < 0 || range->rowi < 0) return;
4721   if(range->col0 < 0 || range->coli < 0) return;
4722
4723
4724   if ( gtk_sheet_locked(sheet)) return ;
4725
4726   if(sheet->state != GTK_SHEET_NORMAL) 
4727        gtk_sheet_real_unselect_range(sheet, NULL);
4728   else
4729   {
4730      gboolean veto = TRUE;
4731      veto = gtk_sheet_deactivate_cell(sheet);
4732      if(!veto) return;
4733   }
4734
4735   sheet->range.row0=range->row0;
4736   sheet->range.rowi=range->rowi;
4737   sheet->range.col0=range->col0;
4738   sheet->range.coli=range->coli;
4739   sheet->active_cell.row=range->row0;
4740   sheet->active_cell.col=range->col0;
4741   sheet->selection_cell.row=range->rowi;
4742   sheet->selection_cell.col=range->coli;
4743
4744   sheet->state = GTK_SHEET_RANGE_SELECTED;
4745   gtk_sheet_real_select_range(sheet, NULL);
4746
4747 }
4748
4749 void
4750 gtk_sheet_unselect_range (GtkSheet * sheet)
4751 {
4752   gtk_sheet_real_unselect_range(sheet, NULL);
4753   sheet->state = GTK_STATE_NORMAL;
4754   gtk_sheet_activate_cell(sheet, sheet->active_cell.row, sheet->active_cell.col);
4755 }
4756
4757
4758 static void
4759 gtk_sheet_real_unselect_range (GtkSheet * sheet,
4760                                const GtkSheetRange *range)
4761 {
4762   g_return_if_fail (sheet != NULL);
4763   g_return_if_fail (GTK_WIDGET_REALIZED(GTK_WIDGET(sheet)));
4764
4765   if(range==NULL){
4766      range=&sheet->range;
4767   }
4768
4769   if(range->row0 < 0 || range->rowi < 0) return;
4770   if(range->col0 < 0 || range->coli < 0) return;
4771
4772   if (gtk_sheet_range_isvisible (sheet, *range)){
4773     gtk_sheet_draw_backing_pixmap(sheet, *range);
4774   }
4775
4776 #if 0
4777   for(i=range->col0; i<=range->coli; i++){
4778      column_button_release(sheet, i);
4779   }
4780
4781   for(i=range->row0; i<=range->rowi; i++){
4782      row_button_release(sheet, i);
4783   }
4784 #endif
4785
4786   gtk_sheet_position_children(sheet);
4787 }
4788
4789
4790 static gint
4791 gtk_sheet_expose (GtkWidget * widget,
4792                   GdkEventExpose * event)
4793 {
4794   GtkSheet *sheet;
4795   GtkSheetRange range;
4796
4797   g_return_val_if_fail (widget != NULL, FALSE);
4798   g_return_val_if_fail (GTK_IS_SHEET (widget), FALSE);
4799   g_return_val_if_fail (event != NULL, FALSE);
4800
4801   sheet = GTK_SHEET (widget);
4802
4803   if (GTK_WIDGET_DRAWABLE (widget))
4804   {
4805       range.row0=ROW_FROM_YPIXEL(sheet,event->area.y);
4806       range.col0=COLUMN_FROM_XPIXEL(sheet,event->area.x);
4807       range.rowi=ROW_FROM_YPIXEL(sheet,event->area.y+event->area.height);
4808       range.coli=COLUMN_FROM_XPIXEL(sheet,event->area.x+event->area.width);
4809
4810       /* exposure events on the sheet */
4811  
4812       if(event->window == sheet->row_title_window && sheet->row_titles_visible){
4813          gint i;
4814          for(i = MIN_VISIBLE_ROW(sheet); i <= MAX_VISIBLE_ROW(sheet); i++)
4815            gtk_sheet_button_draw(sheet,i,-1);
4816       }
4817
4818       if(event->window == sheet->column_title_window && sheet->column_titles_visible){
4819          gint i;
4820          for(i = MIN_VISIBLE_COLUMN(sheet); i <= MAX_VISIBLE_COLUMN(sheet); i++)
4821            gtk_sheet_button_draw(sheet,-1,i);
4822       }
4823
4824       if (event->window == sheet->sheet_window){
4825         gtk_sheet_draw_backing_pixmap(sheet, range);
4826               
4827         if(sheet->state != GTK_SHEET_NORMAL){
4828                 if(gtk_sheet_range_isvisible(sheet, sheet->range))          
4829                    gtk_sheet_draw_backing_pixmap(sheet, sheet->range);
4830                 if(GTK_SHEET_IN_RESIZE(sheet) || GTK_SHEET_IN_DRAG(sheet))
4831                    gtk_sheet_draw_backing_pixmap(sheet, sheet->drag_range);
4832
4833                 if(gtk_sheet_range_isvisible(sheet, sheet->range))          
4834                    gtk_sheet_range_draw_selection(sheet, sheet->range);
4835                 if(GTK_SHEET_IN_RESIZE(sheet) || GTK_SHEET_IN_DRAG(sheet))
4836                    draw_xor_rectangle(sheet, sheet->drag_range);
4837         }
4838
4839         if((!GTK_SHEET_IN_XDRAG(sheet)) && (!GTK_SHEET_IN_YDRAG(sheet))){
4840              if(sheet->state == GTK_SHEET_NORMAL){ 
4841                  gtk_sheet_draw_active_cell(sheet);
4842                  if(!GTK_SHEET_IN_SELECTION(sheet))
4843                          gtk_widget_queue_draw(sheet->sheet_entry);
4844              }
4845         }
4846
4847
4848       }
4849
4850   }
4851
4852   if(sheet->state != GTK_SHEET_NORMAL && GTK_SHEET_IN_SELECTION(sheet))
4853      gtk_widget_grab_focus(GTK_WIDGET(sheet));
4854
4855   (* GTK_WIDGET_CLASS (parent_class)->expose_event) (widget, event);
4856
4857   return FALSE;
4858 }
4859
4860
4861 static gint
4862 gtk_sheet_button_press (GtkWidget * widget,
4863                         GdkEventButton * event)
4864 {
4865   GtkSheet *sheet;
4866   GdkModifierType mods;
4867   gint x, y, row, column;
4868   gboolean veto;
4869
4870   g_return_val_if_fail (widget != NULL, FALSE);
4871   g_return_val_if_fail (GTK_IS_SHEET (widget), FALSE);
4872   g_return_val_if_fail (event != NULL, FALSE);
4873
4874   sheet = GTK_SHEET (widget);
4875
4876   if ( event->type == GDK_2BUTTON_PRESS)
4877     {
4878       gtk_widget_get_pointer (widget, &x, &y);
4879       gtk_sheet_get_pixel_info (sheet, x, y, &row, &column);
4880
4881       if (event->window == sheet->column_title_window ) 
4882         {
4883           gtk_signal_emit (GTK_OBJECT (sheet), 
4884                            sheet_signals[DOUBLE_CLICK_COLUMN], column);
4885         }
4886       else if (event->window == sheet->row_title_window ) 
4887         {
4888           gtk_signal_emit (GTK_OBJECT (sheet), 
4889                            sheet_signals[DOUBLE_CLICK_ROW], row);
4890         }
4891     }
4892
4893   
4894 /*
4895   if(event->type != GDK_BUTTON_PRESS) return TRUE;
4896 */
4897   gdk_window_get_pointer(widget->window, NULL, NULL, &mods);
4898
4899   if(!(mods & GDK_BUTTON1_MASK)) return TRUE;
4900
4901
4902   /* press on resize windows */
4903   if (event->window == sheet->column_title_window &&
4904       gtk_sheet_columns_resizable(sheet))
4905       {
4906         gtk_widget_get_pointer (widget, &sheet->x_drag, NULL);
4907         if(POSSIBLE_XDRAG(sheet, sheet->x_drag, &sheet->drag_cell.col)){
4908           guint req;
4909           if (event->type == GDK_2BUTTON_PRESS){
4910             gtk_sheet_autoresize_column (sheet, sheet->drag_cell.col);
4911             GTK_SHEET_UNSET_FLAGS(sheet, GTK_SHEET_IN_XDRAG);
4912             return TRUE;
4913           }
4914           gtk_sheet_column_size_request(sheet, sheet->drag_cell.col, &req);
4915           GTK_SHEET_SET_FLAGS (sheet, GTK_SHEET_IN_XDRAG);
4916           gdk_pointer_grab (sheet->column_title_window, FALSE,
4917                             GDK_POINTER_MOTION_HINT_MASK |
4918                             GDK_BUTTON1_MOTION_MASK |
4919                             GDK_BUTTON_RELEASE_MASK,
4920                             NULL, NULL, event->time);
4921
4922           draw_xor_vline (sheet);
4923           return TRUE;
4924         }
4925       }
4926
4927   if (event->window == sheet->row_title_window && gtk_sheet_rows_resizable(sheet))
4928       {
4929         gtk_widget_get_pointer (widget, NULL, &sheet->y_drag);
4930
4931         if(POSSIBLE_YDRAG(sheet, sheet->y_drag, &sheet->drag_cell.row)){
4932           guint req;
4933           gtk_sheet_row_size_request(sheet, sheet->drag_cell.row, &req);
4934           GTK_SHEET_SET_FLAGS (sheet, GTK_SHEET_IN_YDRAG);
4935           gdk_pointer_grab (sheet->row_title_window, FALSE,
4936                             GDK_POINTER_MOTION_HINT_MASK |
4937                             GDK_BUTTON1_MOTION_MASK |
4938                             GDK_BUTTON_RELEASE_MASK,
4939                             NULL, NULL, event->time);
4940
4941           draw_xor_hline (sheet);
4942           return TRUE;
4943         }
4944       }
4945
4946   /* the sheet itself does not handle other than single click events */
4947   if(event->type != GDK_BUTTON_PRESS) return FALSE;
4948
4949   /* selections on the sheet */
4950     if(event->window == sheet->sheet_window){
4951      gtk_widget_get_pointer (widget, &x, &y);
4952      gtk_sheet_get_pixel_info (sheet, x, y, &row, &column);
4953      gdk_pointer_grab (sheet->sheet_window, FALSE,
4954                        GDK_POINTER_MOTION_HINT_MASK |
4955                        GDK_BUTTON1_MOTION_MASK |
4956                        GDK_BUTTON_RELEASE_MASK,
4957                        NULL, NULL, event->time);
4958      gtk_grab_add(GTK_WIDGET(sheet));
4959      sheet->timer=gtk_timeout_add(TIMEOUT_SCROLL, gtk_sheet_scroll, sheet); 
4960      gtk_widget_grab_focus(GTK_WIDGET(sheet));
4961
4962      if(sheet->selection_mode != GTK_SELECTION_SINGLE &&
4963         sheet->cursor_drag->type==GDK_SIZING &&
4964         !GTK_SHEET_IN_SELECTION(sheet) && !GTK_SHEET_IN_RESIZE(sheet)){
4965         if(sheet->state==GTK_STATE_NORMAL) {
4966           row=sheet->active_cell.row;
4967           column=sheet->active_cell.col;
4968           if(!gtk_sheet_deactivate_cell(sheet)) return FALSE;
4969           sheet->active_cell.row=row;
4970           sheet->active_cell.col=column;
4971           sheet->drag_range=sheet->range;
4972           sheet->state=GTK_SHEET_RANGE_SELECTED;
4973           gtk_sheet_select_range(sheet, &sheet->drag_range);
4974         }
4975         sheet->x_drag=x;
4976         sheet->y_drag=y;
4977         if(row > sheet->range.rowi) row--;
4978         if(column > sheet->range.coli) column--;
4979         sheet->drag_cell.row = row;
4980         sheet->drag_cell.col = column;
4981         sheet->drag_range=sheet->range;
4982         draw_xor_rectangle(sheet, sheet->drag_range);
4983         GTK_SHEET_SET_FLAGS(sheet, GTK_SHEET_IN_RESIZE);
4984      }
4985      else if(sheet->cursor_drag->type==GDK_TOP_LEFT_ARROW &&
4986              !GTK_SHEET_IN_SELECTION(sheet) 
4987              && ! GTK_SHEET_IN_DRAG(sheet)
4988              && ! gtk_sheet_locked(sheet)
4989              && sheet->active_cell.row >= 0
4990              && sheet->active_cell.col >= 0
4991              ) 
4992        {
4993          if(sheet->state==GTK_STATE_NORMAL) {
4994            row=sheet->active_cell.row;
4995            column=sheet->active_cell.col;
4996            if(!gtk_sheet_deactivate_cell(sheet)) return FALSE;
4997            sheet->active_cell.row=row;
4998            sheet->active_cell.col=column;
4999            sheet->drag_range=sheet->range;
5000            sheet->state=GTK_SHEET_RANGE_SELECTED;
5001            gtk_sheet_select_range(sheet, &sheet->drag_range);
5002          }
5003          sheet->x_drag=x;
5004          sheet->y_drag=y;
5005          if(row < sheet->range.row0) row++;
5006          if(row > sheet->range.rowi) row--;
5007          if(column < sheet->range.col0) column++;
5008          if(column > sheet->range.coli) column--;
5009          sheet->drag_cell.row=row;
5010          sheet->drag_cell.col=column;
5011          sheet->drag_range=sheet->range;
5012          draw_xor_rectangle(sheet, sheet->drag_range);
5013          GTK_SHEET_SET_FLAGS(sheet, GTK_SHEET_IN_DRAG);
5014        }
5015      else 
5016        {
5017          gtk_sheet_click_cell(sheet, row, column, &veto);
5018          if(veto) GTK_SHEET_SET_FLAGS(sheet, GTK_SHEET_IN_SELECTION);
5019        }
5020     }
5021
5022     if(event->window == sheet->column_title_window){
5023      gtk_widget_get_pointer (widget, &x, &y);
5024      column = COLUMN_FROM_XPIXEL(sheet, x);
5025      if(xxx_column_is_sensitive(sheet, column)){
5026        gtk_sheet_click_cell(sheet, -1, column, &veto);
5027        gtk_grab_add(GTK_WIDGET(sheet));
5028        sheet->timer=gtk_timeout_add(TIMEOUT_SCROLL, gtk_sheet_scroll, sheet); 
5029        gtk_widget_grab_focus(GTK_WIDGET(sheet));
5030        GTK_SHEET_SET_FLAGS(sheet, GTK_SHEET_IN_SELECTION);
5031      }
5032     }
5033
5034     if(event->window == sheet->row_title_window){
5035      gtk_widget_get_pointer (widget, &x, &y);
5036      row = ROW_FROM_YPIXEL(sheet, y);
5037      if(yyy_row_is_sensitive(sheet, row)){
5038        gtk_sheet_click_cell(sheet, row, -1, &veto);
5039        gtk_grab_add(GTK_WIDGET(sheet));
5040        sheet->timer=gtk_timeout_add(TIMEOUT_SCROLL, gtk_sheet_scroll, sheet); 
5041        gtk_widget_grab_focus(GTK_WIDGET(sheet));
5042        GTK_SHEET_SET_FLAGS(sheet, GTK_SHEET_IN_SELECTION);
5043      }
5044     }
5045
5046     return TRUE;
5047 }
5048
5049 static gint
5050 gtk_sheet_scroll(gpointer data)
5051 {
5052  GtkSheet *sheet;
5053  gint x,y,row,column;
5054  gint move;
5055   
5056  sheet=GTK_SHEET(data);
5057
5058  GDK_THREADS_ENTER();
5059
5060  gtk_widget_get_pointer (GTK_WIDGET(sheet), &x, &y);
5061  gtk_sheet_get_pixel_info (sheet, x, y, &row, &column);
5062
5063  move=TRUE;
5064
5065  if(GTK_SHEET_IN_SELECTION(sheet))
5066       gtk_sheet_extend_selection(sheet, row, column);
5067
5068  if(GTK_SHEET_IN_DRAG(sheet) || GTK_SHEET_IN_RESIZE(sheet)){
5069        move=gtk_sheet_move_query(sheet, row, column);
5070        if(move) draw_xor_rectangle(sheet, sheet->drag_range);      
5071  }       
5072
5073  GDK_THREADS_LEAVE();
5074
5075  return TRUE;
5076       
5077 }
5078
5079 static void
5080 gtk_sheet_click_cell(GtkSheet *sheet, gint row, gint column, gboolean *veto)
5081 {
5082       *veto = TRUE;
5083
5084       if(row >= yyy_row_count(sheet) || column >= xxx_column_count(sheet)){
5085           *veto = FALSE;
5086           return;
5087       }
5088
5089       if(column >= 0 && row >= 0)
5090        if(! xxx_column_is_visible(sheet, column) || !yyy_row_is_visible(sheet, row)) 
5091          {
5092            *veto = FALSE;
5093            return;
5094          }
5095
5096       _gtkextra_signal_emit(GTK_OBJECT(sheet), sheet_signals[TRAVERSE],
5097                             sheet->active_cell.row, sheet->active_cell.col, 
5098                             &row, &column, veto);
5099
5100       if(!*veto){
5101            if(sheet->state == GTK_STATE_NORMAL) return;
5102
5103            row = sheet->active_cell.row;
5104            column = sheet->active_cell.col;
5105
5106            gtk_sheet_activate_cell(sheet, row, column);
5107            return;
5108       }
5109
5110       if(row == -1 && column >= 0){
5111           if(gtk_sheet_autoscroll(sheet))
5112             gtk_sheet_move_query(sheet, row, column);
5113           gtk_sheet_select_column(sheet, column);
5114           return;
5115       }
5116       if(column == -1 && row >= 0){
5117           if(gtk_sheet_autoscroll(sheet))
5118             gtk_sheet_move_query(sheet, row, column);
5119           gtk_sheet_select_row(sheet, row);
5120           return;
5121       }
5122
5123       if(row==-1 && column ==-1){
5124           sheet->range.row0=0;
5125           sheet->range.col0=0;
5126           sheet->range.rowi = yyy_row_count(sheet) - 1;
5127           sheet->range.coli = xxx_column_count(sheet) - 1;
5128           sheet->active_cell.row=0;
5129           sheet->active_cell.col=0;
5130           gtk_sheet_select_range(sheet, NULL);
5131           return;
5132       }
5133
5134       if(row!=-1 && column !=-1){
5135           if(sheet->state != GTK_SHEET_NORMAL){
5136             sheet->state = GTK_SHEET_NORMAL;
5137             gtk_sheet_real_unselect_range(sheet, NULL);
5138           }
5139           else
5140           {
5141             if(!gtk_sheet_deactivate_cell(sheet)){
5142               *veto = FALSE;
5143               return;
5144             }
5145           }
5146
5147           if(gtk_sheet_autoscroll(sheet))
5148             gtk_sheet_move_query(sheet, row, column);
5149           sheet->active_cell.row=row;
5150           sheet->active_cell.col=column;
5151           sheet->selection_cell.row=row;
5152           sheet->selection_cell.col=column;
5153           sheet->range.row0=row;
5154           sheet->range.col0=column;
5155           sheet->range.rowi=row;
5156           sheet->range.coli=column;
5157           sheet->state=GTK_SHEET_NORMAL;
5158           GTK_SHEET_SET_FLAGS(sheet, GTK_SHEET_IN_SELECTION);
5159           gtk_sheet_draw_active_cell(sheet);
5160           return;
5161       }
5162
5163       g_assert_not_reached();
5164       gtk_sheet_activate_cell(sheet, sheet->active_cell.row,
5165                                      sheet->active_cell.col);
5166 }
5167
5168 static gint
5169 gtk_sheet_button_release (GtkWidget * widget,
5170                         GdkEventButton * event)
5171 {
5172   GtkSheet *sheet;
5173   gint x,y;
5174  
5175   sheet=GTK_SHEET(widget);
5176
5177   /* release on resize windows */
5178   if (GTK_SHEET_IN_XDRAG (sheet)){
5179           GTK_SHEET_UNSET_FLAGS (sheet, GTK_SHEET_IN_XDRAG);
5180           GTK_SHEET_UNSET_FLAGS (sheet, GTK_SHEET_IN_SELECTION);
5181           gtk_widget_get_pointer (widget, &x, NULL);
5182           gdk_pointer_ungrab (event->time);
5183           draw_xor_vline (sheet);
5184           
5185           gtk_sheet_set_column_width (sheet, sheet->drag_cell.col, new_column_width (sheet, sheet->drag_cell.col, &x));
5186           sheet->old_hadjustment = -1.;
5187           gtk_signal_emit_by_name (GTK_OBJECT (sheet->hadjustment), "value_changed");
5188           return TRUE;
5189   }
5190
5191   if (GTK_SHEET_IN_YDRAG (sheet)){
5192           GTK_SHEET_UNSET_FLAGS (sheet, GTK_SHEET_IN_YDRAG);
5193           GTK_SHEET_UNSET_FLAGS (sheet, GTK_SHEET_IN_SELECTION);
5194           gtk_widget_get_pointer (widget, NULL, &y);
5195           gdk_pointer_ungrab (event->time);
5196           draw_xor_hline (sheet);
5197           
5198           gtk_sheet_set_row_height (sheet, sheet->drag_cell.row, new_row_height (sheet, sheet->drag_cell.row, &y));
5199           sheet->old_vadjustment = -1.;
5200           gtk_signal_emit_by_name (GTK_OBJECT (sheet->vadjustment), "value_changed");
5201           return TRUE;
5202   }
5203
5204   
5205   if (GTK_SHEET_IN_DRAG(sheet)){
5206       GtkSheetRange old_range;
5207       draw_xor_rectangle(sheet, sheet->drag_range);
5208       GTK_SHEET_UNSET_FLAGS(sheet, GTK_SHEET_IN_DRAG);
5209       gdk_pointer_ungrab (event->time);
5210
5211       gtk_sheet_real_unselect_range(sheet, NULL);
5212       
5213       sheet->active_cell.row = sheet->active_cell.row +
5214                                (sheet->drag_range.row0 - sheet->range.row0);
5215       sheet->active_cell.col = sheet->active_cell.col +
5216                                (sheet->drag_range.col0 - sheet->range.col0);
5217       sheet->selection_cell.row = sheet->selection_cell.row +
5218                                   (sheet->drag_range.row0 - sheet->range.row0);
5219       sheet->selection_cell.col = sheet->selection_cell.col +
5220                                   (sheet->drag_range.col0 - sheet->range.col0);
5221       old_range=sheet->range;
5222       sheet->range=sheet->drag_range;
5223       sheet->drag_range=old_range;
5224       gtk_signal_emit(GTK_OBJECT(sheet),sheet_signals[MOVE_RANGE],
5225                       &sheet->drag_range, &sheet->range);
5226       gtk_sheet_select_range(sheet, &sheet->range);
5227   }
5228
5229   if (GTK_SHEET_IN_RESIZE(sheet)){
5230       GtkSheetRange old_range;
5231       draw_xor_rectangle(sheet, sheet->drag_range);
5232       GTK_SHEET_UNSET_FLAGS(sheet, GTK_SHEET_IN_RESIZE);
5233       gdk_pointer_ungrab (event->time);
5234
5235       gtk_sheet_real_unselect_range(sheet, NULL);
5236       
5237       sheet->active_cell.row = sheet->active_cell.row +
5238                                (sheet->drag_range.row0 - sheet->range.row0);
5239       sheet->active_cell.col = sheet->active_cell.col +
5240                                (sheet->drag_range.col0 - sheet->range.col0);
5241       if(sheet->drag_range.row0 < sheet->range.row0)
5242                      sheet->selection_cell.row = sheet->drag_range.row0;
5243       if(sheet->drag_range.rowi >= sheet->range.rowi)
5244                      sheet->selection_cell.row = sheet->drag_range.rowi;
5245       if(sheet->drag_range.col0 < sheet->range.col0)
5246                      sheet->selection_cell.col = sheet->drag_range.col0;
5247       if(sheet->drag_range.coli >= sheet->range.coli)
5248                      sheet->selection_cell.col = sheet->drag_range.coli;
5249       old_range = sheet->range;
5250       sheet->range = sheet->drag_range;
5251       sheet->drag_range = old_range;
5252
5253       if(sheet->state==GTK_STATE_NORMAL) sheet->state=GTK_SHEET_RANGE_SELECTED;
5254       gtk_signal_emit(GTK_OBJECT(sheet),sheet_signals[RESIZE_RANGE],
5255                       &sheet->drag_range, &sheet->range);
5256       gtk_sheet_select_range(sheet, &sheet->range);
5257   }
5258
5259   if(sheet->state == GTK_SHEET_NORMAL && GTK_SHEET_IN_SELECTION(sheet)){
5260       GTK_SHEET_UNSET_FLAGS(sheet, GTK_SHEET_IN_SELECTION);
5261       gdk_pointer_ungrab (event->time);
5262       gtk_sheet_activate_cell(sheet, sheet->active_cell.row, 
5263                                      sheet->active_cell.col);
5264   }
5265
5266   if(GTK_SHEET_IN_SELECTION)
5267          gdk_pointer_ungrab (event->time);
5268   if(sheet->timer)
5269          gtk_timeout_remove(sheet->timer);
5270   gtk_grab_remove(GTK_WIDGET(sheet));
5271
5272   GTK_SHEET_UNSET_FLAGS(sheet, GTK_SHEET_IN_SELECTION);
5273
5274   return TRUE;
5275 }
5276
5277 static gint
5278 gtk_sheet_motion (GtkWidget * widget,
5279                   GdkEventMotion * event)
5280 {
5281   GtkSheet *sheet;
5282   GdkModifierType mods;
5283   GdkCursorType new_cursor;
5284   gint x, y, row, column;
5285
5286   g_return_val_if_fail (widget != NULL, FALSE);
5287   g_return_val_if_fail (GTK_IS_SHEET (widget), FALSE);
5288   g_return_val_if_fail (event != NULL, FALSE);
5289
5290
5291   sheet = GTK_SHEET (widget);
5292
5293   /* selections on the sheet */
5294   x = event->x;
5295   y = event->y;
5296
5297   if(event->window == sheet->column_title_window && gtk_sheet_columns_resizable(sheet)){
5298     gtk_widget_get_pointer(widget, &x, &y);
5299     if(!GTK_SHEET_IN_SELECTION(sheet) && POSSIBLE_XDRAG(sheet, x, &column)){
5300       new_cursor=GDK_SB_H_DOUBLE_ARROW;
5301       if(new_cursor != sheet->cursor_drag->type){
5302         gdk_cursor_destroy(sheet->cursor_drag);
5303         sheet->cursor_drag=gdk_cursor_new(GDK_SB_H_DOUBLE_ARROW);
5304         gdk_window_set_cursor(sheet->column_title_window,sheet->cursor_drag);
5305       }
5306     }else{
5307       new_cursor=GDK_TOP_LEFT_ARROW;
5308       if(!GTK_SHEET_IN_XDRAG(sheet) && new_cursor != sheet->cursor_drag->type){
5309         gdk_cursor_destroy(sheet->cursor_drag);
5310         sheet->cursor_drag=gdk_cursor_new(GDK_TOP_LEFT_ARROW);
5311         gdk_window_set_cursor(sheet->column_title_window,sheet->cursor_drag);
5312       }
5313     }
5314   }      
5315
5316   if(event->window == sheet->row_title_window && gtk_sheet_rows_resizable(sheet)){
5317     gtk_widget_get_pointer(widget, &x, &y);
5318     if(!GTK_SHEET_IN_SELECTION(sheet) && POSSIBLE_YDRAG(sheet,y, &column)){
5319       new_cursor=GDK_SB_V_DOUBLE_ARROW;
5320       if(new_cursor != sheet->cursor_drag->type){
5321         gdk_cursor_destroy(sheet->cursor_drag);
5322         sheet->cursor_drag=gdk_cursor_new(GDK_SB_V_DOUBLE_ARROW);
5323         gdk_window_set_cursor(sheet->row_title_window,sheet->cursor_drag);
5324       }
5325     }else{
5326       new_cursor=GDK_TOP_LEFT_ARROW;
5327       if(!GTK_SHEET_IN_YDRAG(sheet) && new_cursor != sheet->cursor_drag->type){
5328         gdk_cursor_destroy(sheet->cursor_drag);
5329         sheet->cursor_drag=gdk_cursor_new(GDK_TOP_LEFT_ARROW);
5330         gdk_window_set_cursor(sheet->row_title_window,sheet->cursor_drag);
5331       }
5332     }
5333   }      
5334
5335   new_cursor=GDK_PLUS;
5336   if(!POSSIBLE_DRAG(sheet,x,y,&row,&column) && !GTK_SHEET_IN_DRAG(sheet) &&
5337      !POSSIBLE_RESIZE(sheet,x,y,&row,&column) && !GTK_SHEET_IN_RESIZE(sheet) &&
5338      event->window == sheet->sheet_window && 
5339      new_cursor != sheet->cursor_drag->type){
5340          gdk_cursor_destroy(sheet->cursor_drag);
5341          sheet->cursor_drag=gdk_cursor_new(GDK_PLUS);
5342          gdk_window_set_cursor(sheet->sheet_window,sheet->cursor_drag);
5343   }
5344
5345   new_cursor=GDK_TOP_LEFT_ARROW;
5346   if(!(POSSIBLE_RESIZE(sheet,x,y,&row,&column) || GTK_SHEET_IN_RESIZE(sheet)) &&
5347      (POSSIBLE_DRAG(sheet, x,y,&row,&column) || GTK_SHEET_IN_DRAG(sheet)) && 
5348      event->window == sheet->sheet_window && 
5349      new_cursor != sheet->cursor_drag->type){
5350          gdk_cursor_destroy(sheet->cursor_drag);
5351          sheet->cursor_drag=gdk_cursor_new(GDK_TOP_LEFT_ARROW);
5352          gdk_window_set_cursor(sheet->sheet_window,sheet->cursor_drag);
5353   }
5354
5355   new_cursor=GDK_SIZING;
5356   if(!GTK_SHEET_IN_DRAG(sheet) &&
5357      (POSSIBLE_RESIZE(sheet,x,y,&row,&column) || GTK_SHEET_IN_RESIZE(sheet)) &&
5358      event->window == sheet->sheet_window && 
5359      new_cursor != sheet->cursor_drag->type){
5360          gdk_cursor_destroy(sheet->cursor_drag);
5361          sheet->cursor_drag=gdk_cursor_new(GDK_SIZING);
5362          gdk_window_set_cursor(sheet->sheet_window,sheet->cursor_drag);
5363   }
5364
5365   gdk_window_get_pointer (widget->window, &x, &y, &mods);
5366   if(!(mods & GDK_BUTTON1_MASK)) return FALSE;
5367
5368   if (GTK_SHEET_IN_XDRAG (sheet)){
5369         if (event->is_hint || event->window != widget->window)
5370             gtk_widget_get_pointer (widget, &x, NULL);
5371           else
5372             x = event->x;
5373
5374           new_column_width (sheet, sheet->drag_cell.col, &x);
5375           if (x != sheet->x_drag)
5376             {
5377               draw_xor_vline (sheet);
5378               sheet->x_drag = x;
5379               draw_xor_vline (sheet);
5380             }
5381           return TRUE;
5382   }
5383
5384   if (GTK_SHEET_IN_YDRAG (sheet)){
5385           if (event->is_hint || event->window != widget->window)
5386             gtk_widget_get_pointer (widget, NULL, &y);
5387           else
5388             y = event->y;
5389
5390           new_row_height (sheet, sheet->drag_cell.row, &y);
5391           if (y != sheet->y_drag)
5392             {
5393               draw_xor_hline (sheet);
5394               sheet->y_drag = y;
5395               draw_xor_hline (sheet);
5396             }
5397           return TRUE;
5398   }
5399
5400   if (GTK_SHEET_IN_DRAG(sheet)){
5401        GtkSheetRange aux;
5402        column=COLUMN_FROM_XPIXEL(sheet,x)-sheet->drag_cell.col;
5403        row=ROW_FROM_YPIXEL(sheet,y)-sheet->drag_cell.row;
5404        if(sheet->state==GTK_SHEET_COLUMN_SELECTED) row=0;
5405        if(sheet->state==GTK_SHEET_ROW_SELECTED) column=0;
5406        sheet->x_drag=x;
5407        sheet->y_drag=y;
5408        aux=sheet->range;
5409        if(aux.row0+row >= 0 && aux.rowi+row < yyy_row_count(sheet) &&
5410           aux.col0+column >= 0 && aux.coli+column < xxx_column_count(sheet)){
5411              aux=sheet->drag_range;
5412              sheet->drag_range.row0=sheet->range.row0+row;
5413              sheet->drag_range.col0=sheet->range.col0+column;
5414              sheet->drag_range.rowi=sheet->range.rowi+row;
5415              sheet->drag_range.coli=sheet->range.coli+column;
5416              if(aux.row0 != sheet->drag_range.row0 ||
5417                 aux.col0 != sheet->drag_range.col0){
5418                 draw_xor_rectangle (sheet, aux);
5419                 draw_xor_rectangle (sheet, sheet->drag_range);
5420              }
5421        }
5422        return TRUE;
5423   }
5424
5425   if (GTK_SHEET_IN_RESIZE(sheet)){
5426        GtkSheetRange aux;
5427        gint v_h, current_col, current_row, col_threshold, row_threshold;
5428        v_h=1;
5429
5430        if(abs(x-COLUMN_LEFT_XPIXEL(sheet,sheet->drag_cell.col)) >
5431           abs(y-ROW_TOP_YPIXEL(sheet,sheet->drag_cell.row))) v_h=2;
5432         
5433        current_col = COLUMN_FROM_XPIXEL(sheet,x);
5434        current_row = ROW_FROM_YPIXEL(sheet,y);
5435        column = current_col-sheet->drag_cell.col;
5436        row    = current_row-sheet->drag_cell.row;
5437
5438        /*use half of column width resp. row height as threshold to expand selection*/
5439        col_threshold = COLUMN_LEFT_XPIXEL(sheet,current_col)+xxx_column_width (sheet,current_col)/2;
5440        if (column > 0){
5441          if (x < col_threshold)
5442            column-=1;
5443        }
5444        else if (column < 0){
5445          if (x > col_threshold) 
5446            column+=1;
5447        }
5448        row_threshold = ROW_TOP_YPIXEL(sheet,current_row)+yyy_row_height (sheet, current_row)/2;
5449        if (row > 0){
5450          if(y < row_threshold)
5451            row-=1;
5452        }
5453        else if (row < 0){
5454          if(y > row_threshold)
5455            row+=1;       
5456        }
5457
5458        if(sheet->state==GTK_SHEET_COLUMN_SELECTED) row=0;
5459        if(sheet->state==GTK_SHEET_ROW_SELECTED) column=0;
5460        sheet->x_drag=x;
5461        sheet->y_drag=y;
5462        aux=sheet->range;
5463
5464        if(v_h==1) 
5465            column=0;
5466        else
5467            row=0;
5468
5469        if(aux.row0+row >= 0 && aux.rowi+row < yyy_row_count(sheet) &&
5470           aux.col0+column >= 0 && aux.coli+column < xxx_column_count(sheet)){
5471
5472              aux=sheet->drag_range;
5473              sheet->drag_range=sheet->range;
5474
5475              if(row<0) sheet->drag_range.row0=sheet->range.row0+row;
5476              if(row>0) sheet->drag_range.rowi=sheet->range.rowi+row;
5477              if(column<0) sheet->drag_range.col0=sheet->range.col0+column;
5478              if(column>0) sheet->drag_range.coli=sheet->range.coli+column;
5479              
5480              if(aux.row0 != sheet->drag_range.row0 ||
5481                 aux.rowi != sheet->drag_range.rowi ||
5482                 aux.col0 != sheet->drag_range.col0 ||
5483                 aux.coli != sheet->drag_range.coli){
5484                      draw_xor_rectangle (sheet, aux);
5485                      draw_xor_rectangle (sheet, sheet->drag_range);
5486              }
5487        }
5488        return TRUE;
5489   }
5490
5491   
5492
5493   gtk_sheet_get_pixel_info (sheet, x, y, &row, &column);
5494
5495   if(sheet->state==GTK_SHEET_NORMAL && row==sheet->active_cell.row &&
5496      column==sheet->active_cell.col) return TRUE;
5497
5498   if(GTK_SHEET_IN_SELECTION(sheet) && mods&GDK_BUTTON1_MASK)
5499                           gtk_sheet_extend_selection(sheet, row, column);
5500
5501   return TRUE;
5502 }
5503
5504 static gint
5505 gtk_sheet_move_query(GtkSheet *sheet, gint row, gint column)
5506 {
5507   gint row_move, column_move;
5508   gfloat row_align, col_align;
5509   guint height, width;
5510   gint new_row = row;
5511   gint new_col = column;
5512
5513   row_move=FALSE;
5514   column_move=FALSE;
5515   row_align=-1.;
5516   col_align=-1.;
5517
5518   height = sheet->sheet_window_height;
5519   width = sheet->sheet_window_width;
5520
5521   if(row>=MAX_VISIBLE_ROW(sheet) && sheet->state!=GTK_SHEET_COLUMN_SELECTED) {
5522           row_align = 1.;
5523           new_row = MIN(yyy_row_count(sheet), row + 1);
5524           row_move = TRUE;
5525           if(MAX_VISIBLE_ROW(sheet) == yyy_row_count(sheet) - 1 &&
5526              ROW_TOP_YPIXEL(sheet, yyy_row_count(sheet)-1) + 
5527              yyy_row_height(sheet, yyy_row_count(sheet)-1) < height){
5528                  row_move = FALSE;
5529                  row_align = -1.;
5530           }
5531   }
5532   if(row<MIN_VISIBLE_ROW(sheet) && sheet->state!=GTK_SHEET_COLUMN_SELECTED) {
5533           row_align= 0.;
5534           row_move = TRUE;
5535   }
5536   if(column>=MAX_VISIBLE_COLUMN(sheet) && sheet->state!=GTK_SHEET_ROW_SELECTED) {
5537           col_align = 1.;
5538           new_col = MIN(xxx_column_count(sheet) - 1, column + 1);
5539           column_move = TRUE;
5540           if(MAX_VISIBLE_COLUMN(sheet) == (xxx_column_count(sheet) - 1) &&
5541              COLUMN_LEFT_XPIXEL(sheet, xxx_column_count(sheet) - 1) + 
5542              xxx_column_width(sheet, xxx_column_count(sheet) - 1) < width)
5543             {
5544               column_move = FALSE;
5545               col_align = -1.;
5546             }
5547   } 
5548   if(column<MIN_VISIBLE_COLUMN(sheet) && sheet->state!=GTK_SHEET_ROW_SELECTED) {
5549           col_align = 0.;
5550           column_move = TRUE;
5551   }
5552
5553   if(row_move || column_move){
5554         gtk_sheet_moveto(sheet, new_row, new_col, row_align, col_align);
5555   }
5556
5557   return(row_move || column_move);
5558 }
5559
5560 static void
5561 gtk_sheet_extend_selection(GtkSheet *sheet, gint row, gint column)
5562 {
5563    GtkSheetRange range;
5564    gint state;
5565    gint r,c;
5566
5567    if(row == sheet->selection_cell.row && column == sheet->selection_cell.col)
5568         return;
5569
5570    if(sheet->selection_mode == GTK_SELECTION_SINGLE) return;
5571
5572    gtk_sheet_move_query(sheet, row, column);
5573    gtk_widget_grab_focus(GTK_WIDGET(sheet));
5574
5575    if(GTK_SHEET_IN_DRAG(sheet)) return;
5576
5577    state=sheet->state;
5578
5579    switch(sheet->state){
5580     case GTK_SHEET_ROW_SELECTED:
5581          column = xxx_column_count(sheet) - 1;
5582          break;
5583     case GTK_SHEET_COLUMN_SELECTED:
5584          row = yyy_row_count(sheet) - 1;
5585          break; 
5586     case GTK_SHEET_NORMAL:
5587          sheet->state=GTK_SHEET_RANGE_SELECTED;
5588          r=sheet->active_cell.row;
5589          c=sheet->active_cell.col;
5590          sheet->range.col0=c;
5591          sheet->range.row0=r;
5592          sheet->range.coli=c;
5593          sheet->range.rowi=r;
5594          gdk_draw_pixmap(sheet->sheet_window,
5595                    GTK_WIDGET(sheet)->style->fg_gc[GTK_STATE_NORMAL],
5596                    sheet->pixmap,
5597                    COLUMN_LEFT_XPIXEL(sheet,c)-1,
5598                    ROW_TOP_YPIXEL(sheet,r)-1,
5599                    COLUMN_LEFT_XPIXEL(sheet,c)-1,
5600                    ROW_TOP_YPIXEL(sheet,r)-1,
5601                    xxx_column_width(sheet, c)+4,
5602                    yyy_row_height(sheet, r)+4);   
5603          gtk_sheet_range_draw_selection(sheet, sheet->range);
5604     case GTK_SHEET_RANGE_SELECTED:
5605          sheet->state=GTK_SHEET_RANGE_SELECTED;
5606    }
5607
5608    sheet->selection_cell.row = row;
5609    sheet->selection_cell.col = column;
5610
5611    range.col0=MIN(column,sheet->active_cell.col);
5612    range.coli=MAX(column,sheet->active_cell.col);
5613    range.row0=MIN(row,sheet->active_cell.row);
5614    range.rowi=MAX(row,sheet->active_cell.row);
5615
5616    if(range.row0 != sheet->range.row0 || range.rowi != sheet->range.rowi ||
5617       range.col0 != sheet->range.col0 || range.coli != sheet->range.coli ||
5618       state==GTK_SHEET_NORMAL)
5619                gtk_sheet_real_select_range(sheet, &range);
5620
5621 }
5622
5623 static gint
5624 gtk_sheet_entry_key_press(GtkWidget *widget,
5625                           GdkEventKey *key)
5626 {
5627   gboolean focus;
5628   gtk_signal_emit_by_name(GTK_OBJECT(widget), "key_press_event", key, &focus);
5629   return focus;
5630 }
5631
5632 static gint
5633 gtk_sheet_key_press(GtkWidget *widget,
5634                     GdkEventKey *key)
5635 {
5636   GtkSheet *sheet;
5637   gint row, col;
5638   gint state;
5639   gboolean extend_selection = FALSE;
5640   gboolean force_move = FALSE;
5641   gboolean in_selection = FALSE;
5642   gboolean veto = TRUE;
5643   gint scroll = 1;
5644
5645   sheet = GTK_SHEET(widget);
5646
5647   if(key->state & GDK_CONTROL_MASK || key->keyval==GDK_Control_L ||
5648      key->keyval==GDK_Control_R) return FALSE;
5649
5650 /*
5651   {
5652     if(key->keyval=='c' || key->keyval == 'C' && sheet->state != GTK_STATE_NORMAL)
5653             gtk_sheet_clip_range(sheet, sheet->range);
5654     if(key->keyval=='x' || key->keyval == 'X')
5655             gtk_sheet_unclip_range(sheet);    
5656     return FALSE;
5657   }
5658 */
5659
5660   extend_selection = (key->state & GDK_SHIFT_MASK) || key->keyval==GDK_Shift_L 
5661 || key->keyval==GDK_Shift_R;
5662
5663   state=sheet->state;
5664   in_selection = GTK_SHEET_IN_SELECTION(sheet);
5665   GTK_SHEET_UNSET_FLAGS(sheet, GTK_SHEET_IN_SELECTION);
5666
5667   switch(key->keyval){
5668     case GDK_Return: case GDK_KP_Enter:
5669       if(sheet->state == GTK_SHEET_NORMAL && 
5670          !GTK_SHEET_IN_SELECTION(sheet))
5671          gtk_signal_emit_stop_by_name(GTK_OBJECT(gtk_sheet_get_entry(sheet)), 
5672                                      "key_press_event");
5673       row = sheet->active_cell.row;
5674       col = sheet->active_cell.col;
5675       if(sheet->state == GTK_SHEET_COLUMN_SELECTED)
5676            row = MIN_VISIBLE_ROW(sheet)-1;
5677       if(sheet->state == GTK_SHEET_ROW_SELECTED)
5678            col = MIN_VISIBLE_COLUMN(sheet);
5679       if(row < yyy_row_count(sheet) - 1){
5680            row = row + scroll;
5681            while(!yyy_row_is_visible(sheet, row) && row<yyy_row_count(sheet)-1) 
5682              row++;
5683       }
5684       gtk_sheet_click_cell(sheet, row, col, &veto);
5685       extend_selection = FALSE;
5686       break;
5687    case GDK_ISO_Left_Tab:
5688       row = sheet->active_cell.row;
5689       col = sheet->active_cell.col;
5690       if(sheet->state == GTK_SHEET_ROW_SELECTED) 
5691            col = MIN_VISIBLE_COLUMN(sheet)-1;
5692       if(sheet->state == GTK_SHEET_COLUMN_SELECTED) 
5693            row = MIN_VISIBLE_ROW(sheet);
5694       if(col > 0){
5695            col = col - scroll; 
5696            while(! xxx_column_is_visible(sheet, col) && col>0) col--;
5697            col=MAX(0, col);
5698       }       
5699       gtk_sheet_click_cell(sheet, row, col, &veto);
5700       extend_selection = FALSE;
5701       break;
5702    case GDK_Tab:
5703       row = sheet->active_cell.row;
5704       col = sheet->active_cell.col;
5705       if(sheet->state == GTK_SHEET_ROW_SELECTED) 
5706            col = MIN_VISIBLE_COLUMN(sheet)-1;
5707       if(sheet->state == GTK_SHEET_COLUMN_SELECTED) 
5708            row = MIN_VISIBLE_ROW(sheet);
5709       if(col < xxx_column_count(sheet) - 1)
5710         {
5711           col = col + scroll; 
5712           while(! xxx_column_is_visible(sheet, col) && 
5713                 col < xxx_column_count(sheet) - 1) 
5714             col++;
5715         }       
5716       gtk_sheet_click_cell(sheet, row, col, &veto);
5717       extend_selection = FALSE;
5718       break;
5719 /*    case GDK_BackSpace:
5720       if(sheet->active_cell.row >= 0 && sheet->active_cell.col >= 0){
5721        if(sheet->active_cell.col > 0){
5722             col = sheet->active_cell.col - scroll; 
5723             row = sheet->active_cell.row;
5724             while(!sheet->column[col].is_visible && col > 0) col--;
5725        }       
5726       }
5727       gtk_sheet_click_cell(sheet, row, col, &veto);
5728       extend_selection = FALSE;
5729       break;
5730 */
5731     case GDK_Page_Up:
5732       scroll=MAX_VISIBLE_ROW(sheet)-MIN_VISIBLE_ROW(sheet)+1;
5733     case GDK_Up:
5734       if(extend_selection){
5735         if(state==GTK_STATE_NORMAL){
5736            row=sheet->active_cell.row;
5737            col=sheet->active_cell.col;
5738            gtk_sheet_click_cell(sheet, row, col, &veto);
5739            if(!veto) break;
5740         }
5741         if(sheet->selection_cell.row > 0){
5742           row = sheet->selection_cell.row - scroll;
5743           while(!yyy_row_is_visible(sheet, row) && row > 0) row--;
5744           row = MAX(0, row);
5745           gtk_sheet_extend_selection(sheet, row, sheet->selection_cell.col);
5746         }
5747         return TRUE;
5748       }
5749       col = sheet->active_cell.col;
5750       row = sheet->active_cell.row;
5751       if(state==GTK_SHEET_COLUMN_SELECTED) 
5752              row = MIN_VISIBLE_ROW(sheet);
5753       if(state==GTK_SHEET_ROW_SELECTED) 
5754              col = MIN_VISIBLE_COLUMN(sheet);
5755       row = row - scroll;
5756       while(!yyy_row_is_visible(sheet, row) && row > 0) row--;
5757       row = MAX(0,row);
5758       gtk_sheet_click_cell(sheet, row, col, &veto);
5759       extend_selection = FALSE;
5760       break;
5761     case GDK_Page_Down:
5762       scroll=MAX_VISIBLE_ROW(sheet)-MIN_VISIBLE_ROW(sheet)+1;
5763     case GDK_Down:
5764       if(extend_selection){
5765         if(state==GTK_STATE_NORMAL){
5766            row=sheet->active_cell.row;
5767            col=sheet->active_cell.col;
5768            gtk_sheet_click_cell(sheet, row, col, &veto);
5769            if(!veto) break;
5770         }
5771         if(sheet->selection_cell.row < yyy_row_count(sheet)-1){
5772           row = sheet->selection_cell.row + scroll;
5773           while(!yyy_row_is_visible(sheet, row) && row < yyy_row_count(sheet)-1) row++;
5774           row = MIN(yyy_row_count(sheet)-1, row);
5775           gtk_sheet_extend_selection(sheet, row, sheet->selection_cell.col);
5776         }
5777         return TRUE;
5778       }
5779       col = sheet->active_cell.col;
5780       row = sheet->active_cell.row;
5781       if(sheet->active_cell.row < yyy_row_count(sheet)-1){
5782            if(state==GTK_SHEET_COLUMN_SELECTED) 
5783                 row = MIN_VISIBLE_ROW(sheet)-1;
5784            if(state==GTK_SHEET_ROW_SELECTED) 
5785                 col = MIN_VISIBLE_COLUMN(sheet);
5786            row = row + scroll;
5787            while(!yyy_row_is_visible(sheet, row) && row < yyy_row_count(sheet)-1) row++;
5788            row = MIN(yyy_row_count(sheet)-1, row);
5789       }
5790       gtk_sheet_click_cell(sheet, row, col, &veto);
5791       extend_selection = FALSE;
5792       break;
5793     case GDK_Right:
5794       if(extend_selection){
5795         if(state==GTK_STATE_NORMAL){
5796            row=sheet->active_cell.row;
5797            col=sheet->active_cell.col;
5798            gtk_sheet_click_cell(sheet, row, col, &veto);
5799            if(!veto) break;
5800         }
5801         if(sheet->selection_cell.col < xxx_column_count(sheet) - 1)
5802           {
5803             col = sheet->selection_cell.col + 1;
5804             while(! xxx_column_is_visible(sheet, col) && col < xxx_column_count(sheet) - 1) 
5805               col++;
5806             gtk_sheet_extend_selection(sheet, sheet->selection_cell.row, col);
5807           }
5808         return TRUE;
5809       }
5810       col = sheet->active_cell.col;
5811       row = sheet->active_cell.row;
5812       if(sheet->active_cell.col < xxx_column_count(sheet) - 1){
5813            col ++;
5814            if(state==GTK_SHEET_ROW_SELECTED) 
5815                 col = MIN_VISIBLE_COLUMN(sheet)-1;
5816            if(state==GTK_SHEET_COLUMN_SELECTED) 
5817                 row = MIN_VISIBLE_ROW(sheet);
5818            while(! xxx_column_is_visible(sheet, col) && col < xxx_column_count(sheet) - 1) col++;
5819            if(strlen(gtk_entry_get_text(GTK_ENTRY(gtk_sheet_get_entry(sheet)))) == 0 
5820               || force_move) {
5821                 gtk_sheet_click_cell(sheet, row, col, &veto);
5822            }
5823            else
5824               return FALSE;
5825       }
5826       extend_selection = FALSE;
5827       break;
5828     case GDK_Left:
5829       if(extend_selection){
5830         if(state==GTK_STATE_NORMAL){
5831            row=sheet->active_cell.row;
5832            col=sheet->active_cell.col;
5833            gtk_sheet_click_cell(sheet, row, col, &veto);
5834            if(!veto) break;
5835         }
5836         if(sheet->selection_cell.col > 0){
5837           col = sheet->selection_cell.col - 1;
5838           while(! xxx_column_is_visible(sheet, col) && col > 0) col--;          
5839           gtk_sheet_extend_selection(sheet, sheet->selection_cell.row, col);
5840         }
5841         return TRUE;
5842       }
5843       col = sheet->active_cell.col - 1;
5844       row = sheet->active_cell.row;
5845       if(state==GTK_SHEET_ROW_SELECTED) 
5846                 col = MIN_VISIBLE_COLUMN(sheet)-1;
5847       if(state==GTK_SHEET_COLUMN_SELECTED) 
5848                 row = MIN_VISIBLE_ROW(sheet);
5849       while(! xxx_column_is_visible(sheet, col) && col > 0) col--;
5850       col = MAX(0, col);
5851
5852       if(strlen(gtk_entry_get_text(GTK_ENTRY(gtk_sheet_get_entry(sheet)))) == 0
5853          || force_move){
5854                 gtk_sheet_click_cell(sheet, row, col, &veto);
5855       }
5856       else
5857          return FALSE;
5858       extend_selection = FALSE;
5859       break;
5860     case GDK_Home:
5861       row=0;
5862       while(!yyy_row_is_visible(sheet, row) && row < yyy_row_count(sheet)-1) row++;
5863       gtk_sheet_click_cell(sheet, row, sheet->active_cell.col, &veto);
5864       extend_selection = FALSE;
5865       break;
5866     case GDK_End:
5867       row=yyy_row_count(sheet)-1;
5868       while(!yyy_row_is_visible(sheet, row) && row > 0) row--;
5869       gtk_sheet_click_cell(sheet, row, sheet->active_cell.col, &veto);
5870       extend_selection = FALSE;
5871       break;
5872     default:
5873       if(in_selection) {
5874         GTK_SHEET_SET_FLAGS(sheet, GTK_SHEET_IN_SELECTION);
5875         if(extend_selection) return TRUE;
5876       }
5877       if(state == GTK_SHEET_ROW_SELECTED) 
5878         sheet->active_cell.col=MIN_VISIBLE_COLUMN(sheet);
5879       if(state == GTK_SHEET_COLUMN_SELECTED)
5880         sheet->active_cell.row=MIN_VISIBLE_ROW(sheet);
5881       return FALSE;
5882   }
5883
5884   if(extend_selection) return TRUE;
5885
5886   gtk_sheet_activate_cell(sheet, sheet->active_cell.row,
5887                                  sheet->active_cell.col);
5888
5889   return TRUE;
5890
5891
5892 static void
5893 gtk_sheet_size_request (GtkWidget * widget,
5894                         GtkRequisition * requisition)
5895 {
5896   GtkSheet *sheet;
5897   GList *children;
5898   GtkSheetChild *child;
5899   GtkRequisition child_requisition;
5900
5901   g_return_if_fail (widget != NULL);
5902   g_return_if_fail (GTK_IS_SHEET (widget));
5903   g_return_if_fail (requisition != NULL);
5904
5905   sheet = GTK_SHEET (widget);
5906
5907   requisition->width = 3*DEFAULT_COLUMN_WIDTH;
5908   requisition->height = 3*DEFAULT_ROW_HEIGHT(widget);
5909
5910   /* compute the size of the column title area */
5911   if(sheet->column_titles_visible) 
5912      requisition->height += sheet->column_title_area.height;
5913
5914   /* compute the size of the row title area */
5915   if(sheet->row_titles_visible) 
5916      requisition->width += sheet->row_title_area.width;
5917
5918   sheet->view.row0=ROW_FROM_YPIXEL(sheet, sheet->column_title_area.height+1);
5919   sheet->view.rowi=ROW_FROM_YPIXEL(sheet, sheet->sheet_window_height-1);
5920   sheet->view.col0=COLUMN_FROM_XPIXEL(sheet, sheet->row_title_area.width+1);
5921   sheet->view.coli=COLUMN_FROM_XPIXEL(sheet, sheet->sheet_window_width);
5922
5923   if(!sheet->column_titles_visible) 
5924      sheet->view.row0=ROW_FROM_YPIXEL(sheet, 1);
5925
5926   if(!sheet->row_titles_visible) 
5927      sheet->view.col0=COLUMN_FROM_XPIXEL(sheet, 1);
5928
5929   children = sheet->children;
5930   while (children)
5931   {
5932     child = children->data;
5933     children = children->next;
5934
5935     gtk_widget_size_request(child->widget, &child_requisition);
5936   }
5937 }
5938
5939  
5940 static void
5941 gtk_sheet_size_allocate (GtkWidget * widget,
5942                          GtkAllocation * allocation)
5943 {
5944   GtkSheet *sheet;
5945   GtkAllocation sheet_allocation;
5946   gint border_width;
5947
5948   g_return_if_fail (widget != NULL);
5949   g_return_if_fail (GTK_IS_SHEET (widget));
5950   g_return_if_fail (allocation != NULL);
5951
5952   sheet = GTK_SHEET (widget);
5953   widget->allocation = *allocation;
5954   border_width = GTK_CONTAINER(widget)->border_width;
5955
5956   if (GTK_WIDGET_REALIZED (widget))
5957     gdk_window_move_resize (widget->window,
5958                             allocation->x + border_width,
5959                             allocation->y + border_width,
5960                             allocation->width - 2*border_width,
5961                             allocation->height - 2*border_width);
5962
5963   /* use internal allocation structure for all the math
5964    * because it's easier than always subtracting the container
5965    * border width */
5966   sheet->internal_allocation.x = 0;
5967   sheet->internal_allocation.y = 0;
5968   sheet->internal_allocation.width = allocation->width - 2*border_width;
5969   sheet->internal_allocation.height = allocation->height - 2*border_width;
5970         
5971   sheet_allocation.x = 0;
5972   sheet_allocation.y = 0;
5973   sheet_allocation.width = allocation->width - 2*border_width;
5974   sheet_allocation.height = allocation->height - 2*border_width;
5975
5976   sheet->sheet_window_width = sheet_allocation.width;
5977   sheet->sheet_window_height = sheet_allocation.height;
5978
5979   if (GTK_WIDGET_REALIZED (widget))
5980     gdk_window_move_resize (sheet->sheet_window,
5981                             sheet_allocation.x,
5982                             sheet_allocation.y,
5983                             sheet_allocation.width,
5984                             sheet_allocation.height);
5985
5986     /* position the window which holds the column title buttons */
5987   sheet->column_title_area.x = 0;
5988   sheet->column_title_area.y = 0;
5989   if(sheet->row_titles_visible)
5990        sheet->column_title_area.x = sheet->row_title_area.width;
5991   sheet->column_title_area.width = sheet_allocation.width - 
5992                                      sheet->column_title_area.x;
5993   if(GTK_WIDGET_REALIZED(widget) && sheet->column_titles_visible)
5994       gdk_window_move_resize (sheet->column_title_window,
5995                               sheet->column_title_area.x,
5996                               sheet->column_title_area.y,
5997                               sheet->column_title_area.width,
5998                               sheet->column_title_area.height);
5999
6000   sheet->sheet_window_width = sheet_allocation.width;
6001   sheet->sheet_window_height = sheet_allocation.height;
6002
6003   /* column button allocation */
6004   size_allocate_column_title_buttons (sheet);
6005
6006   /* position the window which holds the row title buttons */
6007   sheet->row_title_area.x = 0;
6008   sheet->row_title_area.y = 0;
6009   if(sheet->column_titles_visible)
6010        sheet->row_title_area.y = sheet->column_title_area.height;
6011   sheet->row_title_area.height = sheet_allocation.height -
6012                                    sheet->row_title_area.y;
6013
6014   if(GTK_WIDGET_REALIZED(widget) && sheet->row_titles_visible)
6015       gdk_window_move_resize (sheet->row_title_window,
6016                               sheet->row_title_area.x,
6017                               sheet->row_title_area.y,
6018                               sheet->row_title_area.width,
6019                               sheet->row_title_area.height);
6020
6021
6022   /* row button allocation */
6023   size_allocate_row_title_buttons (sheet);
6024
6025   sheet->view.row0=ROW_FROM_YPIXEL(sheet, sheet->column_title_area.height+1);
6026   sheet->view.rowi=ROW_FROM_YPIXEL(sheet, sheet->sheet_window_height-1);
6027   sheet->view.col0=COLUMN_FROM_XPIXEL(sheet, sheet->row_title_area.width+1);
6028   sheet->view.coli=COLUMN_FROM_XPIXEL(sheet, sheet->sheet_window_width);
6029
6030   if(!sheet->column_titles_visible)
6031        sheet->view.row0=ROW_FROM_YPIXEL(sheet, 1);
6032       
6033   if(!sheet->row_titles_visible)
6034        sheet->view.col0=COLUMN_FROM_XPIXEL(sheet, 1);
6035
6036   size_allocate_column_title_buttons(sheet);
6037   size_allocate_row_title_buttons(sheet);
6038
6039   /* re-scale backing pixmap */
6040   gtk_sheet_make_backing_pixmap(sheet, 0, 0); 
6041   gtk_sheet_position_children(sheet);
6042
6043   /* set the scrollbars adjustments */
6044   adjust_scrollbars (sheet);
6045 }
6046
6047 static void
6048 size_allocate_column_title_buttons (GtkSheet * sheet)
6049 {
6050   gint i;
6051   gint x,width;
6052
6053   if (!sheet->column_titles_visible) return;
6054   if (!GTK_WIDGET_REALIZED (sheet))
6055     return;
6056
6057   width = sheet->sheet_window_width;
6058   x = 0;
6059
6060   if(sheet->row_titles_visible)
6061     {
6062       width -= sheet->row_title_area.width;
6063       x = sheet->row_title_area.width;
6064     }
6065
6066   if(sheet->column_title_area.width != width || sheet->column_title_area.x != x)
6067   {
6068      sheet->column_title_area.width = width;
6069      sheet->column_title_area.x = x;
6070      gdk_window_move_resize (sheet->column_title_window,
6071                              sheet->column_title_area.x,
6072                              sheet->column_title_area.y,
6073                              sheet->column_title_area.width,
6074                              sheet->column_title_area.height);
6075   }
6076
6077
6078   if(MAX_VISIBLE_COLUMN(sheet) == xxx_column_count(sheet) - 1)
6079      gdk_window_clear_area (sheet->column_title_window,
6080                             0,0,
6081                             sheet->column_title_area.width, 
6082                             sheet->column_title_area.height);
6083
6084   if(!GTK_WIDGET_DRAWABLE(sheet)) return;
6085
6086   for (i = MIN_VISIBLE_COLUMN(sheet); i <= MAX_VISIBLE_COLUMN(sheet); i++)
6087       gtk_sheet_button_draw(sheet,-1,i);
6088 }
6089         
6090 static void
6091 size_allocate_row_title_buttons (GtkSheet * sheet)
6092 {
6093   gint i;
6094   gint y, height;
6095
6096   if (!sheet->row_titles_visible) return;
6097   if (!GTK_WIDGET_REALIZED (sheet))
6098     return;
6099
6100   height = sheet->sheet_window_height;
6101   y = 0;
6102
6103   if(sheet->column_titles_visible)
6104     {
6105       height -= sheet->column_title_area.height;
6106       y = sheet->column_title_area.height;
6107     }
6108     
6109   if(sheet->row_title_area.height != height || sheet->row_title_area.y != y)
6110     {
6111       sheet->row_title_area.y = y;
6112       sheet->row_title_area.height = height;
6113       gdk_window_move_resize (sheet->row_title_window,
6114                               sheet->row_title_area.x,
6115                               sheet->row_title_area.y,
6116                               sheet->row_title_area.width,
6117                               sheet->row_title_area.height);
6118     }
6119   if(MAX_VISIBLE_ROW(sheet) == yyy_row_count(sheet)-1)
6120     gdk_window_clear_area (sheet->row_title_window,
6121                            0,0,
6122                            sheet->row_title_area.width, 
6123                            sheet->row_title_area.height);
6124
6125   if(!GTK_WIDGET_DRAWABLE(sheet)) return;
6126
6127   for(i = MIN_VISIBLE_ROW(sheet); i <= MAX_VISIBLE_ROW(sheet); i++)
6128       gtk_sheet_button_draw(sheet,i,-1);
6129 }
6130           
6131
6132 static void
6133 gtk_sheet_size_allocate_entry(GtkSheet *sheet)
6134 {
6135  GtkAllocation shentry_allocation;
6136  GtkSheetCellAttr attributes;
6137  GtkEntry *sheet_entry;
6138  GtkStyle *style = NULL, *previous_style = NULL;
6139  gint row, col;
6140  gint size, max_size, text_size, column_width;
6141  const gchar *text;
6142
6143  if(!GTK_WIDGET_REALIZED(GTK_WIDGET(sheet))) return;
6144  if(!GTK_WIDGET_MAPPED(GTK_WIDGET(sheet))) return;
6145
6146  sheet_entry = GTK_ENTRY(gtk_sheet_get_entry(sheet));
6147
6148  gtk_sheet_get_attributes(sheet, sheet->active_cell.row, sheet->active_cell.col, &attributes); 
6149
6150  if(GTK_WIDGET_REALIZED(sheet->sheet_entry)){
6151
6152   if(!GTK_WIDGET(sheet_entry)->style) 
6153         gtk_widget_ensure_style(GTK_WIDGET(sheet_entry));
6154
6155   previous_style = GTK_WIDGET(sheet_entry)->style;
6156
6157   style = gtk_style_copy(previous_style);
6158   style->bg[GTK_STATE_NORMAL] = attributes.background;
6159   style->fg[GTK_STATE_NORMAL] = attributes.foreground;
6160   style->text[GTK_STATE_NORMAL] = attributes.foreground;
6161   style->bg[GTK_STATE_ACTIVE] = attributes.background;
6162   style->fg[GTK_STATE_ACTIVE] = attributes.foreground;
6163   style->text[GTK_STATE_ACTIVE] = attributes.foreground;
6164
6165   pango_font_description_free(style->font_desc);
6166   style->font_desc = pango_font_description_copy(attributes.font_desc);
6167
6168   GTK_WIDGET(sheet_entry)->style = style;
6169   gtk_widget_size_request(sheet->sheet_entry, NULL);
6170   GTK_WIDGET(sheet_entry)->style = previous_style;
6171
6172   if(style != previous_style){
6173     if(!GTK_IS_ITEM_ENTRY(sheet->sheet_entry)){
6174       style->bg[GTK_STATE_NORMAL] = previous_style->bg[GTK_STATE_NORMAL];
6175       style->fg[GTK_STATE_NORMAL] = previous_style->fg[GTK_STATE_NORMAL];
6176       style->bg[GTK_STATE_ACTIVE] = previous_style->bg[GTK_STATE_ACTIVE];
6177       style->fg[GTK_STATE_ACTIVE] = previous_style->fg[GTK_STATE_ACTIVE];
6178     }
6179     gtk_widget_set_style(GTK_WIDGET(sheet_entry), style);
6180   }
6181  }
6182
6183  if(GTK_IS_ITEM_ENTRY(sheet_entry))
6184     max_size = GTK_ITEM_ENTRY(sheet_entry)->text_max_size;
6185  else
6186     max_size = 0;
6187
6188  text_size = 0;
6189  text = gtk_entry_get_text(GTK_ENTRY(sheet_entry));
6190  if(text && strlen(text) > 0){ 
6191      text_size = STRING_WIDTH(GTK_WIDGET(sheet), attributes.font_desc, text);
6192  }
6193
6194  column_width=xxx_column_width(sheet, sheet->active_cell.col);
6195
6196  size=MIN(text_size, max_size);
6197  size=MAX(size,column_width-2*CELLOFFSET);
6198
6199  row=sheet->active_cell.row;
6200  col=sheet->active_cell.col;
6201
6202  shentry_allocation.x = COLUMN_LEFT_XPIXEL(sheet,sheet->active_cell.col);
6203  shentry_allocation.y = ROW_TOP_YPIXEL(sheet,sheet->active_cell.row);
6204  shentry_allocation.width = column_width;
6205  shentry_allocation.height = yyy_row_height(sheet, sheet->active_cell.row);
6206
6207  if(GTK_IS_ITEM_ENTRY(sheet->sheet_entry)){
6208
6209    shentry_allocation.height -= 2*CELLOFFSET;
6210    shentry_allocation.y += CELLOFFSET;
6211    if(gtk_sheet_clip_text(sheet))
6212      shentry_allocation.width = column_width - 2*CELLOFFSET;
6213    else
6214      shentry_allocation.width = size;
6215
6216    switch(GTK_ITEM_ENTRY(sheet_entry)->justification){
6217      case GTK_JUSTIFY_CENTER:
6218        shentry_allocation.x += (column_width)/2 - size/2;
6219        break;
6220      case GTK_JUSTIFY_RIGHT:
6221        shentry_allocation.x += column_width - size - CELLOFFSET;
6222        break;
6223      case GTK_JUSTIFY_LEFT:
6224      case GTK_JUSTIFY_FILL:
6225        shentry_allocation.x += CELLOFFSET;
6226        break;
6227     }
6228
6229  }
6230
6231  if(!GTK_IS_ITEM_ENTRY(sheet->sheet_entry)){
6232    shentry_allocation.x += 2;
6233    shentry_allocation.y += 2;
6234    shentry_allocation.width -= MIN(shentry_allocation.width, 3);
6235    shentry_allocation.height -= MIN(shentry_allocation.height, 3);
6236  }
6237
6238  gtk_widget_size_allocate(sheet->sheet_entry, &shentry_allocation);
6239
6240  if(previous_style == style) gtk_style_unref(previous_style);
6241 }
6242
6243 static void
6244 gtk_sheet_entry_set_max_size(GtkSheet *sheet)
6245 {
6246  gint i;
6247  gint size=0;
6248  gint sizel=0, sizer=0;
6249  gint row,col;
6250  GtkJustification justification;
6251
6252  row=sheet->active_cell.row;
6253  col=sheet->active_cell.col;
6254
6255  if(!GTK_IS_ITEM_ENTRY(sheet->sheet_entry) || gtk_sheet_clip_text(sheet)) return;
6256
6257  justification = GTK_ITEM_ENTRY(sheet->sheet_entry)->justification;
6258
6259  switch(justification){
6260   case GTK_JUSTIFY_FILL:
6261   case GTK_JUSTIFY_LEFT:
6262     for(i=col+1; i<=MAX_VISIBLE_COLUMN(sheet); i++){
6263      if(gtk_sheet_cell_get_text(sheet, row, i)) break;
6264      size+=xxx_column_width(sheet, i);
6265     }
6266     size = MIN(size, sheet->sheet_window_width - COLUMN_LEFT_XPIXEL(sheet, col));
6267     break;
6268   case GTK_JUSTIFY_RIGHT:
6269     for(i=col-1; i>=MIN_VISIBLE_COLUMN(sheet); i--){
6270      if(gtk_sheet_cell_get_text(sheet, row, i)) break;
6271      size+=xxx_column_width(sheet, i);
6272     }
6273     break;
6274   case GTK_JUSTIFY_CENTER:
6275     for(i=col+1; i<=MAX_VISIBLE_COLUMN(sheet); i++){
6276 /*     if(gtk_sheet_cell_get_text(sheet, row, i)) break;
6277 */
6278      sizer+=xxx_column_width(sheet, i);
6279     }
6280     for(i=col-1; i>=MIN_VISIBLE_COLUMN(sheet); i--){
6281      if(gtk_sheet_cell_get_text(sheet, row, i)) break;
6282      sizel+=xxx_column_width(sheet, i);
6283     }
6284     size=2*MIN(sizel, sizer);
6285     break;
6286  }
6287
6288  if(size!=0) size+=xxx_column_width(sheet, col);
6289  GTK_ITEM_ENTRY(sheet->sheet_entry)->text_max_size=size;
6290
6291 }
6292
6293 static void
6294 create_sheet_entry(GtkSheet *sheet)
6295 {
6296  GtkWidget *widget;
6297  GtkWidget *parent;
6298  GtkWidget *entry;
6299  gint found_entry = FALSE;
6300
6301  widget = GTK_WIDGET(sheet);
6302
6303  if(sheet->sheet_entry){
6304     /* avoids warnings */
6305     gtk_widget_ref(sheet->sheet_entry);
6306     gtk_widget_unparent(sheet->sheet_entry);
6307     gtk_widget_destroy(sheet->sheet_entry);
6308  }
6309
6310  if(sheet->entry_type){
6311
6312    if(!g_type_is_a (sheet->entry_type, GTK_TYPE_ENTRY)){
6313
6314      parent = GTK_WIDGET(gtk_type_new(sheet->entry_type));
6315
6316      sheet->sheet_entry = parent;
6317
6318      entry = gtk_sheet_get_entry (sheet);
6319      if(GTK_IS_ENTRY(entry)) found_entry = TRUE;
6320
6321    } else {
6322
6323      parent = GTK_WIDGET(gtk_type_new(sheet->entry_type));
6324      entry = parent;
6325      found_entry = TRUE;
6326
6327    }             
6328                                     
6329    if(!found_entry){
6330
6331      g_warning ("Entry type must be GtkEntry subclass, using default");
6332      entry = gtk_item_entry_new();
6333      sheet->sheet_entry = entry;
6334
6335    } else {
6336
6337      sheet->sheet_entry = parent;
6338
6339    }
6340
6341
6342  } else {
6343
6344      entry = gtk_item_entry_new();
6345      sheet->sheet_entry = entry;
6346
6347  }
6348  
6349  gtk_widget_size_request(sheet->sheet_entry, NULL);
6350  
6351  if(GTK_WIDGET_REALIZED(sheet))
6352    {
6353       gtk_widget_set_parent_window (sheet->sheet_entry, sheet->sheet_window);
6354       gtk_widget_set_parent(sheet->sheet_entry, GTK_WIDGET(sheet));
6355       gtk_widget_realize(sheet->sheet_entry);
6356    }
6357
6358  gtk_signal_connect_object(GTK_OBJECT(entry),"key_press_event",
6359                            (GtkSignalFunc) gtk_sheet_entry_key_press,
6360                            GTK_OBJECT(sheet)); 
6361
6362  gtk_widget_show (sheet->sheet_entry); 
6363 }
6364
6365
6366 /* Finds the last child widget that happens to be of type GtkEntry */
6367 static void
6368 find_entry(GtkWidget *w, gpointer user_data)
6369 {
6370   GtkWidget **entry = user_data;
6371   if ( GTK_IS_ENTRY(w))
6372     {
6373       *entry = w;
6374     }
6375 }
6376
6377 GtkWidget * 
6378 gtk_sheet_get_entry(GtkSheet *sheet)
6379 {
6380  GtkWidget *parent;
6381  GtkWidget *entry = NULL;
6382  GtkTableChild *table_child;
6383  GtkBoxChild *box_child;
6384  GList *children = NULL;
6385
6386  g_return_val_if_fail (sheet != NULL, NULL);
6387  g_return_val_if_fail (GTK_IS_SHEET (sheet), NULL);
6388  g_return_val_if_fail (sheet->sheet_entry != NULL, NULL);
6389
6390  if(GTK_IS_ENTRY(sheet->sheet_entry)) return (sheet->sheet_entry);
6391
6392  parent = GTK_WIDGET(sheet->sheet_entry);
6393
6394  if(GTK_IS_TABLE(parent)) children = GTK_TABLE(parent)->children;
6395  if(GTK_IS_BOX(parent)) children = GTK_BOX(parent)->children;
6396
6397  if(GTK_IS_CONTAINER(parent)) 
6398    {
6399      gtk_container_forall(GTK_CONTAINER(parent), find_entry, &entry);
6400      
6401      if(GTK_IS_ENTRY(entry))  
6402        return entry;
6403    }
6404
6405  if(!children) return NULL;
6406
6407  while(children){
6408       if(GTK_IS_TABLE(parent)) {
6409                  table_child = children->data;
6410                  entry = table_child->widget;
6411       }
6412       if(GTK_IS_BOX(parent)){
6413                  box_child = children->data; 
6414                  entry = box_child->widget;
6415       }
6416
6417       if(GTK_IS_ENTRY(entry))  
6418                                 break;
6419       children = children->next;                        
6420  } 
6421
6422
6423  if(!GTK_IS_ENTRY(entry))   return NULL;
6424
6425  return (entry);
6426
6427 }
6428
6429 GtkWidget * 
6430 gtk_sheet_get_entry_widget(GtkSheet *sheet)
6431 {
6432  g_return_val_if_fail (sheet != NULL, NULL);
6433  g_return_val_if_fail (GTK_IS_SHEET (sheet), NULL);
6434  g_return_val_if_fail (sheet->sheet_entry != NULL, NULL);
6435
6436  return (sheet->sheet_entry);
6437 }
6438
6439 #if 0
6440 /* BUTTONS */
6441 static void
6442 row_button_set (GtkSheet *sheet, gint row)
6443 {
6444   if(sheet->row[row].button.state == GTK_STATE_ACTIVE) return;
6445
6446   sheet->row[row].button.state = GTK_STATE_ACTIVE;
6447   gtk_sheet_button_draw(sheet, row, -1);
6448  
6449 }
6450
6451 static void
6452 row_button_release (GtkSheet *sheet, gint row)
6453 {
6454   if(sheet->row[row].button.state == GTK_STATE_NORMAL) return;
6455
6456   sheet->row[row].button.state = GTK_STATE_NORMAL;
6457   gtk_sheet_button_draw(sheet, row, -1);
6458 }
6459 #endif
6460
6461 static void
6462 gtk_sheet_button_draw (GtkSheet *sheet, gint row, gint column)
6463 {
6464   GdkWindow *window = NULL;
6465   GtkShadowType shadow_type;
6466   guint width = 0, height = 0;
6467   gint x = 0, y = 0;
6468   gint index = 0;
6469   gint text_width = 0, text_height = 0;
6470   const GtkSheetButton *button = NULL;
6471   GtkSheetChild *child = NULL;
6472   GdkRectangle allocation;
6473   gboolean is_sensitive = FALSE;
6474   gint state = 0;
6475   gint len = 0;
6476   gchar *line = 0;
6477
6478   PangoAlignment align = PANGO_ALIGN_LEFT; 
6479   gboolean rtl;
6480
6481   rtl = gtk_widget_get_direction(GTK_WIDGET(sheet)) == GTK_TEXT_DIR_RTL;
6482
6483   if(!GTK_WIDGET_REALIZED(GTK_WIDGET(sheet))) return;
6484
6485   if(row >= 0 && !yyy_row_is_visible(sheet, row)) return;
6486   if(column >= 0 && ! xxx_column_is_visible(sheet, column)) return;
6487   if(row >= 0 && !sheet->row_titles_visible) return;
6488   if(column >= 0 && !sheet->column_titles_visible) return;
6489   if(column>=0 && column < MIN_VISIBLE_COLUMN(sheet)) return;
6490   if(column>=0 && column > MAX_VISIBLE_COLUMN(sheet)) return;
6491   if(row>=0 && row < MIN_VISIBLE_ROW(sheet)) return;
6492   if(row>=0 && row > MAX_VISIBLE_ROW(sheet)) return;
6493   if( (row == -1) && (column == -1) ) return; 
6494
6495   if(row==-1){
6496      window=sheet->column_title_window;
6497      button= xxx_column_button(sheet, column);
6498      index=column;
6499      x = COLUMN_LEFT_XPIXEL(sheet, column)+CELL_SPACING;
6500      if(sheet->row_titles_visible) x -= sheet->row_title_area.width;
6501      y = 0;
6502      width = xxx_column_width(sheet, column);
6503      height = sheet->column_title_area.height;
6504      is_sensitive=xxx_column_is_sensitive(sheet, column);
6505   }
6506   if(column==-1){
6507      window=sheet->row_title_window;
6508      button = yyy_row_button(sheet, row);
6509      index=row;
6510      x = 0;
6511      y = ROW_TOP_YPIXEL(sheet, row)+CELL_SPACING;
6512      if(sheet->column_titles_visible) y-=sheet->column_title_area.height;
6513      width = sheet->row_title_area.width;
6514      height = yyy_row_height(sheet, row);
6515      is_sensitive=yyy_row_is_sensitive(sheet, row);
6516   }
6517
6518   allocation.x = x;
6519   allocation.y = y;
6520   allocation.width = width;
6521   allocation.height = height;
6522  
6523   gdk_window_clear_area (window,
6524                          x, y,
6525                          width, height);
6526
6527   gtk_paint_box (sheet->button->style, window,
6528                  GTK_STATE_NORMAL, GTK_SHADOW_OUT, 
6529                  &allocation, GTK_WIDGET(sheet->button),
6530                  "buttondefault", x, y, width, height);
6531
6532   state = button->state;
6533   if(!is_sensitive) state=GTK_STATE_INSENSITIVE;
6534
6535   if (state == GTK_STATE_ACTIVE)
6536      shadow_type = GTK_SHADOW_IN;
6537   else
6538      shadow_type = GTK_SHADOW_OUT;
6539
6540   if(state != GTK_STATE_NORMAL && state != GTK_STATE_INSENSITIVE)
6541     gtk_paint_box (sheet->button->style, window,
6542                    button->state, shadow_type, 
6543                    &allocation, GTK_WIDGET(sheet->button),
6544                    "button", x, y, width, height);
6545
6546   if(button->label_visible){
6547
6548     text_height=DEFAULT_ROW_HEIGHT(GTK_WIDGET(sheet))-2*CELLOFFSET;
6549
6550     gdk_gc_set_clip_rectangle(GTK_WIDGET(sheet)->style->fg_gc[button->state], 
6551                               &allocation);
6552     gdk_gc_set_clip_rectangle(GTK_WIDGET(sheet)->style->white_gc, &allocation);
6553
6554     y += 2*sheet->button->style->ythickness;
6555
6556
6557     if(button->label && strlen(button->label)>0){
6558            gchar *words = 0;
6559            PangoLayout *layout = NULL;
6560            gint real_x = x, real_y = y;
6561
6562            words=button->label;
6563            line = g_new(gchar, 1);
6564            line[0]='\0';
6565
6566            while(words && *words != '\0'){
6567              if(*words != '\n'){
6568                 len=strlen(line);
6569                 line=g_realloc(line, len+2);
6570                 line[len]=*words;
6571                 line[len+1]='\0';
6572              }
6573              if(*words == '\n' || *(words+1) == '\0'){
6574                text_width = STRING_WIDTH(GTK_WIDGET(sheet), GTK_WIDGET(sheet)->style->font_desc, line);
6575
6576                layout = gtk_widget_create_pango_layout (GTK_WIDGET(sheet), line);
6577                switch(button->justification){
6578                  case GTK_JUSTIFY_LEFT:
6579                    real_x = x + CELLOFFSET;
6580                    align = rtl ? PANGO_ALIGN_RIGHT : PANGO_ALIGN_LEFT;
6581                    break;
6582                  case GTK_JUSTIFY_RIGHT:
6583                    real_x = x + width - text_width - CELLOFFSET;
6584                    align = rtl ? PANGO_ALIGN_LEFT : PANGO_ALIGN_RIGHT;
6585                    break;
6586                  case GTK_JUSTIFY_CENTER:
6587                  default:
6588                    real_x = x + (width - text_width)/2;
6589                    align = rtl ? PANGO_ALIGN_RIGHT : PANGO_ALIGN_LEFT;
6590                    pango_layout_set_justify (layout, TRUE);
6591                }
6592                pango_layout_set_alignment (layout, align);
6593                gtk_paint_layout (GTK_WIDGET(sheet)->style,
6594                                  window,
6595                                  state,
6596                                  FALSE,
6597                                  &allocation,
6598                                  GTK_WIDGET(sheet),
6599                                  "label",
6600                                  real_x, real_y,
6601                                  layout);
6602                g_object_unref(G_OBJECT(layout));
6603
6604                real_y += text_height + 2;
6605
6606                g_free(line);
6607                line = g_new(gchar, 1);
6608                line[0]='\0';
6609              }
6610              words++;
6611            }
6612            g_free(line);
6613     }
6614
6615     gdk_gc_set_clip_rectangle(GTK_WIDGET(sheet)->style->fg_gc[button->state],
6616                             NULL);
6617     gdk_gc_set_clip_rectangle(GTK_WIDGET(sheet)->style->white_gc, NULL);
6618
6619   }
6620
6621   if((child = button->child) && (child->widget)){
6622       child->x = allocation.x;
6623       child->y = allocation.y;
6624
6625       child->x += (width - child->widget->requisition.width) / 2; 
6626       child->y += (height - child->widget->requisition.height) / 2;
6627       allocation.x = child->x;
6628       allocation.y = child->y;
6629       allocation.width = child->widget->requisition.width;
6630       allocation.height = child->widget->requisition.height;
6631
6632       x = child->x;
6633       y = child->y;
6634
6635       gtk_widget_set_state(child->widget, button->state);
6636
6637       if(GTK_WIDGET_REALIZED(GTK_WIDGET(sheet)) &&
6638          GTK_WIDGET_MAPPED(child->widget))
6639             {
6640               gtk_widget_size_allocate(child->widget, 
6641                                        &allocation);
6642               gtk_widget_queue_draw(child->widget);
6643             }
6644   }
6645    
6646 }
6647
6648
6649 /* SCROLLBARS
6650  *
6651  * functions:
6652  *   adjust_scrollbars
6653  *   vadjustment_changed
6654  *   hadjustment_changed
6655  *   vadjustment_value_changed
6656  *   hadjustment_value_changed */
6657
6658 static void
6659 adjust_scrollbars (GtkSheet * sheet)
6660 {
6661
6662  if(sheet->vadjustment){ 
6663   sheet->vadjustment->page_size = sheet->sheet_window_height;
6664   sheet->vadjustment->page_increment = sheet->sheet_window_height / 2;
6665   sheet->vadjustment->step_increment = DEFAULT_ROW_HEIGHT(GTK_WIDGET(sheet));
6666   sheet->vadjustment->lower = 0;
6667   sheet->vadjustment->upper = SHEET_HEIGHT (sheet) + 80;
6668 /*
6669   if (sheet->sheet_window_height - sheet->voffset > SHEET_HEIGHT (sheet))
6670     {
6671       sheet->vadjustment->value = MAX(0, SHEET_HEIGHT (sheet) - 
6672         sheet->sheet_window_height);
6673       gtk_signal_emit_by_name (GTK_OBJECT (sheet->vadjustment), 
6674                                "value_changed");
6675     }
6676 */
6677     gtk_signal_emit_by_name (GTK_OBJECT(sheet->vadjustment), "changed");
6678
6679  }
6680
6681  if(sheet->hadjustment){
6682   sheet->hadjustment->page_size = sheet->sheet_window_width;
6683   sheet->hadjustment->page_increment = sheet->sheet_window_width / 2;
6684   sheet->hadjustment->step_increment = DEFAULT_COLUMN_WIDTH;
6685   sheet->hadjustment->lower = 0;
6686   sheet->hadjustment->upper = SHEET_WIDTH (sheet)+ 80;
6687 /*
6688   if (sheet->sheet_window_width - sheet->hoffset > SHEET_WIDTH (sheet))
6689     {
6690       sheet->hadjustment->value = MAX(0, SHEET_WIDTH (sheet) - 
6691         sheet->sheet_window_width);
6692       gtk_signal_emit_by_name (GTK_OBJECT(sheet->hadjustment), 
6693                                "value_changed");
6694     }
6695 */
6696     gtk_signal_emit_by_name (GTK_OBJECT(sheet->hadjustment), "changed");
6697
6698  }
6699 /*
6700  if(GTK_WIDGET_REALIZED(sheet)) 
6701    {
6702      if(sheet->row_titles_visible){
6703                  size_allocate_row_title_buttons(sheet);
6704                  gdk_window_show(sheet->row_title_window);
6705      }
6706
6707      if(sheet->column_titles_visible){
6708                  size_allocate_column_title_buttons(sheet);
6709                  gdk_window_show(sheet->column_title_window);
6710      }
6711
6712      gtk_sheet_range_draw(sheet, NULL);
6713    }
6714 */
6715 }
6716
6717
6718 static void
6719 vadjustment_changed (GtkAdjustment * adjustment,
6720                                gpointer data)
6721 {
6722   GtkSheet *sheet;
6723
6724   g_return_if_fail (adjustment != NULL);
6725   g_return_if_fail (data != NULL);
6726
6727   sheet = GTK_SHEET (data);
6728
6729 }
6730
6731 static void
6732 hadjustment_changed (GtkAdjustment * adjustment,
6733                                gpointer data)
6734 {
6735   GtkSheet *sheet;
6736
6737   g_return_if_fail (adjustment != NULL);
6738   g_return_if_fail (data != NULL);
6739
6740   sheet = GTK_SHEET (data);
6741 }
6742
6743
6744 static void
6745 vadjustment_value_changed (GtkAdjustment * adjustment,
6746                                      gpointer data)
6747 {
6748   GtkSheet *sheet;
6749   gint diff, value, old_value;
6750   gint row, new_row;
6751   gint y=0;
6752
6753   g_return_if_fail (adjustment != NULL);
6754   g_return_if_fail (data != NULL);
6755   g_return_if_fail (GTK_IS_SHEET (data));
6756
6757   sheet = GTK_SHEET (data);
6758
6759   if(GTK_SHEET_IS_FROZEN(sheet)) return;
6760
6761   row=ROW_FROM_YPIXEL(sheet,sheet->column_title_area.height + CELL_SPACING);
6762   if(!sheet->column_titles_visible)
6763      row=ROW_FROM_YPIXEL(sheet,CELL_SPACING);
6764     
6765   old_value = -sheet->voffset;
6766
6767   new_row = g_sheet_row_pixel_to_row(sheet->row_geometry,
6768                                      adjustment->value,sheet);
6769
6770   y = g_sheet_row_start_pixel(sheet->row_geometry, new_row, sheet);
6771
6772   if (adjustment->value > sheet->old_vadjustment && sheet->old_vadjustment > 0. &&
6773       yyy_row_height(sheet, row) > sheet->vadjustment->step_increment){
6774 /* This avoids embarrassing twitching */
6775           if(row == new_row && row != yyy_row_count(sheet) - 1 &&
6776              adjustment->value - sheet->old_vadjustment >= 
6777                           sheet->vadjustment->step_increment &&
6778              new_row + 1 != MIN_VISIBLE_ROW(sheet)){
6779                 new_row+=1;
6780                 y=y+yyy_row_height(sheet, row);
6781           }
6782   }
6783
6784 /* Negative old_adjustment enforces the redraw, otherwise avoid spureous redraw */
6785   if(sheet->old_vadjustment >= 0. && row == new_row){
6786       sheet->old_vadjustment = sheet->vadjustment->value;
6787       return;
6788   }
6789
6790   sheet->old_vadjustment = sheet->vadjustment->value;
6791   adjustment->value=y;
6792
6793  
6794   if(new_row == 0){
6795    sheet->vadjustment->step_increment=  yyy_row_height(sheet, 0);
6796   }else{
6797    sheet->vadjustment->step_increment=
6798    MIN(yyy_row_height(sheet, new_row), yyy_row_height(sheet, new_row-1));
6799   }
6800
6801   sheet->vadjustment->value=adjustment->value;
6802
6803   value = adjustment->value;
6804
6805   if (value >= -sheet->voffset)
6806         {
6807           /* scroll down */
6808           diff = value + sheet->voffset;
6809         }
6810   else
6811         {
6812           /* scroll up */
6813           diff = -sheet->voffset - value;
6814         }
6815
6816       sheet->voffset = -value;
6817  
6818   sheet->view.row0=ROW_FROM_YPIXEL(sheet, sheet->column_title_area.height+1);
6819   sheet->view.rowi=ROW_FROM_YPIXEL(sheet, sheet->sheet_window_height-1);
6820   if(!sheet->column_titles_visible)
6821      sheet->view.row0=ROW_FROM_YPIXEL(sheet, 1);
6822
6823   if(GTK_WIDGET_REALIZED(sheet->sheet_entry) &&
6824      sheet->state == GTK_SHEET_NORMAL && 
6825      sheet->active_cell.row >= 0 && sheet->active_cell.col >= 0 &&
6826      !gtk_sheet_cell_isvisible(sheet, sheet->active_cell.row,
6827                                       sheet->active_cell.col))
6828     {
6829       const gchar *text;
6830
6831       text = gtk_entry_get_text(GTK_ENTRY(gtk_sheet_get_entry(sheet)));
6832
6833       if(!text || strlen(text)==0) 
6834              gtk_sheet_cell_clear(sheet,
6835                                   sheet->active_cell.row,
6836                                   sheet->active_cell.col);
6837        gtk_widget_unmap(sheet->sheet_entry);
6838     }
6839
6840   gtk_sheet_position_children(sheet);
6841
6842   gtk_sheet_range_draw(sheet, NULL);
6843   size_allocate_row_title_buttons(sheet);
6844   size_allocate_global_button(sheet);
6845 }
6846
6847 static void
6848 hadjustment_value_changed (GtkAdjustment * adjustment,
6849                            gpointer data)
6850 {
6851   GtkSheet *sheet;
6852   gint i, diff, value, old_value;
6853   gint column, new_column;
6854   gint x=0;
6855
6856   g_return_if_fail (adjustment != NULL);
6857   g_return_if_fail (data != NULL);
6858   g_return_if_fail (GTK_IS_SHEET (data));
6859
6860   sheet = GTK_SHEET (data);
6861
6862   if(GTK_SHEET_IS_FROZEN(sheet)) return;
6863
6864   column=COLUMN_FROM_XPIXEL(sheet,sheet->row_title_area.width + CELL_SPACING);
6865   if(!sheet->row_titles_visible)
6866      column=COLUMN_FROM_XPIXEL(sheet, CELL_SPACING);
6867
6868   old_value = -sheet->hoffset;
6869
6870   for(i=0; i < xxx_column_count(sheet); i++)
6871     {
6872       if(xxx_column_is_visible(sheet, i)) x += xxx_column_width(sheet, i);
6873       if(x > adjustment->value) break;
6874     }
6875   x-=xxx_column_width(sheet, i);
6876   new_column=i;
6877
6878   if (adjustment->value > sheet->old_hadjustment && sheet->old_hadjustment > 0 &&
6879       xxx_column_width(sheet, i) > sheet->hadjustment->step_increment){
6880 /* This avoids embarrassing twitching */
6881           if(column == new_column && column != xxx_column_count(sheet) - 1 &&
6882              adjustment->value - sheet->old_hadjustment >= 
6883                           sheet->hadjustment->step_increment &&
6884              new_column + 1 != MIN_VISIBLE_COLUMN(sheet)){
6885              new_column+=1;
6886              x=x+xxx_column_width(sheet, column);
6887           }
6888   }
6889
6890 /* Negative old_adjustment enforces the redraw, otherwise avoid spureous redraw */
6891   if(sheet->old_hadjustment >= 0. && new_column == column){
6892      sheet->old_hadjustment = sheet->hadjustment->value;
6893      return;
6894   }
6895
6896   sheet->old_hadjustment = sheet->hadjustment->value;
6897   adjustment->value=x;
6898
6899   if(new_column == 0){
6900    sheet->hadjustment->step_increment=
6901    xxx_column_width(sheet, 0);
6902   }else{
6903    sheet->hadjustment->step_increment=
6904    MIN(xxx_column_width(sheet, new_column), xxx_column_width(sheet, new_column-1));
6905   }
6906
6907
6908   sheet->hadjustment->value=adjustment->value;
6909
6910   value = adjustment->value;
6911
6912   if (value >= -sheet->hoffset)
6913         {
6914           /* scroll right */
6915           diff = value + sheet->hoffset;
6916         }
6917   else
6918         {
6919           /* scroll left */
6920           diff = -sheet->hoffset - value;
6921         }
6922
6923   sheet->hoffset = -value;
6924
6925   sheet->view.col0=COLUMN_FROM_XPIXEL(sheet, sheet->row_title_area.width+1);
6926   sheet->view.coli=COLUMN_FROM_XPIXEL(sheet, sheet->sheet_window_width);
6927   if(!sheet->row_titles_visible)
6928     sheet->view.col0=COLUMN_FROM_XPIXEL(sheet, 1);
6929
6930   if(GTK_WIDGET_REALIZED(sheet->sheet_entry) &&
6931      sheet->state == GTK_SHEET_NORMAL && 
6932      sheet->active_cell.row >= 0 && sheet->active_cell.col >= 0 &&
6933      !gtk_sheet_cell_isvisible(sheet, sheet->active_cell.row,
6934                                       sheet->active_cell.col))
6935     {
6936       const gchar *text;
6937
6938       text = gtk_entry_get_text(GTK_ENTRY(gtk_sheet_get_entry(sheet)));
6939       if(!text || strlen(text)==0) 
6940              gtk_sheet_cell_clear(sheet,
6941                                   sheet->active_cell.row,
6942                                   sheet->active_cell.col);
6943
6944       gtk_widget_unmap(sheet->sheet_entry);
6945     }
6946
6947   gtk_sheet_position_children(sheet);
6948
6949   gtk_sheet_range_draw(sheet, NULL);
6950   size_allocate_column_title_buttons(sheet);
6951 }
6952         
6953
6954 /* COLUMN RESIZING */
6955 static void                          
6956 draw_xor_vline (GtkSheet * sheet)
6957 {
6958   GtkWidget *widget;
6959   
6960   g_return_if_fail (sheet != NULL);
6961   
6962   widget = GTK_WIDGET (sheet);
6963
6964   gdk_draw_line (widget->window, sheet->xor_gc,  
6965                  sheet->x_drag,                                       
6966                  sheet->column_title_area.height,                               
6967                  sheet->x_drag,                                             
6968                  sheet->sheet_window_height + 1);
6969 }
6970
6971 /* ROW RESIZING */
6972 static void                          
6973 draw_xor_hline (GtkSheet * sheet)
6974 {
6975   GtkWidget *widget;
6976   
6977   g_return_if_fail (sheet != NULL);
6978   
6979   widget = GTK_WIDGET (sheet);
6980
6981   gdk_draw_line (widget->window, sheet->xor_gc,  
6982                  sheet->row_title_area.width,
6983                  sheet->y_drag,                                       
6984                         
6985                  sheet->sheet_window_width + 1,                      
6986                  sheet->y_drag);                                             
6987 }
6988
6989 /* SELECTED RANGE */
6990 static void
6991 draw_xor_rectangle(GtkSheet *sheet, GtkSheetRange range)
6992 {
6993    gint i;
6994    GdkRectangle clip_area, area;
6995    GdkGCValues values;
6996
6997    area.x=COLUMN_LEFT_XPIXEL(sheet, range.col0);
6998    area.y=ROW_TOP_YPIXEL(sheet, range.row0);
6999    area.width=COLUMN_LEFT_XPIXEL(sheet, range.coli)-area.x+
7000                                         xxx_column_width(sheet, range.coli);
7001    area.height=ROW_TOP_YPIXEL(sheet, range.rowi)-area.y+
7002                                         yyy_row_height(sheet, range.rowi);
7003
7004    clip_area.x=sheet->row_title_area.width;
7005    clip_area.y=sheet->column_title_area.height;
7006    clip_area.width=sheet->sheet_window_width;
7007    clip_area.height=sheet->sheet_window_height;
7008
7009    if(!sheet->row_titles_visible) clip_area.x = 0;
7010    if(!sheet->column_titles_visible) clip_area.y = 0;
7011
7012    if(area.x<0) {
7013       area.width=area.width+area.x;
7014       area.x=0;
7015    }
7016    if(area.width>clip_area.width) area.width=clip_area.width+10;
7017    if(area.y<0) {
7018       area.height=area.height+area.y;
7019       area.y=0;
7020    }
7021    if(area.height>clip_area.height) area.height=clip_area.height+10;
7022
7023    clip_area.x--;
7024    clip_area.y--;
7025    clip_area.width+=3;
7026    clip_area.height+=3;
7027
7028    gdk_gc_get_values(sheet->xor_gc, &values);
7029
7030    gdk_gc_set_clip_rectangle(sheet->xor_gc, &clip_area);
7031
7032    for(i=-1;i<=1;++i)
7033      gdk_draw_rectangle(sheet->sheet_window,
7034                         sheet->xor_gc,
7035                         FALSE,
7036                         area.x+i, area.y+i,
7037                         area.width-2*i, area.height-2*i);
7038
7039
7040    gdk_gc_set_clip_rectangle(sheet->xor_gc, NULL);
7041
7042    gdk_gc_set_foreground(sheet->xor_gc, &values.foreground);
7043
7044 }                      
7045
7046   
7047 /* this function returns the new width of the column being resized given
7048  * the column and x position of the cursor; the x cursor position is passed
7049  * in as a pointer and automaticaly corrected if it's beyond min/max limits */
7050 static guint
7051 new_column_width (GtkSheet * sheet,
7052                   gint column,
7053                   gint * x)
7054 {
7055   gint cx, width;
7056   guint min_width;
7057
7058   cx = *x;
7059
7060   min_width = sheet->column_requisition;
7061
7062   /* you can't shrink a column to less than its minimum width */
7063   if (cx < COLUMN_LEFT_XPIXEL (sheet, column) + min_width)
7064     {
7065       *x = cx = COLUMN_LEFT_XPIXEL (sheet, column) + min_width;
7066     }
7067
7068   /* don't grow past the end of the window */
7069   /*
7070   if (cx > sheet->sheet_window_width)
7071     {
7072       *x = cx = sheet->sheet_window_width;
7073     }
7074     */
7075   /* calculate new column width making sure it doesn't end up
7076    * less than the minimum width */
7077   width = cx - COLUMN_LEFT_XPIXEL (sheet, column);
7078   if (width < min_width)
7079     width = min_width;
7080
7081   xxx_set_column_width(sheet, column, width);
7082   sheet->view.coli=COLUMN_FROM_XPIXEL(sheet, sheet->sheet_window_width);
7083   size_allocate_column_title_buttons (sheet);
7084   
7085   return width;
7086 }
7087
7088 /* this function returns the new height of the row being resized given
7089  * the row and y position of the cursor; the y cursor position is passed
7090  * in as a pointer and automaticaly corrected if it's beyond min/max limits */
7091 static guint
7092 new_row_height (GtkSheet * sheet,
7093                 gint row,
7094                 gint * y)
7095 {
7096   gint cy, height;
7097   guint min_height;
7098
7099   cy = *y;
7100   min_height = sheet->row_requisition;
7101
7102   /* you can't shrink a row to less than its minimum height */
7103   if (cy < ROW_TOP_YPIXEL (sheet, row) + min_height)
7104
7105     {
7106       *y = cy = ROW_TOP_YPIXEL (sheet, row) + min_height;
7107     }
7108
7109   /* don't grow past the end of the window */
7110   /*
7111   if (cy > sheet->sheet_window_height)
7112     {
7113       *y = cy = sheet->sheet_window_height;
7114     }
7115     */
7116   /* calculate new row height making sure it doesn't end up
7117    * less than the minimum height */
7118   height = (cy - ROW_TOP_YPIXEL (sheet, row));
7119   if (height < min_height)
7120     height = min_height;
7121
7122   yyy_set_row_height(sheet, row, height);
7123   sheet->view.rowi=ROW_FROM_YPIXEL(sheet, sheet->sheet_window_height-1);
7124   size_allocate_row_title_buttons (sheet);
7125
7126   return height;
7127 }
7128
7129 static void
7130 gtk_sheet_set_column_width (GtkSheet * sheet,
7131                             gint column,
7132                             guint width)
7133 {
7134   guint min_width;
7135
7136   g_return_if_fail (sheet != NULL);
7137   g_return_if_fail (GTK_IS_SHEET (sheet));
7138
7139   if (column < 0 || column >= xxx_column_count(sheet))
7140     return;
7141
7142   gtk_sheet_column_size_request(sheet, column, &min_width);
7143   if(width < min_width) return;
7144
7145   xxx_set_column_width(sheet, column, width);
7146
7147   if(GTK_WIDGET_REALIZED(GTK_WIDGET(sheet)) && !GTK_SHEET_IS_FROZEN(sheet)){
7148     size_allocate_column_title_buttons (sheet);
7149     adjust_scrollbars (sheet);
7150     gtk_sheet_size_allocate_entry(sheet);
7151     gtk_sheet_range_draw (sheet, NULL);
7152   } else
7153
7154   gtk_signal_emit(GTK_OBJECT(sheet), sheet_signals[CHANGED], -1, column);
7155   gtk_signal_emit(GTK_OBJECT(sheet), sheet_signals[NEW_COL_WIDTH], column, width);
7156
7157 }
7158
7159
7160
7161 void
7162 gtk_sheet_set_row_height (GtkSheet * sheet,
7163                             gint row,
7164                             guint height)
7165 {
7166   guint min_height;
7167
7168   g_return_if_fail (sheet != NULL);
7169   g_return_if_fail (GTK_IS_SHEET (sheet));
7170
7171   if (row < 0 || row >= yyy_row_count(sheet))
7172     return;
7173
7174   gtk_sheet_row_size_request(sheet, row, &min_height);
7175   if(height < min_height) return;
7176
7177   yyy_set_row_height(sheet, row, height);
7178
7179   if(GTK_WIDGET_REALIZED(GTK_WIDGET(sheet)) && !GTK_SHEET_IS_FROZEN(sheet)){
7180     size_allocate_row_title_buttons (sheet);
7181     adjust_scrollbars (sheet);
7182     gtk_sheet_size_allocate_entry(sheet);
7183     gtk_sheet_range_draw (sheet, NULL);
7184   }
7185
7186   gtk_signal_emit(GTK_OBJECT(sheet), sheet_signals[CHANGED], row, -1);
7187   gtk_signal_emit(GTK_OBJECT(sheet), sheet_signals[NEW_ROW_HEIGHT], row, height);
7188
7189 }
7190
7191
7192 gboolean
7193 gtk_sheet_get_attributes(GtkSheet *sheet, gint row, gint col, GtkSheetCellAttr *attributes)
7194 {
7195  const GdkColor *fg, *bg; 
7196  const GtkJustification *j ; 
7197  const PangoFontDescription *font_desc ;
7198  const GtkSheetCellBorder *border ;
7199
7200  g_return_val_if_fail (sheet != NULL, FALSE);
7201  g_return_val_if_fail (GTK_IS_SHEET (sheet), FALSE);
7202
7203  if(row < 0 || col < 0) return FALSE;
7204
7205  init_attributes(sheet, col, attributes);
7206
7207  if ( !sheet->model) 
7208          return FALSE;
7209
7210  attributes->is_editable = g_sheet_model_is_editable(sheet->model, row, col);
7211  attributes->is_visible = g_sheet_model_is_visible(sheet->model, row, col);
7212
7213  fg = g_sheet_model_get_foreground(sheet->model, row, col);
7214  if ( fg ) 
7215    attributes->foreground =  *fg;
7216
7217  bg = g_sheet_model_get_background(sheet->model, row, col);
7218  if ( bg ) 
7219    attributes->background =  *bg;
7220
7221  j = g_sheet_model_get_justification(sheet->model, row, col);
7222  if (j)   attributes->justification = *j;
7223
7224  font_desc = g_sheet_model_get_font_desc(sheet->model, row, col);
7225  if ( font_desc )  attributes->font_desc = font_desc;
7226
7227  border = g_sheet_model_get_cell_border(sheet->model, row, col);
7228
7229  if ( border ) attributes->border = *border;
7230
7231  return TRUE;
7232 }
7233
7234 static void
7235 init_attributes(GtkSheet *sheet, gint col, GtkSheetCellAttr *attributes)
7236 {
7237  /* DEFAULT VALUES */    
7238  attributes->foreground = GTK_WIDGET(sheet)->style->black;
7239  attributes->background = sheet->bg_color;
7240  if(!GTK_WIDGET_REALIZED(GTK_WIDGET(sheet))){
7241    GdkColormap *colormap;
7242    colormap=gdk_colormap_get_system();
7243    gdk_color_black(colormap, &attributes->foreground);
7244    attributes->background = sheet->bg_color;
7245  }
7246  attributes->justification = xxx_column_justification(sheet, col);
7247  attributes->border.width = 0;
7248  attributes->border.line_style = GDK_LINE_SOLID;
7249  attributes->border.cap_style = GDK_CAP_NOT_LAST;
7250  attributes->border.join_style = GDK_JOIN_MITER;
7251  attributes->border.mask = 0;
7252  attributes->border.color = GTK_WIDGET(sheet)->style->black;
7253  attributes->is_editable = TRUE;
7254  attributes->is_visible = TRUE;
7255  attributes->font_desc = GTK_WIDGET(sheet)->style->font_desc;
7256
7257 }       
7258  
7259
7260
7261 /********************************************************************
7262  * Container Functions:
7263  * gtk_sheet_add
7264  * gtk_sheet_put
7265  * gtk_sheet_attach
7266  * gtk_sheet_remove
7267  * gtk_sheet_move_child
7268  * gtk_sheet_position_child
7269  * gtk_sheet_position_children 
7270  * gtk_sheet_realize_child
7271  * gtk_sheet_get_child_at
7272  ********************************************************************/ 
7273
7274 GtkSheetChild *
7275 gtk_sheet_put(GtkSheet *sheet, GtkWidget *child, gint x, gint y)
7276 {
7277   GtkRequisition child_requisition;
7278   GtkSheetChild *child_info;
7279
7280   g_return_val_if_fail(sheet != NULL, NULL);
7281   g_return_val_if_fail(GTK_IS_SHEET(sheet), NULL);
7282   g_return_val_if_fail(child != NULL, NULL);
7283   g_return_val_if_fail(child->parent == NULL, NULL);
7284
7285   child_info = g_new (GtkSheetChild, 1);
7286   child_info->widget = child;
7287   child_info->x = x;  
7288   child_info->y = y;
7289   child_info->attached_to_cell = FALSE;
7290   child_info->floating = TRUE;
7291   child_info->xpadding = child_info->ypadding = 0;
7292   child_info->xexpand = child_info->yexpand = FALSE;
7293   child_info->xshrink = child_info->yshrink = FALSE;
7294   child_info->xfill = child_info->yfill = FALSE;
7295
7296   sheet->children = g_list_append(sheet->children, child_info);
7297
7298   gtk_widget_set_parent (child, GTK_WIDGET(sheet));
7299
7300   gtk_widget_size_request(child, &child_requisition);
7301
7302   if (GTK_WIDGET_VISIBLE(GTK_WIDGET(sheet)))
7303     {
7304        if(GTK_WIDGET_REALIZED(GTK_WIDGET(sheet)) && 
7305           (!GTK_WIDGET_REALIZED(child) || GTK_WIDGET_NO_WINDOW(child)))
7306         gtk_sheet_realize_child(sheet, child_info);
7307
7308        if(GTK_WIDGET_MAPPED(GTK_WIDGET(sheet)) && 
7309           !GTK_WIDGET_MAPPED(child))
7310         gtk_widget_map(child);
7311     }
7312
7313   gtk_sheet_position_child(sheet, child_info);
7314
7315 /* This will avoid drawing on the titles */
7316
7317   if(GTK_WIDGET_REALIZED(GTK_WIDGET(sheet)))
7318    {
7319       if(sheet->row_titles_visible)
7320              gdk_window_show(sheet->row_title_window);
7321       if(sheet->column_titles_visible)
7322              gdk_window_show(sheet->column_title_window);
7323    }
7324
7325   return (child_info);
7326 }
7327
7328 void
7329 gtk_sheet_attach_floating       (GtkSheet *sheet,
7330                                  GtkWidget *widget,
7331                                  gint row, gint col)
7332 {
7333   GdkRectangle area;
7334   GtkSheetChild *child;
7335
7336   if(row < 0 || col < 0){
7337     gtk_sheet_button_attach(sheet, widget, row, col);
7338     return;
7339   }
7340
7341   gtk_sheet_get_cell_area(sheet, row, col, &area);
7342   child = gtk_sheet_put(sheet, widget, area.x, area.y);
7343   child->attached_to_cell = TRUE;
7344   child->row = row;
7345   child->col = col;
7346 }
7347
7348 void
7349 gtk_sheet_attach_default        (GtkSheet *sheet,
7350                                  GtkWidget *widget,
7351                                  gint row, gint col)
7352 {
7353   if(row < 0 || col < 0){
7354     gtk_sheet_button_attach(sheet, widget, row, col);
7355     return;
7356   }
7357
7358   gtk_sheet_attach(sheet, widget, row, col, GTK_EXPAND|GTK_FILL, GTK_EXPAND|GTK_FILL, 0, 0);
7359 }
7360
7361 void
7362 gtk_sheet_attach        (GtkSheet *sheet,
7363                          GtkWidget *widget,
7364                          gint row, gint col,
7365                          gint xoptions,
7366                          gint yoptions,
7367                          gint xpadding,
7368                          gint ypadding)
7369 {
7370   GdkRectangle area;
7371   GtkSheetChild *child = NULL;
7372
7373   if(row < 0 || col < 0){
7374     gtk_sheet_button_attach(sheet, widget, row, col);
7375     return;
7376   }
7377
7378   child = g_new0(GtkSheetChild, 1);
7379   child->attached_to_cell = TRUE;
7380   child->floating = FALSE;
7381   child->widget = widget;
7382   child->row = row;
7383   child->col = col;
7384   child->xpadding = xpadding;
7385   child->ypadding = ypadding;
7386   child->xexpand = (xoptions & GTK_EXPAND) != 0;
7387   child->yexpand = (yoptions & GTK_EXPAND) != 0;
7388   child->xshrink = (xoptions & GTK_SHRINK) != 0;
7389   child->yshrink = (yoptions & GTK_SHRINK) != 0;
7390   child->xfill = (xoptions & GTK_FILL) != 0;
7391   child->yfill = (yoptions & GTK_FILL) != 0;
7392
7393   sheet->children = g_list_append(sheet->children, child);
7394
7395   gtk_sheet_get_cell_area(sheet, row, col, &area);
7396
7397   child->x = area.x + child->xpadding;
7398   child->y = area.y + child->ypadding;
7399
7400   if (GTK_WIDGET_VISIBLE(GTK_WIDGET(sheet)))
7401     {
7402        if(GTK_WIDGET_REALIZED(GTK_WIDGET(sheet)) &&
7403           (!GTK_WIDGET_REALIZED(widget) || GTK_WIDGET_NO_WINDOW(widget)))
7404         gtk_sheet_realize_child(sheet, child);
7405
7406        if(GTK_WIDGET_MAPPED(GTK_WIDGET(sheet)) &&
7407           !GTK_WIDGET_MAPPED(widget))
7408         gtk_widget_map(widget);
7409     }
7410
7411   gtk_sheet_position_child(sheet, child);
7412
7413 /* This will avoid drawing on the titles */
7414
7415   if(GTK_WIDGET_REALIZED(GTK_WIDGET(sheet)))
7416    {
7417       if(GTK_SHEET_ROW_TITLES_VISIBLE(sheet))
7418              gdk_window_show(sheet->row_title_window);
7419       if(GTK_SHEET_COL_TITLES_VISIBLE(sheet))
7420              gdk_window_show(sheet->column_title_window);
7421    }
7422
7423 }
7424
7425 void
7426 gtk_sheet_button_attach         (GtkSheet *sheet, 
7427                                  GtkWidget *widget, 
7428                                  gint row, gint col)
7429 {
7430   GtkSheetButton *button = 0;
7431   GtkSheetChild *child;
7432   GtkRequisition button_requisition;
7433
7434   if(row >= 0 && col >= 0) return;
7435   if(row < 0 && col < 0) return;
7436
7437   child = g_new (GtkSheetChild, 1);
7438   child->widget = widget;
7439   child->x = 0;  
7440   child->y = 0;  
7441   child->attached_to_cell = TRUE;
7442   child->floating = FALSE;
7443   child->row = row;
7444   child->col = col;
7445   child->xpadding = child->ypadding = 0;
7446   child->xshrink = child->yshrink = FALSE;
7447   child->xfill = child->yfill = FALSE;
7448
7449
7450   sheet->children = g_list_append(sheet->children, child);
7451
7452   gtk_sheet_button_size_request(sheet, button, &button_requisition);
7453
7454
7455   if (GTK_WIDGET_VISIBLE(GTK_WIDGET(sheet)))
7456     {
7457        if(GTK_WIDGET_REALIZED(GTK_WIDGET(sheet)) && 
7458           (!GTK_WIDGET_REALIZED(widget) || GTK_WIDGET_NO_WINDOW(widget)))
7459         gtk_sheet_realize_child(sheet, child);
7460
7461        if(GTK_WIDGET_MAPPED(GTK_WIDGET(sheet)) && 
7462           !GTK_WIDGET_MAPPED(widget))
7463         gtk_widget_map(widget);
7464     }
7465
7466   if(row == -1) size_allocate_column_title_buttons(sheet);
7467   if(col == -1) size_allocate_row_title_buttons(sheet);
7468
7469 }
7470
7471 static void
7472 label_size_request(GtkSheet *sheet, gchar *label, GtkRequisition *req)
7473 {
7474   gchar *words;
7475   gchar word[1000];
7476   gint n = 0;
7477   gint row_height = DEFAULT_ROW_HEIGHT(GTK_WIDGET(sheet)) - 2*CELLOFFSET + 2;
7478
7479   req->height = 0;
7480   req->width = 0;
7481   words=label;
7482
7483   while(words && *words != '\0'){
7484     if(*words == '\n' || *(words+1) == '\0'){
7485       req->height += row_height;
7486
7487       word[n] = '\0';
7488       req->width = MAX(req->width, STRING_WIDTH(GTK_WIDGET(sheet), GTK_WIDGET(sheet)->style->font_desc, word));
7489       n = 0;
7490     } else {
7491       word[n++] = *words;
7492     }
7493     words++;
7494   }
7495  
7496   if(n > 0) req->height -= 2;
7497 }
7498
7499 static void
7500 gtk_sheet_button_size_request   (GtkSheet *sheet,
7501                                  const GtkSheetButton *button, 
7502                                  GtkRequisition *button_requisition)
7503 {
7504   GtkRequisition requisition;
7505   GtkRequisition label_requisition;
7506
7507   if(gtk_sheet_autoresize(sheet) && button->label && strlen(button->label) > 0){
7508      label_size_request(sheet, button->label, &label_requisition);
7509      label_requisition.width += 2*CELLOFFSET;
7510      label_requisition.height += 2*CELLOFFSET;
7511   } else {
7512      label_requisition.height = DEFAULT_ROW_HEIGHT(GTK_WIDGET(sheet));
7513      label_requisition.width = COLUMN_MIN_WIDTH;
7514   } 
7515
7516   if(button->child)
7517   {
7518      gtk_widget_size_request(button->child->widget, &requisition);
7519      requisition.width += 2*button->child->xpadding;
7520      requisition.height += 2*button->child->ypadding;
7521      requisition.width += 2*sheet->button->style->xthickness;
7522      requisition.height += 2*sheet->button->style->ythickness;
7523   }
7524   else
7525   {
7526      requisition.height = DEFAULT_ROW_HEIGHT(GTK_WIDGET(sheet));
7527      requisition.width = COLUMN_MIN_WIDTH;
7528   }
7529
7530   *button_requisition = requisition;
7531   button_requisition->width = MAX(requisition.width, label_requisition.width);
7532   button_requisition->height = MAX(requisition.height, label_requisition.height);
7533  
7534 }
7535
7536 static void
7537 gtk_sheet_row_size_request      (GtkSheet *sheet,
7538                                  gint row,
7539                                  guint *requisition)
7540 {
7541   GtkRequisition button_requisition;
7542   GList *children;
7543
7544   gtk_sheet_button_size_request(sheet, 
7545                                 yyy_row_button(sheet, row),
7546                                 &button_requisition);
7547
7548   *requisition = button_requisition.height;
7549
7550   children = sheet->children;
7551   while(children){
7552     GtkSheetChild *child = (GtkSheetChild *)children->data;
7553     GtkRequisition child_requisition;
7554
7555     if(child->attached_to_cell && child->row == row && child->col != -1 && !child->floating && !child->yshrink){
7556       gtk_widget_get_child_requisition(child->widget, &child_requisition);
7557
7558       if(child_requisition.height + 2 * child->ypadding > *requisition)
7559         *requisition = child_requisition.height + 2 * child->ypadding;
7560     }
7561     children = children->next;
7562   }
7563
7564   sheet->row_requisition = * requisition;
7565 }
7566
7567 static void
7568 gtk_sheet_column_size_request   (GtkSheet *sheet,
7569                                  gint col,
7570                                  guint *requisition)
7571 {
7572   GtkRequisition button_requisition;
7573   GList *children;
7574
7575   gtk_sheet_button_size_request(sheet, 
7576                                 xxx_column_button(sheet, col),
7577                                 &button_requisition);
7578
7579   *requisition = button_requisition.width;
7580
7581   children = sheet->children;
7582   while(children){
7583     GtkSheetChild *child = (GtkSheetChild *)children->data;
7584     GtkRequisition child_requisition;
7585
7586     if(child->attached_to_cell && child->col == col && child->row != -1 && !child->floating && !child->xshrink){
7587       gtk_widget_get_child_requisition(child->widget, &child_requisition);
7588
7589       if(child_requisition.width + 2 * child->xpadding > *requisition)
7590         *requisition = child_requisition.width + 2 * child->xpadding;
7591     }
7592     children = children->next;
7593   }
7594
7595   sheet->column_requisition = *requisition;
7596 }
7597
7598 void
7599 gtk_sheet_move_child(GtkSheet *sheet, GtkWidget *widget, gint x, gint y)
7600 {
7601   GtkSheetChild *child;
7602   GList *children;
7603
7604   g_return_if_fail(sheet != NULL);
7605   g_return_if_fail(GTK_IS_SHEET(sheet));
7606
7607   children = sheet->children;
7608   while(children)
7609     {
7610        child = children->data;
7611
7612        if(child->widget == widget){
7613          child->x = x;
7614          child->y = y;
7615          child->row = ROW_FROM_YPIXEL(sheet, y);
7616          child->col = COLUMN_FROM_XPIXEL(sheet, x);
7617          gtk_sheet_position_child(sheet, child);
7618          return;
7619        }
7620
7621        children = children->next;
7622     }
7623
7624   g_warning("Widget must be a GtkSheet child"); 
7625
7626 }
7627
7628 static void
7629 gtk_sheet_position_child(GtkSheet *sheet, GtkSheetChild *child)
7630 {
7631    GtkRequisition child_requisition;
7632    GtkAllocation child_allocation;
7633    gint xoffset = 0; 
7634    gint yoffset = 0;
7635    gint x = 0, y = 0;
7636    GdkRectangle area;
7637
7638    gtk_widget_get_child_requisition(child->widget, &child_requisition);
7639
7640    if(sheet->column_titles_visible) 
7641              yoffset = sheet->column_title_area.height;
7642
7643    if(sheet->row_titles_visible)
7644              xoffset = sheet->row_title_area.width;
7645
7646    if(child->attached_to_cell){
7647 /*
7648       child->x = COLUMN_LEFT_XPIXEL(sheet, child->col);
7649       child->y = ROW_TOP_YPIXEL(sheet, child->row);
7650
7651       if(sheet->row_titles_visible) 
7652                                     child->x-=sheet->row_title_area.width;
7653       if(sheet->column_titles_visible) 
7654                                     child->y-=sheet->column_title_area.height;
7655
7656       width = xxx_column_width(sheet, child->col);
7657       height = yyy_row_height(sheet, child->row);
7658 */
7659       
7660       gtk_sheet_get_cell_area(sheet, child->row, child->col, &area);
7661       child->x = area.x + child->xpadding;
7662       child->y = area.y + child->ypadding;
7663
7664       if(!child->floating){
7665         if(child_requisition.width + 2*child->xpadding <= xxx_column_width(sheet, child->col)){
7666           if(child->xfill){
7667             child_requisition.width = child_allocation.width = xxx_column_width(sheet, child->col) - 2*child->xpadding;
7668           } else {
7669             if(child->xexpand){
7670               child->x = area.x + xxx_column_width(sheet, child->col) / 2 -
7671                                   child_requisition.width / 2;
7672             }
7673             child_allocation.width = child_requisition.width;
7674           }
7675         } else {
7676           if(!child->xshrink){
7677             gtk_sheet_set_column_width(sheet, child->col, child_requisition.width + 2 * child->xpadding);
7678           }
7679           child_allocation.width = xxx_column_width(sheet, child->col) - 2*child->xpadding;
7680         }
7681
7682         if(child_requisition.height + 2*child->ypadding <= yyy_row_height(sheet, child->row)){
7683           if(child->yfill){
7684             child_requisition.height = child_allocation.height = yyy_row_height(sheet, child->row) - 2*child->ypadding;
7685           } else {
7686             if(child->yexpand){
7687               child->y = area.y + yyy_row_height(sheet, child->row) / 2 -
7688                                   child_requisition.height / 2;
7689             }
7690             child_allocation.height = child_requisition.height;
7691           }
7692         } else {
7693           if(!child->yshrink){
7694             gtk_sheet_set_row_height(sheet, child->row, child_requisition.height + 2 * child->ypadding);
7695           }
7696           child_allocation.height = yyy_row_height(sheet, child->row) - 2*child->ypadding;
7697         }
7698       } else {
7699         child_allocation.width = child_requisition.width;
7700         child_allocation.height = child_requisition.height;
7701       }
7702
7703       x = child_allocation.x = child->x + xoffset;
7704       y = child_allocation.y = child->y + yoffset;
7705    }
7706    else
7707    {
7708       x = child_allocation.x = child->x + sheet->hoffset + xoffset;   
7709       x = child_allocation.x = child->x + xoffset;   
7710       y = child_allocation.y = child->y + sheet->voffset + yoffset;
7711       y = child_allocation.y = child->y + yoffset;
7712       child_allocation.width = child_requisition.width;
7713       child_allocation.height = child_requisition.height;
7714    }
7715
7716    gtk_widget_size_allocate(child->widget, &child_allocation);
7717    gtk_widget_queue_draw(child->widget);
7718 }
7719
7720 static void
7721 gtk_sheet_forall (GtkContainer *container,
7722                   gboolean      include_internals,
7723                   GtkCallback   callback,
7724                   gpointer      callback_data)
7725 {
7726   GtkSheet *sheet;
7727   GtkSheetChild *child;
7728   GList *children;
7729
7730   g_return_if_fail (GTK_IS_SHEET (container));
7731   g_return_if_fail (callback != NULL);
7732
7733   sheet = GTK_SHEET (container);
7734   children = sheet->children;
7735   while (children)
7736     {
7737       child = children->data;
7738       children = children->next;
7739
7740       (* callback) (child->widget, callback_data);
7741     }
7742   if(sheet->button)
7743      (* callback) (sheet->button, callback_data);
7744   if(sheet->sheet_entry)
7745      (* callback) (sheet->sheet_entry, callback_data);
7746 }
7747
7748
7749 static void
7750 gtk_sheet_position_children(GtkSheet *sheet)
7751 {
7752   GList *children;
7753   GtkSheetChild *child;
7754
7755   children = sheet->children;
7756
7757   while(children)
7758    {
7759      child = (GtkSheetChild *)children->data;
7760
7761      if(child->col !=-1 && child->row != -1)
7762            gtk_sheet_position_child(sheet, child);
7763
7764      if(child->row == -1){
7765         if(child->col < MIN_VISIBLE_COLUMN(sheet) || 
7766            child->col > MAX_VISIBLE_COLUMN(sheet))
7767               gtk_sheet_child_hide(child);
7768         else
7769               gtk_sheet_child_show(child);
7770      }
7771      if(child->col == -1){
7772         if(child->row < MIN_VISIBLE_ROW(sheet) ||
7773            child->row > MAX_VISIBLE_ROW(sheet))
7774               gtk_sheet_child_hide(child);
7775         else
7776               gtk_sheet_child_show(child);
7777      }
7778  
7779      children = children->next;
7780    }
7781     
7782 }
7783
7784 static void
7785 gtk_sheet_remove (GtkContainer *container, GtkWidget *widget)
7786 {
7787   GtkSheet *sheet;
7788   GList *children;
7789   GtkSheetChild *child = 0;
7790
7791   g_return_if_fail(container != NULL);
7792   g_return_if_fail(GTK_IS_SHEET(container));
7793
7794   sheet = GTK_SHEET(container);
7795
7796   children = sheet->children;
7797
7798   while(children)
7799    {
7800      child = (GtkSheetChild *)children->data;
7801
7802      if(child->widget == widget) break;
7803
7804      children = children->next;
7805    }
7806
7807   if (children)
7808    {
7809      gtk_widget_unparent (widget);
7810      child->widget = NULL;
7811
7812      sheet->children = g_list_remove_link (sheet->children, children);
7813      g_list_free_1 (children);
7814      g_free(child);
7815    }
7816
7817 }
7818
7819 static void
7820 gtk_sheet_realize_child(GtkSheet *sheet, GtkSheetChild *child)
7821 {
7822   GtkWidget *widget;
7823
7824   widget = GTK_WIDGET(sheet);
7825
7826   if(GTK_WIDGET_REALIZED(widget)){
7827     if(child->row == -1)
7828       gtk_widget_set_parent_window(child->widget, sheet->column_title_window);
7829     else if(child->col == -1)
7830       gtk_widget_set_parent_window(child->widget, sheet->row_title_window);
7831     else
7832       gtk_widget_set_parent_window(child->widget, sheet->sheet_window);
7833   }
7834
7835   gtk_widget_set_parent(child->widget, widget);
7836 }
7837
7838
7839    
7840 GtkSheetChild *
7841 gtk_sheet_get_child_at(GtkSheet *sheet, gint row, gint col)
7842 {
7843   GList *children;
7844   GtkSheetChild *child = 0;
7845
7846   g_return_val_if_fail(sheet != NULL, NULL);
7847   g_return_val_if_fail(GTK_IS_SHEET(sheet), NULL);
7848
7849   children = sheet->children;
7850
7851   while(children)
7852    {
7853      child = (GtkSheetChild *)children->data;
7854
7855      if(child->attached_to_cell)
7856         if(child->row == row && child->col == col) break; 
7857      
7858      children = children->next;
7859    }
7860
7861   if(children) return child; 
7862
7863   return NULL;
7864 }
7865
7866 static void
7867 gtk_sheet_child_hide(GtkSheetChild *child) 
7868 {
7869   g_return_if_fail(child != NULL);
7870   gtk_widget_hide(child->widget);
7871 }
7872
7873 static void
7874 gtk_sheet_child_show(GtkSheetChild *child) 
7875 {
7876   g_return_if_fail(child != NULL);
7877
7878   gtk_widget_show(child->widget);
7879 }
7880
7881 GSheetModel *
7882 gtk_sheet_get_model(const GtkSheet *sheet)
7883 {
7884   g_return_val_if_fail (GTK_IS_SHEET (sheet), NULL);
7885
7886   return sheet->model;
7887 }
7888