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