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