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