ff7ab3b0d2413994556c311fd3b0d9a7f6861a3f
[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 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 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       GtkSheetButton *button = xxx_column_button(sheet, col);
1811       GtkSheetChild *child = button->child;
1812       if(child)
1813         gtk_sheet_child_show(child);
1814       gtk_sheet_button_free(button);
1815     }
1816   adjust_scrollbars(sheet);
1817  } 
1818
1819  sheet->old_vadjustment = -1.;
1820  if(sheet->vadjustment)
1821      gtk_signal_emit_by_name (GTK_OBJECT (sheet->vadjustment), 
1822                               "value_changed");
1823  size_allocate_global_button(sheet);
1824 }
1825
1826
1827 void
1828 gtk_sheet_show_row_titles(GtkSheet *sheet)
1829 {
1830  gint row;
1831
1832  if(sheet->row_titles_visible) return;
1833
1834  sheet->row_titles_visible = TRUE;
1835
1836
1837  if(GTK_WIDGET_REALIZED(GTK_WIDGET(sheet))){
1838   gdk_window_show(sheet->row_title_window);
1839   gdk_window_move_resize (sheet->row_title_window,
1840                           sheet->row_title_area.x,
1841                           sheet->row_title_area.y,
1842                           sheet->row_title_area.width,
1843                           sheet->row_title_area.height);
1844
1845   for(row = MIN_VISIBLE_ROW(sheet); 
1846       row <= MAX_VISIBLE_ROW(sheet); 
1847       row++)
1848     {
1849       const GtkSheetButton *button = yyy_row_button(sheet, row);
1850       GtkSheetChild *child = button->child;
1851
1852       if(child){
1853         gtk_sheet_child_show(child);
1854       }
1855   }
1856   adjust_scrollbars(sheet);
1857  }
1858
1859  sheet->old_hadjustment = -1.;
1860  if(sheet->hadjustment)
1861      gtk_signal_emit_by_name (GTK_OBJECT (sheet->hadjustment), 
1862                               "value_changed");
1863  size_allocate_global_button(sheet);
1864 }
1865
1866 void
1867 gtk_sheet_hide_column_titles(GtkSheet *sheet)
1868 {
1869  gint col;
1870
1871  if(!sheet->column_titles_visible) return;
1872
1873  sheet->column_titles_visible = FALSE;
1874
1875  if(GTK_WIDGET_REALIZED(GTK_WIDGET(sheet))){
1876   if(sheet->column_title_window) 
1877     gdk_window_hide(sheet->column_title_window);
1878   if(GTK_WIDGET_VISIBLE(sheet->button)) 
1879     gtk_widget_hide(sheet->button);
1880
1881   for(col = MIN_VISIBLE_COLUMN(sheet); 
1882       col <= MAX_VISIBLE_COLUMN(sheet); 
1883       col++)
1884     {
1885       GtkSheetButton *button = xxx_column_button(sheet, col);
1886       GtkSheetChild *child = button->child;
1887       if(child)
1888         gtk_sheet_child_hide(child);
1889       gtk_sheet_button_free(button);
1890   }
1891   adjust_scrollbars(sheet);
1892  }
1893  
1894  sheet->old_vadjustment = -1.;
1895  if(sheet->vadjustment)
1896      gtk_signal_emit_by_name (GTK_OBJECT (sheet->vadjustment), 
1897                               "value_changed");
1898 }
1899
1900 void
1901 gtk_sheet_hide_row_titles(GtkSheet *sheet)
1902 {
1903  gint row;
1904
1905  if(!sheet->row_titles_visible) return;
1906
1907  sheet->row_titles_visible = FALSE;
1908
1909
1910  if(GTK_WIDGET_REALIZED(GTK_WIDGET(sheet))){
1911   if(sheet->row_title_window) 
1912     gdk_window_hide(sheet->row_title_window);
1913   if(GTK_WIDGET_VISIBLE(sheet->button)) 
1914     gtk_widget_hide(sheet->button);
1915   for(row = MIN_VISIBLE_ROW(sheet); 
1916       row <= MAX_VISIBLE_ROW(sheet); 
1917       row++)
1918     {
1919       const GtkSheetButton *button = yyy_row_button(sheet, row);
1920       GtkSheetChild *child = button->child;
1921
1922       if(child)
1923         gtk_sheet_child_hide(child);
1924     }
1925   adjust_scrollbars(sheet);
1926  }
1927
1928  sheet->old_hadjustment = -1.;
1929  if(sheet->hadjustment)
1930      gtk_signal_emit_by_name (GTK_OBJECT (sheet->hadjustment), 
1931                               "value_changed");
1932 }
1933
1934 gboolean
1935 gtk_sheet_column_titles_visible(GtkSheet *sheet)
1936 {
1937   g_return_val_if_fail (sheet != NULL, FALSE);
1938   g_return_val_if_fail (GTK_IS_SHEET (sheet), FALSE);
1939   return sheet->column_titles_visible;
1940 }
1941
1942 gboolean
1943 gtk_sheet_row_titles_visible(GtkSheet *sheet)
1944 {
1945   g_return_val_if_fail (sheet != NULL, FALSE);
1946   g_return_val_if_fail (GTK_IS_SHEET (sheet), FALSE);
1947   return sheet->row_titles_visible;
1948 }
1949
1950
1951
1952 void
1953 gtk_sheet_moveto (GtkSheet * sheet,
1954                   gint row,
1955                   gint column,
1956                   gfloat row_align,
1957                   gfloat col_align)
1958 {
1959   gint x, y;
1960   guint width, height;
1961   gint adjust;
1962   gint min_row, min_col;
1963
1964   g_return_if_fail (sheet != NULL);
1965   g_return_if_fail (GTK_IS_SHEET (sheet));
1966   g_return_if_fail (sheet->hadjustment != NULL);
1967   g_return_if_fail (sheet->vadjustment != NULL);
1968
1969   if (row < 0 || row >= yyy_row_count(sheet))
1970     return;
1971   if (column < 0 || column >= xxx_column_count(sheet))
1972     return;
1973
1974   height = sheet->sheet_window_height;
1975   width = sheet->sheet_window_width;
1976
1977   /* adjust vertical scrollbar */
1978
1979   if (row >= 0 && row_align >=0.)
1980     {
1981 /*
1982       y = ROW_TOP_YPIXEL(sheet, row) - sheet->voffset -
1983           row_align*height-
1984           (1.-row_align)*yyy_row_height(sheet, row);
1985 */
1986       y = ROW_TOP_YPIXEL (sheet, row) - sheet->voffset
1987         - (gint) ( row_align*height + (1. - row_align) * yyy_row_height(sheet, row));
1988
1989       /* This forces the sheet to scroll when you don't see the entire cell */
1990       min_row = row;
1991       adjust = 0;
1992       if(row_align == 1.){
1993         while(min_row >= 0 && min_row > MIN_VISIBLE_ROW(sheet)){
1994          if(yyy_row_is_visible(sheet, min_row))
1995                 adjust += yyy_row_height(sheet, min_row);
1996          if(adjust >= height){
1997            break;
1998          }
1999          min_row--;
2000         }
2001         min_row = MAX(min_row, 0);
2002         y = ROW_TOP_YPIXEL(sheet, min_row) - sheet->voffset +
2003             yyy_row_height(sheet, min_row) - 1;
2004       }
2005
2006       if (y < 0)
2007         sheet->vadjustment->value = 0.0;
2008       else
2009         sheet->vadjustment->value = y;
2010
2011       sheet->old_vadjustment = -1.;
2012       gtk_signal_emit_by_name (GTK_OBJECT (sheet->vadjustment), 
2013                                "value_changed");
2014
2015     } 
2016      
2017   /* adjust horizontal scrollbar */
2018   if (column >= 0 && col_align >= 0.)
2019     {
2020 /*
2021       x = COLUMN_LEFT_XPIXEL (sheet, column) - sheet->hoffset -
2022           col_align*width -
2023           (1.-col_align)*sheet->column[column].width;
2024 */
2025       x = COLUMN_LEFT_XPIXEL (sheet, column) - sheet->hoffset
2026         - (gint) ( col_align*width + (1.-col_align)*
2027                    xxx_column_width(sheet, column));
2028
2029
2030       /* This forces the sheet to scroll when you don't see the entire cell */
2031       min_col = column;
2032       adjust = 0;
2033       if(col_align == 1.){
2034         while(min_col >= 0 && min_col > MIN_VISIBLE_COLUMN(sheet)){
2035           if(xxx_column_is_visible(sheet, min_col))
2036            adjust += xxx_column_width(sheet, min_col);
2037          
2038          if(adjust >= width){
2039            break;
2040          }
2041          min_col--;
2042         }
2043         min_col = MAX(min_col, 0);
2044         x = COLUMN_LEFT_XPIXEL(sheet, min_col) - sheet->hoffset +
2045           xxx_column_width(sheet, min_col) - 1;
2046       }
2047
2048       if (x < 0)
2049         sheet->hadjustment->value = 0.0;
2050       else
2051         sheet->hadjustment->value = x;
2052
2053       sheet->old_vadjustment = -1.;
2054       gtk_signal_emit_by_name (GTK_OBJECT (sheet->hadjustment), 
2055                                "value_changed");
2056
2057     }
2058 }
2059
2060
2061 void
2062 gtk_sheet_columns_set_resizable (GtkSheet *sheet, gboolean resizable)
2063 {
2064   g_return_if_fail (sheet != NULL);
2065   g_return_if_fail (GTK_IS_SHEET (sheet));
2066
2067   sheet->columns_resizable = resizable;
2068 }
2069
2070 gboolean
2071 gtk_sheet_columns_resizable (GtkSheet *sheet)
2072 {
2073   g_return_val_if_fail (sheet != NULL, FALSE);
2074   g_return_val_if_fail (GTK_IS_SHEET (sheet), FALSE);
2075
2076   return sheet->columns_resizable;
2077 }
2078
2079
2080 void
2081 gtk_sheet_rows_set_resizable (GtkSheet *sheet, gboolean resizable)
2082 {
2083   g_return_if_fail (sheet != NULL);
2084   g_return_if_fail (GTK_IS_SHEET (sheet));
2085
2086   sheet->rows_resizable = resizable;
2087 }
2088
2089 gboolean
2090 gtk_sheet_rows_resizable (GtkSheet *sheet)
2091 {
2092   g_return_val_if_fail (sheet != NULL, FALSE);
2093   g_return_val_if_fail (GTK_IS_SHEET (sheet), FALSE);
2094
2095   return sheet->rows_resizable;
2096 }
2097
2098
2099 void
2100 gtk_sheet_select_row (GtkSheet * sheet,
2101                       gint row)
2102 {
2103   g_return_if_fail (sheet != NULL);
2104   g_return_if_fail (GTK_IS_SHEET (sheet));
2105
2106   if (row < 0 || row >= yyy_row_count(sheet))
2107     return;
2108
2109   if(sheet->state != GTK_SHEET_NORMAL) 
2110      gtk_sheet_real_unselect_range(sheet, NULL);
2111   else
2112   {
2113      gboolean veto = TRUE;
2114      veto = gtk_sheet_deactivate_cell(sheet);
2115      if(!veto) return;
2116   }
2117
2118   sheet->state=GTK_SHEET_ROW_SELECTED;                     
2119   sheet->range.row0=row;
2120   sheet->range.col0=0;
2121   sheet->range.rowi=row;
2122   sheet->range.coli = xxx_column_count(sheet) - 1;
2123   sheet->active_cell.row=row;
2124   sheet->active_cell.col=0;
2125
2126   gtk_signal_emit (GTK_OBJECT (sheet), sheet_signals[SELECT_ROW], row);
2127   gtk_sheet_real_select_range(sheet, NULL);
2128
2129 }
2130
2131
2132 void
2133 gtk_sheet_select_column (GtkSheet * sheet,
2134                          gint column)
2135 {
2136   
2137   g_return_if_fail (sheet != NULL);
2138   g_return_if_fail (GTK_IS_SHEET (sheet));
2139
2140   if (column < 0 || column >= xxx_column_count(sheet))
2141     return;
2142
2143   if(sheet->state != GTK_SHEET_NORMAL) 
2144      gtk_sheet_real_unselect_range(sheet, NULL);
2145   else
2146   {
2147      gboolean veto = TRUE;
2148      veto = gtk_sheet_deactivate_cell(sheet);
2149      if(!veto) return;
2150   }
2151
2152   sheet->state=GTK_SHEET_COLUMN_SELECTED;                     
2153   sheet->range.row0=0;
2154   sheet->range.col0=column;
2155   sheet->range.rowi= yyy_row_count(sheet) - 1;
2156   sheet->range.coli=column;
2157   sheet->active_cell.row=0;
2158   sheet->active_cell.col=column;
2159
2160   gtk_signal_emit (GTK_OBJECT (sheet), sheet_signals[SELECT_COLUMN], column);
2161   gtk_sheet_real_select_range(sheet, NULL);
2162
2163 }
2164
2165 void
2166 gtk_sheet_clip_range (GtkSheet *sheet, const GtkSheetRange *range)
2167 {
2168
2169   g_return_if_fail (sheet != NULL);
2170   g_return_if_fail (GTK_IS_SHEET (sheet));
2171
2172   if(GTK_SHEET_IN_CLIP(sheet)) return;
2173
2174   GTK_SHEET_SET_FLAGS(sheet, GTK_SHEET_IN_CLIP);
2175
2176   if(range == NULL)
2177     sheet->clip_range = sheet->range;
2178   else
2179     sheet->clip_range=*range;
2180
2181   sheet->interval=0;
2182   sheet->clip_timer=gtk_timeout_add(TIMEOUT_FLASH, gtk_sheet_flash, sheet); 
2183
2184   gtk_signal_emit(GTK_OBJECT(sheet), sheet_signals[CLIP_RANGE],
2185                                      &sheet->clip_range);
2186
2187 }
2188
2189 void
2190 gtk_sheet_unclip_range(GtkSheet *sheet)
2191 {
2192
2193   g_return_if_fail (sheet != NULL);
2194   g_return_if_fail (GTK_IS_SHEET (sheet));
2195
2196   if(!GTK_SHEET_IN_CLIP(sheet)) return;
2197
2198   GTK_SHEET_UNSET_FLAGS(sheet, GTK_SHEET_IN_CLIP);
2199   gtk_timeout_remove(sheet->clip_timer);
2200   gtk_sheet_range_draw(sheet, &sheet->clip_range);
2201
2202   if(gtk_sheet_range_isvisible(sheet, sheet->range))
2203     gtk_sheet_range_draw(sheet, &sheet->range);
2204 }
2205
2206 gboolean
2207 gtk_sheet_in_clip (GtkSheet *sheet)
2208 {
2209   g_return_val_if_fail (sheet != NULL, FALSE);
2210   g_return_val_if_fail (GTK_IS_SHEET (sheet), FALSE);
2211
2212   return GTK_SHEET_IN_CLIP(sheet);
2213 }
2214
2215 static gint
2216 gtk_sheet_flash(gpointer data)
2217 {
2218   GtkSheet *sheet;
2219   gint x,y,width,height;
2220   GdkRectangle clip_area;
2221
2222   sheet=GTK_SHEET(data);
2223
2224   if(!GTK_WIDGET_REALIZED(GTK_WIDGET(sheet))) return TRUE;
2225   if(!GTK_WIDGET_DRAWABLE(GTK_WIDGET(sheet))) return TRUE;
2226   if(!gtk_sheet_range_isvisible(sheet, sheet->clip_range)) return TRUE;
2227   if(GTK_SHEET_IN_XDRAG(sheet)) return TRUE; 
2228   if(GTK_SHEET_IN_YDRAG(sheet)) return TRUE; 
2229
2230   GDK_THREADS_ENTER();
2231  
2232   x=COLUMN_LEFT_XPIXEL(sheet,sheet->clip_range.col0)+1;
2233   y=ROW_TOP_YPIXEL(sheet,sheet->clip_range.row0)+1;
2234   width=COLUMN_LEFT_XPIXEL(sheet,sheet->clip_range.coli)-x+ 
2235     xxx_column_width(sheet, sheet->clip_range.coli) - 1;
2236   height=ROW_TOP_YPIXEL(sheet,sheet->clip_range.rowi)-y+
2237     yyy_row_height(sheet, sheet->clip_range.rowi)-1;
2238
2239   clip_area.x=COLUMN_LEFT_XPIXEL(sheet, MIN_VISIBLE_COLUMN(sheet));
2240   clip_area.y=ROW_TOP_YPIXEL(sheet, MIN_VISIBLE_ROW(sheet));
2241   clip_area.width=sheet->sheet_window_width;
2242   clip_area.height=sheet->sheet_window_height;
2243
2244   if(x<0) {
2245      width=width+x+1;
2246      x=-1;
2247   }
2248   if(width>clip_area.width) width=clip_area.width+10;
2249   if(y<0) {
2250      height=height+y+1;
2251      y=-1;
2252   }
2253   if(height>clip_area.height) height=clip_area.height+10;
2254
2255   gdk_draw_pixmap(sheet->sheet_window,
2256                   GTK_WIDGET(sheet)->style->fg_gc[GTK_STATE_NORMAL],
2257                   sheet->pixmap,
2258                   x, y,
2259                   x, y,
2260                   1, height);
2261
2262   gdk_draw_pixmap(sheet->sheet_window,
2263                   GTK_WIDGET(sheet)->style->fg_gc[GTK_STATE_NORMAL],
2264                   sheet->pixmap,
2265                   x, y,
2266                   x, y,
2267                   width, 1);
2268
2269   gdk_draw_pixmap(sheet->sheet_window,
2270                   GTK_WIDGET(sheet)->style->fg_gc[GTK_STATE_NORMAL],
2271                   sheet->pixmap,
2272                   x, y+height,
2273                   x, y+height,
2274                   width, 1);
2275
2276   gdk_draw_pixmap(sheet->sheet_window,
2277                   GTK_WIDGET(sheet)->style->fg_gc[GTK_STATE_NORMAL],
2278                   sheet->pixmap,
2279                   x+width, y,
2280                   x+width, y,
2281                   1, height);
2282
2283
2284   sheet->interval=sheet->interval+1;
2285   if(sheet->interval==TIME_INTERVAL) sheet->interval=0;
2286
2287   gdk_gc_set_dashes(sheet->xor_gc, sheet->interval, (gint8*)"\4\4", 2);
2288   gtk_sheet_draw_flashing_range(sheet,sheet->clip_range);
2289   gdk_gc_set_dashes(sheet->xor_gc, 0, (gint8*)"\4\4", 2);
2290
2291   GDK_THREADS_LEAVE();
2292
2293   return TRUE;
2294
2295 }
2296
2297 static void
2298 gtk_sheet_draw_flashing_range(GtkSheet *sheet, GtkSheetRange range)
2299 {
2300   GdkRectangle clip_area;
2301   gint x,y,width,height;
2302
2303   if(!gtk_sheet_range_isvisible(sheet, sheet->clip_range)) return;
2304   
2305   clip_area.x=COLUMN_LEFT_XPIXEL(sheet, MIN_VISIBLE_COLUMN(sheet));
2306   clip_area.y=ROW_TOP_YPIXEL(sheet, MIN_VISIBLE_ROW(sheet));
2307   clip_area.width=sheet->sheet_window_width;
2308   clip_area.height=sheet->sheet_window_height;
2309
2310   gdk_gc_set_clip_rectangle(sheet->xor_gc, &clip_area);  
2311
2312   x=COLUMN_LEFT_XPIXEL(sheet,sheet->clip_range.col0)+1;
2313   y=ROW_TOP_YPIXEL(sheet,sheet->clip_range.row0)+1;
2314   width=COLUMN_LEFT_XPIXEL(sheet,sheet->clip_range.coli)-x+ 
2315     xxx_column_width(sheet, sheet->clip_range.coli) - 1;
2316   height=ROW_TOP_YPIXEL(sheet,sheet->clip_range.rowi)-y+
2317              yyy_row_height(sheet, sheet->clip_range.rowi)-1;
2318
2319   if(x<0) {
2320      width=width+x+1;
2321      x=-1;
2322   }
2323   if(width>clip_area.width) width=clip_area.width+10;
2324   if(y<0) {
2325      height=height+y+1;
2326      y=-1;
2327   }
2328   if(height>clip_area.height) height=clip_area.height+10;
2329
2330   gdk_gc_set_line_attributes(sheet->xor_gc, 1, 1, 0 ,0 );
2331
2332   gdk_draw_rectangle(sheet->sheet_window, sheet->xor_gc, FALSE, 
2333                      x, y,
2334                      width, height);
2335
2336   gdk_gc_set_line_attributes (sheet->xor_gc, 1, 0, 0, 0);
2337
2338   gdk_gc_set_clip_rectangle(sheet->xor_gc, NULL);
2339
2340 }
2341
2342 static gint
2343 gtk_sheet_range_isvisible (GtkSheet * sheet,
2344                          GtkSheetRange range)
2345 {
2346   g_return_val_if_fail (sheet != NULL, FALSE);
2347
2348   if (range.row0 < 0 || range.row0 >= yyy_row_count(sheet))
2349     return FALSE;
2350
2351   if (range.rowi < 0 || range.rowi >= yyy_row_count(sheet))
2352     return FALSE;
2353
2354   if (range.col0 < 0 || range.col0 >= xxx_column_count(sheet))
2355     return FALSE;
2356
2357   if (range.coli < 0 || range.coli >= xxx_column_count(sheet))
2358     return FALSE;
2359
2360   if (range.rowi < MIN_VISIBLE_ROW (sheet))
2361     return FALSE;
2362
2363   if (range.row0 > MAX_VISIBLE_ROW (sheet))
2364     return FALSE;
2365
2366   if (range.coli < MIN_VISIBLE_COLUMN (sheet))
2367     return FALSE;
2368
2369   if (range.col0 > MAX_VISIBLE_COLUMN (sheet))
2370     return FALSE;
2371
2372   return TRUE;
2373 }
2374
2375 static gint
2376 gtk_sheet_cell_isvisible (GtkSheet * sheet,
2377                           gint row, gint column)
2378 {
2379   GtkSheetRange range;
2380
2381   range.row0 = row;
2382   range.col0 = column;
2383   range.rowi = row;
2384   range.coli = column;
2385
2386   return gtk_sheet_range_isvisible(sheet, range);
2387 }
2388
2389 void 
2390 gtk_sheet_get_visible_range(GtkSheet *sheet, GtkSheetRange *range)
2391 {
2392
2393   g_return_if_fail (sheet != NULL);
2394   g_return_if_fail (GTK_IS_SHEET (sheet)) ;
2395   g_return_if_fail (range != NULL);
2396
2397   range->row0 = MIN_VISIBLE_ROW(sheet);
2398   range->col0 = MIN_VISIBLE_COLUMN(sheet);
2399   range->rowi = MAX_VISIBLE_ROW(sheet);
2400   range->coli = MAX_VISIBLE_COLUMN(sheet);
2401
2402 }
2403
2404 GtkAdjustment *
2405 gtk_sheet_get_vadjustment (GtkSheet * sheet)
2406 {
2407   g_return_val_if_fail (sheet != NULL, NULL);
2408   g_return_val_if_fail (GTK_IS_SHEET (sheet), NULL);
2409
2410   return sheet->vadjustment;
2411 }
2412
2413 GtkAdjustment *
2414 gtk_sheet_get_hadjustment (GtkSheet * sheet)
2415 {
2416   g_return_val_if_fail (sheet != NULL, NULL);
2417   g_return_val_if_fail (GTK_IS_SHEET (sheet), NULL);
2418
2419   return sheet->hadjustment;
2420 }
2421
2422 void
2423 gtk_sheet_set_vadjustment (GtkSheet      *sheet,
2424                            GtkAdjustment *adjustment)
2425 {
2426   GtkAdjustment *old_adjustment;
2427
2428   g_return_if_fail (sheet != NULL);
2429   g_return_if_fail (GTK_IS_SHEET (sheet));
2430   if (adjustment)
2431     g_return_if_fail (GTK_IS_ADJUSTMENT (adjustment));
2432   
2433   if (sheet->vadjustment == adjustment)
2434     return;
2435   
2436   old_adjustment = sheet->vadjustment;
2437
2438   if (sheet->vadjustment)
2439     {
2440       gtk_signal_disconnect_by_data (GTK_OBJECT (sheet->vadjustment), sheet);
2441       gtk_object_unref (GTK_OBJECT (sheet->vadjustment));
2442     }
2443
2444   sheet->vadjustment = adjustment;
2445
2446   if (sheet->vadjustment)
2447     {
2448       gtk_object_ref (GTK_OBJECT (sheet->vadjustment));
2449       gtk_object_sink (GTK_OBJECT (sheet->vadjustment));
2450
2451       gtk_signal_connect (GTK_OBJECT (sheet->vadjustment), "changed",
2452                           (GtkSignalFunc) vadjustment_changed,
2453                           (gpointer) sheet);
2454       gtk_signal_connect (GTK_OBJECT (sheet->vadjustment), "value_changed",
2455                           (GtkSignalFunc) vadjustment_value_changed,
2456                           (gpointer) sheet);
2457     }
2458
2459   if (!sheet->vadjustment || !old_adjustment)
2460      {
2461        gtk_widget_queue_resize (GTK_WIDGET (sheet));
2462        return;
2463      }
2464
2465   sheet->old_vadjustment = sheet->vadjustment->value;
2466 }
2467
2468 void
2469 gtk_sheet_set_hadjustment (GtkSheet      *sheet,
2470                            GtkAdjustment *adjustment)
2471 {
2472   GtkAdjustment *old_adjustment;
2473
2474   g_return_if_fail (sheet != NULL);
2475   g_return_if_fail (GTK_IS_SHEET (sheet));
2476   if (adjustment)
2477     g_return_if_fail (GTK_IS_ADJUSTMENT (adjustment));
2478   
2479   if (sheet->hadjustment == adjustment)
2480     return;
2481   
2482   old_adjustment = sheet->hadjustment;
2483
2484   if (sheet->hadjustment)
2485     {
2486       gtk_signal_disconnect_by_data (GTK_OBJECT (sheet->hadjustment), sheet);
2487       gtk_object_unref (GTK_OBJECT (sheet->hadjustment));
2488     }
2489
2490   sheet->hadjustment = adjustment;
2491
2492   if (sheet->hadjustment)
2493     {
2494       gtk_object_ref (GTK_OBJECT (sheet->hadjustment));
2495       gtk_object_sink (GTK_OBJECT (sheet->hadjustment));
2496
2497       gtk_signal_connect (GTK_OBJECT (sheet->hadjustment), "changed",
2498                           (GtkSignalFunc) hadjustment_changed,
2499                           (gpointer) sheet);
2500       gtk_signal_connect (GTK_OBJECT (sheet->hadjustment), "value_changed",
2501                           (GtkSignalFunc) hadjustment_value_changed,
2502                           (gpointer) sheet);
2503     }
2504
2505   if (!sheet->hadjustment || !old_adjustment)
2506      {
2507        gtk_widget_queue_resize (GTK_WIDGET (sheet));
2508        return;
2509      }
2510
2511   sheet->old_hadjustment = sheet->hadjustment->value;
2512 }
2513
2514 static void
2515 gtk_sheet_set_scroll_adjustments (GtkSheet *sheet,
2516                                   GtkAdjustment *hadjustment,
2517                                   GtkAdjustment *vadjustment)
2518 {
2519    if(sheet->hadjustment != hadjustment)
2520          gtk_sheet_set_hadjustment (sheet, hadjustment);
2521    if(sheet->vadjustment != vadjustment)
2522          gtk_sheet_set_vadjustment (sheet, vadjustment);
2523 }
2524
2525 static void
2526 gtk_sheet_finalize (GObject * object)
2527 {
2528   GtkSheet *sheet;
2529
2530   g_return_if_fail (object != NULL);
2531   g_return_if_fail (GTK_IS_SHEET (object));
2532
2533   sheet = GTK_SHEET (object);
2534
2535   /* get rid of all the cells */
2536   gtk_sheet_range_clear (sheet, NULL);
2537   gtk_sheet_range_delete(sheet, NULL);
2538
2539   if(sheet->name){
2540       g_free(sheet->name);
2541       sheet->name = NULL;
2542   }
2543
2544   if (G_OBJECT_CLASS (parent_class)->finalize)
2545     (*G_OBJECT_CLASS (parent_class)->finalize) (object);
2546 }
2547
2548 static void
2549 gtk_sheet_destroy (GtkObject * object)
2550 {
2551   GtkSheet *sheet;
2552   GList *children;
2553
2554   g_return_if_fail (object != NULL);
2555   g_return_if_fail (GTK_IS_SHEET (object));
2556
2557   sheet = GTK_SHEET (object);
2558
2559   /* destroy the entry */
2560   if(sheet->sheet_entry && GTK_IS_WIDGET(sheet->sheet_entry)){
2561     gtk_widget_destroy (sheet->sheet_entry);
2562     sheet->sheet_entry = NULL;
2563   }
2564
2565   /* destroy the global selection button */
2566   if(sheet->button && GTK_IS_WIDGET(sheet->button)){
2567     gtk_widget_destroy (sheet->button);
2568     sheet->button = NULL;
2569   }
2570
2571   if(sheet->timer){
2572      gtk_timeout_remove(sheet->timer);
2573      sheet->timer = 0;
2574   }
2575
2576   if(sheet->clip_timer){
2577      gtk_timeout_remove(sheet->clip_timer);
2578      sheet->clip_timer = 0;
2579   }
2580
2581   /* unref adjustments */
2582   if (sheet->hadjustment)
2583     {
2584       gtk_signal_disconnect_by_data (GTK_OBJECT (sheet->hadjustment), sheet);
2585       gtk_object_unref (GTK_OBJECT (sheet->hadjustment));
2586       sheet->hadjustment = NULL;
2587     }
2588   if (sheet->vadjustment)
2589     {
2590       gtk_signal_disconnect_by_data (GTK_OBJECT (sheet->vadjustment), sheet);
2591       gtk_object_unref (GTK_OBJECT (sheet->vadjustment));
2592       sheet->vadjustment = NULL;
2593     }
2594
2595   children = sheet->children;
2596   while(children){
2597     GtkSheetChild *child = (GtkSheetChild *)children->data;
2598     if(child && child->widget) 
2599       gtk_sheet_remove(GTK_CONTAINER(sheet), child->widget);
2600     children = sheet->children;
2601   }  
2602   sheet->children = NULL;
2603
2604   if (GTK_OBJECT_CLASS (parent_class)->destroy)
2605     (*GTK_OBJECT_CLASS (parent_class)->destroy) (object);
2606 }
2607
2608 static void
2609 gtk_sheet_style_set (GtkWidget *widget,
2610                      GtkStyle  *previous_style)
2611 {
2612   GtkSheet *sheet;
2613
2614   g_return_if_fail (widget != NULL);
2615   g_return_if_fail (GTK_IS_SHEET (widget));
2616
2617   if (GTK_WIDGET_CLASS (parent_class)->style_set)
2618     (*GTK_WIDGET_CLASS (parent_class)->style_set) (widget, previous_style);
2619
2620   sheet = GTK_SHEET (widget);
2621
2622   if(GTK_WIDGET_REALIZED(widget))
2623      {
2624        gtk_style_set_background (widget->style, widget->window, widget->state);
2625      }
2626
2627 }
2628
2629 static void
2630 gtk_sheet_realize (GtkWidget * widget)
2631 {
2632   GtkSheet *sheet;
2633   GdkWindowAttr attributes;
2634   gint attributes_mask;
2635   GdkGCValues values, auxvalues;
2636   GdkColormap *colormap;
2637   gchar *name;
2638   GtkSheetChild *child;
2639   GList *children;
2640
2641   g_return_if_fail (widget != NULL);
2642   g_return_if_fail (GTK_IS_SHEET (widget));
2643
2644   sheet = GTK_SHEET (widget);
2645
2646   GTK_WIDGET_SET_FLAGS (widget, GTK_REALIZED);
2647
2648   attributes.window_type = GDK_WINDOW_CHILD;
2649   attributes.x = widget->allocation.x;
2650   attributes.y = widget->allocation.y;
2651   attributes.width = widget->allocation.width;
2652   attributes.height = widget->allocation.height;
2653   attributes.wclass = GDK_INPUT_OUTPUT;
2654
2655   attributes.visual = gtk_widget_get_visual (widget);
2656   attributes.colormap = gtk_widget_get_colormap (widget);
2657
2658   attributes.event_mask = gtk_widget_get_events (widget);
2659   attributes.event_mask |= (GDK_EXPOSURE_MASK |
2660                             GDK_BUTTON_PRESS_MASK |
2661                             GDK_BUTTON_RELEASE_MASK |
2662                             GDK_KEY_PRESS_MASK |
2663                             GDK_POINTER_MOTION_MASK |
2664                             GDK_POINTER_MOTION_HINT_MASK);
2665   attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL | GDK_WA_COLORMAP |
2666                     GDK_WA_CURSOR;
2667
2668   attributes.cursor = gdk_cursor_new(GDK_TOP_LEFT_ARROW);
2669
2670   /* main window */
2671   widget->window = gdk_window_new (gtk_widget_get_parent_window (widget), &attributes, attributes_mask);
2672
2673   gdk_window_set_user_data (widget->window, sheet);
2674
2675   widget->style = gtk_style_attach (widget->style, widget->window);
2676
2677   gtk_style_set_background (widget->style, widget->window, GTK_STATE_NORMAL);
2678
2679   attributes.x = 0;
2680   if(sheet->row_titles_visible)
2681        attributes.x = sheet->row_title_area.width;
2682   attributes.y = 0;
2683   attributes.width = sheet->column_title_area.width;
2684   attributes.height = sheet->column_title_area.height;
2685
2686   /* column-title window */
2687   sheet->column_title_window = gdk_window_new (widget->window, &attributes, attributes_mask);
2688   gdk_window_set_user_data (sheet->column_title_window, sheet);
2689   gtk_style_set_background (widget->style, sheet->column_title_window, GTK_STATE_NORMAL);
2690
2691   attributes.x = 0;
2692   attributes.y = 0;
2693   if(sheet->column_titles_visible)
2694        attributes.y = sheet->column_title_area.height;
2695   attributes.width = sheet->row_title_area.width;
2696   attributes.height = sheet->row_title_area.height;
2697
2698   /* row-title window */
2699   sheet->row_title_window = gdk_window_new (widget->window, &attributes, attributes_mask);
2700   gdk_window_set_user_data (sheet->row_title_window, sheet);
2701   gtk_style_set_background (widget->style, sheet->row_title_window, GTK_STATE_NORMAL);
2702
2703   /* sheet-window */
2704   attributes.cursor = gdk_cursor_new(GDK_PLUS);
2705
2706   attributes.x = 0;
2707   attributes.y = 0;
2708   attributes.width = sheet->sheet_window_width, 
2709   attributes.height = sheet->sheet_window_height;
2710
2711   sheet->sheet_window = gdk_window_new (widget->window, &attributes, attributes_mask);
2712   gdk_window_set_user_data (sheet->sheet_window, sheet);
2713
2714   gdk_cursor_unref(attributes.cursor);
2715
2716   gdk_window_set_background (sheet->sheet_window, &widget->style->white);
2717   gdk_window_show (sheet->sheet_window);
2718
2719   /* backing_pixmap */
2720   gtk_sheet_make_backing_pixmap(sheet, 0, 0);  
2721
2722   /* GCs */
2723   if(sheet->fg_gc) 
2724       gdk_gc_unref(sheet->fg_gc);
2725   if(sheet->bg_gc) 
2726       gdk_gc_unref(sheet->bg_gc);
2727   sheet->fg_gc = gdk_gc_new (widget->window);
2728   sheet->bg_gc = gdk_gc_new (widget->window);
2729
2730   colormap = gtk_widget_get_colormap(widget);
2731
2732   gdk_color_white(colormap, &widget->style->white);
2733   gdk_color_black(colormap, &widget->style->black);
2734
2735   gdk_gc_get_values(sheet->fg_gc, &auxvalues);
2736
2737   values.foreground = widget->style->white;
2738   values.function = GDK_INVERT;
2739   values.subwindow_mode = GDK_INCLUDE_INFERIORS;
2740   if(sheet->xor_gc)
2741     gdk_gc_unref(sheet->xor_gc);
2742   sheet->xor_gc = gdk_gc_new_with_values (widget->window,
2743                                           &values,
2744                                           GDK_GC_FOREGROUND |
2745                                           GDK_GC_FUNCTION |
2746                                           GDK_GC_SUBWINDOW);
2747
2748   if(sheet->sheet_entry->parent){
2749           gtk_widget_ref(sheet->sheet_entry);
2750           gtk_widget_unparent(sheet->sheet_entry);
2751   }
2752   gtk_widget_set_parent_window (sheet->sheet_entry, sheet->sheet_window);
2753   gtk_widget_set_parent(sheet->sheet_entry, GTK_WIDGET(sheet));
2754
2755   if(sheet->button && sheet->button->parent){
2756           gtk_widget_ref(sheet->button);
2757           gtk_widget_unparent(sheet->button);
2758   }
2759   gtk_widget_set_parent_window(sheet->button, sheet->sheet_window);
2760   gtk_widget_set_parent(sheet->button, GTK_WIDGET(sheet));
2761
2762 /*
2763   gtk_sheet_activate_cell(sheet, sheet->active_cell.row, sheet->active_cell.col);
2764 */
2765   if(!sheet->cursor_drag)
2766        sheet->cursor_drag = gdk_cursor_new(GDK_PLUS);
2767  
2768   if(sheet->column_titles_visible)
2769      gdk_window_show(sheet->column_title_window);
2770   if(sheet->row_titles_visible)
2771      gdk_window_show(sheet->row_title_window);
2772
2773   size_allocate_row_title_buttons(sheet);
2774   size_allocate_column_title_buttons(sheet);
2775
2776   name = g_strdup(sheet->name);
2777   gtk_sheet_set_title(sheet, name);
2778
2779   g_free(name);
2780
2781   children = sheet->children;
2782   while(children)
2783     {
2784       child = children->data;
2785       children = children->next;
2786  
2787       gtk_sheet_realize_child(sheet, child);
2788     }
2789 }
2790
2791 static void
2792 create_global_button(GtkSheet *sheet)
2793 {
2794    sheet->button = gtk_button_new_with_label(" ");
2795
2796    gtk_signal_connect (GTK_OBJECT (sheet->button),
2797                       "pressed",
2798                       (GtkSignalFunc) global_button_clicked,
2799                       (gpointer) sheet);
2800 }
2801
2802 static void
2803 size_allocate_global_button(GtkSheet *sheet)
2804 {
2805   GtkAllocation allocation;
2806
2807   if(!sheet->column_titles_visible) return;
2808   if(!sheet->row_titles_visible) return;
2809
2810   gtk_widget_size_request(sheet->button, NULL);
2811
2812   allocation.x=0;
2813   allocation.y=0;
2814   allocation.width=sheet->row_title_area.width;
2815   allocation.height=sheet->column_title_area.height;
2816
2817   gtk_widget_size_allocate(sheet->button, &allocation);
2818   gtk_widget_show(sheet->button);
2819 }
2820
2821 static void
2822 global_button_clicked(GtkWidget *widget, gpointer data)
2823 {
2824   gboolean veto;
2825
2826   gtk_sheet_click_cell(GTK_SHEET(data), -1, -1, &veto);
2827   gtk_widget_grab_focus(GTK_WIDGET(data));
2828 }
2829
2830
2831 static void
2832 gtk_sheet_unrealize (GtkWidget * widget)
2833 {
2834   GtkSheet *sheet;
2835
2836   g_return_if_fail (widget != NULL);
2837   g_return_if_fail (GTK_IS_SHEET (widget));
2838
2839   sheet = GTK_SHEET (widget);
2840
2841   gdk_cursor_destroy (sheet->cursor_drag);
2842
2843   gdk_gc_destroy (sheet->xor_gc);
2844   gdk_gc_destroy (sheet->fg_gc);
2845   gdk_gc_destroy (sheet->bg_gc);
2846
2847   gdk_window_destroy (sheet->sheet_window);
2848   gdk_window_destroy (sheet->column_title_window);
2849   gdk_window_destroy (sheet->row_title_window);
2850
2851   if (sheet->pixmap){
2852     g_object_unref(sheet->pixmap);
2853     sheet->pixmap = NULL;
2854   }
2855
2856   sheet->column_title_window=NULL;
2857   sheet->sheet_window = NULL;
2858   sheet->cursor_drag = NULL;
2859   sheet->xor_gc = NULL;
2860   sheet->fg_gc = NULL;
2861   sheet->bg_gc = NULL;
2862
2863   if (GTK_WIDGET_CLASS (parent_class)->unrealize)
2864     (* GTK_WIDGET_CLASS (parent_class)->unrealize) (widget);
2865 }
2866
2867 static void
2868 gtk_sheet_map (GtkWidget * widget)
2869 {
2870   GtkSheet *sheet;
2871   GtkSheetChild *child;
2872   GList *children;
2873
2874   g_return_if_fail (widget != NULL);
2875   g_return_if_fail (GTK_IS_SHEET (widget));
2876
2877   sheet = GTK_SHEET (widget);
2878
2879   if (!GTK_WIDGET_MAPPED (widget))
2880     {
2881       GTK_WIDGET_SET_FLAGS (widget, GTK_MAPPED);
2882
2883       if(!sheet->cursor_drag) sheet->cursor_drag=gdk_cursor_new(GDK_PLUS);
2884
2885       gdk_window_show (widget->window);
2886
2887       gdk_window_show (sheet->sheet_window);
2888
2889       if(sheet->column_titles_visible){
2890            size_allocate_column_title_buttons(sheet);
2891            gdk_window_show (sheet->column_title_window);
2892       }
2893       if(sheet->row_titles_visible){
2894            size_allocate_row_title_buttons(sheet);
2895            gdk_window_show (sheet->row_title_window);
2896       }
2897
2898       if(!GTK_WIDGET_MAPPED (sheet->sheet_entry)
2899          && ! gtk_sheet_locked(sheet)
2900          && sheet->active_cell.row  >=0
2901          && sheet->active_cell.col  >=0 )
2902         {
2903           gtk_widget_show (sheet->sheet_entry);
2904           gtk_widget_map (sheet->sheet_entry);
2905         }
2906
2907       if (GTK_WIDGET_VISIBLE (sheet->button) &&
2908           !GTK_WIDGET_MAPPED (sheet->button)){
2909                   gtk_widget_show(sheet->button);
2910                   gtk_widget_map (sheet->button);
2911       }
2912
2913       if(GTK_BIN(sheet->button)->child)
2914         if (GTK_WIDGET_VISIBLE (GTK_BIN(sheet->button)->child) &&
2915            !GTK_WIDGET_MAPPED (GTK_BIN(sheet->button)->child))
2916                   gtk_widget_map (GTK_BIN(sheet->button)->child);
2917
2918       gtk_sheet_range_draw(sheet, NULL);
2919       gtk_sheet_activate_cell(sheet, 
2920                               sheet->active_cell.row, 
2921                               sheet->active_cell.col);
2922
2923       children = sheet->children;
2924       while (children)
2925       {
2926         child = children->data;
2927         children = children->next;
2928
2929         if (GTK_WIDGET_VISIBLE (child->widget) &&
2930             !GTK_WIDGET_MAPPED (child->widget)){
2931           gtk_widget_map (child->widget);
2932           gtk_sheet_position_child(sheet, child);
2933         }
2934       }
2935
2936     }
2937 }
2938
2939 static void
2940 gtk_sheet_unmap (GtkWidget * widget)
2941 {
2942   GtkSheet *sheet;
2943   GtkSheetChild *child;
2944   GList *children;
2945
2946   g_return_if_fail (widget != NULL);
2947   g_return_if_fail (GTK_IS_SHEET (widget));
2948
2949   sheet = GTK_SHEET (widget);
2950
2951   if (GTK_WIDGET_MAPPED (widget))
2952     {
2953       GTK_WIDGET_UNSET_FLAGS (widget, GTK_MAPPED);
2954
2955       gdk_window_hide (sheet->sheet_window);
2956       if(sheet->column_titles_visible)
2957           gdk_window_hide (sheet->column_title_window);
2958       if(sheet->row_titles_visible)
2959           gdk_window_hide (sheet->row_title_window);
2960       gdk_window_hide (widget->window);
2961
2962       if (GTK_WIDGET_MAPPED (sheet->sheet_entry))
2963         gtk_widget_unmap (sheet->sheet_entry);
2964
2965       if (GTK_WIDGET_MAPPED (sheet->button))
2966         gtk_widget_unmap (sheet->button);
2967
2968       children = sheet->children;
2969       while (children)
2970         {
2971           child = children->data;
2972           children = children->next;
2973
2974           if (GTK_WIDGET_VISIBLE (child->widget) &&
2975               GTK_WIDGET_MAPPED (child->widget))
2976                 {
2977                      gtk_widget_unmap (child->widget);
2978                 }
2979         }
2980
2981     }
2982 }
2983
2984
2985 static void
2986 gtk_sheet_cell_draw_default (GtkSheet *sheet, gint row, gint col)
2987 {
2988   GtkWidget *widget;
2989   GdkGC *fg_gc, *bg_gc;
2990   GtkSheetCellAttr attributes;
2991   GdkRectangle area;
2992
2993   g_return_if_fail (sheet != NULL);
2994
2995   /* bail now if we arn't drawable yet */
2996   if (!GTK_WIDGET_DRAWABLE (sheet)) return;
2997
2998   if (row < 0 || row >= yyy_row_count(sheet)) return;
2999   if (col < 0 || col >= xxx_column_count(sheet)) return;
3000   if (! xxx_column_is_visible(sheet, col)) return;
3001   if (! yyy_row_is_visible(sheet, row)) return;
3002
3003   widget = GTK_WIDGET (sheet);
3004
3005   gtk_sheet_get_attributes(sheet, row, col, &attributes);
3006  
3007   /* select GC for background rectangle */
3008   gdk_gc_set_foreground (sheet->fg_gc, &attributes.foreground);
3009   gdk_gc_set_foreground (sheet->bg_gc, &attributes.background);
3010
3011   fg_gc = sheet->fg_gc;
3012   bg_gc = sheet->bg_gc;
3013
3014   area.x=COLUMN_LEFT_XPIXEL(sheet,col);
3015   area.y=ROW_TOP_YPIXEL(sheet,row);
3016   area.width= xxx_column_width(sheet, col);
3017   area.height=yyy_row_height(sheet, row);
3018
3019   gdk_draw_rectangle (sheet->pixmap,
3020                       bg_gc,
3021                       TRUE,
3022                       area.x,
3023                       area.y,
3024                       area.width,
3025                       area.height);
3026
3027   gdk_gc_set_line_attributes (sheet->fg_gc, 1, 0, 0, 0);
3028
3029   if(sheet->show_grid){
3030     gdk_gc_set_foreground (sheet->bg_gc, &sheet->grid_color);
3031
3032     gdk_draw_rectangle (sheet->pixmap,
3033                         sheet->bg_gc,
3034                         FALSE,
3035                         area.x, area.y,
3036                         area.width, area.height);
3037   }
3038 }
3039
3040 static void
3041 gtk_sheet_cell_draw_border (GtkSheet *sheet, gint row, gint col, gint mask)
3042 {
3043   GtkWidget *widget;
3044   GdkGC *fg_gc, *bg_gc;
3045   GtkSheetCellAttr attributes;
3046   GdkRectangle area;
3047   guint width;
3048
3049   g_return_if_fail (sheet != NULL);
3050
3051   /* bail now if we arn't drawable yet */
3052   if (!GTK_WIDGET_DRAWABLE (sheet)) return;
3053
3054   if (row < 0 || row >= yyy_row_count(sheet)) return;
3055   if (col < 0 || col >= xxx_column_count(sheet)) return;
3056   if (!xxx_column_is_visible(sheet, col)) return;
3057   if (!yyy_row_is_visible(sheet, row)) return;
3058
3059   widget = GTK_WIDGET (sheet);
3060
3061   gtk_sheet_get_attributes(sheet, row, col, &attributes);
3062
3063   /* select GC for background rectangle */
3064   gdk_gc_set_foreground (sheet->fg_gc, &attributes.border.color);
3065   gdk_gc_set_foreground (sheet->bg_gc, &attributes.background);
3066
3067   fg_gc = sheet->fg_gc;
3068   bg_gc = sheet->bg_gc;
3069
3070   area.x=COLUMN_LEFT_XPIXEL(sheet,col);
3071   area.y=ROW_TOP_YPIXEL(sheet,row);
3072   area.width=xxx_column_width(sheet, col);
3073   area.height=yyy_row_height(sheet, row);
3074
3075   width = attributes.border.width;
3076   gdk_gc_set_line_attributes(sheet->fg_gc, attributes.border.width,
3077                                            attributes.border.line_style,
3078                                            attributes.border.cap_style,
3079                                            attributes.border.join_style);
3080   if(width>0){
3081
3082    if(attributes.border.mask & GTK_SHEET_LEFT_BORDER & mask)
3083       gdk_draw_line(sheet->pixmap, sheet->fg_gc,
3084                     area.x, area.y-width/2,
3085                     area.x, area.y+area.height+width/2+1);
3086
3087    if(attributes.border.mask & GTK_SHEET_RIGHT_BORDER & mask)
3088       gdk_draw_line(sheet->pixmap, sheet->fg_gc,
3089                     area.x+area.width, area.y-width/2,
3090                     area.x+area.width, 
3091                     area.y+area.height+width/2+1);
3092
3093    if(attributes.border.mask & GTK_SHEET_TOP_BORDER & mask)
3094       gdk_draw_line(sheet->pixmap, sheet->fg_gc,
3095                     area.x-width/2,area.y,
3096                     area.x+area.width+width/2+1, 
3097                     area.y);
3098
3099    if(attributes.border.mask & GTK_SHEET_BOTTOM_BORDER & mask)
3100       gdk_draw_line(sheet->pixmap, sheet->fg_gc,
3101                     area.x-width/2, area.y+area.height,
3102                     area.x+area.width+width/2+1, 
3103                     area.y+area.height);
3104   }
3105
3106 }
3107
3108
3109 static void
3110 gtk_sheet_cell_draw_label (GtkSheet *sheet, gint row, gint col)
3111 {
3112   GtkWidget *widget;
3113   GdkRectangle area, clip_area;
3114   gint i;
3115   gint text_width, text_height, y;
3116   gint xoffset=0;  
3117   gint size, sizel, sizer;
3118   GdkGC *fg_gc, *bg_gc;
3119   GtkSheetCellAttr attributes;
3120   PangoLayout *layout;
3121   PangoRectangle rect;
3122   PangoRectangle logical_rect;
3123   PangoLayoutLine *line;
3124   PangoFontMetrics *metrics;
3125   PangoContext *context = gtk_widget_get_pango_context(GTK_WIDGET(sheet)); 
3126   gint ascent, descent, y_pos;
3127
3128   gchar *label;
3129
3130   g_return_if_fail (sheet != NULL);
3131
3132    /* bail now if we aren't drawable yet */
3133    if (!GTK_WIDGET_DRAWABLE (sheet))
3134     return;
3135
3136   label = gtk_sheet_cell_get_text(sheet, row, col);
3137   if (!label)
3138       return;
3139
3140   if (row < 0 || row >= yyy_row_count(sheet)) return;
3141   if (col < 0 || col >= xxx_column_count(sheet)) return;
3142   if (! xxx_column_is_visible(sheet, col)) return;
3143   if (!yyy_row_is_visible(sheet, row)) return;
3144
3145
3146   widget = GTK_WIDGET(sheet);
3147
3148   gtk_sheet_get_attributes(sheet, row, col, &attributes);
3149
3150   /* select GC for background rectangle */
3151   gdk_gc_set_foreground (sheet->fg_gc, &attributes.foreground);
3152   gdk_gc_set_foreground (sheet->bg_gc, &attributes.background);
3153
3154   fg_gc = sheet->fg_gc;
3155   bg_gc = sheet->bg_gc;
3156
3157   area.x=COLUMN_LEFT_XPIXEL(sheet,col);
3158   area.y=ROW_TOP_YPIXEL(sheet,row);
3159   area.width  = xxx_column_width(sheet, col);
3160   area.height = yyy_row_height(sheet, row);
3161
3162   clip_area = area;
3163
3164   layout = gtk_widget_create_pango_layout (GTK_WIDGET(sheet), label);
3165   dispose_string(sheet, label);
3166   pango_layout_set_font_description (layout, attributes.font_desc);
3167
3168   pango_layout_get_pixel_extents (layout, NULL, &rect);
3169
3170   line = pango_layout_get_lines (layout)->data;
3171   pango_layout_line_get_extents (line, NULL, &logical_rect);
3172
3173   metrics = pango_context_get_metrics(context,
3174                                   attributes.font_desc,
3175                                   pango_context_get_language(context)); 
3176
3177   ascent = pango_font_metrics_get_ascent(metrics) / PANGO_SCALE;
3178   descent = pango_font_metrics_get_descent(metrics) / PANGO_SCALE;
3179
3180   pango_font_metrics_unref(metrics);
3181
3182   /* Align primarily for locale's ascent/descent */
3183
3184   logical_rect.height /= PANGO_SCALE;
3185   logical_rect.y /= PANGO_SCALE;
3186   y_pos =  area.height - logical_rect.height;
3187
3188   if (logical_rect.height > area.height)
3189     y_pos = (logical_rect.height - area.height - 2*CELLOFFSET) / 2;
3190   else if (y_pos < 0)
3191     y_pos = 0;
3192   else if (y_pos + logical_rect.height > area.height)
3193     y_pos = area.height - logical_rect.height;
3194
3195   text_width = rect.width;
3196   text_height = rect.height;
3197   y = area.y + y_pos - CELLOFFSET;
3198
3199   switch(attributes.justification){
3200     case GTK_JUSTIFY_RIGHT:
3201           size=area.width;
3202           area.x+=area.width;
3203           if(!gtk_sheet_clip_text(sheet)){          
3204            for(i=col-1; i>=MIN_VISIBLE_COLUMN(sheet); i--){
3205              if( !gtk_sheet_cell_empty(sheet, row, i)) break;
3206              if(size>=text_width+CELLOFFSET) break;
3207              size+=xxx_column_width(sheet, i);
3208              xxx_column_set_right_column(sheet, i, 
3209                                          MAX(col,
3210                                              xxx_column_right_column(sheet, i)));
3211            }
3212            area.width=size;
3213           }
3214           area.x-=size;
3215           xoffset+=area.width-text_width - 2 * CELLOFFSET -
3216                    attributes.border.width/2;
3217           break;
3218      case GTK_JUSTIFY_CENTER:
3219           sizel=area.width/2;
3220           sizer=area.width/2;
3221           area.x+=area.width/2;
3222           if(!gtk_sheet_clip_text(sheet)){          
3223            for(i=col+1; i<=MAX_VISIBLE_COLUMN(sheet); i++){
3224              if( ! gtk_sheet_cell_empty(sheet, row, i)) break;
3225              if(sizer>=text_width/2) break;
3226              sizer+= xxx_column_width(sheet, i);
3227              xxx_column_set_left_column(sheet, i, 
3228                                         MIN(
3229                                             col, 
3230                                             xxx_column_left_column(sheet, i)));
3231            }
3232            for(i=col-1; i>=MIN_VISIBLE_COLUMN(sheet); i--){
3233              if( ! gtk_sheet_cell_empty(sheet, row, i)) break;
3234              if(sizel>=text_width/2) break;
3235              sizel+=xxx_column_width(sheet, i);
3236              xxx_column_set_right_column(sheet, i, 
3237                                          MAX(col,
3238                                              xxx_column_right_column(sheet, i)));
3239            }
3240            size=MIN(sizel, sizer);
3241           }
3242           area.x-=sizel;
3243           xoffset+= sizel - text_width/2 - CELLOFFSET;
3244           area.width=sizel+sizer;
3245           break;
3246       case GTK_JUSTIFY_LEFT:
3247       default:
3248           size=area.width;
3249           if(!gtk_sheet_clip_text(sheet)){          
3250            for(i=col+1; i<=MAX_VISIBLE_COLUMN(sheet); i++){
3251              if(! gtk_sheet_cell_empty(sheet, row, i)) break;
3252              if(size>=text_width+CELLOFFSET) break;
3253              size+=xxx_column_width(sheet, i);
3254              xxx_column_set_left_column(sheet, i, 
3255                                         MIN(
3256                                             col, 
3257                                             xxx_column_left_column(sheet, i)));
3258
3259            }
3260            area.width=size;
3261           }
3262           xoffset += attributes.border.width/2;
3263           break;
3264    }
3265
3266   if(!gtk_sheet_clip_text(sheet)) clip_area = area;
3267   gdk_gc_set_clip_rectangle(fg_gc, &clip_area);
3268
3269
3270   gdk_draw_layout (sheet->pixmap, fg_gc,
3271                    area.x + xoffset + CELLOFFSET,
3272                    y,
3273                    layout);
3274
3275   gdk_gc_set_clip_rectangle(fg_gc, NULL);
3276   g_object_unref(G_OBJECT(layout));
3277
3278   gdk_draw_pixmap(sheet->sheet_window,
3279                   GTK_WIDGET(sheet)->style->fg_gc[GTK_STATE_NORMAL],
3280                   sheet->pixmap,
3281                   area.x,
3282                   area.y,
3283                   area.x,
3284                   area.y,
3285                   area.width,
3286                   area.height);      
3287
3288 }
3289
3290
3291
3292 static void
3293 gtk_sheet_range_draw(GtkSheet *sheet, const GtkSheetRange *range)
3294 {
3295  gint i,j;
3296  GtkSheetRange drawing_range;
3297  GdkRectangle area;
3298
3299  g_return_if_fail(sheet != NULL);
3300  g_return_if_fail(GTK_SHEET(sheet));
3301  
3302  if(!GTK_WIDGET_DRAWABLE(GTK_WIDGET(sheet))) return;
3303  if(!GTK_WIDGET_REALIZED(GTK_WIDGET(sheet))) return;
3304  if(!GTK_WIDGET_MAPPED(GTK_WIDGET(sheet))) return;
3305
3306  if(range == NULL)
3307  {
3308    drawing_range.row0=MIN_VISIBLE_ROW(sheet);
3309    drawing_range.col0=MIN_VISIBLE_COLUMN(sheet);
3310    drawing_range.rowi=MAX_VISIBLE_ROW(sheet);
3311    drawing_range.coli=MAX_VISIBLE_COLUMN(sheet);
3312 /*
3313    gdk_draw_rectangle (sheet->pixmap,
3314                        GTK_WIDGET(sheet)->style->white_gc,
3315                        TRUE,
3316                        0,0,
3317                        sheet->sheet_window_width,sheet->sheet_window_height);
3318 */
3319  }
3320  else
3321  {
3322    drawing_range.row0=MAX(range->row0, MIN_VISIBLE_ROW(sheet));
3323    drawing_range.col0=MAX(range->col0, MIN_VISIBLE_COLUMN(sheet));
3324    drawing_range.rowi=MIN(range->rowi, MAX_VISIBLE_ROW(sheet));
3325    drawing_range.coli=MIN(range->coli, MAX_VISIBLE_COLUMN(sheet));
3326  }
3327
3328
3329  if(drawing_range.coli == xxx_column_count(sheet) - 1)
3330    {
3331      area.x=COLUMN_LEFT_XPIXEL(sheet,
3332                                xxx_column_count(sheet) - 1) +
3333        xxx_column_width(sheet, xxx_column_count(sheet) - 1) + 1;
3334
3335      area.y=0;
3336
3337      gdk_gc_set_foreground(sheet->fg_gc, &sheet->bg_color);
3338
3339      gdk_draw_rectangle (sheet->pixmap,
3340                          sheet->fg_gc,
3341                          TRUE,
3342                          area.x,area.y,
3343                          sheet->sheet_window_width - area.x, 
3344                          sheet->sheet_window_height);
3345
3346      gdk_draw_pixmap(sheet->sheet_window,
3347                      GTK_WIDGET(sheet)->style->fg_gc[GTK_STATE_NORMAL],
3348                      sheet->pixmap,
3349                      area.x,
3350                      area.y,
3351                      area.x,
3352                      area.y,
3353                      sheet->sheet_window_width - area.x, 
3354                      sheet->sheet_window_height);                  
3355    }
3356  
3357  if(drawing_range.rowi == yyy_row_count(sheet) - 1){
3358   area.x=0;
3359   area.y=ROW_TOP_YPIXEL(sheet,
3360                         yyy_row_count(sheet) - 1) + 
3361     yyy_row_height(sheet, yyy_row_count(sheet) - 1) + 1;
3362
3363   gdk_gc_set_foreground(sheet->fg_gc, &sheet->bg_color);
3364
3365   gdk_draw_rectangle (sheet->pixmap,
3366                       sheet->fg_gc,
3367                       TRUE,
3368                       area.x,area.y,
3369                       sheet->sheet_window_width,
3370                       sheet->sheet_window_height - area.y);
3371
3372   gdk_draw_pixmap(sheet->sheet_window,
3373                   GTK_WIDGET(sheet)->style->fg_gc[GTK_STATE_NORMAL],
3374                   sheet->pixmap,
3375                   area.x,
3376                   area.y,
3377                   area.x,
3378                   area.y,
3379                   sheet->sheet_window_width,
3380                   sheet->sheet_window_height - area.y);
3381  }
3382
3383  for(i=drawing_range.row0; i<=drawing_range.rowi; i++)
3384   for(j=drawing_range.col0; j<=drawing_range.coli; j++){
3385      gtk_sheet_cell_draw_default(sheet, i, j);
3386   }
3387
3388  for(i=drawing_range.row0; i<=drawing_range.rowi; i++)
3389   for(j=drawing_range.col0; j<=drawing_range.coli; j++){
3390      gtk_sheet_cell_draw_border(sheet, i-1, j, GTK_SHEET_BOTTOM_BORDER);
3391      gtk_sheet_cell_draw_border(sheet, i+1, j, GTK_SHEET_TOP_BORDER);
3392      gtk_sheet_cell_draw_border(sheet, i, j-1, GTK_SHEET_RIGHT_BORDER);
3393      gtk_sheet_cell_draw_border(sheet, i, j+1, GTK_SHEET_LEFT_BORDER);
3394      gtk_sheet_cell_draw_border(sheet, i, j, 15);
3395   }
3396
3397  for(i=drawing_range.row0; i<=drawing_range.rowi; i++)
3398   for(j=drawing_range.col0; j<=drawing_range.coli; j++)
3399                   gtk_sheet_cell_draw_label (sheet, i, j);
3400      
3401  for(i=drawing_range.row0; i<=drawing_range.rowi; i++)
3402    for(j= xxx_column_left_column(sheet, drawing_range.col0);
3403        j<drawing_range.col0; j++)
3404      gtk_sheet_cell_draw_label (sheet, i, j);
3405     
3406  for(i=drawing_range.row0; i<=drawing_range.rowi; i++)
3407    for(j = drawing_range.coli+1; 
3408        j <= xxx_column_right_column(sheet, drawing_range.coli);
3409        j++)
3410      gtk_sheet_cell_draw_label (sheet, i, j); 
3411
3412   gtk_sheet_draw_backing_pixmap(sheet, drawing_range);
3413
3414   if(sheet->state != GTK_SHEET_NORMAL && gtk_sheet_range_isvisible(sheet, sheet->range))
3415        gtk_sheet_range_draw_selection(sheet, drawing_range);
3416   
3417   if(sheet->state == GTK_STATE_NORMAL && 
3418      sheet->active_cell.row >= drawing_range.row0 &&
3419      sheet->active_cell.row <= drawing_range.rowi &&
3420      sheet->active_cell.col >= drawing_range.col0 &&
3421      sheet->active_cell.col <= drawing_range.coli)    
3422                             gtk_sheet_show_active_cell(sheet);
3423
3424 }
3425
3426 static void
3427 gtk_sheet_range_draw_selection(GtkSheet *sheet, GtkSheetRange range)
3428 {
3429   GdkRectangle area;
3430   gint i,j;
3431   GtkSheetRange aux;
3432
3433   if(range.col0 > sheet->range.coli || range.coli < sheet->range.col0 ||
3434      range.row0 > sheet->range.rowi || range.rowi < sheet->range.row0)
3435      return;
3436
3437   if(!gtk_sheet_range_isvisible(sheet, range)) return;
3438   if(!GTK_WIDGET_REALIZED(GTK_WIDGET(sheet))) return;
3439
3440   aux=range;
3441
3442   range.col0=MAX(sheet->range.col0, range.col0);
3443   range.coli=MIN(sheet->range.coli, range.coli);
3444   range.row0=MAX(sheet->range.row0, range.row0);
3445   range.rowi=MIN(sheet->range.rowi, range.rowi);
3446
3447   range.col0=MAX(range.col0, MIN_VISIBLE_COLUMN(sheet));
3448   range.coli=MIN(range.coli, MAX_VISIBLE_COLUMN(sheet));
3449   range.row0=MAX(range.row0, MIN_VISIBLE_ROW(sheet));
3450   range.rowi=MIN(range.rowi, MAX_VISIBLE_ROW(sheet));
3451
3452   for(i=range.row0; i<=range.rowi; i++){
3453    for(j=range.col0; j<=range.coli; j++){
3454
3455     if(gtk_sheet_cell_get_state(sheet, i, j)==GTK_STATE_SELECTED && 
3456        xxx_column_is_visible(sheet, j) && yyy_row_is_visible(sheet, i)){
3457
3458 #if 0
3459       row_button_set(sheet, i);
3460       column_button_set(sheet, j);
3461 #endif
3462
3463       area.x=COLUMN_LEFT_XPIXEL(sheet,j);
3464       area.y=ROW_TOP_YPIXEL(sheet,i);
3465       area.width= xxx_column_width(sheet, j);
3466       area.height=yyy_row_height(sheet, i);
3467
3468       if(i==sheet->range.row0){
3469             area.y=area.y+2;
3470             area.height=area.height-2;
3471       }
3472       if(i==sheet->range.rowi) area.height=area.height-3;
3473       if(j==sheet->range.col0){
3474             area.x=area.x+2;
3475             area.width=area.width-2;
3476       }
3477       if(j==sheet->range.coli) area.width=area.width-3;
3478
3479       if(i!=sheet->active_cell.row || j!=sheet->active_cell.col){
3480        gdk_draw_rectangle (sheet->sheet_window,
3481                            sheet->xor_gc,
3482                            TRUE,
3483                            area.x+1,area.y+1,
3484                            area.width,area.height);
3485       }
3486     }
3487
3488    }
3489   }
3490
3491   gtk_sheet_draw_border(sheet, sheet->range);
3492
3493 }
3494
3495 static void
3496 gtk_sheet_draw_backing_pixmap(GtkSheet *sheet, GtkSheetRange range)
3497 {
3498   gint x,y,width,height;
3499   
3500   if(!GTK_WIDGET_REALIZED(GTK_WIDGET(sheet))) return;
3501  
3502   x = COLUMN_LEFT_XPIXEL(sheet,range.col0);
3503   y = ROW_TOP_YPIXEL(sheet, range.row0);  
3504   width = COLUMN_LEFT_XPIXEL(sheet, range.coli) - x +
3505     xxx_column_width(sheet, range.coli);
3506
3507   height=ROW_TOP_YPIXEL(sheet, range.rowi)-y+yyy_row_height(sheet, range.rowi);
3508
3509   if(range.row0==sheet->range.row0){
3510           y=y-5;
3511           height=height+5;
3512   }
3513   if(range.rowi==sheet->range.rowi) height=height+5;
3514   if(range.col0==sheet->range.col0){
3515             x=x-5;
3516             width=width+5;
3517   }
3518   if(range.coli==sheet->range.coli) width=width+5;
3519
3520   
3521   width=MIN(width, sheet->sheet_window_width-x);
3522   height=MIN(height, sheet->sheet_window_height-y);
3523
3524   x--; 
3525   y--;
3526   width+=2;
3527   height+=2;
3528
3529   x = (sheet->row_titles_visible)
3530        ? MAX(x, sheet->row_title_area.width) : MAX(x, 0);
3531   y = (sheet->column_titles_visible)
3532        ? MAX(y, sheet->column_title_area.height) : MAX(y, 0);
3533
3534   if(range.coli == xxx_column_count(sheet) - 1) 
3535     width = sheet->sheet_window_width - x; 
3536   if(range.rowi == yyy_row_count(sheet)    - 1) 
3537     height=sheet->sheet_window_height - y;
3538
3539   gdk_draw_pixmap(sheet->sheet_window,
3540                   GTK_WIDGET(sheet)->style->fg_gc[GTK_STATE_NORMAL],
3541                   sheet->pixmap,
3542                   x,
3543                   y,
3544                   x,
3545                   y,
3546                   width+1,
3547                   height+1);                  
3548 }
3549
3550
3551 void 
3552 gtk_sheet_set_cell_text(GtkSheet *sheet, gint row, gint col, const gchar *text)
3553 {
3554  GtkSheetCellAttr attributes;
3555
3556  g_return_if_fail (sheet != NULL);
3557  g_return_if_fail (GTK_IS_SHEET (sheet));
3558  if (col >= xxx_column_count(sheet) || row >= yyy_row_count(sheet)) return;
3559  if (col < 0 || row < 0) return;
3560
3561  gtk_sheet_get_attributes(sheet, row, col, &attributes);
3562  gtk_sheet_set_cell(sheet, row, col, attributes.justification, text);
3563 }
3564
3565 static inline gint 
3566 safe_strcmp(const gchar *s1, const gchar *s2)
3567 {
3568   if ( !s1 && !s2) return 0;
3569   if ( !s1) return -1;
3570   if ( !s2) return +1;
3571   return strcmp(s1, s2);
3572 }
3573
3574 void 
3575 gtk_sheet_set_cell(GtkSheet *sheet, gint row, gint col, 
3576                    GtkJustification justification,
3577                    const gchar *text)
3578 {
3579   GSheetModel *model ;
3580   gboolean changed ;
3581   gchar *old_text ; 
3582
3583   GtkSheetRange range;
3584   gint text_width;
3585   GtkSheetCellAttr attributes;
3586
3587   g_return_if_fail (sheet != NULL);
3588   g_return_if_fail (GTK_IS_SHEET (sheet));
3589   if (col >= xxx_column_count(sheet) || row >= yyy_row_count(sheet)) return;
3590   if (col < 0 || row < 0) return;
3591
3592   gtk_sheet_get_attributes(sheet, row, col, &attributes);
3593
3594   attributes.justification = justification;
3595
3596   model =  gtk_sheet_get_model(sheet);
3597
3598   old_text = g_sheet_model_get_string(model, row, col);
3599
3600   changed = FALSE;
3601
3602   if (0 != safe_strcmp(old_text, text))
3603     changed = g_sheet_model_set_string(model, text, row, col);
3604
3605   if ( g_sheet_model_free_strings(model))
3606     g_free(old_text);
3607
3608
3609   if(changed && attributes.is_visible)
3610     {
3611       gchar *s = gtk_sheet_cell_get_text(sheet, row, col);
3612       text_width = 0;
3613       if(s && strlen(s) > 0) {
3614         text_width = STRING_WIDTH(GTK_WIDGET(sheet), 
3615                                   attributes.font_desc, text);
3616       }
3617       dispose_string(sheet, s);
3618
3619     range.row0 = row;
3620     range.rowi = row;
3621     range.col0 = sheet->view.col0;
3622     range.coli = sheet->view.coli;
3623
3624     if(gtk_sheet_autoresize(sheet) &&
3625        text_width > xxx_column_width(sheet, col) - 2*CELLOFFSET-attributes.border.width){
3626       gtk_sheet_set_column_width(sheet, col, text_width+2*CELLOFFSET+attributes.border.width);
3627       GTK_SHEET_SET_FLAGS(sheet, GTK_SHEET_REDRAW_PENDING);
3628     }
3629     else
3630       if(!GTK_SHEET_IS_FROZEN(sheet))
3631         gtk_sheet_range_draw(sheet, &range);
3632   }
3633
3634   if ( changed ) 
3635     gtk_signal_emit(GTK_OBJECT(sheet),sheet_signals[CHANGED], row, col);
3636
3637 }
3638
3639
3640 void
3641 gtk_sheet_cell_clear (GtkSheet *sheet, gint row, gint column)
3642 {
3643   GtkSheetRange range;
3644
3645   g_return_if_fail (sheet != NULL);
3646   g_return_if_fail (GTK_IS_SHEET (sheet));
3647   if (column >= xxx_column_count(sheet) || row >= yyy_row_count(sheet)) return;
3648   if (column < 0 || row < 0) return;
3649
3650   range.row0 = row;
3651   range.rowi = row;
3652   range.col0 = sheet->view.col0;
3653   range.coli = sheet->view.coli;
3654
3655   gtk_sheet_real_cell_clear(sheet, row, column, FALSE);
3656
3657   if(!GTK_SHEET_IS_FROZEN(sheet)){
3658      gtk_sheet_range_draw(sheet, &range);
3659   }
3660 }
3661
3662 void
3663 gtk_sheet_cell_delete (GtkSheet *sheet, gint row, gint column)
3664 {
3665   GtkSheetRange range;
3666
3667   g_return_if_fail (sheet != NULL);
3668   g_return_if_fail (GTK_IS_SHEET (sheet));
3669   if (column >= xxx_column_count(sheet) || row >= yyy_row_count(sheet)) return;
3670   if (column < 0 || row < 0) return;
3671
3672   range.row0 = row;
3673   range.rowi = row;
3674   range.col0 = sheet->view.col0;
3675   range.coli = sheet->view.coli;
3676
3677   gtk_sheet_real_cell_clear(sheet, row, column, TRUE);
3678
3679   if(!GTK_SHEET_IS_FROZEN(sheet)){
3680      gtk_sheet_range_draw(sheet, &range);
3681   }
3682 }
3683
3684 static void
3685 gtk_sheet_real_cell_clear (GtkSheet *sheet, gint row, gint column, gboolean delete)
3686 {
3687   GSheetModel *model =  gtk_sheet_get_model(sheet);
3688
3689   gchar *old_text = gtk_sheet_cell_get_text(sheet, row, column); 
3690  
3691   if (old_text && strlen(old_text) > 0 )
3692     {
3693       g_sheet_model_datum_clear(model, row, column);
3694       
3695       if(GTK_IS_OBJECT(sheet) && G_OBJECT(sheet)->ref_count > 0)
3696         gtk_signal_emit(GTK_OBJECT(sheet),sheet_signals[CLEAR_CELL], 
3697                         row, column);
3698     }  
3699
3700   dispose_string (sheet, old_text);
3701 }
3702     
3703 void
3704 gtk_sheet_range_clear (GtkSheet *sheet, const GtkSheetRange *range)
3705 {
3706   g_return_if_fail (sheet != NULL);
3707   g_return_if_fail (GTK_IS_SHEET (sheet));
3708
3709   gtk_sheet_real_range_clear(sheet, range, FALSE);
3710 }
3711
3712 void
3713 gtk_sheet_range_delete (GtkSheet *sheet, const GtkSheetRange *range)
3714 {
3715   g_return_if_fail (sheet != NULL);
3716   g_return_if_fail (GTK_IS_SHEET (sheet));
3717
3718   gtk_sheet_real_range_clear(sheet, range, TRUE);
3719 }
3720  
3721
3722 static void
3723 gtk_sheet_real_range_clear (GtkSheet *sheet, const GtkSheetRange *range, 
3724                             gboolean delete)
3725 {
3726   gint i, j;
3727   GtkSheetRange clear;
3728
3729   if(!range){
3730     clear.row0=0;
3731     clear.rowi = yyy_row_count(sheet) - 1;
3732     clear.col0=0;
3733     clear.coli = xxx_column_count(sheet) - 1;
3734   }else
3735     clear=*range;  
3736
3737   clear.row0=MAX(clear.row0, 0);
3738   clear.col0=MAX(clear.col0, 0);
3739   clear.rowi=MIN(clear.rowi, yyy_row_count(sheet) - 1 );
3740   clear.coli=MIN(clear.coli, xxx_column_count(sheet) - 1 );
3741
3742   for(i=clear.row0; i<=clear.rowi; i++)
3743     for(j=clear.col0; j<=clear.coli; j++){
3744       gtk_sheet_real_cell_clear(sheet, i, j, delete);
3745     }
3746
3747   gtk_sheet_range_draw(sheet, NULL);
3748 }
3749
3750
3751 static gboolean
3752 gtk_sheet_cell_empty (const GtkSheet *sheet, gint row, gint col)
3753 {
3754   gboolean empty;
3755   char *text = gtk_sheet_cell_get_text(sheet, row, col);
3756   empty = (text == NULL );
3757  
3758   dispose_string(sheet, text);
3759
3760   return empty;
3761 }
3762
3763
3764 gchar *     
3765 gtk_sheet_cell_get_text (const GtkSheet *sheet, gint row, gint col)
3766 {
3767   GSheetModel *model;
3768   g_return_val_if_fail (sheet != NULL, NULL);
3769   g_return_val_if_fail (GTK_IS_SHEET (sheet), NULL);
3770
3771   if(col >= xxx_column_count(sheet) || row >= yyy_row_count(sheet)) 
3772     return NULL;
3773   if(col < 0 || row < 0) return NULL;
3774
3775   model =  gtk_sheet_get_model(sheet);
3776
3777   if ( !model ) 
3778     return NULL;
3779
3780   return g_sheet_model_get_string(model, row, col);
3781 }
3782
3783
3784 GtkStateType
3785 gtk_sheet_cell_get_state (GtkSheet *sheet, gint row, gint col)
3786 {
3787  gint state;
3788  GtkSheetRange *range;
3789
3790  g_return_val_if_fail (sheet != NULL, 0);
3791  g_return_val_if_fail (GTK_IS_SHEET (sheet), 0);
3792  if(col >= xxx_column_count(sheet) || row >= yyy_row_count(sheet)) return 0;
3793  if(col < 0 || row < 0) return 0;
3794
3795  state = sheet->state;
3796  range = &sheet->range;
3797
3798  switch (state)
3799    {
3800    case GTK_SHEET_NORMAL:
3801      return GTK_STATE_NORMAL;
3802      break;
3803    case GTK_SHEET_ROW_SELECTED:
3804      if(row>=range->row0 && row<=range->rowi) 
3805        return GTK_STATE_SELECTED;
3806      break;
3807    case GTK_SHEET_COLUMN_SELECTED:
3808      if(col>=range->col0 && col<=range->coli) 
3809        return GTK_STATE_SELECTED;
3810      break;
3811    case GTK_SHEET_RANGE_SELECTED:
3812      if(row >= range->row0 && row <= range->rowi && \
3813         col >= range->col0 && col <= range->coli)
3814        return GTK_STATE_SELECTED;
3815      break;
3816    }
3817  return GTK_STATE_NORMAL;
3818 }
3819
3820 gboolean
3821 gtk_sheet_get_pixel_info (GtkSheet * sheet,
3822                           gint x,
3823                           gint y,
3824                           gint * row,
3825                           gint * column)
3826 {
3827   gint trow, tcol;
3828
3829   g_return_val_if_fail (sheet != NULL, 0);
3830   g_return_val_if_fail (GTK_IS_SHEET (sheet), 0);
3831
3832   /* bounds checking, return false if the user clicked 
3833    * on a blank area */
3834   trow = ROW_FROM_YPIXEL (sheet, y);
3835   if (trow >= yyy_row_count(sheet))
3836     return FALSE;
3837
3838   *row = trow;
3839
3840   tcol = COLUMN_FROM_XPIXEL (sheet, x);
3841   if (tcol >= xxx_column_count(sheet))
3842     return FALSE;
3843
3844  *column = tcol;
3845
3846   return TRUE;
3847 }
3848
3849 gboolean
3850 gtk_sheet_get_cell_area  (GtkSheet * sheet,
3851                           gint row,
3852                           gint column,
3853                           GdkRectangle *area)
3854 {
3855   g_return_val_if_fail (sheet != NULL, 0);
3856   g_return_val_if_fail (GTK_IS_SHEET (sheet), 0);
3857
3858   if(row >= yyy_row_count(sheet) || column >= xxx_column_count(sheet)) 
3859     return FALSE;
3860
3861   area->x = (column == -1) ? 0 : (COLUMN_LEFT_XPIXEL(sheet, column) -
3862                                  (sheet->row_titles_visible
3863                                    ? sheet->row_title_area.width
3864                                    : 0));
3865   area->y = (row == -1) ? 0 : (ROW_TOP_YPIXEL(sheet, row) -
3866                               (sheet->column_titles_visible
3867                                ? sheet->column_title_area.height
3868                                : 0));
3869   area->width= (column == -1) ? sheet->row_title_area.width
3870     : xxx_column_width(sheet, column);
3871
3872   area->height= (row == -1) ? sheet->column_title_area.height
3873                             : yyy_row_height(sheet, row);
3874
3875 /*
3876   if(row < 0 || column < 0) return FALSE;
3877
3878   area->x = COLUMN_LEFT_XPIXEL(sheet, column);
3879   area->y = ROW_TOP_YPIXEL(sheet, row);
3880   if(sheet->row_titles_visible)
3881            area->x -= sheet->row_title_area.width;
3882   if(sheet->column_titles_visible)
3883            area->y -= sheet->column_title_area.height;
3884
3885   area->width=sheet->column[column].width;
3886   area->height=yyy_row_height(sheet, row);  
3887 */
3888   return TRUE;
3889 }
3890
3891 gboolean 
3892 gtk_sheet_set_active_cell (GtkSheet *sheet, gint row, gint column)
3893 {
3894  g_return_val_if_fail (sheet != NULL, 0);
3895  g_return_val_if_fail (GTK_IS_SHEET (sheet), 0);
3896
3897  if(row < -1 || column < -1) return FALSE;
3898  if(row >= yyy_row_count(sheet) || column >= xxx_column_count(sheet)) 
3899    return FALSE;
3900
3901  if(GTK_WIDGET_REALIZED(GTK_WIDGET(sheet)))
3902    {
3903        if(!gtk_sheet_deactivate_cell(sheet)) return FALSE;
3904    }
3905
3906  sheet->active_cell.row = row;
3907  sheet->active_cell.col = column;
3908  
3909  if ( row == -1 || column == -1)
3910    {
3911      gtk_sheet_hide_active_cell(sheet);
3912      return TRUE;
3913    }
3914
3915  if(!gtk_sheet_activate_cell(sheet, row, column)) return FALSE;
3916  
3917  if(gtk_sheet_autoscroll(sheet))
3918    gtk_sheet_move_query(sheet, row, column);
3919
3920  return TRUE;
3921 }
3922
3923 void
3924 gtk_sheet_get_active_cell (GtkSheet *sheet, gint *row, gint *column)
3925 {
3926   g_return_if_fail (sheet != NULL);
3927   g_return_if_fail (GTK_IS_SHEET (sheet));
3928
3929   *row = sheet->active_cell.row;
3930   *column = sheet->active_cell.col;
3931 }
3932
3933 static void
3934 gtk_sheet_entry_changed(GtkWidget *widget, gpointer data)
3935 {
3936  GtkSheet *sheet;
3937  gint row,col;
3938  const char *text;
3939  GtkJustification justification;
3940  GtkSheetCellAttr attributes;
3941
3942  g_return_if_fail (data != NULL);
3943  g_return_if_fail (GTK_IS_SHEET (data));
3944
3945  sheet=GTK_SHEET(data);
3946
3947  if(!GTK_WIDGET_VISIBLE(widget)) return;
3948  if(sheet->state != GTK_STATE_NORMAL) return;
3949
3950  row=sheet->active_cell.row;
3951  col=sheet->active_cell.col;
3952
3953  if(row<0 || col<0) return;
3954
3955  sheet->active_cell.row=-1;
3956  sheet->active_cell.col=-1;
3957
3958  text = gtk_entry_get_text(GTK_ENTRY(gtk_sheet_get_entry(sheet)));
3959
3960  GTK_SHEET_SET_FLAGS(sheet, GTK_SHEET_IS_FROZEN);
3961
3962  if(text && strlen(text) > 0){
3963       gtk_sheet_get_attributes(sheet, row, col, &attributes); 
3964       justification=attributes.justification;
3965       gtk_sheet_set_cell(sheet, row, col, justification, text);
3966  }
3967
3968  if(sheet->freeze_count == 0)
3969         GTK_SHEET_UNSET_FLAGS(sheet, GTK_SHEET_IS_FROZEN);
3970  
3971  sheet->active_cell.row=row;;
3972  sheet->active_cell.col=col;
3973 }
3974
3975
3976 static gboolean 
3977 gtk_sheet_deactivate_cell(GtkSheet *sheet)
3978 {
3979  gboolean veto = TRUE;
3980
3981  g_return_val_if_fail (sheet != NULL, FALSE);
3982  g_return_val_if_fail (GTK_IS_SHEET (sheet), FALSE);
3983
3984  if(!GTK_WIDGET_REALIZED(GTK_WIDGET(sheet))) return FALSE;
3985  if(sheet->state != GTK_SHEET_NORMAL) return FALSE;
3986
3987  _gtkextra_signal_emit(GTK_OBJECT(sheet),sheet_signals[DEACTIVATE], 
3988                                    sheet->active_cell.row,
3989                                    sheet->active_cell.col, &veto);
3990
3991  if(!veto) return FALSE;
3992
3993  if ( sheet->active_cell.row == -1 || sheet->active_cell.col == -1 )
3994    return TRUE;
3995
3996  gtk_signal_disconnect_by_func(GTK_OBJECT(gtk_sheet_get_entry(sheet)),
3997                                (GtkSignalFunc) gtk_sheet_entry_changed,
3998                                GTK_OBJECT(GTK_WIDGET(sheet)));
3999
4000  gtk_sheet_hide_active_cell(sheet);
4001  sheet->active_cell.row = -1;
4002  sheet->active_cell.col = -1;
4003  
4004  if(GTK_SHEET_REDRAW_PENDING(sheet)){
4005    GTK_SHEET_UNSET_FLAGS(sheet, GTK_SHEET_REDRAW_PENDING);
4006    gtk_sheet_range_draw(sheet, NULL);
4007  }
4008
4009  return TRUE;
4010 }       
4011
4012 static void
4013 gtk_sheet_hide_active_cell(GtkSheet *sheet)
4014 {
4015  const char *text;
4016  gint row,col;
4017  GtkJustification justification;
4018  GtkSheetCellAttr attributes;
4019
4020  if(!GTK_WIDGET_REALIZED(GTK_WIDGET(sheet))) return;
4021
4022  row=sheet->active_cell.row;
4023  col=sheet->active_cell.col;
4024
4025  if(row < 0 || col < 0) return;
4026
4027  if(sheet->freeze_count == 0)
4028      GTK_SHEET_UNSET_FLAGS(sheet, GTK_SHEET_IS_FROZEN);
4029
4030  text=gtk_entry_get_text(GTK_ENTRY(gtk_sheet_get_entry(sheet)));
4031
4032  gtk_sheet_get_attributes(sheet, row, col, &attributes); 
4033  justification=attributes.justification;
4034
4035  if(text && strlen(text) != 0) 
4036  {
4037       gtk_sheet_set_cell(sheet, row, col, justification, text);
4038       gtk_signal_emit(GTK_OBJECT(sheet),sheet_signals[SET_CELL], row, col);
4039  }
4040  else
4041  {
4042       gtk_sheet_cell_clear(sheet, row, col);
4043  }
4044
4045  row=sheet->active_cell.row;
4046  col=sheet->active_cell.col;
4047
4048 #if 0
4049  column_button_release(sheet, col);
4050  row_button_release(sheet, row);
4051 #endif
4052
4053  gtk_widget_hide(sheet->sheet_entry);
4054  gtk_widget_unmap(sheet->sheet_entry);
4055
4056  if(row != -1 && col != -1)
4057    gdk_draw_pixmap(sheet->sheet_window,
4058                    GTK_WIDGET(sheet)->style->fg_gc[GTK_STATE_NORMAL],
4059                    sheet->pixmap,
4060                    COLUMN_LEFT_XPIXEL(sheet,col)-1,
4061                    ROW_TOP_YPIXEL(sheet,row)-1,
4062                    COLUMN_LEFT_XPIXEL(sheet,col)-1,
4063                    ROW_TOP_YPIXEL(sheet,row)-1,
4064                    xxx_column_width(sheet, col) + 4,
4065                    yyy_row_height(sheet, row)+4);   
4066
4067  gtk_widget_grab_focus(GTK_WIDGET(sheet));
4068
4069  GTK_WIDGET_UNSET_FLAGS(GTK_WIDGET(sheet->sheet_entry), GTK_VISIBLE);
4070
4071 }
4072
4073 static gboolean
4074 gtk_sheet_activate_cell(GtkSheet *sheet, gint row, gint col)
4075 {
4076  gboolean veto = TRUE;
4077
4078  g_return_val_if_fail (sheet != NULL, FALSE);
4079  g_return_val_if_fail (GTK_IS_SHEET (sheet), FALSE);
4080
4081  if(row < 0 || col < 0) return FALSE;
4082  if(row >= yyy_row_count(sheet) || col >= xxx_column_count(sheet)) 
4083    return FALSE;
4084
4085 /* _gtkextra_signal_emit(GTK_OBJECT(sheet),sheet_signals[ACTIVATE], row, col, &veto);
4086  if(!GTK_WIDGET_REALIZED(GTK_WIDGET(sheet))) return veto;
4087 */
4088
4089  if(!veto) return FALSE;
4090  if(sheet->state != GTK_SHEET_NORMAL){
4091         sheet->state=GTK_SHEET_NORMAL;
4092         gtk_sheet_real_unselect_range(sheet, NULL);
4093  }
4094
4095  sheet->range.row0=row;
4096  sheet->range.col0=col;
4097  sheet->range.rowi=row;
4098  sheet->range.coli=col;
4099  sheet->active_cell.row=row;
4100  sheet->active_cell.col=col;
4101  sheet->selection_cell.row=row;
4102  sheet->selection_cell.col=col;
4103 #if 0
4104  row_button_set(sheet, row);
4105  column_button_set(sheet, col); 
4106 #endif
4107
4108  GTK_SHEET_UNSET_FLAGS(sheet, GTK_SHEET_IN_SELECTION);
4109  gtk_sheet_show_active_cell(sheet);
4110
4111    g_signal_connect(G_OBJECT(gtk_sheet_get_entry(sheet)),
4112                     "changed",
4113                     G_CALLBACK(gtk_sheet_entry_changed),
4114                     sheet);
4115
4116  _gtkextra_signal_emit(GTK_OBJECT(sheet),sheet_signals[ACTIVATE], row, col, &veto);
4117
4118  return TRUE;
4119 }
4120
4121 static void
4122 gtk_sheet_show_active_cell(GtkSheet *sheet)
4123 {
4124  GtkEntry *sheet_entry;
4125  GtkSheetCellAttr attributes;
4126  gchar *text = NULL;
4127  const gchar *old_text;
4128  GtkJustification justification;
4129  gint row, col;
4130
4131  g_return_if_fail (sheet != NULL);
4132  g_return_if_fail (GTK_IS_SHEET (sheet));
4133
4134  row = sheet->active_cell.row;
4135  col = sheet->active_cell.col;
4136
4137  /* Don't show the active cell, if there is no active cell: */
4138  if(!(row >= 0 && col >= 0)) /* e.g row or coll == -1. */
4139    return;
4140
4141  if(!GTK_WIDGET_REALIZED(GTK_WIDGET(sheet))) return;
4142  if(sheet->state != GTK_SHEET_NORMAL) return;
4143  if(GTK_SHEET_IN_SELECTION(sheet)) return;
4144
4145  GTK_WIDGET_SET_FLAGS(GTK_WIDGET(sheet->sheet_entry), GTK_VISIBLE);
4146
4147  sheet_entry = GTK_ENTRY(gtk_sheet_get_entry(sheet));
4148
4149  gtk_sheet_get_attributes(sheet, row, col, &attributes); 
4150
4151  justification = GTK_JUSTIFY_LEFT;
4152
4153  if(gtk_sheet_justify_entry(sheet))
4154       justification = attributes.justification;
4155
4156  text = gtk_sheet_cell_get_text(sheet, row, col);
4157  if ( ! text ) 
4158          text = g_strdup("");
4159
4160  gtk_entry_set_visibility(GTK_ENTRY(sheet_entry), attributes.is_visible);
4161
4162  if(gtk_sheet_locked(sheet) || !attributes.is_editable)
4163    gtk_entry_set_editable(GTK_ENTRY(sheet_entry), FALSE);
4164  else
4165    gtk_entry_set_editable(GTK_ENTRY(sheet_entry), TRUE);
4166
4167 /*** Added by John Gotts. Mar 25, 2005 *********/
4168  old_text = gtk_entry_get_text(GTK_ENTRY(sheet_entry));
4169  if (strcmp(old_text, text) != 0) 
4170 {
4171   if(!GTK_IS_ITEM_ENTRY(sheet_entry))
4172      gtk_entry_set_text(GTK_ENTRY(sheet_entry), text);
4173   else
4174      gtk_item_entry_set_text(GTK_ITEM_ENTRY(sheet_entry), text, justification);
4175  }
4176
4177  gtk_sheet_entry_set_max_size(sheet);
4178  gtk_sheet_size_allocate_entry(sheet);
4179
4180  gtk_widget_map(sheet->sheet_entry);
4181  gtk_sheet_draw_active_cell(sheet);
4182
4183  gtk_widget_grab_focus(GTK_WIDGET(sheet_entry));
4184
4185  dispose_string(sheet, text);
4186 }
4187
4188 static void
4189 gtk_sheet_draw_active_cell(GtkSheet *sheet)
4190 {
4191     gint row, col;
4192
4193     if(!GTK_WIDGET_DRAWABLE(GTK_WIDGET(sheet))) return;
4194     if(!GTK_WIDGET_REALIZED(GTK_WIDGET(sheet))) return;
4195
4196     row = sheet->active_cell.row;
4197     col = sheet->active_cell.col;
4198  
4199     if(row < 0 || col < 0) return;
4200
4201     if(!gtk_sheet_cell_isvisible(sheet, row, col)) return;
4202 #if 0
4203     row_button_set(sheet, row);
4204     column_button_set(sheet, col);
4205 #endif
4206     gtk_sheet_draw_backing_pixmap(sheet, sheet->range);
4207     gtk_sheet_draw_border(sheet, sheet->range);
4208 }
4209
4210
4211 static void
4212 gtk_sheet_make_backing_pixmap (GtkSheet *sheet, guint width, guint height)
4213 {
4214   gint pixmap_width, pixmap_height;
4215
4216   if(!GTK_WIDGET_REALIZED(GTK_WIDGET(sheet))) return;
4217
4218   if(width == 0 && height == 0){
4219      width=sheet->sheet_window_width+80;
4220      height=sheet->sheet_window_height+80;
4221   }
4222
4223   if (!sheet->pixmap)
4224     {
4225       /* allocate */
4226       sheet->pixmap = gdk_pixmap_new (sheet->sheet_window,
4227                                       width, height,
4228                                       -1);
4229       if(!GTK_SHEET_IS_FROZEN(sheet)) gtk_sheet_range_draw(sheet, NULL);
4230     }
4231   else
4232     {
4233       /* reallocate if sizes don't match */
4234       gdk_window_get_size (sheet->pixmap,
4235                            &pixmap_width, &pixmap_height);
4236       if ((pixmap_width != width) || (pixmap_height != height))
4237         {
4238           g_object_unref(sheet->pixmap);
4239           sheet->pixmap = gdk_pixmap_new (sheet->sheet_window,
4240                                                width, height,
4241                                                -1);
4242           if(!GTK_SHEET_IS_FROZEN(sheet)) gtk_sheet_range_draw(sheet, NULL);
4243         }
4244     }
4245 }
4246
4247 static void
4248 gtk_sheet_new_selection(GtkSheet *sheet, GtkSheetRange *range)
4249 {
4250   gint i,j, mask1, mask2;
4251   gint state, selected;
4252   gint x,y,width,height;
4253   GtkSheetRange new_range, aux_range;
4254
4255   g_return_if_fail (sheet != NULL);
4256
4257   if(range==NULL) range=&sheet->range;
4258
4259   new_range=*range;
4260
4261   range->row0=MIN(range->row0, sheet->range.row0);
4262   range->rowi=MAX(range->rowi, sheet->range.rowi);
4263   range->col0=MIN(range->col0, sheet->range.col0);
4264   range->coli=MAX(range->coli, sheet->range.coli);
4265
4266   range->row0=MAX(range->row0, MIN_VISIBLE_ROW(sheet));
4267   range->rowi=MIN(range->rowi, MAX_VISIBLE_ROW(sheet));
4268   range->col0=MAX(range->col0, MIN_VISIBLE_COLUMN(sheet));
4269   range->coli=MIN(range->coli, MAX_VISIBLE_COLUMN(sheet));
4270
4271   aux_range.row0=MAX(new_range.row0, MIN_VISIBLE_ROW(sheet));
4272   aux_range.rowi=MIN(new_range.rowi, MAX_VISIBLE_ROW(sheet));
4273   aux_range.col0=MAX(new_range.col0, MIN_VISIBLE_COLUMN(sheet));
4274   aux_range.coli=MIN(new_range.coli, MAX_VISIBLE_COLUMN(sheet));
4275
4276   for(i=range->row0; i<=range->rowi; i++){
4277    for(j=range->col0; j<=range->coli; j++){     
4278
4279     state=gtk_sheet_cell_get_state(sheet, i, j);
4280     selected=(i<=new_range.rowi && i>=new_range.row0 && 
4281         j<=new_range.coli && j>=new_range.col0) ? TRUE : FALSE;
4282
4283     if(state==GTK_STATE_SELECTED && selected &&
4284        xxx_column_is_visible(sheet, j) && yyy_row_is_visible(sheet, i) &&
4285        (i==sheet->range.row0 || i==sheet->range.rowi ||
4286         j==sheet->range.col0 || j==sheet->range.coli ||
4287         i==new_range.row0 || i==new_range.rowi ||
4288         j==new_range.col0 || j==new_range.coli)){
4289
4290        mask1 = i==sheet->range.row0 ? 1 : 0;
4291        mask1 = i==sheet->range.rowi ? mask1+2 : mask1;
4292        mask1 = j==sheet->range.col0 ? mask1+4 : mask1;
4293        mask1 = j==sheet->range.coli ? mask1+8 : mask1;
4294
4295        mask2 = i==new_range.row0 ? 1 : 0;
4296        mask2 = i==new_range.rowi ? mask2+2 : mask2;
4297        mask2 = j==new_range.col0 ? mask2+4 : mask2;
4298        mask2 = j==new_range.coli ? mask2+8 : mask2;     
4299
4300        if(mask1 != mask2){
4301          x=COLUMN_LEFT_XPIXEL(sheet,j);
4302          y=ROW_TOP_YPIXEL(sheet, i);  
4303          width=COLUMN_LEFT_XPIXEL(sheet, j)-x+
4304            xxx_column_width(sheet, j);
4305          height=ROW_TOP_YPIXEL(sheet, i)-y+yyy_row_height(sheet, i);
4306
4307          if(i==sheet->range.row0){
4308             y=y-3;
4309             height=height+3;
4310          }
4311          if(i==sheet->range.rowi) height=height+3;
4312          if(j==sheet->range.col0){
4313             x=x-3;
4314             width=width+3;
4315          }
4316          if(j==sheet->range.coli) width=width+3;
4317
4318          gdk_draw_pixmap(sheet->sheet_window,
4319                   GTK_WIDGET(sheet)->style->fg_gc[GTK_STATE_NORMAL],
4320                   sheet->pixmap,
4321                   x+1,
4322                   y+1,
4323                   x+1,
4324                   y+1,
4325                   width,
4326                   height);           
4327
4328          if(i != sheet->active_cell.row || j != sheet->active_cell.col){
4329            x=COLUMN_LEFT_XPIXEL(sheet,j);
4330            y=ROW_TOP_YPIXEL(sheet, i);  
4331            width=COLUMN_LEFT_XPIXEL(sheet, j)-x+
4332              xxx_column_width(sheet, j);
4333
4334            height=ROW_TOP_YPIXEL(sheet, i)-y+yyy_row_height(sheet, i);
4335
4336            if(i==new_range.row0){
4337                y=y+2;
4338                height=height-2;
4339             }
4340             if(i==new_range.rowi) height=height-3;
4341             if(j==new_range.col0){
4342                x=x+2;
4343                width=width-2;
4344             }
4345             if(j==new_range.coli) width=width-3;
4346
4347             gdk_draw_rectangle (sheet->sheet_window,
4348                            sheet->xor_gc,
4349                            TRUE,
4350                            x+1,y+1,
4351                            width,height);
4352           }
4353        }
4354     }
4355    }
4356   }
4357
4358   for(i=range->row0; i<=range->rowi; i++){
4359    for(j=range->col0; j<=range->coli; j++){     
4360
4361     state=gtk_sheet_cell_get_state(sheet, i, j);
4362     selected=(i<=new_range.rowi && i>=new_range.row0 && 
4363         j<=new_range.coli && j>=new_range.col0) ? TRUE : FALSE;
4364
4365     if(state==GTK_STATE_SELECTED && !selected &&   
4366        xxx_column_is_visible(sheet, j) && yyy_row_is_visible(sheet, i)){
4367
4368       x=COLUMN_LEFT_XPIXEL(sheet,j);
4369       y=ROW_TOP_YPIXEL(sheet, i);  
4370       width=COLUMN_LEFT_XPIXEL(sheet, j)-x+ xxx_column_width(sheet, j);
4371       height=ROW_TOP_YPIXEL(sheet, i)-y+yyy_row_height(sheet, i);
4372
4373       if(i==sheet->range.row0){
4374             y=y-3;
4375             height=height+3;
4376       }
4377       if(i==sheet->range.rowi) height=height+3;
4378       if(j==sheet->range.col0){
4379             x=x-3;
4380             width=width+3;
4381       }
4382       if(j==sheet->range.coli) width=width+3;
4383
4384       gdk_draw_pixmap(sheet->sheet_window,
4385                   GTK_WIDGET(sheet)->style->fg_gc[GTK_STATE_NORMAL],
4386                   sheet->pixmap,
4387                   x+1,
4388                   y+1,
4389                   x+1,
4390                   y+1,
4391                   width,
4392                   height);           
4393     }
4394    }
4395   }
4396
4397   for(i=range->row0; i<=range->rowi; i++){
4398    for(j=range->col0; j<=range->coli; j++){     
4399
4400     state=gtk_sheet_cell_get_state(sheet, i, j);
4401     selected=(i<=new_range.rowi && i>=new_range.row0 && 
4402         j<=new_range.coli && j>=new_range.col0) ? TRUE : FALSE;
4403
4404     if(state!=GTK_STATE_SELECTED && selected &&
4405        xxx_column_is_visible(sheet, j) && yyy_row_is_visible(sheet, i) &&
4406        (i != sheet->active_cell.row || j != sheet->active_cell.col)){
4407
4408       x=COLUMN_LEFT_XPIXEL(sheet,j);
4409       y=ROW_TOP_YPIXEL(sheet, i);  
4410       width=COLUMN_LEFT_XPIXEL(sheet, j)-x+ xxx_column_width(sheet, j);
4411       height=ROW_TOP_YPIXEL(sheet, i)-y+yyy_row_height(sheet, i);
4412
4413       if(i==new_range.row0){
4414             y=y+2;
4415             height=height-2;
4416        }
4417        if(i==new_range.rowi) height=height-3;
4418        if(j==new_range.col0){
4419             x=x+2;
4420             width=width-2;
4421        }
4422        if(j==new_range.coli) width=width-3;
4423
4424        gdk_draw_rectangle (sheet->sheet_window,
4425                            sheet->xor_gc,
4426                            TRUE,
4427                            x+1,y+1,
4428                            width,height);
4429
4430     }   
4431
4432    }
4433   }
4434
4435   for(i=aux_range.row0; i<=aux_range.rowi; i++){
4436    for(j=aux_range.col0; j<=aux_range.coli; j++){     
4437
4438     if(xxx_column_is_visible(sheet, j) && yyy_row_is_visible(sheet, i)){
4439
4440        state=gtk_sheet_cell_get_state(sheet, i, j);
4441
4442        mask1 = i==sheet->range.row0 ? 1 : 0;
4443        mask1 = i==sheet->range.rowi ? mask1+2 : mask1;
4444        mask1 = j==sheet->range.col0 ? mask1+4 : mask1;
4445        mask1 = j==sheet->range.coli ? mask1+8 : mask1;
4446
4447        mask2 = i==new_range.row0 ? 1 : 0;
4448        mask2 = i==new_range.rowi ? mask2+2 : mask2;
4449        mask2 = j==new_range.col0 ? mask2+4 : mask2;
4450        mask2 = j==new_range.coli ? mask2+8 : mask2;    
4451        if(mask2!=mask1 || (mask2==mask1 && state!=GTK_STATE_SELECTED)){
4452          x=COLUMN_LEFT_XPIXEL(sheet,j);
4453          y=ROW_TOP_YPIXEL(sheet, i);  
4454          width=xxx_column_width(sheet, j);
4455          height=yyy_row_height(sheet, i);
4456          if(mask2 & 1)
4457                gdk_draw_rectangle (sheet->sheet_window,
4458                                    sheet->xor_gc,
4459                                    TRUE,
4460                                    x+1,y-1,
4461                                    width,3);
4462
4463            
4464          if(mask2 & 2)
4465                gdk_draw_rectangle (sheet->sheet_window,
4466                                    sheet->xor_gc,
4467                                    TRUE,
4468                                    x+1,y+height-1,
4469                                    width,3);
4470
4471          if(mask2 & 4)
4472                gdk_draw_rectangle (sheet->sheet_window,
4473                                    sheet->xor_gc,
4474                                    TRUE,
4475                                    x-1,y+1,
4476                                    3,height);
4477
4478
4479          if(mask2 & 8)
4480                gdk_draw_rectangle (sheet->sheet_window,
4481                                    sheet->xor_gc,
4482                                    TRUE,
4483                                    x+width-1,y+1,
4484                                    3,height);
4485
4486        
4487
4488        }         
4489
4490     } 
4491
4492    }
4493   } 
4494
4495
4496   *range=new_range;
4497   gtk_sheet_draw_corners(sheet, new_range);
4498
4499 }
4500
4501 static void
4502 gtk_sheet_draw_border (GtkSheet *sheet, GtkSheetRange new_range)
4503 {
4504   GtkWidget *widget;
4505   GdkRectangle area;
4506   gint i;
4507   gint x,y,width,height;
4508
4509   widget = GTK_WIDGET(sheet);
4510
4511   x=COLUMN_LEFT_XPIXEL(sheet,new_range.col0);
4512   y=ROW_TOP_YPIXEL(sheet,new_range.row0);
4513   width=COLUMN_LEFT_XPIXEL(sheet,new_range.coli)-x+ 
4514     xxx_column_width(sheet, new_range.coli);
4515
4516   height=ROW_TOP_YPIXEL(sheet,new_range.rowi)-y+
4517              yyy_row_height(sheet, new_range.rowi);
4518
4519   area.x=COLUMN_LEFT_XPIXEL(sheet, MIN_VISIBLE_COLUMN(sheet));
4520   area.y=ROW_TOP_YPIXEL(sheet, MIN_VISIBLE_ROW(sheet));
4521   area.width=sheet->sheet_window_width;
4522   area.height=sheet->sheet_window_height;
4523
4524   if(x<0) {
4525       width=width+x;
4526       x=0;
4527   }
4528   if(width>area.width) width=area.width+10;
4529   if(y<0) {
4530       height=height+y;
4531       y=0;
4532   }
4533   if(height>area.height) height=area.height+10;
4534
4535   gdk_gc_set_clip_rectangle(sheet->xor_gc, &area);
4536
4537   for(i=-1; i<=1; ++i)
4538      gdk_draw_rectangle (sheet->sheet_window,
4539                          sheet->xor_gc,
4540                          FALSE,
4541                          x+i,y+i,
4542                          width-2*i,height-2*i);
4543
4544   gdk_gc_set_clip_rectangle(sheet->xor_gc, NULL);
4545   
4546   gtk_sheet_draw_corners(sheet, new_range);
4547
4548 }
4549
4550 static void
4551 gtk_sheet_draw_corners(GtkSheet *sheet, GtkSheetRange range)
4552 {
4553   gint x,y;
4554   guint width = 1;
4555
4556   if(gtk_sheet_cell_isvisible(sheet, range.row0, range.col0)){
4557        x=COLUMN_LEFT_XPIXEL(sheet,range.col0);
4558        y=ROW_TOP_YPIXEL(sheet,range.row0);
4559        gdk_draw_pixmap(sheet->sheet_window,
4560                        GTK_WIDGET(sheet)->style->fg_gc[GTK_STATE_NORMAL],
4561                        sheet->pixmap,
4562                        x-1,
4563                        y-1,
4564                        x-1,
4565                        y-1,
4566                        3,
4567                        3);         
4568        gdk_draw_rectangle (sheet->sheet_window,
4569                            sheet->xor_gc,
4570                            TRUE,
4571                            x-1,y-1,
4572                            3,3);
4573   }
4574
4575   if(gtk_sheet_cell_isvisible(sheet, range.row0, range.coli) ||
4576      sheet->state == GTK_SHEET_COLUMN_SELECTED){
4577        x=COLUMN_LEFT_XPIXEL(sheet,range.coli)+
4578          xxx_column_width(sheet, range.coli);
4579        y=ROW_TOP_YPIXEL(sheet,range.row0);
4580        width = 1;
4581        if(sheet->state == GTK_SHEET_COLUMN_SELECTED)
4582          {
4583              y = ROW_TOP_YPIXEL(sheet, sheet->view.row0)+3;
4584              width = 3;
4585          }
4586        gdk_draw_pixmap(sheet->sheet_window,
4587                        GTK_WIDGET(sheet)->style->fg_gc[GTK_STATE_NORMAL],
4588                        sheet->pixmap,
4589                        x-width,
4590                        y-width,
4591                        x-width,
4592                        y-width,
4593                        2*width+1,
4594                        2*width+1);         
4595        gdk_draw_rectangle (sheet->sheet_window,
4596                            sheet->xor_gc,
4597                            TRUE,
4598                            x-width+width/2,y-width+width/2,
4599                            2+width,2+width);
4600   }
4601
4602   if(gtk_sheet_cell_isvisible(sheet, range.rowi, range.col0) ||
4603      sheet->state == GTK_SHEET_ROW_SELECTED){
4604        x=COLUMN_LEFT_XPIXEL(sheet,range.col0);
4605        y=ROW_TOP_YPIXEL(sheet,range.rowi)+
4606          yyy_row_height(sheet, range.rowi);
4607        width = 1;
4608        if(sheet->state == GTK_SHEET_ROW_SELECTED) 
4609          {
4610              x = COLUMN_LEFT_XPIXEL(sheet, sheet->view.col0)+3;
4611              width = 3;
4612          }
4613        gdk_draw_pixmap(sheet->sheet_window,
4614                        GTK_WIDGET(sheet)->style->fg_gc[GTK_STATE_NORMAL],
4615                        sheet->pixmap,
4616                        x-width,
4617                        y-width,
4618                        x-width,
4619                        y-width,
4620                        2*width+1,
4621                        2*width+1);         
4622        gdk_draw_rectangle (sheet->sheet_window,
4623                            sheet->xor_gc,
4624                            TRUE,
4625                            x-width+width/2,y-width+width/2,
4626                            2+width,2+width);
4627   }
4628
4629   if(gtk_sheet_cell_isvisible(sheet, range.rowi, range.coli)){
4630        x=COLUMN_LEFT_XPIXEL(sheet,range.coli)+
4631          xxx_column_width(sheet, range.coli);
4632        y=ROW_TOP_YPIXEL(sheet,range.rowi)+
4633          yyy_row_height(sheet, range.rowi);
4634        width = 1;
4635        if(sheet->state == GTK_SHEET_RANGE_SELECTED) width = 3;
4636        if(sheet->state == GTK_SHEET_NORMAL) width = 3;
4637        gdk_draw_pixmap(sheet->sheet_window,
4638                        GTK_WIDGET(sheet)->style->fg_gc[GTK_STATE_NORMAL],
4639                        sheet->pixmap,
4640                        x-width,
4641                        y-width,
4642                        x-width,
4643                        y-width,
4644                        2*width+1,
4645                        2*width+1);         
4646        gdk_draw_rectangle (sheet->sheet_window,
4647                            sheet->xor_gc,
4648                            TRUE,
4649                            x-width+width/2,y-width+width/2,
4650                            2+width,2+width);
4651
4652   }
4653
4654 }
4655
4656
4657 static void
4658 gtk_sheet_real_select_range (GtkSheet * sheet,
4659                              GtkSheetRange * range)
4660 {
4661   gint state;
4662
4663   g_return_if_fail (sheet != NULL);
4664
4665   if(range==NULL) range=&sheet->range;
4666
4667   if(range->row0 < 0 || range->rowi < 0) return;
4668   if(range->col0 < 0 || range->coli < 0) return;
4669
4670   state=sheet->state;
4671
4672 #if 0
4673   if(state==GTK_SHEET_COLUMN_SELECTED || state==GTK_SHEET_RANGE_SELECTED){
4674    for(i=sheet->range.col0; i< range->col0; i++)
4675     column_button_release(sheet, i);
4676    for(i=range->coli+1; i<= sheet->range.coli; i++)
4677     column_button_release(sheet, i);
4678    for(i=range->col0; i<=range->coli; i++){
4679     column_button_set(sheet, i);
4680    }
4681   }
4682  
4683   if(state==GTK_SHEET_ROW_SELECTED || state==GTK_SHEET_RANGE_SELECTED){
4684    for(i=sheet->range.row0; i< range->row0; i++)
4685     row_button_release(sheet, i);
4686    for(i=range->rowi+1; i<= sheet->range.rowi; i++)
4687     row_button_release(sheet, i);
4688    for(i=range->row0; i<=range->rowi; i++){
4689     row_button_set(sheet, i);
4690    }
4691   }
4692 #endif
4693
4694   if(range->coli != sheet->range.coli || range->col0 != sheet->range.col0 ||
4695      range->rowi != sheet->range.rowi || range->row0 != sheet->range.row0)
4696          {
4697
4698            gtk_sheet_new_selection(sheet, range);
4699
4700            sheet->range.col0=range->col0;
4701            sheet->range.coli=range->coli;
4702            sheet->range.row0=range->row0;
4703            sheet->range.rowi=range->rowi;
4704
4705          }
4706   else
4707          {
4708            gtk_sheet_draw_backing_pixmap(sheet, sheet->range);
4709            gtk_sheet_range_draw_selection(sheet, sheet->range);
4710          }
4711
4712   gtk_signal_emit(GTK_OBJECT(sheet), sheet_signals[SELECT_RANGE], range);
4713 }
4714
4715 void
4716 gtk_sheet_select_range(GtkSheet * sheet, const GtkSheetRange *range)
4717 {
4718   g_return_if_fail (sheet != NULL);
4719
4720   if(range==NULL) range=&sheet->range;
4721
4722   if(range->row0 < 0 || range->rowi < 0) return;
4723   if(range->col0 < 0 || range->coli < 0) return;
4724
4725
4726   if ( gtk_sheet_locked(sheet)) return ;
4727
4728   if(sheet->state != GTK_SHEET_NORMAL) 
4729        gtk_sheet_real_unselect_range(sheet, NULL);
4730   else
4731   {
4732      gboolean veto = TRUE;
4733      veto = gtk_sheet_deactivate_cell(sheet);
4734      if(!veto) return;
4735   }
4736
4737   sheet->range.row0=range->row0;
4738   sheet->range.rowi=range->rowi;
4739   sheet->range.col0=range->col0;
4740   sheet->range.coli=range->coli;
4741   sheet->active_cell.row=range->row0;
4742   sheet->active_cell.col=range->col0;
4743   sheet->selection_cell.row=range->rowi;
4744   sheet->selection_cell.col=range->coli;
4745
4746   sheet->state = GTK_SHEET_RANGE_SELECTED;
4747   gtk_sheet_real_select_range(sheet, NULL);
4748
4749 }
4750
4751 void
4752 gtk_sheet_unselect_range (GtkSheet * sheet)
4753 {
4754   gtk_sheet_real_unselect_range(sheet, NULL);
4755   sheet->state = GTK_STATE_NORMAL;
4756   gtk_sheet_activate_cell(sheet, sheet->active_cell.row, sheet->active_cell.col);
4757 }
4758
4759
4760 static void
4761 gtk_sheet_real_unselect_range (GtkSheet * sheet,
4762                                const GtkSheetRange *range)
4763 {
4764   g_return_if_fail (sheet != NULL);
4765   g_return_if_fail (GTK_WIDGET_REALIZED(GTK_WIDGET(sheet)));
4766
4767   if(range==NULL){
4768      range=&sheet->range;
4769   }
4770
4771   if(range->row0 < 0 || range->rowi < 0) return;
4772   if(range->col0 < 0 || range->coli < 0) return;
4773
4774   if (gtk_sheet_range_isvisible (sheet, *range)){
4775     gtk_sheet_draw_backing_pixmap(sheet, *range);
4776   }
4777
4778 #if 0
4779   for(i=range->col0; i<=range->coli; i++){
4780      column_button_release(sheet, i);
4781   }
4782
4783   for(i=range->row0; i<=range->rowi; i++){
4784      row_button_release(sheet, i);
4785   }
4786 #endif
4787
4788   gtk_sheet_position_children(sheet);
4789 }
4790
4791
4792 static gint
4793 gtk_sheet_expose (GtkWidget * widget,
4794                   GdkEventExpose * event)
4795 {
4796   GtkSheet *sheet;
4797   GtkSheetRange range;
4798
4799   g_return_val_if_fail (widget != NULL, FALSE);
4800   g_return_val_if_fail (GTK_IS_SHEET (widget), FALSE);
4801   g_return_val_if_fail (event != NULL, FALSE);
4802
4803   sheet = GTK_SHEET (widget);
4804
4805   if (GTK_WIDGET_DRAWABLE (widget))
4806   {
4807       range.row0=ROW_FROM_YPIXEL(sheet,event->area.y);
4808       range.col0=COLUMN_FROM_XPIXEL(sheet,event->area.x);
4809       range.rowi=ROW_FROM_YPIXEL(sheet,event->area.y+event->area.height);
4810       range.coli=COLUMN_FROM_XPIXEL(sheet,event->area.x+event->area.width);
4811
4812       /* exposure events on the sheet */
4813  
4814       if(event->window == sheet->row_title_window && sheet->row_titles_visible){
4815          gint i;
4816          for(i = MIN_VISIBLE_ROW(sheet); i <= MAX_VISIBLE_ROW(sheet); i++)
4817            gtk_sheet_button_draw(sheet,i,-1);
4818       }
4819
4820       if(event->window == sheet->column_title_window && sheet->column_titles_visible){
4821          gint i;
4822          for(i = MIN_VISIBLE_COLUMN(sheet); i <= MAX_VISIBLE_COLUMN(sheet); i++)
4823            gtk_sheet_button_draw(sheet,-1,i);
4824       }
4825
4826       if (event->window == sheet->sheet_window){
4827         gtk_sheet_draw_backing_pixmap(sheet, range);
4828               
4829         if(sheet->state != GTK_SHEET_NORMAL){
4830                 if(gtk_sheet_range_isvisible(sheet, sheet->range))          
4831                    gtk_sheet_draw_backing_pixmap(sheet, sheet->range);
4832                 if(GTK_SHEET_IN_RESIZE(sheet) || GTK_SHEET_IN_DRAG(sheet))
4833                    gtk_sheet_draw_backing_pixmap(sheet, sheet->drag_range);
4834
4835                 if(gtk_sheet_range_isvisible(sheet, sheet->range))          
4836                    gtk_sheet_range_draw_selection(sheet, sheet->range);
4837                 if(GTK_SHEET_IN_RESIZE(sheet) || GTK_SHEET_IN_DRAG(sheet))
4838                    draw_xor_rectangle(sheet, sheet->drag_range);
4839         }
4840
4841         if((!GTK_SHEET_IN_XDRAG(sheet)) && (!GTK_SHEET_IN_YDRAG(sheet))){
4842              if(sheet->state == GTK_SHEET_NORMAL){ 
4843                  gtk_sheet_draw_active_cell(sheet);
4844                  if(!GTK_SHEET_IN_SELECTION(sheet))
4845                          gtk_widget_queue_draw(sheet->sheet_entry);
4846              }
4847         }
4848
4849
4850       }
4851
4852   }
4853
4854   if(sheet->state != GTK_SHEET_NORMAL && GTK_SHEET_IN_SELECTION(sheet))
4855      gtk_widget_grab_focus(GTK_WIDGET(sheet));
4856
4857   (* GTK_WIDGET_CLASS (parent_class)->expose_event) (widget, event);
4858
4859   return FALSE;
4860 }
4861
4862
4863 static gint
4864 gtk_sheet_button_press (GtkWidget * widget,
4865                         GdkEventButton * event)
4866 {
4867   GtkSheet *sheet;
4868   GdkModifierType mods;
4869   gint x, y, row, column;
4870   gboolean veto;
4871
4872   g_return_val_if_fail (widget != NULL, FALSE);
4873   g_return_val_if_fail (GTK_IS_SHEET (widget), FALSE);
4874   g_return_val_if_fail (event != NULL, FALSE);
4875
4876   sheet = GTK_SHEET (widget);
4877
4878   if ( event->type == GDK_2BUTTON_PRESS)
4879     {
4880       gtk_widget_get_pointer (widget, &x, &y);
4881       gtk_sheet_get_pixel_info (sheet, x, y, &row, &column);
4882
4883       if (event->window == sheet->column_title_window ) 
4884         {
4885           gtk_signal_emit (GTK_OBJECT (sheet), 
4886                            sheet_signals[DOUBLE_CLICK_COLUMN], column);
4887         }
4888       else if (event->window == sheet->row_title_window ) 
4889         {
4890           gtk_signal_emit (GTK_OBJECT (sheet), 
4891                            sheet_signals[DOUBLE_CLICK_ROW], row);
4892         }
4893     }
4894
4895   
4896 /*
4897   if(event->type != GDK_BUTTON_PRESS) return TRUE;
4898 */
4899   gdk_window_get_pointer(widget->window, NULL, NULL, &mods);
4900
4901   if(!(mods & GDK_BUTTON1_MASK)) return TRUE;
4902
4903
4904   /* press on resize windows */
4905   if (event->window == sheet->column_title_window &&
4906       gtk_sheet_columns_resizable(sheet))
4907       {
4908         gtk_widget_get_pointer (widget, &sheet->x_drag, NULL);
4909         if(POSSIBLE_XDRAG(sheet, sheet->x_drag, &sheet->drag_cell.col)){
4910           guint req;
4911           if (event->type == GDK_2BUTTON_PRESS){
4912             gtk_sheet_autoresize_column (sheet, sheet->drag_cell.col);
4913             GTK_SHEET_UNSET_FLAGS(sheet, GTK_SHEET_IN_XDRAG);
4914             return TRUE;
4915           }
4916           gtk_sheet_column_size_request(sheet, sheet->drag_cell.col, &req);
4917           GTK_SHEET_SET_FLAGS (sheet, GTK_SHEET_IN_XDRAG);
4918           gdk_pointer_grab (sheet->column_title_window, FALSE,
4919                             GDK_POINTER_MOTION_HINT_MASK |
4920                             GDK_BUTTON1_MOTION_MASK |
4921                             GDK_BUTTON_RELEASE_MASK,
4922                             NULL, NULL, event->time);
4923
4924           draw_xor_vline (sheet);
4925           return TRUE;
4926         }
4927       }
4928
4929   if (event->window == sheet->row_title_window && gtk_sheet_rows_resizable(sheet))
4930       {
4931         gtk_widget_get_pointer (widget, NULL, &sheet->y_drag);
4932
4933         if(POSSIBLE_YDRAG(sheet, sheet->y_drag, &sheet->drag_cell.row)){
4934           guint req;
4935           gtk_sheet_row_size_request(sheet, sheet->drag_cell.row, &req);
4936           GTK_SHEET_SET_FLAGS (sheet, GTK_SHEET_IN_YDRAG);
4937           gdk_pointer_grab (sheet->row_title_window, FALSE,
4938                             GDK_POINTER_MOTION_HINT_MASK |
4939                             GDK_BUTTON1_MOTION_MASK |
4940                             GDK_BUTTON_RELEASE_MASK,
4941                             NULL, NULL, event->time);
4942
4943           draw_xor_hline (sheet);
4944           return TRUE;
4945         }
4946       }
4947
4948   /* the sheet itself does not handle other than single click events */
4949   if(event->type != GDK_BUTTON_PRESS) return FALSE;
4950
4951   /* selections on the sheet */
4952     if(event->window == sheet->sheet_window){
4953      gtk_widget_get_pointer (widget, &x, &y);
4954      gtk_sheet_get_pixel_info (sheet, x, y, &row, &column);
4955      gdk_pointer_grab (sheet->sheet_window, FALSE,
4956                        GDK_POINTER_MOTION_HINT_MASK |
4957                        GDK_BUTTON1_MOTION_MASK |
4958                        GDK_BUTTON_RELEASE_MASK,
4959                        NULL, NULL, event->time);
4960      gtk_grab_add(GTK_WIDGET(sheet));
4961      sheet->timer=gtk_timeout_add(TIMEOUT_SCROLL, gtk_sheet_scroll, sheet); 
4962      gtk_widget_grab_focus(GTK_WIDGET(sheet));
4963
4964      if(sheet->selection_mode != GTK_SELECTION_SINGLE &&
4965         sheet->cursor_drag->type==GDK_SIZING &&
4966         !GTK_SHEET_IN_SELECTION(sheet) && !GTK_SHEET_IN_RESIZE(sheet)){
4967         if(sheet->state==GTK_STATE_NORMAL) {
4968           row=sheet->active_cell.row;
4969           column=sheet->active_cell.col;
4970           if(!gtk_sheet_deactivate_cell(sheet)) return FALSE;
4971           sheet->active_cell.row=row;
4972           sheet->active_cell.col=column;
4973           sheet->drag_range=sheet->range;
4974           sheet->state=GTK_SHEET_RANGE_SELECTED;
4975           gtk_sheet_select_range(sheet, &sheet->drag_range);
4976         }
4977         sheet->x_drag=x;
4978         sheet->y_drag=y;
4979         if(row > sheet->range.rowi) row--;
4980         if(column > sheet->range.coli) column--;
4981         sheet->drag_cell.row = row;
4982         sheet->drag_cell.col = column;
4983         sheet->drag_range=sheet->range;
4984         draw_xor_rectangle(sheet, sheet->drag_range);
4985         GTK_SHEET_SET_FLAGS(sheet, GTK_SHEET_IN_RESIZE);
4986      }
4987      else if(sheet->cursor_drag->type==GDK_TOP_LEFT_ARROW &&
4988              !GTK_SHEET_IN_SELECTION(sheet) 
4989              && ! GTK_SHEET_IN_DRAG(sheet)
4990              && ! gtk_sheet_locked(sheet)
4991              && sheet->active_cell.row >= 0
4992              && sheet->active_cell.col >= 0
4993              ) 
4994        {
4995          if(sheet->state==GTK_STATE_NORMAL) {
4996            row=sheet->active_cell.row;
4997            column=sheet->active_cell.col;
4998            if(!gtk_sheet_deactivate_cell(sheet)) return FALSE;
4999            sheet->active_cell.row=row;
5000            sheet->active_cell.col=column;
5001            sheet->drag_range=sheet->range;
5002            sheet->state=GTK_SHEET_RANGE_SELECTED;
5003            gtk_sheet_select_range(sheet, &sheet->drag_range);
5004          }
5005          sheet->x_drag=x;
5006          sheet->y_drag=y;
5007          if(row < sheet->range.row0) row++;
5008          if(row > sheet->range.rowi) row--;
5009          if(column < sheet->range.col0) column++;
5010          if(column > sheet->range.coli) column--;
5011          sheet->drag_cell.row=row;
5012          sheet->drag_cell.col=column;
5013          sheet->drag_range=sheet->range;
5014          draw_xor_rectangle(sheet, sheet->drag_range);
5015          GTK_SHEET_SET_FLAGS(sheet, GTK_SHEET_IN_DRAG);
5016        }
5017      else 
5018        {
5019          gtk_sheet_click_cell(sheet, row, column, &veto);
5020          if(veto) GTK_SHEET_SET_FLAGS(sheet, GTK_SHEET_IN_SELECTION);
5021        }
5022     }
5023
5024     if(event->window == sheet->column_title_window){
5025      gtk_widget_get_pointer (widget, &x, &y);
5026      column = COLUMN_FROM_XPIXEL(sheet, x);
5027      if(xxx_column_is_sensitive(sheet, column)){
5028        gtk_sheet_click_cell(sheet, -1, column, &veto);
5029        gtk_grab_add(GTK_WIDGET(sheet));
5030        sheet->timer=gtk_timeout_add(TIMEOUT_SCROLL, gtk_sheet_scroll, sheet); 
5031        gtk_widget_grab_focus(GTK_WIDGET(sheet));
5032        GTK_SHEET_SET_FLAGS(sheet, GTK_SHEET_IN_SELECTION);
5033      }
5034     }
5035
5036     if(event->window == sheet->row_title_window){
5037      gtk_widget_get_pointer (widget, &x, &y);
5038      row = ROW_FROM_YPIXEL(sheet, y);
5039      if(yyy_row_is_sensitive(sheet, row)){
5040        gtk_sheet_click_cell(sheet, row, -1, &veto);
5041        gtk_grab_add(GTK_WIDGET(sheet));
5042        sheet->timer=gtk_timeout_add(TIMEOUT_SCROLL, gtk_sheet_scroll, sheet); 
5043        gtk_widget_grab_focus(GTK_WIDGET(sheet));
5044        GTK_SHEET_SET_FLAGS(sheet, GTK_SHEET_IN_SELECTION);
5045      }
5046     }
5047
5048     return TRUE;
5049 }
5050
5051 static gint
5052 gtk_sheet_scroll(gpointer data)
5053 {
5054  GtkSheet *sheet;
5055  gint x,y,row,column;
5056  gint move;
5057   
5058  sheet=GTK_SHEET(data);
5059
5060  GDK_THREADS_ENTER();
5061
5062  gtk_widget_get_pointer (GTK_WIDGET(sheet), &x, &y);
5063  gtk_sheet_get_pixel_info (sheet, x, y, &row, &column);
5064
5065  move=TRUE;
5066
5067  if(GTK_SHEET_IN_SELECTION(sheet))
5068       gtk_sheet_extend_selection(sheet, row, column);
5069
5070  if(GTK_SHEET_IN_DRAG(sheet) || GTK_SHEET_IN_RESIZE(sheet)){
5071        move=gtk_sheet_move_query(sheet, row, column);
5072        if(move) draw_xor_rectangle(sheet, sheet->drag_range);      
5073  }       
5074
5075  GDK_THREADS_LEAVE();
5076
5077  return TRUE;
5078       
5079 }
5080
5081 static void
5082 gtk_sheet_click_cell(GtkSheet *sheet, gint row, gint column, gboolean *veto)
5083 {
5084       *veto = TRUE;
5085
5086       if(row >= yyy_row_count(sheet) || column >= xxx_column_count(sheet)){
5087           *veto = FALSE;
5088           return;
5089       }
5090
5091       if(column >= 0 && row >= 0)
5092        if(! xxx_column_is_visible(sheet, column) || !yyy_row_is_visible(sheet, row)) 
5093          {
5094            *veto = FALSE;
5095            return;
5096          }
5097
5098       _gtkextra_signal_emit(GTK_OBJECT(sheet), sheet_signals[TRAVERSE],
5099                             sheet->active_cell.row, sheet->active_cell.col, 
5100                             &row, &column, veto);
5101
5102       if(!*veto){
5103            if(sheet->state == GTK_STATE_NORMAL) return;
5104
5105            row = sheet->active_cell.row;
5106            column = sheet->active_cell.col;
5107
5108            gtk_sheet_activate_cell(sheet, row, column);
5109            return;
5110       }
5111
5112       if(row == -1 && column >= 0){
5113           if(gtk_sheet_autoscroll(sheet))
5114             gtk_sheet_move_query(sheet, row, column);
5115           gtk_sheet_select_column(sheet, column);
5116           return;
5117       }
5118       if(column == -1 && row >= 0){
5119           if(gtk_sheet_autoscroll(sheet))
5120             gtk_sheet_move_query(sheet, row, column);
5121           gtk_sheet_select_row(sheet, row);
5122           return;
5123       }
5124
5125       if(row==-1 && column ==-1){
5126           sheet->range.row0=0;
5127           sheet->range.col0=0;
5128           sheet->range.rowi = yyy_row_count(sheet) - 1;
5129           sheet->range.coli = xxx_column_count(sheet) - 1;
5130           sheet->active_cell.row=0;
5131           sheet->active_cell.col=0;
5132           gtk_sheet_select_range(sheet, NULL);
5133           return;
5134       }
5135
5136       if(row!=-1 && column !=-1){
5137           if(sheet->state != GTK_SHEET_NORMAL){
5138             sheet->state = GTK_SHEET_NORMAL;
5139             gtk_sheet_real_unselect_range(sheet, NULL);
5140           }
5141           else
5142           {
5143             if(!gtk_sheet_deactivate_cell(sheet)){
5144               *veto = FALSE;
5145               return;
5146             }
5147           }
5148
5149           if(gtk_sheet_autoscroll(sheet))
5150             gtk_sheet_move_query(sheet, row, column);
5151           sheet->active_cell.row=row;
5152           sheet->active_cell.col=column;
5153           sheet->selection_cell.row=row;
5154           sheet->selection_cell.col=column;
5155           sheet->range.row0=row;
5156           sheet->range.col0=column;
5157           sheet->range.rowi=row;
5158           sheet->range.coli=column;
5159           sheet->state=GTK_SHEET_NORMAL;
5160           GTK_SHEET_SET_FLAGS(sheet, GTK_SHEET_IN_SELECTION);
5161           gtk_sheet_draw_active_cell(sheet);
5162           return;
5163       }
5164
5165       g_assert_not_reached();
5166       gtk_sheet_activate_cell(sheet, sheet->active_cell.row,
5167                                      sheet->active_cell.col);
5168 }
5169
5170 static gint
5171 gtk_sheet_button_release (GtkWidget * widget,
5172                         GdkEventButton * event)
5173 {
5174   GtkSheet *sheet;
5175   gint x,y;
5176  
5177   sheet=GTK_SHEET(widget);
5178
5179   /* release on resize windows */
5180   if (GTK_SHEET_IN_XDRAG (sheet)){
5181           GTK_SHEET_UNSET_FLAGS (sheet, GTK_SHEET_IN_XDRAG);
5182           GTK_SHEET_UNSET_FLAGS (sheet, GTK_SHEET_IN_SELECTION);
5183           gtk_widget_get_pointer (widget, &x, NULL);
5184           gdk_pointer_ungrab (event->time);
5185           draw_xor_vline (sheet);
5186           
5187           gtk_sheet_set_column_width (sheet, sheet->drag_cell.col, new_column_width (sheet, sheet->drag_cell.col, &x));
5188           sheet->old_hadjustment = -1.;
5189           gtk_signal_emit_by_name (GTK_OBJECT (sheet->hadjustment), "value_changed");
5190           return TRUE;
5191   }
5192
5193   if (GTK_SHEET_IN_YDRAG (sheet)){
5194           GTK_SHEET_UNSET_FLAGS (sheet, GTK_SHEET_IN_YDRAG);
5195           GTK_SHEET_UNSET_FLAGS (sheet, GTK_SHEET_IN_SELECTION);
5196           gtk_widget_get_pointer (widget, NULL, &y);
5197           gdk_pointer_ungrab (event->time);
5198           draw_xor_hline (sheet);
5199           
5200           gtk_sheet_set_row_height (sheet, sheet->drag_cell.row, new_row_height (sheet, sheet->drag_cell.row, &y));
5201           sheet->old_vadjustment = -1.;
5202           gtk_signal_emit_by_name (GTK_OBJECT (sheet->vadjustment), "value_changed");
5203           return TRUE;
5204   }
5205
5206   
5207   if (GTK_SHEET_IN_DRAG(sheet)){
5208       GtkSheetRange old_range;
5209       draw_xor_rectangle(sheet, sheet->drag_range);
5210       GTK_SHEET_UNSET_FLAGS(sheet, GTK_SHEET_IN_DRAG);
5211       gdk_pointer_ungrab (event->time);
5212
5213       gtk_sheet_real_unselect_range(sheet, NULL);
5214       
5215       sheet->active_cell.row = sheet->active_cell.row +
5216                                (sheet->drag_range.row0 - sheet->range.row0);
5217       sheet->active_cell.col = sheet->active_cell.col +
5218                                (sheet->drag_range.col0 - sheet->range.col0);
5219       sheet->selection_cell.row = sheet->selection_cell.row +
5220                                   (sheet->drag_range.row0 - sheet->range.row0);
5221       sheet->selection_cell.col = sheet->selection_cell.col +
5222                                   (sheet->drag_range.col0 - sheet->range.col0);
5223       old_range=sheet->range;
5224       sheet->range=sheet->drag_range;
5225       sheet->drag_range=old_range;
5226       gtk_signal_emit(GTK_OBJECT(sheet),sheet_signals[MOVE_RANGE],
5227                       &sheet->drag_range, &sheet->range);
5228       gtk_sheet_select_range(sheet, &sheet->range);
5229   }
5230
5231   if (GTK_SHEET_IN_RESIZE(sheet)){
5232       GtkSheetRange old_range;
5233       draw_xor_rectangle(sheet, sheet->drag_range);
5234       GTK_SHEET_UNSET_FLAGS(sheet, GTK_SHEET_IN_RESIZE);
5235       gdk_pointer_ungrab (event->time);
5236
5237       gtk_sheet_real_unselect_range(sheet, NULL);
5238       
5239       sheet->active_cell.row = sheet->active_cell.row +
5240                                (sheet->drag_range.row0 - sheet->range.row0);
5241       sheet->active_cell.col = sheet->active_cell.col +
5242                                (sheet->drag_range.col0 - sheet->range.col0);
5243       if(sheet->drag_range.row0 < sheet->range.row0)
5244                      sheet->selection_cell.row = sheet->drag_range.row0;
5245       if(sheet->drag_range.rowi >= sheet->range.rowi)
5246                      sheet->selection_cell.row = sheet->drag_range.rowi;
5247       if(sheet->drag_range.col0 < sheet->range.col0)
5248                      sheet->selection_cell.col = sheet->drag_range.col0;
5249       if(sheet->drag_range.coli >= sheet->range.coli)
5250                      sheet->selection_cell.col = sheet->drag_range.coli;
5251       old_range = sheet->range;
5252       sheet->range = sheet->drag_range;
5253       sheet->drag_range = old_range;
5254
5255       if(sheet->state==GTK_STATE_NORMAL) sheet->state=GTK_SHEET_RANGE_SELECTED;
5256       gtk_signal_emit(GTK_OBJECT(sheet),sheet_signals[RESIZE_RANGE],
5257                       &sheet->drag_range, &sheet->range);
5258       gtk_sheet_select_range(sheet, &sheet->range);
5259   }
5260
5261   if(sheet->state == GTK_SHEET_NORMAL && GTK_SHEET_IN_SELECTION(sheet)){
5262       GTK_SHEET_UNSET_FLAGS(sheet, GTK_SHEET_IN_SELECTION);
5263       gdk_pointer_ungrab (event->time);
5264       gtk_sheet_activate_cell(sheet, sheet->active_cell.row, 
5265                                      sheet->active_cell.col);
5266   }
5267
5268   if(GTK_SHEET_IN_SELECTION)
5269          gdk_pointer_ungrab (event->time);
5270   if(sheet->timer)
5271          gtk_timeout_remove(sheet->timer);
5272   gtk_grab_remove(GTK_WIDGET(sheet));
5273
5274   GTK_SHEET_UNSET_FLAGS(sheet, GTK_SHEET_IN_SELECTION);
5275
5276   return TRUE;
5277 }
5278
5279 static gint
5280 gtk_sheet_motion (GtkWidget * widget,
5281                   GdkEventMotion * event)
5282 {
5283   GtkSheet *sheet;
5284   GdkModifierType mods;
5285   GdkCursorType new_cursor;
5286   gint x, y, row, column;
5287
5288   g_return_val_if_fail (widget != NULL, FALSE);
5289   g_return_val_if_fail (GTK_IS_SHEET (widget), FALSE);
5290   g_return_val_if_fail (event != NULL, FALSE);
5291
5292
5293   sheet = GTK_SHEET (widget);
5294
5295   /* selections on the sheet */
5296   x = event->x;
5297   y = event->y;
5298
5299   if(event->window == sheet->column_title_window && gtk_sheet_columns_resizable(sheet)){
5300     gtk_widget_get_pointer(widget, &x, &y);
5301     if(!GTK_SHEET_IN_SELECTION(sheet) && POSSIBLE_XDRAG(sheet, x, &column)){
5302       new_cursor=GDK_SB_H_DOUBLE_ARROW;
5303       if(new_cursor != sheet->cursor_drag->type){
5304         gdk_cursor_destroy(sheet->cursor_drag);
5305         sheet->cursor_drag=gdk_cursor_new(GDK_SB_H_DOUBLE_ARROW);
5306         gdk_window_set_cursor(sheet->column_title_window,sheet->cursor_drag);
5307       }
5308     }else{
5309       new_cursor=GDK_TOP_LEFT_ARROW;
5310       if(!GTK_SHEET_IN_XDRAG(sheet) && new_cursor != sheet->cursor_drag->type){
5311         gdk_cursor_destroy(sheet->cursor_drag);
5312         sheet->cursor_drag=gdk_cursor_new(GDK_TOP_LEFT_ARROW);
5313         gdk_window_set_cursor(sheet->column_title_window,sheet->cursor_drag);
5314       }
5315     }
5316   }      
5317
5318   if(event->window == sheet->row_title_window && gtk_sheet_rows_resizable(sheet)){
5319     gtk_widget_get_pointer(widget, &x, &y);
5320     if(!GTK_SHEET_IN_SELECTION(sheet) && POSSIBLE_YDRAG(sheet,y, &column)){
5321       new_cursor=GDK_SB_V_DOUBLE_ARROW;
5322       if(new_cursor != sheet->cursor_drag->type){
5323         gdk_cursor_destroy(sheet->cursor_drag);
5324         sheet->cursor_drag=gdk_cursor_new(GDK_SB_V_DOUBLE_ARROW);
5325         gdk_window_set_cursor(sheet->row_title_window,sheet->cursor_drag);
5326       }
5327     }else{
5328       new_cursor=GDK_TOP_LEFT_ARROW;
5329       if(!GTK_SHEET_IN_YDRAG(sheet) && new_cursor != sheet->cursor_drag->type){
5330         gdk_cursor_destroy(sheet->cursor_drag);
5331         sheet->cursor_drag=gdk_cursor_new(GDK_TOP_LEFT_ARROW);
5332         gdk_window_set_cursor(sheet->row_title_window,sheet->cursor_drag);
5333       }
5334     }
5335   }      
5336
5337   new_cursor=GDK_PLUS;
5338   if(!POSSIBLE_DRAG(sheet,x,y,&row,&column) && !GTK_SHEET_IN_DRAG(sheet) &&
5339      !POSSIBLE_RESIZE(sheet,x,y,&row,&column) && !GTK_SHEET_IN_RESIZE(sheet) &&
5340      event->window == sheet->sheet_window && 
5341      new_cursor != sheet->cursor_drag->type){
5342          gdk_cursor_destroy(sheet->cursor_drag);
5343          sheet->cursor_drag=gdk_cursor_new(GDK_PLUS);
5344          gdk_window_set_cursor(sheet->sheet_window,sheet->cursor_drag);
5345   }
5346
5347   new_cursor=GDK_TOP_LEFT_ARROW;
5348   if(!(POSSIBLE_RESIZE(sheet,x,y,&row,&column) || GTK_SHEET_IN_RESIZE(sheet)) &&
5349      (POSSIBLE_DRAG(sheet, x,y,&row,&column) || GTK_SHEET_IN_DRAG(sheet)) && 
5350      event->window == sheet->sheet_window && 
5351      new_cursor != sheet->cursor_drag->type){
5352          gdk_cursor_destroy(sheet->cursor_drag);
5353          sheet->cursor_drag=gdk_cursor_new(GDK_TOP_LEFT_ARROW);
5354          gdk_window_set_cursor(sheet->sheet_window,sheet->cursor_drag);
5355   }
5356
5357   new_cursor=GDK_SIZING;
5358   if(!GTK_SHEET_IN_DRAG(sheet) &&
5359      (POSSIBLE_RESIZE(sheet,x,y,&row,&column) || GTK_SHEET_IN_RESIZE(sheet)) &&
5360      event->window == sheet->sheet_window && 
5361      new_cursor != sheet->cursor_drag->type){
5362          gdk_cursor_destroy(sheet->cursor_drag);
5363          sheet->cursor_drag=gdk_cursor_new(GDK_SIZING);
5364          gdk_window_set_cursor(sheet->sheet_window,sheet->cursor_drag);
5365   }
5366
5367   gdk_window_get_pointer (widget->window, &x, &y, &mods);
5368   if(!(mods & GDK_BUTTON1_MASK)) return FALSE;
5369
5370   if (GTK_SHEET_IN_XDRAG (sheet)){
5371         if (event->is_hint || event->window != widget->window)
5372             gtk_widget_get_pointer (widget, &x, NULL);
5373           else
5374             x = event->x;
5375
5376           new_column_width (sheet, sheet->drag_cell.col, &x);
5377           if (x != sheet->x_drag)
5378             {
5379               draw_xor_vline (sheet);
5380               sheet->x_drag = x;
5381               draw_xor_vline (sheet);
5382             }
5383           return TRUE;
5384   }
5385
5386   if (GTK_SHEET_IN_YDRAG (sheet)){
5387           if (event->is_hint || event->window != widget->window)
5388             gtk_widget_get_pointer (widget, NULL, &y);
5389           else
5390             y = event->y;
5391
5392           new_row_height (sheet, sheet->drag_cell.row, &y);
5393           if (y != sheet->y_drag)
5394             {
5395               draw_xor_hline (sheet);
5396               sheet->y_drag = y;
5397               draw_xor_hline (sheet);
5398             }
5399           return TRUE;
5400   }
5401
5402   if (GTK_SHEET_IN_DRAG(sheet)){
5403        GtkSheetRange aux;
5404        column=COLUMN_FROM_XPIXEL(sheet,x)-sheet->drag_cell.col;
5405        row=ROW_FROM_YPIXEL(sheet,y)-sheet->drag_cell.row;
5406        if(sheet->state==GTK_SHEET_COLUMN_SELECTED) row=0;
5407        if(sheet->state==GTK_SHEET_ROW_SELECTED) column=0;
5408        sheet->x_drag=x;
5409        sheet->y_drag=y;
5410        aux=sheet->range;
5411        if(aux.row0+row >= 0 && aux.rowi+row < yyy_row_count(sheet) &&
5412           aux.col0+column >= 0 && aux.coli+column < xxx_column_count(sheet)){
5413              aux=sheet->drag_range;
5414              sheet->drag_range.row0=sheet->range.row0+row;
5415              sheet->drag_range.col0=sheet->range.col0+column;
5416              sheet->drag_range.rowi=sheet->range.rowi+row;
5417              sheet->drag_range.coli=sheet->range.coli+column;
5418              if(aux.row0 != sheet->drag_range.row0 ||
5419                 aux.col0 != sheet->drag_range.col0){
5420                 draw_xor_rectangle (sheet, aux);
5421                 draw_xor_rectangle (sheet, sheet->drag_range);
5422              }
5423        }
5424        return TRUE;
5425   }
5426
5427   if (GTK_SHEET_IN_RESIZE(sheet)){
5428        GtkSheetRange aux;
5429        gint v_h, current_col, current_row, col_threshold, row_threshold;
5430        v_h=1;
5431
5432        if(abs(x-COLUMN_LEFT_XPIXEL(sheet,sheet->drag_cell.col)) >
5433           abs(y-ROW_TOP_YPIXEL(sheet,sheet->drag_cell.row))) v_h=2;
5434         
5435        current_col = COLUMN_FROM_XPIXEL(sheet,x);
5436        current_row = ROW_FROM_YPIXEL(sheet,y);
5437        column = current_col-sheet->drag_cell.col;
5438        row    = current_row-sheet->drag_cell.row;
5439
5440        /*use half of column width resp. row height as threshold to expand selection*/
5441        col_threshold = COLUMN_LEFT_XPIXEL(sheet,current_col)+xxx_column_width (sheet,current_col)/2;
5442        if (column > 0){
5443          if (x < col_threshold)
5444            column-=1;
5445        }
5446        else if (column < 0){
5447          if (x > col_threshold) 
5448            column+=1;
5449        }
5450        row_threshold = ROW_TOP_YPIXEL(sheet,current_row)+yyy_row_height (sheet, current_row)/2;
5451        if (row > 0){
5452          if(y < row_threshold)
5453            row-=1;
5454        }
5455        else if (row < 0){
5456          if(y > row_threshold)
5457            row+=1;       
5458        }
5459
5460        if(sheet->state==GTK_SHEET_COLUMN_SELECTED) row=0;
5461        if(sheet->state==GTK_SHEET_ROW_SELECTED) column=0;
5462        sheet->x_drag=x;
5463        sheet->y_drag=y;
5464        aux=sheet->range;
5465
5466        if(v_h==1) 
5467            column=0;
5468        else
5469            row=0;
5470
5471        if(aux.row0+row >= 0 && aux.rowi+row < yyy_row_count(sheet) &&
5472           aux.col0+column >= 0 && aux.coli+column < xxx_column_count(sheet)){
5473
5474              aux=sheet->drag_range;
5475              sheet->drag_range=sheet->range;
5476
5477              if(row<0) sheet->drag_range.row0=sheet->range.row0+row;
5478              if(row>0) sheet->drag_range.rowi=sheet->range.rowi+row;
5479              if(column<0) sheet->drag_range.col0=sheet->range.col0+column;
5480              if(column>0) sheet->drag_range.coli=sheet->range.coli+column;
5481              
5482              if(aux.row0 != sheet->drag_range.row0 ||
5483                 aux.rowi != sheet->drag_range.rowi ||
5484                 aux.col0 != sheet->drag_range.col0 ||
5485                 aux.coli != sheet->drag_range.coli){
5486                      draw_xor_rectangle (sheet, aux);
5487                      draw_xor_rectangle (sheet, sheet->drag_range);
5488              }
5489        }
5490        return TRUE;
5491   }
5492
5493   
5494
5495   gtk_sheet_get_pixel_info (sheet, x, y, &row, &column);
5496
5497   if(sheet->state==GTK_SHEET_NORMAL && row==sheet->active_cell.row &&
5498      column==sheet->active_cell.col) return TRUE;
5499
5500   if(GTK_SHEET_IN_SELECTION(sheet) && mods&GDK_BUTTON1_MASK)
5501                           gtk_sheet_extend_selection(sheet, row, column);
5502
5503   return TRUE;
5504 }
5505
5506 static gint
5507 gtk_sheet_move_query(GtkSheet *sheet, gint row, gint column)
5508 {
5509   gint row_move, column_move;
5510   gfloat row_align, col_align;
5511   guint height, width;
5512   gint new_row = row;
5513   gint new_col = column;
5514
5515   row_move=FALSE;
5516   column_move=FALSE;
5517   row_align=-1.;
5518   col_align=-1.;
5519
5520   height = sheet->sheet_window_height;
5521   width = sheet->sheet_window_width;
5522
5523   if(row>=MAX_VISIBLE_ROW(sheet) && sheet->state!=GTK_SHEET_COLUMN_SELECTED) {
5524           row_align = 1.;
5525           new_row = MIN(yyy_row_count(sheet), row + 1);
5526           row_move = TRUE;
5527           if(MAX_VISIBLE_ROW(sheet) == yyy_row_count(sheet) - 1 &&
5528              ROW_TOP_YPIXEL(sheet, yyy_row_count(sheet)-1) + 
5529              yyy_row_height(sheet, yyy_row_count(sheet)-1) < height){
5530                  row_move = FALSE;
5531                  row_align = -1.;
5532           }
5533   }
5534   if(row<MIN_VISIBLE_ROW(sheet) && sheet->state!=GTK_SHEET_COLUMN_SELECTED) {
5535           row_align= 0.;
5536           row_move = TRUE;
5537   }
5538   if(column>=MAX_VISIBLE_COLUMN(sheet) && sheet->state!=GTK_SHEET_ROW_SELECTED) {
5539           col_align = 1.;
5540           new_col = MIN(xxx_column_count(sheet) - 1, column + 1);
5541           column_move = TRUE;
5542           if(MAX_VISIBLE_COLUMN(sheet) == (xxx_column_count(sheet) - 1) &&
5543              COLUMN_LEFT_XPIXEL(sheet, xxx_column_count(sheet) - 1) + 
5544              xxx_column_width(sheet, xxx_column_count(sheet) - 1) < width)
5545             {
5546               column_move = FALSE;
5547               col_align = -1.;
5548             }
5549   } 
5550   if(column<MIN_VISIBLE_COLUMN(sheet) && sheet->state!=GTK_SHEET_ROW_SELECTED) {
5551           col_align = 0.;
5552           column_move = TRUE;
5553   }
5554
5555   if(row_move || column_move){
5556         gtk_sheet_moveto(sheet, new_row, new_col, row_align, col_align);
5557   }
5558
5559   return(row_move || column_move);
5560 }
5561
5562 static void
5563 gtk_sheet_extend_selection(GtkSheet *sheet, gint row, gint column)
5564 {
5565    GtkSheetRange range;
5566    gint state;
5567    gint r,c;
5568
5569    if(row == sheet->selection_cell.row && column == sheet->selection_cell.col)
5570         return;
5571
5572    if(sheet->selection_mode == GTK_SELECTION_SINGLE) return;
5573
5574    gtk_sheet_move_query(sheet, row, column);
5575    gtk_widget_grab_focus(GTK_WIDGET(sheet));
5576
5577    if(GTK_SHEET_IN_DRAG(sheet)) return;
5578
5579    state=sheet->state;
5580
5581    switch(sheet->state){
5582     case GTK_SHEET_ROW_SELECTED:
5583          column = xxx_column_count(sheet) - 1;
5584          break;
5585     case GTK_SHEET_COLUMN_SELECTED:
5586          row = yyy_row_count(sheet) - 1;
5587          break; 
5588     case GTK_SHEET_NORMAL:
5589          sheet->state=GTK_SHEET_RANGE_SELECTED;
5590          r=sheet->active_cell.row;
5591          c=sheet->active_cell.col;
5592          sheet->range.col0=c;
5593          sheet->range.row0=r;
5594          sheet->range.coli=c;
5595          sheet->range.rowi=r;
5596          gdk_draw_pixmap(sheet->sheet_window,
5597                    GTK_WIDGET(sheet)->style->fg_gc[GTK_STATE_NORMAL],
5598                    sheet->pixmap,
5599                    COLUMN_LEFT_XPIXEL(sheet,c)-1,
5600                    ROW_TOP_YPIXEL(sheet,r)-1,
5601                    COLUMN_LEFT_XPIXEL(sheet,c)-1,
5602                    ROW_TOP_YPIXEL(sheet,r)-1,
5603                    xxx_column_width(sheet, c)+4,
5604                    yyy_row_height(sheet, r)+4);   
5605          gtk_sheet_range_draw_selection(sheet, sheet->range);
5606     case GTK_SHEET_RANGE_SELECTED:
5607          sheet->state=GTK_SHEET_RANGE_SELECTED;
5608    }
5609
5610    sheet->selection_cell.row = row;
5611    sheet->selection_cell.col = column;
5612
5613    range.col0=MIN(column,sheet->active_cell.col);
5614    range.coli=MAX(column,sheet->active_cell.col);
5615    range.row0=MIN(row,sheet->active_cell.row);
5616    range.rowi=MAX(row,sheet->active_cell.row);
5617
5618    if(range.row0 != sheet->range.row0 || range.rowi != sheet->range.rowi ||
5619       range.col0 != sheet->range.col0 || range.coli != sheet->range.coli ||
5620       state==GTK_SHEET_NORMAL)
5621                gtk_sheet_real_select_range(sheet, &range);
5622
5623 }
5624
5625 static gint
5626 gtk_sheet_entry_key_press(GtkWidget *widget,
5627                           GdkEventKey *key)
5628 {
5629   gboolean focus;
5630   gtk_signal_emit_by_name(GTK_OBJECT(widget), "key_press_event", key, &focus);
5631   return focus;
5632 }
5633
5634 static gint
5635 gtk_sheet_key_press(GtkWidget *widget,
5636                     GdkEventKey *key)
5637 {
5638   GtkSheet *sheet;
5639   gint row, col;
5640   gint state;
5641   gboolean extend_selection = FALSE;
5642   gboolean force_move = FALSE;
5643   gboolean in_selection = FALSE;
5644   gboolean veto = TRUE;
5645   gint scroll = 1;
5646
5647   sheet = GTK_SHEET(widget);
5648
5649   if(key->state & GDK_CONTROL_MASK || key->keyval==GDK_Control_L ||
5650      key->keyval==GDK_Control_R) return FALSE;
5651
5652 /*
5653   {
5654     if(key->keyval=='c' || key->keyval == 'C' && sheet->state != GTK_STATE_NORMAL)
5655             gtk_sheet_clip_range(sheet, sheet->range);
5656     if(key->keyval=='x' || key->keyval == 'X')
5657             gtk_sheet_unclip_range(sheet);    
5658     return FALSE;
5659   }
5660 */
5661
5662   extend_selection = (key->state & GDK_SHIFT_MASK) || key->keyval==GDK_Shift_L 
5663 || key->keyval==GDK_Shift_R;
5664
5665   state=sheet->state;
5666   in_selection = GTK_SHEET_IN_SELECTION(sheet);
5667   GTK_SHEET_UNSET_FLAGS(sheet, GTK_SHEET_IN_SELECTION);
5668
5669   switch(key->keyval){
5670     case GDK_Return: case GDK_KP_Enter:
5671       if(sheet->state == GTK_SHEET_NORMAL && 
5672          !GTK_SHEET_IN_SELECTION(sheet))
5673          gtk_signal_emit_stop_by_name(GTK_OBJECT(gtk_sheet_get_entry(sheet)), 
5674                                      "key_press_event");
5675       row = sheet->active_cell.row;
5676       col = sheet->active_cell.col;
5677       if(sheet->state == GTK_SHEET_COLUMN_SELECTED)
5678            row = MIN_VISIBLE_ROW(sheet)-1;
5679       if(sheet->state == GTK_SHEET_ROW_SELECTED)
5680            col = MIN_VISIBLE_COLUMN(sheet);
5681       if(row < yyy_row_count(sheet) - 1){
5682            row = row + scroll;
5683            while(!yyy_row_is_visible(sheet, row) && row<yyy_row_count(sheet)-1) 
5684              row++;
5685       }
5686       gtk_sheet_click_cell(sheet, row, col, &veto);
5687       extend_selection = FALSE;
5688       break;
5689    case GDK_ISO_Left_Tab:
5690       row = sheet->active_cell.row;
5691       col = sheet->active_cell.col;
5692       if(sheet->state == GTK_SHEET_ROW_SELECTED) 
5693            col = MIN_VISIBLE_COLUMN(sheet)-1;
5694       if(sheet->state == GTK_SHEET_COLUMN_SELECTED) 
5695            row = MIN_VISIBLE_ROW(sheet);
5696       if(col > 0){
5697            col = col - scroll; 
5698            while(! xxx_column_is_visible(sheet, col) && col>0) col--;
5699            col=MAX(0, col);
5700       }       
5701       gtk_sheet_click_cell(sheet, row, col, &veto);
5702       extend_selection = FALSE;
5703       break;
5704    case GDK_Tab:
5705       row = sheet->active_cell.row;
5706       col = sheet->active_cell.col;
5707       if(sheet->state == GTK_SHEET_ROW_SELECTED) 
5708            col = MIN_VISIBLE_COLUMN(sheet)-1;
5709       if(sheet->state == GTK_SHEET_COLUMN_SELECTED) 
5710            row = MIN_VISIBLE_ROW(sheet);
5711       if(col < xxx_column_count(sheet) - 1)
5712         {
5713           col = col + scroll; 
5714           while(! xxx_column_is_visible(sheet, col) && 
5715                 col < xxx_column_count(sheet) - 1) 
5716             col++;
5717         }       
5718       gtk_sheet_click_cell(sheet, row, col, &veto);
5719       extend_selection = FALSE;
5720       break;
5721 /*    case GDK_BackSpace:
5722       if(sheet->active_cell.row >= 0 && sheet->active_cell.col >= 0){
5723        if(sheet->active_cell.col > 0){
5724             col = sheet->active_cell.col - scroll; 
5725             row = sheet->active_cell.row;
5726             while(!sheet->column[col].is_visible && col > 0) col--;
5727        }       
5728       }
5729       gtk_sheet_click_cell(sheet, row, col, &veto);
5730       extend_selection = FALSE;
5731       break;
5732 */
5733     case GDK_Page_Up:
5734       scroll=MAX_VISIBLE_ROW(sheet)-MIN_VISIBLE_ROW(sheet)+1;
5735     case GDK_Up:
5736       if(extend_selection){
5737         if(state==GTK_STATE_NORMAL){
5738            row=sheet->active_cell.row;
5739            col=sheet->active_cell.col;
5740            gtk_sheet_click_cell(sheet, row, col, &veto);
5741            if(!veto) break;
5742         }
5743         if(sheet->selection_cell.row > 0){
5744           row = sheet->selection_cell.row - scroll;
5745           while(!yyy_row_is_visible(sheet, row) && row > 0) row--;
5746           row = MAX(0, row);
5747           gtk_sheet_extend_selection(sheet, row, sheet->selection_cell.col);
5748         }
5749         return TRUE;
5750       }
5751       col = sheet->active_cell.col;
5752       row = sheet->active_cell.row;
5753       if(state==GTK_SHEET_COLUMN_SELECTED) 
5754              row = MIN_VISIBLE_ROW(sheet);
5755       if(state==GTK_SHEET_ROW_SELECTED) 
5756              col = MIN_VISIBLE_COLUMN(sheet);
5757       row = row - scroll;
5758       while(!yyy_row_is_visible(sheet, row) && row > 0) row--;
5759       row = MAX(0,row);
5760       gtk_sheet_click_cell(sheet, row, col, &veto);
5761       extend_selection = FALSE;
5762       break;
5763     case GDK_Page_Down:
5764       scroll=MAX_VISIBLE_ROW(sheet)-MIN_VISIBLE_ROW(sheet)+1;
5765     case GDK_Down:
5766       if(extend_selection){
5767         if(state==GTK_STATE_NORMAL){
5768            row=sheet->active_cell.row;
5769            col=sheet->active_cell.col;
5770            gtk_sheet_click_cell(sheet, row, col, &veto);
5771            if(!veto) break;
5772         }
5773         if(sheet->selection_cell.row < yyy_row_count(sheet)-1){
5774           row = sheet->selection_cell.row + scroll;
5775           while(!yyy_row_is_visible(sheet, row) && row < yyy_row_count(sheet)-1) row++;
5776           row = MIN(yyy_row_count(sheet)-1, row);
5777           gtk_sheet_extend_selection(sheet, row, sheet->selection_cell.col);
5778         }
5779         return TRUE;
5780       }
5781       col = sheet->active_cell.col;
5782       row = sheet->active_cell.row;
5783       if(sheet->active_cell.row < yyy_row_count(sheet)-1){
5784            if(state==GTK_SHEET_COLUMN_SELECTED) 
5785                 row = MIN_VISIBLE_ROW(sheet)-1;
5786            if(state==GTK_SHEET_ROW_SELECTED) 
5787                 col = MIN_VISIBLE_COLUMN(sheet);
5788            row = row + scroll;
5789            while(!yyy_row_is_visible(sheet, row) && row < yyy_row_count(sheet)-1) row++;
5790            row = MIN(yyy_row_count(sheet)-1, row);
5791       }
5792       gtk_sheet_click_cell(sheet, row, col, &veto);
5793       extend_selection = FALSE;
5794       break;
5795     case GDK_Right:
5796       if(extend_selection){
5797         if(state==GTK_STATE_NORMAL){
5798            row=sheet->active_cell.row;
5799            col=sheet->active_cell.col;
5800            gtk_sheet_click_cell(sheet, row, col, &veto);
5801            if(!veto) break;
5802         }
5803         if(sheet->selection_cell.col < xxx_column_count(sheet) - 1)
5804           {
5805             col = sheet->selection_cell.col + 1;
5806             while(! xxx_column_is_visible(sheet, col) && col < xxx_column_count(sheet) - 1) 
5807               col++;
5808             gtk_sheet_extend_selection(sheet, sheet->selection_cell.row, col);
5809           }
5810         return TRUE;
5811       }
5812       col = sheet->active_cell.col;
5813       row = sheet->active_cell.row;
5814       if(sheet->active_cell.col < xxx_column_count(sheet) - 1){
5815            col ++;
5816            if(state==GTK_SHEET_ROW_SELECTED) 
5817                 col = MIN_VISIBLE_COLUMN(sheet)-1;
5818            if(state==GTK_SHEET_COLUMN_SELECTED) 
5819                 row = MIN_VISIBLE_ROW(sheet);
5820            while(! xxx_column_is_visible(sheet, col) && col < xxx_column_count(sheet) - 1) col++;
5821            if(strlen(gtk_entry_get_text(GTK_ENTRY(gtk_sheet_get_entry(sheet)))) == 0 
5822               || force_move) {
5823                 gtk_sheet_click_cell(sheet, row, col, &veto);
5824            }
5825            else
5826               return FALSE;
5827       }
5828       extend_selection = FALSE;
5829       break;
5830     case GDK_Left:
5831       if(extend_selection){
5832         if(state==GTK_STATE_NORMAL){
5833            row=sheet->active_cell.row;
5834            col=sheet->active_cell.col;
5835            gtk_sheet_click_cell(sheet, row, col, &veto);
5836            if(!veto) break;
5837         }
5838         if(sheet->selection_cell.col > 0){
5839           col = sheet->selection_cell.col - 1;
5840           while(! xxx_column_is_visible(sheet, col) && col > 0) col--;          
5841           gtk_sheet_extend_selection(sheet, sheet->selection_cell.row, col);
5842         }
5843         return TRUE;
5844       }
5845       col = sheet->active_cell.col - 1;
5846       row = sheet->active_cell.row;
5847       if(state==GTK_SHEET_ROW_SELECTED) 
5848                 col = MIN_VISIBLE_COLUMN(sheet)-1;
5849       if(state==GTK_SHEET_COLUMN_SELECTED) 
5850                 row = MIN_VISIBLE_ROW(sheet);
5851       while(! xxx_column_is_visible(sheet, col) && col > 0) col--;
5852       col = MAX(0, col);
5853
5854       if(strlen(gtk_entry_get_text(GTK_ENTRY(gtk_sheet_get_entry(sheet)))) == 0
5855          || force_move){
5856                 gtk_sheet_click_cell(sheet, row, col, &veto);
5857       }
5858       else
5859          return FALSE;
5860       extend_selection = FALSE;
5861       break;
5862     case GDK_Home:
5863       row=0;
5864       while(!yyy_row_is_visible(sheet, row) && row < yyy_row_count(sheet)-1) row++;
5865       gtk_sheet_click_cell(sheet, row, sheet->active_cell.col, &veto);
5866       extend_selection = FALSE;
5867       break;
5868     case GDK_End:
5869       row=yyy_row_count(sheet)-1;
5870       while(!yyy_row_is_visible(sheet, row) && row > 0) row--;
5871       gtk_sheet_click_cell(sheet, row, sheet->active_cell.col, &veto);
5872       extend_selection = FALSE;
5873       break;
5874     default:
5875       if(in_selection) {
5876         GTK_SHEET_SET_FLAGS(sheet, GTK_SHEET_IN_SELECTION);
5877         if(extend_selection) return TRUE;
5878       }
5879       if(state == GTK_SHEET_ROW_SELECTED) 
5880         sheet->active_cell.col=MIN_VISIBLE_COLUMN(sheet);
5881       if(state == GTK_SHEET_COLUMN_SELECTED)
5882         sheet->active_cell.row=MIN_VISIBLE_ROW(sheet);
5883       return FALSE;
5884   }
5885
5886   if(extend_selection) return TRUE;
5887
5888   gtk_sheet_activate_cell(sheet, sheet->active_cell.row,
5889                                  sheet->active_cell.col);
5890
5891   return TRUE;
5892
5893
5894 static void
5895 gtk_sheet_size_request (GtkWidget * widget,
5896                         GtkRequisition * requisition)
5897 {
5898   GtkSheet *sheet;
5899   GList *children;
5900   GtkSheetChild *child;
5901   GtkRequisition child_requisition;
5902
5903   g_return_if_fail (widget != NULL);
5904   g_return_if_fail (GTK_IS_SHEET (widget));
5905   g_return_if_fail (requisition != NULL);
5906
5907   sheet = GTK_SHEET (widget);
5908
5909   requisition->width = 3*DEFAULT_COLUMN_WIDTH;
5910   requisition->height = 3*DEFAULT_ROW_HEIGHT(widget);
5911
5912   /* compute the size of the column title area */
5913   if(sheet->column_titles_visible) 
5914      requisition->height += sheet->column_title_area.height;
5915
5916   /* compute the size of the row title area */
5917   if(sheet->row_titles_visible) 
5918      requisition->width += sheet->row_title_area.width;
5919
5920   sheet->view.row0=ROW_FROM_YPIXEL(sheet, sheet->column_title_area.height+1);
5921   sheet->view.rowi=ROW_FROM_YPIXEL(sheet, sheet->sheet_window_height-1);
5922   sheet->view.col0=COLUMN_FROM_XPIXEL(sheet, sheet->row_title_area.width+1);
5923   sheet->view.coli=COLUMN_FROM_XPIXEL(sheet, sheet->sheet_window_width);
5924
5925   if(!sheet->column_titles_visible) 
5926      sheet->view.row0=ROW_FROM_YPIXEL(sheet, 1);
5927
5928   if(!sheet->row_titles_visible) 
5929      sheet->view.col0=COLUMN_FROM_XPIXEL(sheet, 1);
5930
5931   children = sheet->children;
5932   while (children)
5933   {
5934     child = children->data;
5935     children = children->next;
5936
5937     gtk_widget_size_request(child->widget, &child_requisition);
5938   }
5939 }
5940
5941  
5942 static void
5943 gtk_sheet_size_allocate (GtkWidget * widget,
5944                          GtkAllocation * allocation)
5945 {
5946   GtkSheet *sheet;
5947   GtkAllocation sheet_allocation;
5948   gint border_width;
5949
5950   g_return_if_fail (widget != NULL);
5951   g_return_if_fail (GTK_IS_SHEET (widget));
5952   g_return_if_fail (allocation != NULL);
5953
5954   sheet = GTK_SHEET (widget);
5955   widget->allocation = *allocation;
5956   border_width = GTK_CONTAINER(widget)->border_width;
5957
5958   if (GTK_WIDGET_REALIZED (widget))
5959     gdk_window_move_resize (widget->window,
5960                             allocation->x + border_width,
5961                             allocation->y + border_width,
5962                             allocation->width - 2*border_width,
5963                             allocation->height - 2*border_width);
5964
5965   /* use internal allocation structure for all the math
5966    * because it's easier than always subtracting the container
5967    * border width */
5968   sheet->internal_allocation.x = 0;
5969   sheet->internal_allocation.y = 0;
5970   sheet->internal_allocation.width = allocation->width - 2*border_width;
5971   sheet->internal_allocation.height = allocation->height - 2*border_width;
5972         
5973   sheet_allocation.x = 0;
5974   sheet_allocation.y = 0;
5975   sheet_allocation.width = allocation->width - 2*border_width;
5976   sheet_allocation.height = allocation->height - 2*border_width;
5977
5978   sheet->sheet_window_width = sheet_allocation.width;
5979   sheet->sheet_window_height = sheet_allocation.height;
5980
5981   if (GTK_WIDGET_REALIZED (widget))
5982     gdk_window_move_resize (sheet->sheet_window,
5983                             sheet_allocation.x,
5984                             sheet_allocation.y,
5985                             sheet_allocation.width,
5986                             sheet_allocation.height);
5987
5988     /* position the window which holds the column title buttons */
5989   sheet->column_title_area.x = 0;
5990   sheet->column_title_area.y = 0;
5991   if(sheet->row_titles_visible)
5992        sheet->column_title_area.x = sheet->row_title_area.width;
5993   sheet->column_title_area.width = sheet_allocation.width - 
5994                                      sheet->column_title_area.x;
5995   if(GTK_WIDGET_REALIZED(widget) && sheet->column_titles_visible)
5996       gdk_window_move_resize (sheet->column_title_window,
5997                               sheet->column_title_area.x,
5998                               sheet->column_title_area.y,
5999                               sheet->column_title_area.width,
6000                               sheet->column_title_area.height);
6001
6002   sheet->sheet_window_width = sheet_allocation.width;
6003   sheet->sheet_window_height = sheet_allocation.height;
6004
6005   /* column button allocation */
6006   size_allocate_column_title_buttons (sheet);
6007
6008   /* position the window which holds the row title buttons */
6009   sheet->row_title_area.x = 0;
6010   sheet->row_title_area.y = 0;
6011   if(sheet->column_titles_visible)
6012        sheet->row_title_area.y = sheet->column_title_area.height;
6013   sheet->row_title_area.height = sheet_allocation.height -
6014                                    sheet->row_title_area.y;
6015
6016   if(GTK_WIDGET_REALIZED(widget) && sheet->row_titles_visible)
6017       gdk_window_move_resize (sheet->row_title_window,
6018                               sheet->row_title_area.x,
6019                               sheet->row_title_area.y,
6020                               sheet->row_title_area.width,
6021                               sheet->row_title_area.height);
6022
6023
6024   /* row button allocation */
6025   size_allocate_row_title_buttons (sheet);
6026
6027   sheet->view.row0=ROW_FROM_YPIXEL(sheet, sheet->column_title_area.height+1);
6028   sheet->view.rowi=ROW_FROM_YPIXEL(sheet, sheet->sheet_window_height-1);
6029   sheet->view.col0=COLUMN_FROM_XPIXEL(sheet, sheet->row_title_area.width+1);
6030   sheet->view.coli=COLUMN_FROM_XPIXEL(sheet, sheet->sheet_window_width);
6031
6032   if(!sheet->column_titles_visible)
6033        sheet->view.row0=ROW_FROM_YPIXEL(sheet, 1);
6034       
6035   if(!sheet->row_titles_visible)
6036        sheet->view.col0=COLUMN_FROM_XPIXEL(sheet, 1);
6037
6038   size_allocate_column_title_buttons(sheet);
6039   size_allocate_row_title_buttons(sheet);
6040
6041   /* re-scale backing pixmap */
6042   gtk_sheet_make_backing_pixmap(sheet, 0, 0); 
6043   gtk_sheet_position_children(sheet);
6044
6045   /* set the scrollbars adjustments */
6046   adjust_scrollbars (sheet);
6047 }
6048
6049 static void
6050 size_allocate_column_title_buttons (GtkSheet * sheet)
6051 {
6052   gint i;
6053   gint x,width;
6054
6055   if (!sheet->column_titles_visible) return;
6056   if (!GTK_WIDGET_REALIZED (sheet))
6057     return;
6058
6059   width = sheet->sheet_window_width;
6060   x = 0;
6061
6062   if(sheet->row_titles_visible)
6063     {
6064       width -= sheet->row_title_area.width;
6065       x = sheet->row_title_area.width;
6066     }
6067
6068   if(sheet->column_title_area.width != width || sheet->column_title_area.x != x)
6069   {
6070      sheet->column_title_area.width = width;
6071      sheet->column_title_area.x = x;
6072      gdk_window_move_resize (sheet->column_title_window,
6073                              sheet->column_title_area.x,
6074                              sheet->column_title_area.y,
6075                              sheet->column_title_area.width,
6076                              sheet->column_title_area.height);
6077   }
6078
6079
6080   if(MAX_VISIBLE_COLUMN(sheet) == xxx_column_count(sheet) - 1)
6081      gdk_window_clear_area (sheet->column_title_window,
6082                             0,0,
6083                             sheet->column_title_area.width, 
6084                             sheet->column_title_area.height);
6085
6086   if(!GTK_WIDGET_DRAWABLE(sheet)) return;
6087
6088   for (i = MIN_VISIBLE_COLUMN(sheet); i <= MAX_VISIBLE_COLUMN(sheet); i++)
6089       gtk_sheet_button_draw(sheet,-1,i);
6090 }
6091         
6092 static void
6093 size_allocate_row_title_buttons (GtkSheet * sheet)
6094 {
6095   gint i;
6096   gint y, height;
6097
6098   if (!sheet->row_titles_visible) return;
6099   if (!GTK_WIDGET_REALIZED (sheet))
6100     return;
6101
6102   height = sheet->sheet_window_height;
6103   y = 0;
6104
6105   if(sheet->column_titles_visible)
6106     {
6107       height -= sheet->column_title_area.height;
6108       y = sheet->column_title_area.height;
6109     }
6110     
6111   if(sheet->row_title_area.height != height || sheet->row_title_area.y != y)
6112     {
6113       sheet->row_title_area.y = y;
6114       sheet->row_title_area.height = height;
6115       gdk_window_move_resize (sheet->row_title_window,
6116                               sheet->row_title_area.x,
6117                               sheet->row_title_area.y,
6118                               sheet->row_title_area.width,
6119                               sheet->row_title_area.height);
6120     }
6121   if(MAX_VISIBLE_ROW(sheet) == yyy_row_count(sheet)-1)
6122     gdk_window_clear_area (sheet->row_title_window,
6123                            0,0,
6124                            sheet->row_title_area.width, 
6125                            sheet->row_title_area.height);
6126
6127   if(!GTK_WIDGET_DRAWABLE(sheet)) return;
6128
6129   for(i = MIN_VISIBLE_ROW(sheet); i <= MAX_VISIBLE_ROW(sheet); i++)
6130       gtk_sheet_button_draw(sheet,i,-1);
6131 }
6132           
6133
6134 static void
6135 gtk_sheet_size_allocate_entry(GtkSheet *sheet)
6136 {
6137  GtkAllocation shentry_allocation;
6138  GtkSheetCellAttr attributes;
6139  GtkEntry *sheet_entry;
6140  GtkStyle *style = NULL, *previous_style = NULL;
6141  gint row, col;
6142  gint size, max_size, text_size, column_width;
6143  const gchar *text;
6144
6145  if(!GTK_WIDGET_REALIZED(GTK_WIDGET(sheet))) return;
6146  if(!GTK_WIDGET_MAPPED(GTK_WIDGET(sheet))) return;
6147
6148  sheet_entry = GTK_ENTRY(gtk_sheet_get_entry(sheet));
6149
6150  gtk_sheet_get_attributes(sheet, sheet->active_cell.row, sheet->active_cell.col, &attributes); 
6151
6152  if(GTK_WIDGET_REALIZED(sheet->sheet_entry)){
6153
6154   if(!GTK_WIDGET(sheet_entry)->style) 
6155         gtk_widget_ensure_style(GTK_WIDGET(sheet_entry));
6156
6157   previous_style = GTK_WIDGET(sheet_entry)->style;
6158
6159   style = gtk_style_copy(previous_style);
6160   style->bg[GTK_STATE_NORMAL] = attributes.background;
6161   style->fg[GTK_STATE_NORMAL] = attributes.foreground;
6162   style->text[GTK_STATE_NORMAL] = attributes.foreground;
6163   style->bg[GTK_STATE_ACTIVE] = attributes.background;
6164   style->fg[GTK_STATE_ACTIVE] = attributes.foreground;
6165   style->text[GTK_STATE_ACTIVE] = attributes.foreground;
6166
6167   pango_font_description_free(style->font_desc);
6168   style->font_desc = pango_font_description_copy(attributes.font_desc);
6169
6170   GTK_WIDGET(sheet_entry)->style = style;
6171   gtk_widget_size_request(sheet->sheet_entry, NULL);
6172   GTK_WIDGET(sheet_entry)->style = previous_style;
6173
6174   if(style != previous_style){
6175     if(!GTK_IS_ITEM_ENTRY(sheet->sheet_entry)){
6176       style->bg[GTK_STATE_NORMAL] = previous_style->bg[GTK_STATE_NORMAL];
6177       style->fg[GTK_STATE_NORMAL] = previous_style->fg[GTK_STATE_NORMAL];
6178       style->bg[GTK_STATE_ACTIVE] = previous_style->bg[GTK_STATE_ACTIVE];
6179       style->fg[GTK_STATE_ACTIVE] = previous_style->fg[GTK_STATE_ACTIVE];
6180     }
6181     gtk_widget_set_style(GTK_WIDGET(sheet_entry), style);
6182   }
6183  }
6184
6185  if(GTK_IS_ITEM_ENTRY(sheet_entry))
6186     max_size = GTK_ITEM_ENTRY(sheet_entry)->text_max_size;
6187  else
6188     max_size = 0;
6189
6190  text_size = 0;
6191  text = gtk_entry_get_text(GTK_ENTRY(sheet_entry));
6192  if(text && strlen(text) > 0){ 
6193      text_size = STRING_WIDTH(GTK_WIDGET(sheet), attributes.font_desc, text);
6194  }
6195
6196  column_width=xxx_column_width(sheet, sheet->active_cell.col);
6197
6198  size=MIN(text_size, max_size);
6199  size=MAX(size,column_width-2*CELLOFFSET);
6200
6201  row=sheet->active_cell.row;
6202  col=sheet->active_cell.col;
6203
6204  shentry_allocation.x = COLUMN_LEFT_XPIXEL(sheet,sheet->active_cell.col);
6205  shentry_allocation.y = ROW_TOP_YPIXEL(sheet,sheet->active_cell.row);
6206  shentry_allocation.width = column_width;
6207  shentry_allocation.height = yyy_row_height(sheet, sheet->active_cell.row);
6208
6209  if(GTK_IS_ITEM_ENTRY(sheet->sheet_entry)){
6210
6211    shentry_allocation.height -= 2*CELLOFFSET;
6212    shentry_allocation.y += CELLOFFSET;
6213    if(gtk_sheet_clip_text(sheet))
6214      shentry_allocation.width = column_width - 2*CELLOFFSET;
6215    else
6216      shentry_allocation.width = size;
6217
6218    switch(GTK_ITEM_ENTRY(sheet_entry)->justification){
6219      case GTK_JUSTIFY_CENTER:
6220        shentry_allocation.x += (column_width)/2 - size/2;
6221        break;
6222      case GTK_JUSTIFY_RIGHT:
6223        shentry_allocation.x += column_width - size - CELLOFFSET;
6224        break;
6225      case GTK_JUSTIFY_LEFT:
6226      case GTK_JUSTIFY_FILL:
6227        shentry_allocation.x += CELLOFFSET;
6228        break;
6229     }
6230
6231  }
6232
6233  if(!GTK_IS_ITEM_ENTRY(sheet->sheet_entry)){
6234    shentry_allocation.x += 2;
6235    shentry_allocation.y += 2;
6236    shentry_allocation.width -= MIN(shentry_allocation.width, 3);
6237    shentry_allocation.height -= MIN(shentry_allocation.height, 3);
6238  }
6239
6240  gtk_widget_size_allocate(sheet->sheet_entry, &shentry_allocation);
6241
6242  if(previous_style == style) gtk_style_unref(previous_style);
6243 }
6244
6245 static void
6246 gtk_sheet_entry_set_max_size(GtkSheet *sheet)
6247 {
6248  gint i;
6249  gint size=0;
6250  gint sizel=0, sizer=0;
6251  gint row,col;
6252  GtkJustification justification;
6253  gchar *s = NULL;
6254
6255  row=sheet->active_cell.row;
6256  col=sheet->active_cell.col;
6257
6258  if(!GTK_IS_ITEM_ENTRY(sheet->sheet_entry) || gtk_sheet_clip_text(sheet)) return;
6259
6260  justification = GTK_ITEM_ENTRY(sheet->sheet_entry)->justification;
6261
6262  switch(justification){
6263   case GTK_JUSTIFY_FILL:
6264   case GTK_JUSTIFY_LEFT:
6265     for(i=col+1; i<=MAX_VISIBLE_COLUMN(sheet); i++){
6266       if((s = gtk_sheet_cell_get_text(sheet, row, i)))
6267         {
6268           g_free(s);
6269           break;
6270         }
6271      size+=xxx_column_width(sheet, i);
6272     }
6273     size = MIN(size, sheet->sheet_window_width - COLUMN_LEFT_XPIXEL(sheet, col));
6274     break;
6275  case GTK_JUSTIFY_RIGHT:
6276    for(i=col-1; i>=MIN_VISIBLE_COLUMN(sheet); i--)
6277      {
6278        if((s = gtk_sheet_cell_get_text(sheet, row, i)))
6279          {
6280            g_free(s);
6281            break;
6282          }
6283        size+=xxx_column_width(sheet, i);
6284      }
6285     break;
6286   case GTK_JUSTIFY_CENTER:
6287     for(i=col+1; i<=MAX_VISIBLE_COLUMN(sheet); i++){
6288 /*     if((s = gtk_sheet_cell_get_text(sheet, row, i)))
6289              {
6290              g_free(s);
6291              break;
6292              }
6293 */
6294      sizer+=xxx_column_width(sheet, i);
6295     }
6296     for(i=col-1; i>=MIN_VISIBLE_COLUMN(sheet); i--)
6297       {
6298         if((s = gtk_sheet_cell_get_text(sheet, row, i)))
6299           {
6300             g_free(s);
6301             break;
6302           }
6303         sizel+=xxx_column_width(sheet, i);
6304       }
6305     size=2*MIN(sizel, sizer);
6306     break;
6307  }
6308
6309  if(size != 0) 
6310    size += xxx_column_width(sheet, col);
6311  GTK_ITEM_ENTRY(sheet->sheet_entry)->text_max_size = size;
6312 }
6313
6314 static void
6315 create_sheet_entry(GtkSheet *sheet)
6316 {
6317  GtkWidget *widget;
6318  GtkWidget *parent;
6319  GtkWidget *entry;
6320  gint found_entry = FALSE;
6321
6322  widget = GTK_WIDGET(sheet);
6323
6324  if(sheet->sheet_entry){
6325     /* avoids warnings */
6326     gtk_widget_ref(sheet->sheet_entry);
6327     gtk_widget_unparent(sheet->sheet_entry);
6328     gtk_widget_destroy(sheet->sheet_entry);
6329  }
6330
6331  if(sheet->entry_type){
6332
6333    if(!g_type_is_a (sheet->entry_type, GTK_TYPE_ENTRY)){
6334
6335      parent = GTK_WIDGET(gtk_type_new(sheet->entry_type));
6336
6337      sheet->sheet_entry = parent;
6338
6339      entry = gtk_sheet_get_entry (sheet);
6340      if(GTK_IS_ENTRY(entry)) found_entry = TRUE;
6341
6342    } else {
6343
6344      parent = GTK_WIDGET(gtk_type_new(sheet->entry_type));
6345      entry = parent;
6346      found_entry = TRUE;
6347
6348    }             
6349                                     
6350    if(!found_entry){
6351
6352      g_warning ("Entry type must be GtkEntry subclass, using default");
6353      entry = gtk_item_entry_new();
6354      sheet->sheet_entry = entry;
6355
6356    } else {
6357
6358      sheet->sheet_entry = parent;
6359
6360    }
6361
6362
6363  } else {
6364
6365      entry = gtk_item_entry_new();
6366      sheet->sheet_entry = entry;
6367
6368  }
6369  
6370  gtk_widget_size_request(sheet->sheet_entry, NULL);
6371  
6372  if(GTK_WIDGET_REALIZED(sheet))
6373    {
6374       gtk_widget_set_parent_window (sheet->sheet_entry, sheet->sheet_window);
6375       gtk_widget_set_parent(sheet->sheet_entry, GTK_WIDGET(sheet));
6376       gtk_widget_realize(sheet->sheet_entry);
6377    }
6378
6379  gtk_signal_connect_object(GTK_OBJECT(entry),"key_press_event",
6380                            (GtkSignalFunc) gtk_sheet_entry_key_press,
6381                            GTK_OBJECT(sheet)); 
6382
6383  gtk_widget_show (sheet->sheet_entry); 
6384 }
6385
6386
6387 /* Finds the last child widget that happens to be of type GtkEntry */
6388 static void
6389 find_entry(GtkWidget *w, gpointer user_data)
6390 {
6391   GtkWidget **entry = user_data;
6392   if ( GTK_IS_ENTRY(w))
6393     {
6394       *entry = w;
6395     }
6396 }
6397
6398 GtkWidget * 
6399 gtk_sheet_get_entry(GtkSheet *sheet)
6400 {
6401  GtkWidget *parent;
6402  GtkWidget *entry = NULL;
6403  GtkTableChild *table_child;
6404  GtkBoxChild *box_child;
6405  GList *children = NULL;
6406
6407  g_return_val_if_fail (sheet != NULL, NULL);
6408  g_return_val_if_fail (GTK_IS_SHEET (sheet), NULL);
6409  g_return_val_if_fail (sheet->sheet_entry != NULL, NULL);
6410
6411  if(GTK_IS_ENTRY(sheet->sheet_entry)) return (sheet->sheet_entry);
6412
6413  parent = GTK_WIDGET(sheet->sheet_entry);
6414
6415  if(GTK_IS_TABLE(parent)) children = GTK_TABLE(parent)->children;
6416  if(GTK_IS_BOX(parent)) children = GTK_BOX(parent)->children;
6417
6418  if(GTK_IS_CONTAINER(parent)) 
6419    {
6420      gtk_container_forall(GTK_CONTAINER(parent), find_entry, &entry);
6421      
6422      if(GTK_IS_ENTRY(entry))  
6423        return entry;
6424    }
6425
6426  if(!children) return NULL;
6427
6428  while(children){
6429       if(GTK_IS_TABLE(parent)) {
6430                  table_child = children->data;
6431                  entry = table_child->widget;
6432       }
6433       if(GTK_IS_BOX(parent)){
6434                  box_child = children->data; 
6435                  entry = box_child->widget;
6436       }
6437
6438       if(GTK_IS_ENTRY(entry))  
6439                                 break;
6440       children = children->next;                        
6441  } 
6442
6443
6444  if(!GTK_IS_ENTRY(entry))   return NULL;
6445
6446  return (entry);
6447
6448 }
6449
6450 GtkWidget * 
6451 gtk_sheet_get_entry_widget(GtkSheet *sheet)
6452 {
6453  g_return_val_if_fail (sheet != NULL, NULL);
6454  g_return_val_if_fail (GTK_IS_SHEET (sheet), NULL);
6455  g_return_val_if_fail (sheet->sheet_entry != NULL, NULL);
6456
6457  return (sheet->sheet_entry);
6458 }
6459
6460 #if 0
6461 /* BUTTONS */
6462 static void
6463 row_button_set (GtkSheet *sheet, gint row)
6464 {
6465   if(sheet->row[row].button.state == GTK_STATE_ACTIVE) return;
6466
6467   sheet->row[row].button.state = GTK_STATE_ACTIVE;
6468   gtk_sheet_button_draw(sheet, row, -1);
6469  
6470 }
6471
6472 static void
6473 row_button_release (GtkSheet *sheet, gint row)
6474 {
6475   if(sheet->row[row].button.state == GTK_STATE_NORMAL) return;
6476
6477   sheet->row[row].button.state = GTK_STATE_NORMAL;
6478   gtk_sheet_button_draw(sheet, row, -1);
6479 }
6480 #endif
6481
6482 static void
6483 gtk_sheet_button_draw (GtkSheet *sheet, gint row, gint column)
6484 {
6485   GdkWindow *window = NULL;
6486   GtkShadowType shadow_type;
6487   guint width = 0, height = 0;
6488   gint x = 0, y = 0;
6489   gint index = 0;
6490   gint text_width = 0, text_height = 0;
6491   GtkSheetButton *button = NULL;
6492   GtkSheetChild *child = NULL;
6493   GdkRectangle allocation;
6494   gboolean is_sensitive = FALSE;
6495   gint state = 0;
6496   gint len = 0;
6497   gchar *line = 0;
6498
6499   PangoAlignment align = PANGO_ALIGN_LEFT; 
6500   gboolean rtl;
6501
6502   rtl = gtk_widget_get_direction(GTK_WIDGET(sheet)) == GTK_TEXT_DIR_RTL;
6503
6504   if(!GTK_WIDGET_REALIZED(GTK_WIDGET(sheet))) return;
6505
6506   if(row >= 0 && !yyy_row_is_visible(sheet, row)) return;
6507   if(column >= 0 && ! xxx_column_is_visible(sheet, column)) return;
6508   if(row >= 0 && !sheet->row_titles_visible) return;
6509   if(column >= 0 && !sheet->column_titles_visible) return;
6510   if(column>=0 && column < MIN_VISIBLE_COLUMN(sheet)) return;
6511   if(column>=0 && column > MAX_VISIBLE_COLUMN(sheet)) return;
6512   if(row>=0 && row < MIN_VISIBLE_ROW(sheet)) return;
6513   if(row>=0 && row > MAX_VISIBLE_ROW(sheet)) return;
6514   if( (row == -1) && (column == -1) ) return; 
6515
6516   if(row==-1){
6517      window=sheet->column_title_window;
6518      button= xxx_column_button(sheet, column);
6519      index=column;
6520      x = COLUMN_LEFT_XPIXEL(sheet, column)+CELL_SPACING;
6521      if(sheet->row_titles_visible) x -= sheet->row_title_area.width;
6522      y = 0;
6523      width = xxx_column_width(sheet, column);
6524      height = sheet->column_title_area.height;
6525      is_sensitive=xxx_column_is_sensitive(sheet, column);
6526   }
6527   if(column==-1){
6528      window=sheet->row_title_window;
6529      button = yyy_row_button(sheet, row);
6530      index=row;
6531      x = 0;
6532      y = ROW_TOP_YPIXEL(sheet, row)+CELL_SPACING;
6533      if(sheet->column_titles_visible) y-=sheet->column_title_area.height;
6534      width = sheet->row_title_area.width;
6535      height = yyy_row_height(sheet, row);
6536      is_sensitive=yyy_row_is_sensitive(sheet, row);
6537   }
6538
6539   allocation.x = x;
6540   allocation.y = y;
6541   allocation.width = width;
6542   allocation.height = height;
6543  
6544   gdk_window_clear_area (window,
6545                          x, y,
6546                          width, height);
6547
6548   gtk_paint_box (sheet->button->style, window,
6549                  GTK_STATE_NORMAL, GTK_SHADOW_OUT, 
6550                  &allocation, GTK_WIDGET(sheet->button),
6551                  "buttondefault", x, y, width, height);
6552
6553   state = button->state;
6554   if(!is_sensitive) state=GTK_STATE_INSENSITIVE;
6555
6556   if (state == GTK_STATE_ACTIVE)
6557      shadow_type = GTK_SHADOW_IN;
6558   else
6559      shadow_type = GTK_SHADOW_OUT;
6560
6561   if(state != GTK_STATE_NORMAL && state != GTK_STATE_INSENSITIVE)
6562     gtk_paint_box (sheet->button->style, window,
6563                    button->state, shadow_type, 
6564                    &allocation, GTK_WIDGET(sheet->button),
6565                    "button", x, y, width, height);
6566
6567   if(button->label_visible){
6568
6569     text_height=DEFAULT_ROW_HEIGHT(GTK_WIDGET(sheet))-2*CELLOFFSET;
6570
6571     gdk_gc_set_clip_rectangle(GTK_WIDGET(sheet)->style->fg_gc[button->state], 
6572                               &allocation);
6573     gdk_gc_set_clip_rectangle(GTK_WIDGET(sheet)->style->white_gc, &allocation);
6574
6575     y += 2*sheet->button->style->ythickness;
6576
6577
6578     if(button->label && strlen(button->label)>0){
6579            gchar *words = 0;
6580            PangoLayout *layout = NULL;
6581            gint real_x = x, real_y = y;
6582
6583            words=button->label;
6584            line = g_new(gchar, 1);
6585            line[0]='\0';
6586
6587            while(words && *words != '\0'){
6588              if(*words != '\n'){
6589                 len=strlen(line);
6590                 line=g_realloc(line, len+2);
6591                 line[len]=*words;
6592                 line[len+1]='\0';
6593              }
6594              if(*words == '\n' || *(words+1) == '\0'){
6595                text_width = STRING_WIDTH(GTK_WIDGET(sheet), GTK_WIDGET(sheet)->style->font_desc, line);
6596
6597                layout = gtk_widget_create_pango_layout (GTK_WIDGET(sheet), line);
6598                switch(button->justification){
6599                  case GTK_JUSTIFY_LEFT:
6600                    real_x = x + CELLOFFSET;
6601                    align = rtl ? PANGO_ALIGN_RIGHT : PANGO_ALIGN_LEFT;
6602                    break;
6603                  case GTK_JUSTIFY_RIGHT:
6604                    real_x = x + width - text_width - CELLOFFSET;
6605                    align = rtl ? PANGO_ALIGN_LEFT : PANGO_ALIGN_RIGHT;
6606                    break;
6607                  case GTK_JUSTIFY_CENTER:
6608                  default:
6609                    real_x = x + (width - text_width)/2;
6610                    align = rtl ? PANGO_ALIGN_RIGHT : PANGO_ALIGN_LEFT;
6611                    pango_layout_set_justify (layout, TRUE);
6612                }
6613                pango_layout_set_alignment (layout, align);
6614                gtk_paint_layout (GTK_WIDGET(sheet)->style,
6615                                  window,
6616                                  state,
6617                                  FALSE,
6618                                  &allocation,
6619                                  GTK_WIDGET(sheet),
6620                                  "label",
6621                                  real_x, real_y,
6622                                  layout);
6623                g_object_unref(G_OBJECT(layout));
6624
6625                real_y += text_height + 2;
6626
6627                g_free(line);
6628                line = g_new(gchar, 1);
6629                line[0]='\0';
6630              }
6631              words++;
6632            }
6633            g_free(line);
6634     }
6635
6636     gdk_gc_set_clip_rectangle(GTK_WIDGET(sheet)->style->fg_gc[button->state],
6637                             NULL);
6638     gdk_gc_set_clip_rectangle(GTK_WIDGET(sheet)->style->white_gc, NULL);
6639
6640   }
6641
6642   if((child = button->child) && (child->widget)){
6643       child->x = allocation.x;
6644       child->y = allocation.y;
6645
6646       child->x += (width - child->widget->requisition.width) / 2; 
6647       child->y += (height - child->widget->requisition.height) / 2;
6648       allocation.x = child->x;
6649       allocation.y = child->y;
6650       allocation.width = child->widget->requisition.width;
6651       allocation.height = child->widget->requisition.height;
6652
6653       x = child->x;
6654       y = child->y;
6655
6656       gtk_widget_set_state(child->widget, button->state);
6657
6658       if(GTK_WIDGET_REALIZED(GTK_WIDGET(sheet)) &&
6659          GTK_WIDGET_MAPPED(child->widget))
6660             {
6661               gtk_widget_size_allocate(child->widget, 
6662                                        &allocation);
6663               gtk_widget_queue_draw(child->widget);
6664             }
6665   }
6666
6667   gtk_sheet_button_free(button);
6668    
6669 }
6670
6671
6672 /* SCROLLBARS
6673  *
6674  * functions:
6675  *   adjust_scrollbars
6676  *   vadjustment_changed
6677  *   hadjustment_changed
6678  *   vadjustment_value_changed
6679  *   hadjustment_value_changed */
6680
6681 static void
6682 adjust_scrollbars (GtkSheet * sheet)
6683 {
6684
6685  if(sheet->vadjustment){ 
6686   sheet->vadjustment->page_size = sheet->sheet_window_height;
6687   sheet->vadjustment->page_increment = sheet->sheet_window_height / 2;
6688   sheet->vadjustment->step_increment = DEFAULT_ROW_HEIGHT(GTK_WIDGET(sheet));
6689   sheet->vadjustment->lower = 0;
6690   sheet->vadjustment->upper = SHEET_HEIGHT (sheet) + 80;
6691 /*
6692   if (sheet->sheet_window_height - sheet->voffset > SHEET_HEIGHT (sheet))
6693     {
6694       sheet->vadjustment->value = MAX(0, SHEET_HEIGHT (sheet) - 
6695         sheet->sheet_window_height);
6696       gtk_signal_emit_by_name (GTK_OBJECT (sheet->vadjustment), 
6697                                "value_changed");
6698     }
6699 */
6700     gtk_signal_emit_by_name (GTK_OBJECT(sheet->vadjustment), "changed");
6701
6702  }
6703
6704  if(sheet->hadjustment){
6705   sheet->hadjustment->page_size = sheet->sheet_window_width;
6706   sheet->hadjustment->page_increment = sheet->sheet_window_width / 2;
6707   sheet->hadjustment->step_increment = DEFAULT_COLUMN_WIDTH;
6708   sheet->hadjustment->lower = 0;
6709   sheet->hadjustment->upper = SHEET_WIDTH (sheet)+ 80;
6710 /*
6711   if (sheet->sheet_window_width - sheet->hoffset > SHEET_WIDTH (sheet))
6712     {
6713       sheet->hadjustment->value = MAX(0, SHEET_WIDTH (sheet) - 
6714         sheet->sheet_window_width);
6715       gtk_signal_emit_by_name (GTK_OBJECT(sheet->hadjustment), 
6716                                "value_changed");
6717     }
6718 */
6719     gtk_signal_emit_by_name (GTK_OBJECT(sheet->hadjustment), "changed");
6720
6721  }
6722 /*
6723  if(GTK_WIDGET_REALIZED(sheet)) 
6724    {
6725      if(sheet->row_titles_visible){
6726                  size_allocate_row_title_buttons(sheet);
6727                  gdk_window_show(sheet->row_title_window);
6728      }
6729
6730      if(sheet->column_titles_visible){
6731                  size_allocate_column_title_buttons(sheet);
6732                  gdk_window_show(sheet->column_title_window);
6733      }
6734
6735      gtk_sheet_range_draw(sheet, NULL);
6736    }
6737 */
6738 }
6739
6740
6741 static void
6742 vadjustment_changed (GtkAdjustment * adjustment,
6743                                gpointer data)
6744 {
6745   GtkSheet *sheet;
6746
6747   g_return_if_fail (adjustment != NULL);
6748   g_return_if_fail (data != NULL);
6749
6750   sheet = GTK_SHEET (data);
6751
6752 }
6753
6754 static void
6755 hadjustment_changed (GtkAdjustment * adjustment,
6756                                gpointer data)
6757 {
6758   GtkSheet *sheet;
6759
6760   g_return_if_fail (adjustment != NULL);
6761   g_return_if_fail (data != NULL);
6762
6763   sheet = GTK_SHEET (data);
6764 }
6765
6766
6767 static void
6768 vadjustment_value_changed (GtkAdjustment * adjustment,
6769                                      gpointer data)
6770 {
6771   GtkSheet *sheet;
6772   gint diff, value, old_value;
6773   gint row, new_row;
6774   gint y=0;
6775
6776   g_return_if_fail (adjustment != NULL);
6777   g_return_if_fail (data != NULL);
6778   g_return_if_fail (GTK_IS_SHEET (data));
6779
6780   sheet = GTK_SHEET (data);
6781
6782   if(GTK_SHEET_IS_FROZEN(sheet)) return;
6783
6784   row=ROW_FROM_YPIXEL(sheet,sheet->column_title_area.height + CELL_SPACING);
6785   if(!sheet->column_titles_visible)
6786      row=ROW_FROM_YPIXEL(sheet,CELL_SPACING);
6787     
6788   old_value = -sheet->voffset;
6789
6790   new_row = g_sheet_row_pixel_to_row(sheet->row_geometry,
6791                                      adjustment->value,sheet);
6792
6793   y = g_sheet_row_start_pixel(sheet->row_geometry, new_row, sheet);
6794
6795   if (adjustment->value > sheet->old_vadjustment && sheet->old_vadjustment > 0. &&
6796       yyy_row_height(sheet, row) > sheet->vadjustment->step_increment){
6797 /* This avoids embarrassing twitching */
6798           if(row == new_row && row != yyy_row_count(sheet) - 1 &&
6799              adjustment->value - sheet->old_vadjustment >= 
6800                           sheet->vadjustment->step_increment &&
6801              new_row + 1 != MIN_VISIBLE_ROW(sheet)){
6802                 new_row+=1;
6803                 y=y+yyy_row_height(sheet, row);
6804           }
6805   }
6806
6807 /* Negative old_adjustment enforces the redraw, otherwise avoid spureous redraw */
6808   if(sheet->old_vadjustment >= 0. && row == new_row){
6809       sheet->old_vadjustment = sheet->vadjustment->value;
6810       return;
6811   }
6812
6813   sheet->old_vadjustment = sheet->vadjustment->value;
6814   adjustment->value=y;
6815
6816  
6817   if(new_row == 0){
6818    sheet->vadjustment->step_increment=  yyy_row_height(sheet, 0);
6819   }else{
6820    sheet->vadjustment->step_increment=
6821    MIN(yyy_row_height(sheet, new_row), yyy_row_height(sheet, new_row-1));
6822   }
6823
6824   sheet->vadjustment->value=adjustment->value;
6825
6826   value = adjustment->value;
6827
6828   if (value >= -sheet->voffset)
6829         {
6830           /* scroll down */
6831           diff = value + sheet->voffset;
6832         }
6833   else
6834         {
6835           /* scroll up */
6836           diff = -sheet->voffset - value;
6837         }
6838
6839       sheet->voffset = -value;
6840  
6841   sheet->view.row0=ROW_FROM_YPIXEL(sheet, sheet->column_title_area.height+1);
6842   sheet->view.rowi=ROW_FROM_YPIXEL(sheet, sheet->sheet_window_height-1);
6843   if(!sheet->column_titles_visible)
6844      sheet->view.row0=ROW_FROM_YPIXEL(sheet, 1);
6845
6846   if(GTK_WIDGET_REALIZED(sheet->sheet_entry) &&
6847      sheet->state == GTK_SHEET_NORMAL && 
6848      sheet->active_cell.row >= 0 && sheet->active_cell.col >= 0 &&
6849      !gtk_sheet_cell_isvisible(sheet, sheet->active_cell.row,
6850                                       sheet->active_cell.col))
6851     {
6852       const gchar *text;
6853
6854       text = gtk_entry_get_text(GTK_ENTRY(gtk_sheet_get_entry(sheet)));
6855
6856       if(!text || strlen(text)==0) 
6857              gtk_sheet_cell_clear(sheet,
6858                                   sheet->active_cell.row,
6859                                   sheet->active_cell.col);
6860        gtk_widget_unmap(sheet->sheet_entry);
6861     }
6862
6863   gtk_sheet_position_children(sheet);
6864
6865   gtk_sheet_range_draw(sheet, NULL);
6866   size_allocate_row_title_buttons(sheet);
6867   size_allocate_global_button(sheet);
6868 }
6869
6870 static void
6871 hadjustment_value_changed (GtkAdjustment * adjustment,
6872                            gpointer data)
6873 {
6874   GtkSheet *sheet;
6875   gint i, diff, value, old_value;
6876   gint column, new_column;
6877   gint x=0;
6878
6879   g_return_if_fail (adjustment != NULL);
6880   g_return_if_fail (data != NULL);
6881   g_return_if_fail (GTK_IS_SHEET (data));
6882
6883   sheet = GTK_SHEET (data);
6884
6885   if(GTK_SHEET_IS_FROZEN(sheet)) return;
6886
6887   column=COLUMN_FROM_XPIXEL(sheet,sheet->row_title_area.width + CELL_SPACING);
6888   if(!sheet->row_titles_visible)
6889      column=COLUMN_FROM_XPIXEL(sheet, CELL_SPACING);
6890
6891   old_value = -sheet->hoffset;
6892
6893   for(i=0; i < xxx_column_count(sheet); i++)
6894     {
6895       if(xxx_column_is_visible(sheet, i)) x += xxx_column_width(sheet, i);
6896       if(x > adjustment->value) break;
6897     }
6898   x-=xxx_column_width(sheet, i);
6899   new_column=i;
6900
6901   if (adjustment->value > sheet->old_hadjustment && sheet->old_hadjustment > 0 &&
6902       xxx_column_width(sheet, i) > sheet->hadjustment->step_increment){
6903 /* This avoids embarrassing twitching */
6904           if(column == new_column && column != xxx_column_count(sheet) - 1 &&
6905              adjustment->value - sheet->old_hadjustment >= 
6906                           sheet->hadjustment->step_increment &&
6907              new_column + 1 != MIN_VISIBLE_COLUMN(sheet)){
6908              new_column+=1;
6909              x=x+xxx_column_width(sheet, column);
6910           }
6911   }
6912
6913 /* Negative old_adjustment enforces the redraw, otherwise avoid spureous redraw */
6914   if(sheet->old_hadjustment >= 0. && new_column == column){
6915      sheet->old_hadjustment = sheet->hadjustment->value;
6916      return;
6917   }
6918
6919   sheet->old_hadjustment = sheet->hadjustment->value;
6920   adjustment->value=x;
6921
6922   if(new_column == 0){
6923    sheet->hadjustment->step_increment=
6924    xxx_column_width(sheet, 0);
6925   }else{
6926    sheet->hadjustment->step_increment=
6927    MIN(xxx_column_width(sheet, new_column), xxx_column_width(sheet, new_column-1));
6928   }
6929
6930
6931   sheet->hadjustment->value=adjustment->value;
6932
6933   value = adjustment->value;
6934
6935   if (value >= -sheet->hoffset)
6936         {
6937           /* scroll right */
6938           diff = value + sheet->hoffset;
6939         }
6940   else
6941         {
6942           /* scroll left */
6943           diff = -sheet->hoffset - value;
6944         }
6945
6946   sheet->hoffset = -value;
6947
6948   sheet->view.col0=COLUMN_FROM_XPIXEL(sheet, sheet->row_title_area.width+1);
6949   sheet->view.coli=COLUMN_FROM_XPIXEL(sheet, sheet->sheet_window_width);
6950   if(!sheet->row_titles_visible)
6951     sheet->view.col0=COLUMN_FROM_XPIXEL(sheet, 1);
6952
6953   if(GTK_WIDGET_REALIZED(sheet->sheet_entry) &&
6954      sheet->state == GTK_SHEET_NORMAL && 
6955      sheet->active_cell.row >= 0 && sheet->active_cell.col >= 0 &&
6956      !gtk_sheet_cell_isvisible(sheet, sheet->active_cell.row,
6957                                       sheet->active_cell.col))
6958     {
6959       const gchar *text;
6960
6961       text = gtk_entry_get_text(GTK_ENTRY(gtk_sheet_get_entry(sheet)));
6962       if(!text || strlen(text)==0) 
6963              gtk_sheet_cell_clear(sheet,
6964                                   sheet->active_cell.row,
6965                                   sheet->active_cell.col);
6966
6967       gtk_widget_unmap(sheet->sheet_entry);
6968     }
6969
6970   gtk_sheet_position_children(sheet);
6971
6972   gtk_sheet_range_draw(sheet, NULL);
6973   size_allocate_column_title_buttons(sheet);
6974 }
6975         
6976
6977 /* COLUMN RESIZING */
6978 static void                          
6979 draw_xor_vline (GtkSheet * sheet)
6980 {
6981   GtkWidget *widget;
6982   
6983   g_return_if_fail (sheet != NULL);
6984   
6985   widget = GTK_WIDGET (sheet);
6986
6987   gdk_draw_line (widget->window, sheet->xor_gc,  
6988                  sheet->x_drag,                                       
6989                  sheet->column_title_area.height,                               
6990                  sheet->x_drag,                                             
6991                  sheet->sheet_window_height + 1);
6992 }
6993
6994 /* ROW RESIZING */
6995 static void                          
6996 draw_xor_hline (GtkSheet * sheet)
6997 {
6998   GtkWidget *widget;
6999   
7000   g_return_if_fail (sheet != NULL);
7001   
7002   widget = GTK_WIDGET (sheet);
7003
7004   gdk_draw_line (widget->window, sheet->xor_gc,  
7005                  sheet->row_title_area.width,
7006                  sheet->y_drag,                                       
7007                         
7008                  sheet->sheet_window_width + 1,                      
7009                  sheet->y_drag);                                             
7010 }
7011
7012 /* SELECTED RANGE */
7013 static void
7014 draw_xor_rectangle(GtkSheet *sheet, GtkSheetRange range)
7015 {
7016    gint i;
7017    GdkRectangle clip_area, area;
7018    GdkGCValues values;
7019
7020    area.x=COLUMN_LEFT_XPIXEL(sheet, range.col0);
7021    area.y=ROW_TOP_YPIXEL(sheet, range.row0);
7022    area.width=COLUMN_LEFT_XPIXEL(sheet, range.coli)-area.x+
7023                                         xxx_column_width(sheet, range.coli);
7024    area.height=ROW_TOP_YPIXEL(sheet, range.rowi)-area.y+
7025                                         yyy_row_height(sheet, range.rowi);
7026
7027    clip_area.x=sheet->row_title_area.width;
7028    clip_area.y=sheet->column_title_area.height;
7029    clip_area.width=sheet->sheet_window_width;
7030    clip_area.height=sheet->sheet_window_height;
7031
7032    if(!sheet->row_titles_visible) clip_area.x = 0;
7033    if(!sheet->column_titles_visible) clip_area.y = 0;
7034
7035    if(area.x<0) {
7036       area.width=area.width+area.x;
7037       area.x=0;
7038    }
7039    if(area.width>clip_area.width) area.width=clip_area.width+10;
7040    if(area.y<0) {
7041       area.height=area.height+area.y;
7042       area.y=0;
7043    }
7044    if(area.height>clip_area.height) area.height=clip_area.height+10;
7045
7046    clip_area.x--;
7047    clip_area.y--;
7048    clip_area.width+=3;
7049    clip_area.height+=3;
7050
7051    gdk_gc_get_values(sheet->xor_gc, &values);
7052
7053    gdk_gc_set_clip_rectangle(sheet->xor_gc, &clip_area);
7054
7055    for(i=-1;i<=1;++i)
7056      gdk_draw_rectangle(sheet->sheet_window,
7057                         sheet->xor_gc,
7058                         FALSE,
7059                         area.x+i, area.y+i,
7060                         area.width-2*i, area.height-2*i);
7061
7062
7063    gdk_gc_set_clip_rectangle(sheet->xor_gc, NULL);
7064
7065    gdk_gc_set_foreground(sheet->xor_gc, &values.foreground);
7066
7067 }                      
7068
7069   
7070 /* this function returns the new width of the column being resized given
7071  * the column and x position of the cursor; the x cursor position is passed
7072  * in as a pointer and automaticaly corrected if it's beyond min/max limits */
7073 static guint
7074 new_column_width (GtkSheet * sheet,
7075                   gint column,
7076                   gint * x)
7077 {
7078   gint cx, width;
7079   guint min_width;
7080
7081   cx = *x;
7082
7083   min_width = sheet->column_requisition;
7084
7085   /* you can't shrink a column to less than its minimum width */
7086   if (cx < COLUMN_LEFT_XPIXEL (sheet, column) + min_width)
7087     {
7088       *x = cx = COLUMN_LEFT_XPIXEL (sheet, column) + min_width;
7089     }
7090
7091   /* don't grow past the end of the window */
7092   /*
7093   if (cx > sheet->sheet_window_width)
7094     {
7095       *x = cx = sheet->sheet_window_width;
7096     }
7097     */
7098   /* calculate new column width making sure it doesn't end up
7099    * less than the minimum width */
7100   width = cx - COLUMN_LEFT_XPIXEL (sheet, column);
7101   if (width < min_width)
7102     width = min_width;
7103
7104   xxx_set_column_width(sheet, column, width);
7105   sheet->view.coli=COLUMN_FROM_XPIXEL(sheet, sheet->sheet_window_width);
7106   size_allocate_column_title_buttons (sheet);
7107   
7108   return width;
7109 }
7110
7111 /* this function returns the new height of the row being resized given
7112  * the row and y position of the cursor; the y cursor position is passed
7113  * in as a pointer and automaticaly corrected if it's beyond min/max limits */
7114 static guint
7115 new_row_height (GtkSheet * sheet,
7116                 gint row,
7117                 gint * y)
7118 {
7119   gint cy, height;
7120   guint min_height;
7121
7122   cy = *y;
7123   min_height = sheet->row_requisition;
7124
7125   /* you can't shrink a row to less than its minimum height */
7126   if (cy < ROW_TOP_YPIXEL (sheet, row) + min_height)
7127
7128     {
7129       *y = cy = ROW_TOP_YPIXEL (sheet, row) + min_height;
7130     }
7131
7132   /* don't grow past the end of the window */
7133   /*
7134   if (cy > sheet->sheet_window_height)
7135     {
7136       *y = cy = sheet->sheet_window_height;
7137     }
7138     */
7139   /* calculate new row height making sure it doesn't end up
7140    * less than the minimum height */
7141   height = (cy - ROW_TOP_YPIXEL (sheet, row));
7142   if (height < min_height)
7143     height = min_height;
7144
7145   yyy_set_row_height(sheet, row, height);
7146   sheet->view.rowi=ROW_FROM_YPIXEL(sheet, sheet->sheet_window_height-1);
7147   size_allocate_row_title_buttons (sheet);
7148
7149   return height;
7150 }
7151
7152 static void
7153 gtk_sheet_set_column_width (GtkSheet * sheet,
7154                             gint column,
7155                             guint width)
7156 {
7157   guint min_width;
7158
7159   g_return_if_fail (sheet != NULL);
7160   g_return_if_fail (GTK_IS_SHEET (sheet));
7161
7162   if (column < 0 || column >= xxx_column_count(sheet))
7163     return;
7164
7165   gtk_sheet_column_size_request(sheet, column, &min_width);
7166   if(width < min_width) return;
7167
7168   xxx_set_column_width(sheet, column, width);
7169
7170   if(GTK_WIDGET_REALIZED(GTK_WIDGET(sheet)) && !GTK_SHEET_IS_FROZEN(sheet)){
7171     size_allocate_column_title_buttons (sheet);
7172     adjust_scrollbars (sheet);
7173     gtk_sheet_size_allocate_entry(sheet);
7174     gtk_sheet_range_draw (sheet, NULL);
7175   } else
7176
7177   gtk_signal_emit(GTK_OBJECT(sheet), sheet_signals[CHANGED], -1, column);
7178   gtk_signal_emit(GTK_OBJECT(sheet), sheet_signals[NEW_COL_WIDTH], column, width);
7179
7180 }
7181
7182
7183
7184 void
7185 gtk_sheet_set_row_height (GtkSheet * sheet,
7186                             gint row,
7187                             guint height)
7188 {
7189   guint min_height;
7190
7191   g_return_if_fail (sheet != NULL);
7192   g_return_if_fail (GTK_IS_SHEET (sheet));
7193
7194   if (row < 0 || row >= yyy_row_count(sheet))
7195     return;
7196
7197   gtk_sheet_row_size_request(sheet, row, &min_height);
7198   if(height < min_height) return;
7199
7200   yyy_set_row_height(sheet, row, height);
7201
7202   if(GTK_WIDGET_REALIZED(GTK_WIDGET(sheet)) && !GTK_SHEET_IS_FROZEN(sheet)){
7203     size_allocate_row_title_buttons (sheet);
7204     adjust_scrollbars (sheet);
7205     gtk_sheet_size_allocate_entry(sheet);
7206     gtk_sheet_range_draw (sheet, NULL);
7207   }
7208
7209   gtk_signal_emit(GTK_OBJECT(sheet), sheet_signals[CHANGED], row, -1);
7210   gtk_signal_emit(GTK_OBJECT(sheet), sheet_signals[NEW_ROW_HEIGHT], row, height);
7211
7212 }
7213
7214
7215 gboolean
7216 gtk_sheet_get_attributes(GtkSheet *sheet, gint row, gint col, GtkSheetCellAttr *attributes)
7217 {
7218  const GdkColor *fg, *bg; 
7219  const GtkJustification *j ; 
7220  const PangoFontDescription *font_desc ;
7221  const GtkSheetCellBorder *border ;
7222
7223  g_return_val_if_fail (sheet != NULL, FALSE);
7224  g_return_val_if_fail (GTK_IS_SHEET (sheet), FALSE);
7225
7226  if(row < 0 || col < 0) return FALSE;
7227
7228  init_attributes(sheet, col, attributes);
7229
7230  if ( !sheet->model) 
7231          return FALSE;
7232
7233  attributes->is_editable = g_sheet_model_is_editable(sheet->model, row, col);
7234  attributes->is_visible = g_sheet_model_is_visible(sheet->model, row, col);
7235
7236  fg = g_sheet_model_get_foreground(sheet->model, row, col);
7237  if ( fg ) 
7238    attributes->foreground =  *fg;
7239
7240  bg = g_sheet_model_get_background(sheet->model, row, col);
7241  if ( bg ) 
7242    attributes->background =  *bg;
7243
7244  j = g_sheet_model_get_justification(sheet->model, row, col);
7245  if (j)   attributes->justification = *j;
7246
7247  font_desc = g_sheet_model_get_font_desc(sheet->model, row, col);
7248  if ( font_desc )  attributes->font_desc = font_desc;
7249
7250  border = g_sheet_model_get_cell_border(sheet->model, row, col);
7251
7252  if ( border ) attributes->border = *border;
7253
7254  return TRUE;
7255 }
7256
7257 static void
7258 init_attributes(GtkSheet *sheet, gint col, GtkSheetCellAttr *attributes)
7259 {
7260  /* DEFAULT VALUES */    
7261  attributes->foreground = GTK_WIDGET(sheet)->style->black;
7262  attributes->background = sheet->bg_color;
7263  if(!GTK_WIDGET_REALIZED(GTK_WIDGET(sheet))){
7264    GdkColormap *colormap;
7265    colormap=gdk_colormap_get_system();
7266    gdk_color_black(colormap, &attributes->foreground);
7267    attributes->background = sheet->bg_color;
7268  }
7269  attributes->justification = xxx_column_justification(sheet, col);
7270  attributes->border.width = 0;
7271  attributes->border.line_style = GDK_LINE_SOLID;
7272  attributes->border.cap_style = GDK_CAP_NOT_LAST;
7273  attributes->border.join_style = GDK_JOIN_MITER;
7274  attributes->border.mask = 0;
7275  attributes->border.color = GTK_WIDGET(sheet)->style->black;
7276  attributes->is_editable = TRUE;
7277  attributes->is_visible = TRUE;
7278  attributes->font_desc = GTK_WIDGET(sheet)->style->font_desc;
7279
7280 }       
7281  
7282
7283
7284 /********************************************************************
7285  * Container Functions:
7286  * gtk_sheet_add
7287  * gtk_sheet_put
7288  * gtk_sheet_attach
7289  * gtk_sheet_remove
7290  * gtk_sheet_move_child
7291  * gtk_sheet_position_child
7292  * gtk_sheet_position_children 
7293  * gtk_sheet_realize_child
7294  * gtk_sheet_get_child_at
7295  ********************************************************************/ 
7296
7297 GtkSheetChild *
7298 gtk_sheet_put(GtkSheet *sheet, GtkWidget *child, gint x, gint y)
7299 {
7300   GtkRequisition child_requisition;
7301   GtkSheetChild *child_info;
7302
7303   g_return_val_if_fail(sheet != NULL, NULL);
7304   g_return_val_if_fail(GTK_IS_SHEET(sheet), NULL);
7305   g_return_val_if_fail(child != NULL, NULL);
7306   g_return_val_if_fail(child->parent == NULL, NULL);
7307
7308   child_info = g_new (GtkSheetChild, 1);
7309   child_info->widget = child;
7310   child_info->x = x;  
7311   child_info->y = y;
7312   child_info->attached_to_cell = FALSE;
7313   child_info->floating = TRUE;
7314   child_info->xpadding = child_info->ypadding = 0;
7315   child_info->xexpand = child_info->yexpand = FALSE;
7316   child_info->xshrink = child_info->yshrink = FALSE;
7317   child_info->xfill = child_info->yfill = FALSE;
7318
7319   sheet->children = g_list_append(sheet->children, child_info);
7320
7321   gtk_widget_set_parent (child, GTK_WIDGET(sheet));
7322
7323   gtk_widget_size_request(child, &child_requisition);
7324
7325   if (GTK_WIDGET_VISIBLE(GTK_WIDGET(sheet)))
7326     {
7327        if(GTK_WIDGET_REALIZED(GTK_WIDGET(sheet)) && 
7328           (!GTK_WIDGET_REALIZED(child) || GTK_WIDGET_NO_WINDOW(child)))
7329         gtk_sheet_realize_child(sheet, child_info);
7330
7331        if(GTK_WIDGET_MAPPED(GTK_WIDGET(sheet)) && 
7332           !GTK_WIDGET_MAPPED(child))
7333         gtk_widget_map(child);
7334     }
7335
7336   gtk_sheet_position_child(sheet, child_info);
7337
7338 /* This will avoid drawing on the titles */
7339
7340   if(GTK_WIDGET_REALIZED(GTK_WIDGET(sheet)))
7341    {
7342       if(sheet->row_titles_visible)
7343              gdk_window_show(sheet->row_title_window);
7344       if(sheet->column_titles_visible)
7345              gdk_window_show(sheet->column_title_window);
7346    }
7347
7348   return (child_info);
7349 }
7350
7351 void
7352 gtk_sheet_attach_floating       (GtkSheet *sheet,
7353                                  GtkWidget *widget,
7354                                  gint row, gint col)
7355 {
7356   GdkRectangle area;
7357   GtkSheetChild *child;
7358
7359   if(row < 0 || col < 0){
7360     gtk_sheet_button_attach(sheet, widget, row, col);
7361     return;
7362   }
7363
7364   gtk_sheet_get_cell_area(sheet, row, col, &area);
7365   child = gtk_sheet_put(sheet, widget, area.x, area.y);
7366   child->attached_to_cell = TRUE;
7367   child->row = row;
7368   child->col = col;
7369 }
7370
7371 void
7372 gtk_sheet_attach_default        (GtkSheet *sheet,
7373                                  GtkWidget *widget,
7374                                  gint row, gint col)
7375 {
7376   if(row < 0 || col < 0){
7377     gtk_sheet_button_attach(sheet, widget, row, col);
7378     return;
7379   }
7380
7381   gtk_sheet_attach(sheet, widget, row, col, GTK_EXPAND|GTK_FILL, GTK_EXPAND|GTK_FILL, 0, 0);
7382 }
7383
7384 void
7385 gtk_sheet_attach        (GtkSheet *sheet,
7386                          GtkWidget *widget,
7387                          gint row, gint col,
7388                          gint xoptions,
7389                          gint yoptions,
7390                          gint xpadding,
7391                          gint ypadding)
7392 {
7393   GdkRectangle area;
7394   GtkSheetChild *child = NULL;
7395
7396   if(row < 0 || col < 0){
7397     gtk_sheet_button_attach(sheet, widget, row, col);
7398     return;
7399   }
7400
7401   child = g_new0(GtkSheetChild, 1);
7402   child->attached_to_cell = TRUE;
7403   child->floating = FALSE;
7404   child->widget = widget;
7405   child->row = row;
7406   child->col = col;
7407   child->xpadding = xpadding;
7408   child->ypadding = ypadding;
7409   child->xexpand = (xoptions & GTK_EXPAND) != 0;
7410   child->yexpand = (yoptions & GTK_EXPAND) != 0;
7411   child->xshrink = (xoptions & GTK_SHRINK) != 0;
7412   child->yshrink = (yoptions & GTK_SHRINK) != 0;
7413   child->xfill = (xoptions & GTK_FILL) != 0;
7414   child->yfill = (yoptions & GTK_FILL) != 0;
7415
7416   sheet->children = g_list_append(sheet->children, child);
7417
7418   gtk_sheet_get_cell_area(sheet, row, col, &area);
7419
7420   child->x = area.x + child->xpadding;
7421   child->y = area.y + child->ypadding;
7422
7423   if (GTK_WIDGET_VISIBLE(GTK_WIDGET(sheet)))
7424     {
7425        if(GTK_WIDGET_REALIZED(GTK_WIDGET(sheet)) &&
7426           (!GTK_WIDGET_REALIZED(widget) || GTK_WIDGET_NO_WINDOW(widget)))
7427         gtk_sheet_realize_child(sheet, child);
7428
7429        if(GTK_WIDGET_MAPPED(GTK_WIDGET(sheet)) &&
7430           !GTK_WIDGET_MAPPED(widget))
7431         gtk_widget_map(widget);
7432     }
7433
7434   gtk_sheet_position_child(sheet, child);
7435
7436 /* This will avoid drawing on the titles */
7437
7438   if(GTK_WIDGET_REALIZED(GTK_WIDGET(sheet)))
7439    {
7440       if(GTK_SHEET_ROW_TITLES_VISIBLE(sheet))
7441              gdk_window_show(sheet->row_title_window);
7442       if(GTK_SHEET_COL_TITLES_VISIBLE(sheet))
7443              gdk_window_show(sheet->column_title_window);
7444    }
7445
7446 }
7447
7448 void
7449 gtk_sheet_button_attach         (GtkSheet *sheet, 
7450                                  GtkWidget *widget, 
7451                                  gint row, gint col)
7452 {
7453   GtkSheetButton *button = 0;
7454   GtkSheetChild *child;
7455   GtkRequisition button_requisition;
7456
7457   if(row >= 0 && col >= 0) return;
7458   if(row < 0 && col < 0) return;
7459
7460   child = g_new (GtkSheetChild, 1);
7461   child->widget = widget;
7462   child->x = 0;  
7463   child->y = 0;  
7464   child->attached_to_cell = TRUE;
7465   child->floating = FALSE;
7466   child->row = row;
7467   child->col = col;
7468   child->xpadding = child->ypadding = 0;
7469   child->xshrink = child->yshrink = FALSE;
7470   child->xfill = child->yfill = FALSE;
7471
7472
7473   sheet->children = g_list_append(sheet->children, child);
7474
7475   gtk_sheet_button_size_request(sheet, button, &button_requisition);
7476
7477
7478   if (GTK_WIDGET_VISIBLE(GTK_WIDGET(sheet)))
7479     {
7480        if(GTK_WIDGET_REALIZED(GTK_WIDGET(sheet)) && 
7481           (!GTK_WIDGET_REALIZED(widget) || GTK_WIDGET_NO_WINDOW(widget)))
7482         gtk_sheet_realize_child(sheet, child);
7483
7484        if(GTK_WIDGET_MAPPED(GTK_WIDGET(sheet)) && 
7485           !GTK_WIDGET_MAPPED(widget))
7486         gtk_widget_map(widget);
7487     }
7488
7489   if(row == -1) size_allocate_column_title_buttons(sheet);
7490   if(col == -1) size_allocate_row_title_buttons(sheet);
7491
7492 }
7493
7494 static void
7495 label_size_request(GtkSheet *sheet, gchar *label, GtkRequisition *req)
7496 {
7497   gchar *words;
7498   gchar word[1000];
7499   gint n = 0;
7500   gint row_height = DEFAULT_ROW_HEIGHT(GTK_WIDGET(sheet)) - 2*CELLOFFSET + 2;
7501
7502   req->height = 0;
7503   req->width = 0;
7504   words=label;
7505
7506   while(words && *words != '\0'){
7507     if(*words == '\n' || *(words+1) == '\0'){
7508       req->height += row_height;
7509
7510       word[n] = '\0';
7511       req->width = MAX(req->width, STRING_WIDTH(GTK_WIDGET(sheet), GTK_WIDGET(sheet)->style->font_desc, word));
7512       n = 0;
7513     } else {
7514       word[n++] = *words;
7515     }
7516     words++;
7517   }
7518  
7519   if(n > 0) req->height -= 2;
7520 }
7521
7522 static void
7523 gtk_sheet_button_size_request   (GtkSheet *sheet,
7524                                  const GtkSheetButton *button, 
7525                                  GtkRequisition *button_requisition)
7526 {
7527   GtkRequisition requisition;
7528   GtkRequisition label_requisition;
7529
7530   if(gtk_sheet_autoresize(sheet) && button->label && strlen(button->label) > 0){
7531      label_size_request(sheet, button->label, &label_requisition);
7532      label_requisition.width += 2*CELLOFFSET;
7533      label_requisition.height += 2*CELLOFFSET;
7534   } else {
7535      label_requisition.height = DEFAULT_ROW_HEIGHT(GTK_WIDGET(sheet));
7536      label_requisition.width = COLUMN_MIN_WIDTH;
7537   } 
7538
7539   if(button->child)
7540   {
7541      gtk_widget_size_request(button->child->widget, &requisition);
7542      requisition.width += 2*button->child->xpadding;
7543      requisition.height += 2*button->child->ypadding;
7544      requisition.width += 2*sheet->button->style->xthickness;
7545      requisition.height += 2*sheet->button->style->ythickness;
7546   }
7547   else
7548   {
7549      requisition.height = DEFAULT_ROW_HEIGHT(GTK_WIDGET(sheet));
7550      requisition.width = COLUMN_MIN_WIDTH;
7551   }
7552
7553   *button_requisition = requisition;
7554   button_requisition->width = MAX(requisition.width, label_requisition.width);
7555   button_requisition->height = MAX(requisition.height, label_requisition.height);
7556  
7557 }
7558
7559 static void
7560 gtk_sheet_row_size_request      (GtkSheet *sheet,
7561                                  gint row,
7562                                  guint *requisition)
7563 {
7564   GtkRequisition button_requisition;
7565   GList *children;
7566
7567   gtk_sheet_button_size_request(sheet, 
7568                                 yyy_row_button(sheet, row),
7569                                 &button_requisition);
7570
7571   *requisition = button_requisition.height;
7572
7573   children = sheet->children;
7574   while(children){
7575     GtkSheetChild *child = (GtkSheetChild *)children->data;
7576     GtkRequisition child_requisition;
7577
7578     if(child->attached_to_cell && child->row == row && child->col != -1 && !child->floating && !child->yshrink){
7579       gtk_widget_get_child_requisition(child->widget, &child_requisition);
7580
7581       if(child_requisition.height + 2 * child->ypadding > *requisition)
7582         *requisition = child_requisition.height + 2 * child->ypadding;
7583     }
7584     children = children->next;
7585   }
7586
7587   sheet->row_requisition = * requisition;
7588 }
7589
7590 static void
7591 gtk_sheet_column_size_request   (GtkSheet *sheet,
7592                                  gint col,
7593                                  guint *requisition)
7594 {
7595   GtkRequisition button_requisition;
7596   GList *children;
7597
7598   gtk_sheet_button_size_request(sheet, 
7599                                 xxx_column_button(sheet, col),
7600                                 &button_requisition);
7601
7602   *requisition = button_requisition.width;
7603
7604   children = sheet->children;
7605   while(children){
7606     GtkSheetChild *child = (GtkSheetChild *)children->data;
7607     GtkRequisition child_requisition;
7608
7609     if(child->attached_to_cell && child->col == col && child->row != -1 && !child->floating && !child->xshrink){
7610       gtk_widget_get_child_requisition(child->widget, &child_requisition);
7611
7612       if(child_requisition.width + 2 * child->xpadding > *requisition)
7613         *requisition = child_requisition.width + 2 * child->xpadding;
7614     }
7615     children = children->next;
7616   }
7617
7618   sheet->column_requisition = *requisition;
7619 }
7620
7621 void
7622 gtk_sheet_move_child(GtkSheet *sheet, GtkWidget *widget, gint x, gint y)
7623 {
7624   GtkSheetChild *child;
7625   GList *children;
7626
7627   g_return_if_fail(sheet != NULL);
7628   g_return_if_fail(GTK_IS_SHEET(sheet));
7629
7630   children = sheet->children;
7631   while(children)
7632     {
7633        child = children->data;
7634
7635        if(child->widget == widget){
7636          child->x = x;
7637          child->y = y;
7638          child->row = ROW_FROM_YPIXEL(sheet, y);
7639          child->col = COLUMN_FROM_XPIXEL(sheet, x);
7640          gtk_sheet_position_child(sheet, child);
7641          return;
7642        }
7643
7644        children = children->next;
7645     }
7646
7647   g_warning("Widget must be a GtkSheet child"); 
7648
7649 }
7650
7651 static void
7652 gtk_sheet_position_child(GtkSheet *sheet, GtkSheetChild *child)
7653 {
7654    GtkRequisition child_requisition;
7655    GtkAllocation child_allocation;
7656    gint xoffset = 0; 
7657    gint yoffset = 0;
7658    gint x = 0, y = 0;
7659    GdkRectangle area;
7660
7661    gtk_widget_get_child_requisition(child->widget, &child_requisition);
7662
7663    if(sheet->column_titles_visible) 
7664              yoffset = sheet->column_title_area.height;
7665
7666    if(sheet->row_titles_visible)
7667              xoffset = sheet->row_title_area.width;
7668
7669    if(child->attached_to_cell){
7670 /*
7671       child->x = COLUMN_LEFT_XPIXEL(sheet, child->col);
7672       child->y = ROW_TOP_YPIXEL(sheet, child->row);
7673
7674       if(sheet->row_titles_visible) 
7675                                     child->x-=sheet->row_title_area.width;
7676       if(sheet->column_titles_visible) 
7677                                     child->y-=sheet->column_title_area.height;
7678
7679       width = xxx_column_width(sheet, child->col);
7680       height = yyy_row_height(sheet, child->row);
7681 */
7682       
7683       gtk_sheet_get_cell_area(sheet, child->row, child->col, &area);
7684       child->x = area.x + child->xpadding;
7685       child->y = area.y + child->ypadding;
7686
7687       if(!child->floating){
7688         if(child_requisition.width + 2*child->xpadding <= xxx_column_width(sheet, child->col)){
7689           if(child->xfill){
7690             child_requisition.width = child_allocation.width = xxx_column_width(sheet, child->col) - 2*child->xpadding;
7691           } else {
7692             if(child->xexpand){
7693               child->x = area.x + xxx_column_width(sheet, child->col) / 2 -
7694                                   child_requisition.width / 2;
7695             }
7696             child_allocation.width = child_requisition.width;
7697           }
7698         } else {
7699           if(!child->xshrink){
7700             gtk_sheet_set_column_width(sheet, child->col, child_requisition.width + 2 * child->xpadding);
7701           }
7702           child_allocation.width = xxx_column_width(sheet, child->col) - 2*child->xpadding;
7703         }
7704
7705         if(child_requisition.height + 2*child->ypadding <= yyy_row_height(sheet, child->row)){
7706           if(child->yfill){
7707             child_requisition.height = child_allocation.height = yyy_row_height(sheet, child->row) - 2*child->ypadding;
7708           } else {
7709             if(child->yexpand){
7710               child->y = area.y + yyy_row_height(sheet, child->row) / 2 -
7711                                   child_requisition.height / 2;
7712             }
7713             child_allocation.height = child_requisition.height;
7714           }
7715         } else {
7716           if(!child->yshrink){
7717             gtk_sheet_set_row_height(sheet, child->row, child_requisition.height + 2 * child->ypadding);
7718           }
7719           child_allocation.height = yyy_row_height(sheet, child->row) - 2*child->ypadding;
7720         }
7721       } else {
7722         child_allocation.width = child_requisition.width;
7723         child_allocation.height = child_requisition.height;
7724       }
7725
7726       x = child_allocation.x = child->x + xoffset;
7727       y = child_allocation.y = child->y + yoffset;
7728    }
7729    else
7730    {
7731       x = child_allocation.x = child->x + sheet->hoffset + xoffset;   
7732       x = child_allocation.x = child->x + xoffset;   
7733       y = child_allocation.y = child->y + sheet->voffset + yoffset;
7734       y = child_allocation.y = child->y + yoffset;
7735       child_allocation.width = child_requisition.width;
7736       child_allocation.height = child_requisition.height;
7737    }
7738
7739    gtk_widget_size_allocate(child->widget, &child_allocation);
7740    gtk_widget_queue_draw(child->widget);
7741 }
7742
7743 static void
7744 gtk_sheet_forall (GtkContainer *container,
7745                   gboolean      include_internals,
7746                   GtkCallback   callback,
7747                   gpointer      callback_data)
7748 {
7749   GtkSheet *sheet;
7750   GtkSheetChild *child;
7751   GList *children;
7752
7753   g_return_if_fail (GTK_IS_SHEET (container));
7754   g_return_if_fail (callback != NULL);
7755
7756   sheet = GTK_SHEET (container);
7757   children = sheet->children;
7758   while (children)
7759     {
7760       child = children->data;
7761       children = children->next;
7762
7763       (* callback) (child->widget, callback_data);
7764     }
7765   if(sheet->button)
7766      (* callback) (sheet->button, callback_data);
7767   if(sheet->sheet_entry)
7768      (* callback) (sheet->sheet_entry, callback_data);
7769 }
7770
7771
7772 static void
7773 gtk_sheet_position_children(GtkSheet *sheet)
7774 {
7775   GList *children;
7776   GtkSheetChild *child;
7777
7778   children = sheet->children;
7779
7780   while(children)
7781    {
7782      child = (GtkSheetChild *)children->data;
7783
7784      if(child->col !=-1 && child->row != -1)
7785            gtk_sheet_position_child(sheet, child);
7786
7787      if(child->row == -1){
7788         if(child->col < MIN_VISIBLE_COLUMN(sheet) || 
7789            child->col > MAX_VISIBLE_COLUMN(sheet))
7790               gtk_sheet_child_hide(child);
7791         else
7792               gtk_sheet_child_show(child);
7793      }
7794      if(child->col == -1){
7795         if(child->row < MIN_VISIBLE_ROW(sheet) ||
7796            child->row > MAX_VISIBLE_ROW(sheet))
7797               gtk_sheet_child_hide(child);
7798         else
7799               gtk_sheet_child_show(child);
7800      }
7801  
7802      children = children->next;
7803    }
7804     
7805 }
7806
7807 static void
7808 gtk_sheet_remove (GtkContainer *container, GtkWidget *widget)
7809 {
7810   GtkSheet *sheet;
7811   GList *children;
7812   GtkSheetChild *child = 0;
7813
7814   g_return_if_fail(container != NULL);
7815   g_return_if_fail(GTK_IS_SHEET(container));
7816
7817   sheet = GTK_SHEET(container);
7818
7819   children = sheet->children;
7820
7821   while(children)
7822    {
7823      child = (GtkSheetChild *)children->data;
7824
7825      if(child->widget == widget) break;
7826
7827      children = children->next;
7828    }
7829
7830   if (children)
7831    {
7832      gtk_widget_unparent (widget);
7833      child->widget = NULL;
7834
7835      sheet->children = g_list_remove_link (sheet->children, children);
7836      g_list_free_1 (children);
7837      g_free(child);
7838    }
7839
7840 }
7841
7842 static void
7843 gtk_sheet_realize_child(GtkSheet *sheet, GtkSheetChild *child)
7844 {
7845   GtkWidget *widget;
7846
7847   widget = GTK_WIDGET(sheet);
7848
7849   if(GTK_WIDGET_REALIZED(widget)){
7850     if(child->row == -1)
7851       gtk_widget_set_parent_window(child->widget, sheet->column_title_window);
7852     else if(child->col == -1)
7853       gtk_widget_set_parent_window(child->widget, sheet->row_title_window);
7854     else
7855       gtk_widget_set_parent_window(child->widget, sheet->sheet_window);
7856   }
7857
7858   gtk_widget_set_parent(child->widget, widget);
7859 }
7860
7861
7862    
7863 GtkSheetChild *
7864 gtk_sheet_get_child_at(GtkSheet *sheet, gint row, gint col)
7865 {
7866   GList *children;
7867   GtkSheetChild *child = 0;
7868
7869   g_return_val_if_fail(sheet != NULL, NULL);
7870   g_return_val_if_fail(GTK_IS_SHEET(sheet), NULL);
7871
7872   children = sheet->children;
7873
7874   while(children)
7875    {
7876      child = (GtkSheetChild *)children->data;
7877
7878      if(child->attached_to_cell)
7879         if(child->row == row && child->col == col) break; 
7880      
7881      children = children->next;
7882    }
7883
7884   if(children) return child; 
7885
7886   return NULL;
7887 }
7888
7889 static void
7890 gtk_sheet_child_hide(GtkSheetChild *child) 
7891 {
7892   g_return_if_fail(child != NULL);
7893   gtk_widget_hide(child->widget);
7894 }
7895
7896 static void
7897 gtk_sheet_child_show(GtkSheetChild *child) 
7898 {
7899   g_return_if_fail(child != NULL);
7900
7901   gtk_widget_show(child->widget);
7902 }
7903
7904 GSheetModel *
7905 gtk_sheet_get_model(const GtkSheet *sheet)
7906 {
7907   g_return_val_if_fail (GTK_IS_SHEET (sheet), NULL);
7908
7909   return sheet->model;
7910 }
7911
7912
7913 GtkSheetButton *
7914 gtk_sheet_button_new(void)
7915 {
7916   GtkSheetButton *button = g_slice_new(GtkSheetButton);
7917   
7918   button->state = GTK_STATE_NORMAL;
7919   button->label = NULL;
7920   button->label_visible = TRUE;
7921   button->child = NULL;
7922   button->justification = GTK_JUSTIFY_FILL;
7923
7924   return button;
7925 }
7926
7927
7928 inline void
7929 gtk_sheet_button_free(GtkSheetButton *button)
7930 {
7931   g_free(button->label);
7932   g_slice_free(GtkSheetButton, button);
7933 }