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