Added new files resulting from directory restructuring.
[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  GtkSheetRange range;
3502  gint text_width;
3503  GtkSheetCellAttr attributes;
3504
3505  g_return_if_fail (sheet != NULL);
3506  g_return_if_fail (GTK_IS_SHEET (sheet));
3507  if (col >= xxx_column_count(sheet) || row >= yyy_row_count(sheet)) return;
3508  if (col < 0 || row < 0) return;
3509
3510  gtk_sheet_get_attributes(sheet, row, col, &attributes);
3511
3512  attributes.justification = justification;
3513
3514  GSheetModel *model =  gtk_sheet_get_model(sheet);
3515
3516  const gchar *old_text = g_sheet_model_get_string(model, row, col);
3517
3518  gboolean changed = FALSE;
3519
3520  if (0 != safe_strcmp(old_text, text))
3521    changed = g_sheet_model_set_string(model, text, row, col);
3522
3523  if(changed && attributes.is_visible){
3524    const gchar *s = gtk_sheet_cell_get_text(sheet, row, col);
3525    text_width = 0;
3526    if(s && strlen(s) > 0) {
3527      text_width = STRING_WIDTH(GTK_WIDGET(sheet), attributes.font_desc, text);
3528    }
3529
3530    range.row0 = row;
3531    range.rowi = row;
3532    range.col0 = sheet->view.col0;
3533    range.coli = sheet->view.coli;
3534
3535    if(gtk_sheet_autoresize(sheet) &&
3536       text_width > xxx_column_width(sheet, col) - 2*CELLOFFSET-attributes.border.width){
3537       gtk_sheet_set_column_width(sheet, col, text_width+2*CELLOFFSET+attributes.border.width);
3538       GTK_SHEET_SET_FLAGS(sheet, GTK_SHEET_REDRAW_PENDING);
3539    }
3540    else
3541      if(!GTK_SHEET_IS_FROZEN(sheet))
3542        gtk_sheet_range_draw(sheet, &range);
3543  }
3544
3545  if ( changed ) 
3546    gtk_signal_emit(GTK_OBJECT(sheet),sheet_signals[CHANGED], row, col);
3547
3548 }
3549
3550
3551 void
3552 gtk_sheet_cell_clear (GtkSheet *sheet, gint row, gint column)
3553 {
3554   GtkSheetRange range;
3555
3556   g_return_if_fail (sheet != NULL);
3557   g_return_if_fail (GTK_IS_SHEET (sheet));
3558   if (column >= xxx_column_count(sheet) || row >= yyy_row_count(sheet)) return;
3559   if (column < 0 || row < 0) return;
3560
3561   range.row0 = row;
3562   range.rowi = row;
3563   range.col0 = sheet->view.col0;
3564   range.coli = sheet->view.coli;
3565
3566   gtk_sheet_real_cell_clear(sheet, row, column, FALSE);
3567
3568   if(!GTK_SHEET_IS_FROZEN(sheet)){
3569      gtk_sheet_range_draw(sheet, &range);
3570   }
3571 }
3572
3573 void
3574 gtk_sheet_cell_delete (GtkSheet *sheet, gint row, gint column)
3575 {
3576   GtkSheetRange range;
3577
3578   g_return_if_fail (sheet != NULL);
3579   g_return_if_fail (GTK_IS_SHEET (sheet));
3580   if (column >= xxx_column_count(sheet) || row >= yyy_row_count(sheet)) return;
3581   if (column < 0 || row < 0) return;
3582
3583   range.row0 = row;
3584   range.rowi = row;
3585   range.col0 = sheet->view.col0;
3586   range.coli = sheet->view.coli;
3587
3588   gtk_sheet_real_cell_clear(sheet, row, column, TRUE);
3589
3590   if(!GTK_SHEET_IS_FROZEN(sheet)){
3591      gtk_sheet_range_draw(sheet, &range);
3592   }
3593 }
3594
3595 static void
3596 gtk_sheet_real_cell_clear (GtkSheet *sheet, gint row, gint column, gboolean delete)
3597 {
3598   const gchar *old_text;
3599
3600   old_text = gtk_sheet_cell_get_text(sheet, row, column); 
3601  
3602   GSheetModel *model =  gtk_sheet_get_model(sheet);
3603
3604   if (old_text && strlen(old_text) > 0 )
3605     {
3606       g_sheet_model_datum_clear(model, row, column);
3607       
3608       if(GTK_IS_OBJECT(sheet) && G_OBJECT(sheet)->ref_count > 0)
3609         gtk_signal_emit(GTK_OBJECT(sheet),sheet_signals[CLEAR_CELL], 
3610                         row, column);
3611     }  
3612
3613 }
3614     
3615 void
3616 gtk_sheet_range_clear (GtkSheet *sheet, const GtkSheetRange *range)
3617 {
3618   g_return_if_fail (sheet != NULL);
3619   g_return_if_fail (GTK_IS_SHEET (sheet));
3620
3621   gtk_sheet_real_range_clear(sheet, range, FALSE);
3622 }
3623
3624 void
3625 gtk_sheet_range_delete (GtkSheet *sheet, const GtkSheetRange *range)
3626 {
3627   g_return_if_fail (sheet != NULL);
3628   g_return_if_fail (GTK_IS_SHEET (sheet));
3629
3630   gtk_sheet_real_range_clear(sheet, range, TRUE);
3631 }
3632  
3633
3634 static void
3635 gtk_sheet_real_range_clear (GtkSheet *sheet, const GtkSheetRange *range, 
3636                             gboolean delete)
3637 {
3638   gint i, j;
3639   GtkSheetRange clear;
3640
3641   if(!range){
3642     clear.row0=0;
3643     clear.rowi = yyy_row_count(sheet) - 1;
3644     clear.col0=0;
3645     clear.coli = xxx_column_count(sheet) - 1;
3646   }else
3647     clear=*range;  
3648
3649   clear.row0=MAX(clear.row0, 0);
3650   clear.col0=MAX(clear.col0, 0);
3651   clear.rowi=MIN(clear.rowi, yyy_row_count(sheet) - 1 );
3652   clear.coli=MIN(clear.coli, xxx_column_count(sheet) - 1 );
3653
3654   for(i=clear.row0; i<=clear.rowi; i++)
3655     for(j=clear.col0; j<=clear.coli; j++){
3656       gtk_sheet_real_cell_clear(sheet, i, j, delete);
3657     }
3658
3659   gtk_sheet_range_draw(sheet, NULL);
3660 }
3661
3662
3663 const gchar *     
3664 gtk_sheet_cell_get_text (GtkSheet *sheet, gint row, gint col)
3665 {
3666   GSheetModel *model;
3667   g_return_val_if_fail (sheet != NULL, NULL);
3668   g_return_val_if_fail (GTK_IS_SHEET (sheet), NULL);
3669
3670   if(col >= xxx_column_count(sheet) || row >= yyy_row_count(sheet)) 
3671     return NULL;
3672   if(col < 0 || row < 0) return NULL;
3673
3674   model =  gtk_sheet_get_model(sheet);
3675
3676   if ( !model ) 
3677     return NULL;
3678
3679   return g_sheet_model_get_string(model, row, col);
3680 }
3681
3682
3683 GtkStateType
3684 gtk_sheet_cell_get_state (GtkSheet *sheet, gint row, gint col)
3685 {
3686  gint state;
3687  GtkSheetRange *range;
3688
3689  g_return_val_if_fail (sheet != NULL, 0);
3690  g_return_val_if_fail (GTK_IS_SHEET (sheet), 0);
3691  if(col >= xxx_column_count(sheet) || row >= yyy_row_count(sheet)) return 0;
3692  if(col < 0 || row < 0) return 0;
3693
3694  state = sheet->state;
3695  range = &sheet->range;
3696
3697  switch (state)
3698    {
3699    case GTK_SHEET_NORMAL:
3700      return GTK_STATE_NORMAL;
3701      break;
3702    case GTK_SHEET_ROW_SELECTED:
3703      if(row>=range->row0 && row<=range->rowi) 
3704        return GTK_STATE_SELECTED;
3705      break;
3706    case GTK_SHEET_COLUMN_SELECTED:
3707      if(col>=range->col0 && col<=range->coli) 
3708        return GTK_STATE_SELECTED;
3709      break;
3710    case GTK_SHEET_RANGE_SELECTED:
3711      if(row >= range->row0 && row <= range->rowi && \
3712         col >= range->col0 && col <= range->coli)
3713        return GTK_STATE_SELECTED;
3714      break;
3715    }
3716  return GTK_STATE_NORMAL;
3717 }
3718
3719 gboolean
3720 gtk_sheet_get_pixel_info (GtkSheet * sheet,
3721                           gint x,
3722                           gint y,
3723                           gint * row,
3724                           gint * column)
3725 {
3726   gint trow, tcol;
3727
3728   g_return_val_if_fail (sheet != NULL, 0);
3729   g_return_val_if_fail (GTK_IS_SHEET (sheet), 0);
3730
3731   /* bounds checking, return false if the user clicked 
3732    * on a blank area */
3733   trow = ROW_FROM_YPIXEL (sheet, y);
3734   if (trow >= yyy_row_count(sheet))
3735     return FALSE;
3736
3737   *row = trow;
3738
3739   tcol = COLUMN_FROM_XPIXEL (sheet, x);
3740   if (tcol >= xxx_column_count(sheet))
3741     return FALSE;
3742
3743  *column = tcol;
3744
3745   return TRUE;
3746 }
3747
3748 gboolean
3749 gtk_sheet_get_cell_area  (GtkSheet * sheet,
3750                           gint row,
3751                           gint column,
3752                           GdkRectangle *area)
3753 {
3754   g_return_val_if_fail (sheet != NULL, 0);
3755   g_return_val_if_fail (GTK_IS_SHEET (sheet), 0);
3756
3757   if(row >= yyy_row_count(sheet) || column >= xxx_column_count(sheet)) 
3758     return FALSE;
3759
3760   area->x = (column == -1) ? 0 : (COLUMN_LEFT_XPIXEL(sheet, column) -
3761                                  (sheet->row_titles_visible
3762                                    ? sheet->row_title_area.width
3763                                    : 0));
3764   area->y = (row == -1) ? 0 : (ROW_TOP_YPIXEL(sheet, row) -
3765                               (sheet->column_titles_visible
3766                                ? sheet->column_title_area.height
3767                                : 0));
3768   area->width= (column == -1) ? sheet->row_title_area.width
3769     : xxx_column_width(sheet, column);
3770
3771   area->height= (row == -1) ? sheet->column_title_area.height
3772                             : yyy_row_height(sheet, row);
3773
3774 /*
3775   if(row < 0 || column < 0) return FALSE;
3776
3777   area->x = COLUMN_LEFT_XPIXEL(sheet, column);
3778   area->y = ROW_TOP_YPIXEL(sheet, row);
3779   if(sheet->row_titles_visible)
3780            area->x -= sheet->row_title_area.width;
3781   if(sheet->column_titles_visible)
3782            area->y -= sheet->column_title_area.height;
3783
3784   area->width=sheet->column[column].width;
3785   area->height=yyy_row_height(sheet, row);  
3786 */
3787   return TRUE;
3788 }
3789
3790 gboolean 
3791 gtk_sheet_set_active_cell (GtkSheet *sheet, gint row, gint column)
3792 {
3793  g_return_val_if_fail (sheet != NULL, 0);
3794  g_return_val_if_fail (GTK_IS_SHEET (sheet), 0);
3795
3796  if(row < 0 || column < 0) return FALSE;
3797  if(row >= yyy_row_count(sheet) || column >= xxx_column_count(sheet)) 
3798    return FALSE;
3799
3800  if(GTK_WIDGET_REALIZED(GTK_WIDGET(sheet)))
3801    {
3802        if(!gtk_sheet_deactivate_cell(sheet)) return FALSE;
3803    }
3804
3805  sheet->active_cell.row=row;
3806  sheet->active_cell.col=column;
3807  
3808  if(!gtk_sheet_activate_cell(sheet, row, column)) return FALSE;
3809  
3810  if(gtk_sheet_autoscroll(sheet))
3811    gtk_sheet_move_query(sheet, row, column);
3812
3813  return TRUE;
3814 }
3815
3816 void
3817 gtk_sheet_get_active_cell (GtkSheet *sheet, gint *row, gint *column)
3818 {
3819   g_return_if_fail (sheet != NULL);
3820   g_return_if_fail (GTK_IS_SHEET (sheet));
3821
3822   *row = sheet->active_cell.row;
3823   *column = sheet->active_cell.col;
3824 }
3825
3826 static void
3827 gtk_sheet_entry_changed(GtkWidget *widget, gpointer data)
3828 {
3829  GtkSheet *sheet;
3830  gint row,col;
3831  const char *text;
3832  GtkJustification justification;
3833  GtkSheetCellAttr attributes;
3834
3835  g_return_if_fail (data != NULL);
3836  g_return_if_fail (GTK_IS_SHEET (data));
3837
3838  sheet=GTK_SHEET(data);
3839
3840  if(!GTK_WIDGET_VISIBLE(widget)) return;
3841  if(sheet->state != GTK_STATE_NORMAL) return;
3842
3843  row=sheet->active_cell.row;
3844  col=sheet->active_cell.col;
3845
3846  if(row<0 || col<0) return;
3847
3848  sheet->active_cell.row=-1;
3849  sheet->active_cell.col=-1;
3850
3851  text = gtk_entry_get_text(GTK_ENTRY(gtk_sheet_get_entry(sheet)));
3852
3853  GTK_SHEET_SET_FLAGS(sheet, GTK_SHEET_IS_FROZEN);
3854
3855  if(text && strlen(text) > 0){
3856       gtk_sheet_get_attributes(sheet, row, col, &attributes); 
3857       justification=attributes.justification;
3858       gtk_sheet_set_cell(sheet, row, col, justification, text);
3859  }
3860
3861  if(sheet->freeze_count == 0)
3862         GTK_SHEET_UNSET_FLAGS(sheet, GTK_SHEET_IS_FROZEN);
3863  
3864  sheet->active_cell.row=row;;
3865  sheet->active_cell.col=col;
3866 }
3867
3868
3869 static gboolean 
3870 gtk_sheet_deactivate_cell(GtkSheet *sheet)
3871 {
3872  gboolean veto = TRUE;
3873
3874  g_return_val_if_fail (sheet != NULL, FALSE);
3875  g_return_val_if_fail (GTK_IS_SHEET (sheet), FALSE);
3876
3877  if(!GTK_WIDGET_REALIZED(GTK_WIDGET(sheet))) return FALSE;
3878  if(sheet->state != GTK_SHEET_NORMAL) return FALSE;
3879
3880  _gtkextra_signal_emit(GTK_OBJECT(sheet),sheet_signals[DEACTIVATE], 
3881                                    sheet->active_cell.row,
3882                                    sheet->active_cell.col, &veto);
3883
3884  if(!veto) return FALSE;
3885
3886  gtk_signal_disconnect_by_func(GTK_OBJECT(gtk_sheet_get_entry(sheet)),
3887                                (GtkSignalFunc) gtk_sheet_entry_changed,
3888                                GTK_OBJECT(GTK_WIDGET(sheet)));
3889
3890  gtk_sheet_hide_active_cell(sheet);
3891  sheet->active_cell.row=-1;
3892  sheet->active_cell.col=-1;
3893  
3894  if(GTK_SHEET_REDRAW_PENDING(sheet)){
3895    GTK_SHEET_UNSET_FLAGS(sheet, GTK_SHEET_REDRAW_PENDING);
3896    gtk_sheet_range_draw(sheet, NULL);
3897  }
3898
3899  return TRUE;
3900 }       
3901
3902 static void
3903 gtk_sheet_hide_active_cell(GtkSheet *sheet)
3904 {
3905  const char *text;
3906  gint row,col;
3907  GtkJustification justification;
3908  GtkSheetCellAttr attributes;
3909
3910  if(!GTK_WIDGET_REALIZED(GTK_WIDGET(sheet))) return;
3911
3912  row=sheet->active_cell.row;
3913  col=sheet->active_cell.col;
3914
3915  if(row < 0 || col < 0) return;
3916
3917  if(sheet->freeze_count == 0)
3918      GTK_SHEET_UNSET_FLAGS(sheet, GTK_SHEET_IS_FROZEN);
3919
3920  text=gtk_entry_get_text(GTK_ENTRY(gtk_sheet_get_entry(sheet)));
3921
3922  gtk_sheet_get_attributes(sheet, row, col, &attributes); 
3923  justification=attributes.justification;
3924
3925  if(text && strlen(text)!=0){
3926       gtk_sheet_set_cell(sheet, row, col, justification, text);
3927       gtk_signal_emit(GTK_OBJECT(sheet),sheet_signals[SET_CELL], row, col);
3928  }
3929  else
3930  {
3931       gtk_sheet_cell_clear(sheet, row, col);
3932  }
3933
3934  row=sheet->active_cell.row;
3935  col=sheet->active_cell.col;
3936
3937 #if 0
3938  column_button_release(sheet, col);
3939  row_button_release(sheet, row);
3940 #endif
3941
3942  gtk_widget_unmap(sheet->sheet_entry);
3943
3944  if(row != -1 && col != -1)
3945    gdk_draw_pixmap(sheet->sheet_window,
3946                    GTK_WIDGET(sheet)->style->fg_gc[GTK_STATE_NORMAL],
3947                    sheet->pixmap,
3948                    COLUMN_LEFT_XPIXEL(sheet,col)-1,
3949                    ROW_TOP_YPIXEL(sheet,row)-1,
3950                    COLUMN_LEFT_XPIXEL(sheet,col)-1,
3951                    ROW_TOP_YPIXEL(sheet,row)-1,
3952                    xxx_column_width(sheet, col) + 4,
3953                    yyy_row_height(sheet, row)+4);   
3954
3955  gtk_widget_grab_focus(GTK_WIDGET(sheet));
3956
3957  GTK_WIDGET_UNSET_FLAGS(GTK_WIDGET(sheet->sheet_entry), GTK_VISIBLE);
3958
3959 }
3960
3961 static gboolean
3962 gtk_sheet_activate_cell(GtkSheet *sheet, gint row, gint col)
3963 {
3964  gboolean veto = TRUE;
3965
3966  g_return_val_if_fail (sheet != NULL, FALSE);
3967  g_return_val_if_fail (GTK_IS_SHEET (sheet), FALSE);
3968
3969  if(row < 0 || col < 0) return FALSE;
3970  if(row >= yyy_row_count(sheet) || col >= xxx_column_count(sheet)) 
3971    return FALSE;
3972
3973 /* _gtkextra_signal_emit(GTK_OBJECT(sheet),sheet_signals[ACTIVATE], row, col, &veto);
3974  if(!GTK_WIDGET_REALIZED(GTK_WIDGET(sheet))) return veto;
3975 */
3976
3977  if(!veto) return FALSE;
3978  if(sheet->state != GTK_SHEET_NORMAL){
3979         sheet->state=GTK_SHEET_NORMAL;
3980         gtk_sheet_real_unselect_range(sheet, NULL);
3981  }
3982
3983  sheet->range.row0=row;
3984  sheet->range.col0=col;
3985  sheet->range.rowi=row;
3986  sheet->range.coli=col;
3987  sheet->active_cell.row=row;
3988  sheet->active_cell.col=col;
3989  sheet->selection_cell.row=row;
3990  sheet->selection_cell.col=col;
3991 #if 0
3992  row_button_set(sheet, row);
3993  column_button_set(sheet, col); 
3994 #endif
3995
3996  GTK_SHEET_UNSET_FLAGS(sheet, GTK_SHEET_IN_SELECTION);
3997  gtk_sheet_show_active_cell(sheet);
3998
3999    g_signal_connect(G_OBJECT(gtk_sheet_get_entry(sheet)),
4000                     "changed",
4001                     G_CALLBACK(gtk_sheet_entry_changed),
4002                     sheet);
4003
4004  _gtkextra_signal_emit(GTK_OBJECT(sheet),sheet_signals[ACTIVATE], row, col, &veto);
4005
4006  return TRUE;
4007 }
4008
4009 static void
4010 gtk_sheet_show_active_cell(GtkSheet *sheet)
4011 {
4012  GtkEntry *sheet_entry;
4013  GtkSheetCellAttr attributes;
4014  gchar *text = NULL;
4015  const gchar *old_text;
4016  GtkJustification justification;
4017  gint row, col;
4018
4019  g_return_if_fail (sheet != NULL);
4020  g_return_if_fail (GTK_IS_SHEET (sheet));
4021
4022  row = sheet->active_cell.row;
4023  col = sheet->active_cell.col;
4024
4025  /* Don't show the active cell, if there is no active cell: */
4026  if(!(row >= 0 && col >= 0)) /* e.g row or coll == -1. */
4027    return;
4028   
4029  if(!GTK_WIDGET_REALIZED(GTK_WIDGET(sheet))) return;
4030  if(sheet->state != GTK_SHEET_NORMAL) return;
4031  if(GTK_SHEET_IN_SELECTION(sheet)) return;
4032
4033  GTK_WIDGET_SET_FLAGS(GTK_WIDGET(sheet->sheet_entry), GTK_VISIBLE);
4034
4035  sheet_entry = GTK_ENTRY(gtk_sheet_get_entry(sheet));
4036
4037  gtk_sheet_get_attributes(sheet, row, col, &attributes); 
4038
4039  justification = GTK_JUSTIFY_LEFT;
4040
4041  if(gtk_sheet_justify_entry(sheet))
4042       justification = attributes.justification;
4043
4044  text = g_strdup(gtk_sheet_cell_get_text(sheet, row, col));
4045
4046  if(!text) text = g_strdup("");
4047
4048  gtk_entry_set_visibility(GTK_ENTRY(sheet_entry), attributes.is_visible);
4049
4050  if(gtk_sheet_locked(sheet) || !attributes.is_editable){ 
4051             gtk_entry_set_editable(GTK_ENTRY(sheet_entry), FALSE);
4052  }else{
4053             gtk_entry_set_editable(GTK_ENTRY(sheet_entry), TRUE);
4054  }
4055
4056 /*** Added by John Gotts. Mar 25, 2005 *********/
4057  old_text = gtk_entry_get_text(GTK_ENTRY(sheet_entry));
4058  if (strcmp(old_text, text) != 0) 
4059 {
4060   if(!GTK_IS_ITEM_ENTRY(sheet_entry))
4061      gtk_entry_set_text(GTK_ENTRY(sheet_entry), text);
4062   else
4063      gtk_item_entry_set_text(GTK_ITEM_ENTRY(sheet_entry), text, justification);
4064  }
4065
4066  gtk_sheet_entry_set_max_size(sheet);
4067  gtk_sheet_size_allocate_entry(sheet);
4068
4069  gtk_widget_map(sheet->sheet_entry);
4070  gtk_sheet_draw_active_cell(sheet);
4071
4072  gtk_widget_grab_focus(GTK_WIDGET(sheet_entry));
4073
4074  g_free(text);
4075 }
4076
4077 static void
4078 gtk_sheet_draw_active_cell(GtkSheet *sheet)
4079 {
4080     gint row, col;
4081
4082     if(!GTK_WIDGET_DRAWABLE(GTK_WIDGET(sheet))) return;
4083     if(!GTK_WIDGET_REALIZED(GTK_WIDGET(sheet))) return;
4084
4085     row = sheet->active_cell.row;
4086     col = sheet->active_cell.col;
4087  
4088     if(row<0 || col<0) return;
4089
4090     if(!gtk_sheet_cell_isvisible(sheet, row, col)) return;
4091 #if 0
4092     row_button_set(sheet, row);
4093     column_button_set(sheet, col);
4094 #endif
4095     gtk_sheet_draw_backing_pixmap(sheet, sheet->range);
4096     gtk_sheet_draw_border(sheet, sheet->range);
4097
4098 }
4099
4100
4101 static void
4102 gtk_sheet_make_backing_pixmap (GtkSheet *sheet, guint width, guint height)
4103 {
4104   gint pixmap_width, pixmap_height;
4105
4106   if(!GTK_WIDGET_REALIZED(GTK_WIDGET(sheet))) return;
4107
4108   if(width == 0 && height == 0){
4109      width=sheet->sheet_window_width+80;
4110      height=sheet->sheet_window_height+80;
4111   }
4112
4113   if (!sheet->pixmap)
4114     {
4115       /* allocate */
4116       sheet->pixmap = gdk_pixmap_new (sheet->sheet_window,
4117                                       width, height,
4118                                       -1);
4119       if(!GTK_SHEET_IS_FROZEN(sheet)) gtk_sheet_range_draw(sheet, NULL);
4120     }
4121   else
4122     {
4123       /* reallocate if sizes don't match */
4124       gdk_window_get_size (sheet->pixmap,
4125                            &pixmap_width, &pixmap_height);
4126       if ((pixmap_width != width) || (pixmap_height != height))
4127         {
4128           g_free(sheet->pixmap);
4129           sheet->pixmap = gdk_pixmap_new (sheet->sheet_window,
4130                                                width, height,
4131                                                -1);
4132           if(!GTK_SHEET_IS_FROZEN(sheet)) gtk_sheet_range_draw(sheet, NULL);
4133         }
4134     }
4135 }
4136
4137 static void
4138 gtk_sheet_new_selection(GtkSheet *sheet, GtkSheetRange *range)
4139 {
4140   gint i,j, mask1, mask2;
4141   gint state, selected;
4142   gint x,y,width,height;
4143   GtkSheetRange new_range, aux_range;
4144
4145   g_return_if_fail (sheet != NULL);
4146
4147   if(range==NULL) range=&sheet->range;
4148
4149   new_range=*range;
4150
4151   range->row0=MIN(range->row0, sheet->range.row0);
4152   range->rowi=MAX(range->rowi, sheet->range.rowi);
4153   range->col0=MIN(range->col0, sheet->range.col0);
4154   range->coli=MAX(range->coli, sheet->range.coli);
4155
4156   range->row0=MAX(range->row0, MIN_VISIBLE_ROW(sheet));
4157   range->rowi=MIN(range->rowi, MAX_VISIBLE_ROW(sheet));
4158   range->col0=MAX(range->col0, MIN_VISIBLE_COLUMN(sheet));
4159   range->coli=MIN(range->coli, MAX_VISIBLE_COLUMN(sheet));
4160
4161   aux_range.row0=MAX(new_range.row0, MIN_VISIBLE_ROW(sheet));
4162   aux_range.rowi=MIN(new_range.rowi, MAX_VISIBLE_ROW(sheet));
4163   aux_range.col0=MAX(new_range.col0, MIN_VISIBLE_COLUMN(sheet));
4164   aux_range.coli=MIN(new_range.coli, MAX_VISIBLE_COLUMN(sheet));
4165
4166   for(i=range->row0; i<=range->rowi; i++){
4167    for(j=range->col0; j<=range->coli; j++){     
4168
4169     state=gtk_sheet_cell_get_state(sheet, i, j);
4170     selected=(i<=new_range.rowi && i>=new_range.row0 && 
4171         j<=new_range.coli && j>=new_range.col0) ? TRUE : FALSE;
4172
4173     if(state==GTK_STATE_SELECTED && selected &&
4174        xxx_column_is_visible(sheet, j) && yyy_row_is_visible(sheet, i) &&
4175        (i==sheet->range.row0 || i==sheet->range.rowi ||
4176         j==sheet->range.col0 || j==sheet->range.coli ||
4177         i==new_range.row0 || i==new_range.rowi ||
4178         j==new_range.col0 || j==new_range.coli)){
4179
4180        mask1 = i==sheet->range.row0 ? 1 : 0;
4181        mask1 = i==sheet->range.rowi ? mask1+2 : mask1;
4182        mask1 = j==sheet->range.col0 ? mask1+4 : mask1;
4183        mask1 = j==sheet->range.coli ? mask1+8 : mask1;
4184
4185        mask2 = i==new_range.row0 ? 1 : 0;
4186        mask2 = i==new_range.rowi ? mask2+2 : mask2;
4187        mask2 = j==new_range.col0 ? mask2+4 : mask2;
4188        mask2 = j==new_range.coli ? mask2+8 : mask2;     
4189
4190        if(mask1 != mask2){
4191          x=COLUMN_LEFT_XPIXEL(sheet,j);
4192          y=ROW_TOP_YPIXEL(sheet, i);  
4193          width=COLUMN_LEFT_XPIXEL(sheet, j)-x+
4194            xxx_column_width(sheet, j);
4195          height=ROW_TOP_YPIXEL(sheet, i)-y+yyy_row_height(sheet, i);
4196
4197          if(i==sheet->range.row0){
4198             y=y-3;
4199             height=height+3;
4200          }
4201          if(i==sheet->range.rowi) height=height+3;
4202          if(j==sheet->range.col0){
4203             x=x-3;
4204             width=width+3;
4205          }
4206          if(j==sheet->range.coli) width=width+3;
4207
4208          gdk_draw_pixmap(sheet->sheet_window,
4209                   GTK_WIDGET(sheet)->style->fg_gc[GTK_STATE_NORMAL],
4210                   sheet->pixmap,
4211                   x+1,
4212                   y+1,
4213                   x+1,
4214                   y+1,
4215                   width,
4216                   height);           
4217
4218          if(i != sheet->active_cell.row || j != sheet->active_cell.col){
4219            x=COLUMN_LEFT_XPIXEL(sheet,j);
4220            y=ROW_TOP_YPIXEL(sheet, i);  
4221            width=COLUMN_LEFT_XPIXEL(sheet, j)-x+
4222              xxx_column_width(sheet, j);
4223
4224            height=ROW_TOP_YPIXEL(sheet, i)-y+yyy_row_height(sheet, i);
4225
4226            if(i==new_range.row0){
4227                y=y+2;
4228                height=height-2;
4229             }
4230             if(i==new_range.rowi) height=height-3;
4231             if(j==new_range.col0){
4232                x=x+2;
4233                width=width-2;
4234             }
4235             if(j==new_range.coli) width=width-3;
4236
4237             gdk_draw_rectangle (sheet->sheet_window,
4238                            sheet->xor_gc,
4239                            TRUE,
4240                            x+1,y+1,
4241                            width,height);
4242           }
4243        }
4244     }
4245    }
4246   }
4247
4248   for(i=range->row0; i<=range->rowi; i++){
4249    for(j=range->col0; j<=range->coli; j++){     
4250
4251     state=gtk_sheet_cell_get_state(sheet, i, j);
4252     selected=(i<=new_range.rowi && i>=new_range.row0 && 
4253         j<=new_range.coli && j>=new_range.col0) ? TRUE : FALSE;
4254
4255     if(state==GTK_STATE_SELECTED && !selected &&   
4256        xxx_column_is_visible(sheet, j) && yyy_row_is_visible(sheet, i)){
4257
4258       x=COLUMN_LEFT_XPIXEL(sheet,j);
4259       y=ROW_TOP_YPIXEL(sheet, i);  
4260       width=COLUMN_LEFT_XPIXEL(sheet, j)-x+ xxx_column_width(sheet, j);
4261       height=ROW_TOP_YPIXEL(sheet, i)-y+yyy_row_height(sheet, i);
4262
4263       if(i==sheet->range.row0){
4264             y=y-3;
4265             height=height+3;
4266       }
4267       if(i==sheet->range.rowi) height=height+3;
4268       if(j==sheet->range.col0){
4269             x=x-3;
4270             width=width+3;
4271       }
4272       if(j==sheet->range.coli) width=width+3;
4273
4274       gdk_draw_pixmap(sheet->sheet_window,
4275                   GTK_WIDGET(sheet)->style->fg_gc[GTK_STATE_NORMAL],
4276                   sheet->pixmap,
4277                   x+1,
4278                   y+1,
4279                   x+1,
4280                   y+1,
4281                   width,
4282                   height);           
4283     }
4284    }
4285   }
4286
4287   for(i=range->row0; i<=range->rowi; i++){
4288    for(j=range->col0; j<=range->coli; j++){     
4289
4290     state=gtk_sheet_cell_get_state(sheet, i, j);
4291     selected=(i<=new_range.rowi && i>=new_range.row0 && 
4292         j<=new_range.coli && j>=new_range.col0) ? TRUE : FALSE;
4293
4294     if(state!=GTK_STATE_SELECTED && selected &&
4295        xxx_column_is_visible(sheet, j) && yyy_row_is_visible(sheet, i) &&
4296        (i != sheet->active_cell.row || j != sheet->active_cell.col)){
4297
4298       x=COLUMN_LEFT_XPIXEL(sheet,j);
4299       y=ROW_TOP_YPIXEL(sheet, i);  
4300       width=COLUMN_LEFT_XPIXEL(sheet, j)-x+ xxx_column_width(sheet, j);
4301       height=ROW_TOP_YPIXEL(sheet, i)-y+yyy_row_height(sheet, i);
4302
4303       if(i==new_range.row0){
4304             y=y+2;
4305             height=height-2;
4306        }
4307        if(i==new_range.rowi) height=height-3;
4308        if(j==new_range.col0){
4309             x=x+2;
4310             width=width-2;
4311        }
4312        if(j==new_range.coli) width=width-3;
4313
4314        gdk_draw_rectangle (sheet->sheet_window,
4315                            sheet->xor_gc,
4316                            TRUE,
4317                            x+1,y+1,
4318                            width,height);
4319
4320     }   
4321
4322    }
4323   }
4324
4325   for(i=aux_range.row0; i<=aux_range.rowi; i++){
4326    for(j=aux_range.col0; j<=aux_range.coli; j++){     
4327
4328     if(xxx_column_is_visible(sheet, j) && yyy_row_is_visible(sheet, i)){
4329
4330        state=gtk_sheet_cell_get_state(sheet, i, j);
4331
4332        mask1 = i==sheet->range.row0 ? 1 : 0;
4333        mask1 = i==sheet->range.rowi ? mask1+2 : mask1;
4334        mask1 = j==sheet->range.col0 ? mask1+4 : mask1;
4335        mask1 = j==sheet->range.coli ? mask1+8 : mask1;
4336
4337        mask2 = i==new_range.row0 ? 1 : 0;
4338        mask2 = i==new_range.rowi ? mask2+2 : mask2;
4339        mask2 = j==new_range.col0 ? mask2+4 : mask2;
4340        mask2 = j==new_range.coli ? mask2+8 : mask2;    
4341        if(mask2!=mask1 || (mask2==mask1 && state!=GTK_STATE_SELECTED)){
4342          x=COLUMN_LEFT_XPIXEL(sheet,j);
4343          y=ROW_TOP_YPIXEL(sheet, i);  
4344          width=xxx_column_width(sheet, j);
4345          height=yyy_row_height(sheet, i);
4346          if(mask2 & 1)
4347                gdk_draw_rectangle (sheet->sheet_window,
4348                                    sheet->xor_gc,
4349                                    TRUE,
4350                                    x+1,y-1,
4351                                    width,3);
4352
4353            
4354          if(mask2 & 2)
4355                gdk_draw_rectangle (sheet->sheet_window,
4356                                    sheet->xor_gc,
4357                                    TRUE,
4358                                    x+1,y+height-1,
4359                                    width,3);
4360
4361          if(mask2 & 4)
4362                gdk_draw_rectangle (sheet->sheet_window,
4363                                    sheet->xor_gc,
4364                                    TRUE,
4365                                    x-1,y+1,
4366                                    3,height);
4367
4368
4369          if(mask2 & 8)
4370                gdk_draw_rectangle (sheet->sheet_window,
4371                                    sheet->xor_gc,
4372                                    TRUE,
4373                                    x+width-1,y+1,
4374                                    3,height);
4375
4376        
4377
4378        }         
4379
4380     } 
4381
4382    }
4383   } 
4384
4385
4386   *range=new_range;
4387   gtk_sheet_draw_corners(sheet, new_range);
4388
4389 }
4390
4391 static void
4392 gtk_sheet_draw_border (GtkSheet *sheet, GtkSheetRange new_range)
4393 {
4394   GtkWidget *widget;
4395   GdkRectangle area;
4396   gint i;
4397   gint x,y,width,height;
4398
4399   widget = GTK_WIDGET(sheet);
4400
4401   x=COLUMN_LEFT_XPIXEL(sheet,new_range.col0);
4402   y=ROW_TOP_YPIXEL(sheet,new_range.row0);
4403   width=COLUMN_LEFT_XPIXEL(sheet,new_range.coli)-x+ 
4404     xxx_column_width(sheet, new_range.coli);
4405
4406   height=ROW_TOP_YPIXEL(sheet,new_range.rowi)-y+
4407              yyy_row_height(sheet, new_range.rowi);
4408
4409   area.x=COLUMN_LEFT_XPIXEL(sheet, MIN_VISIBLE_COLUMN(sheet));
4410   area.y=ROW_TOP_YPIXEL(sheet, MIN_VISIBLE_ROW(sheet));
4411   area.width=sheet->sheet_window_width;
4412   area.height=sheet->sheet_window_height;
4413
4414   if(x<0) {
4415       width=width+x;
4416       x=0;
4417   }
4418   if(width>area.width) width=area.width+10;
4419   if(y<0) {
4420       height=height+y;
4421       y=0;
4422   }
4423   if(height>area.height) height=area.height+10;
4424
4425   gdk_gc_set_clip_rectangle(sheet->xor_gc, &area);
4426
4427   for(i=-1; i<=1; ++i)
4428      gdk_draw_rectangle (sheet->sheet_window,
4429                          sheet->xor_gc,
4430                          FALSE,
4431                          x+i,y+i,
4432                          width-2*i,height-2*i);
4433
4434   gdk_gc_set_clip_rectangle(sheet->xor_gc, NULL);
4435   
4436   gtk_sheet_draw_corners(sheet, new_range);
4437
4438 }
4439
4440 static void
4441 gtk_sheet_draw_corners(GtkSheet *sheet, GtkSheetRange range)
4442 {
4443   gint x,y;
4444   guint width = 1;
4445
4446   if(gtk_sheet_cell_isvisible(sheet, range.row0, range.col0)){
4447        x=COLUMN_LEFT_XPIXEL(sheet,range.col0);
4448        y=ROW_TOP_YPIXEL(sheet,range.row0);
4449        gdk_draw_pixmap(sheet->sheet_window,
4450                        GTK_WIDGET(sheet)->style->fg_gc[GTK_STATE_NORMAL],
4451                        sheet->pixmap,
4452                        x-1,
4453                        y-1,
4454                        x-1,
4455                        y-1,
4456                        3,
4457                        3);         
4458        gdk_draw_rectangle (sheet->sheet_window,
4459                            sheet->xor_gc,
4460                            TRUE,
4461                            x-1,y-1,
4462                            3,3);
4463   }
4464
4465   if(gtk_sheet_cell_isvisible(sheet, range.row0, range.coli) ||
4466      sheet->state == GTK_SHEET_COLUMN_SELECTED){
4467        x=COLUMN_LEFT_XPIXEL(sheet,range.coli)+
4468          xxx_column_width(sheet, range.coli);
4469        y=ROW_TOP_YPIXEL(sheet,range.row0);
4470        width = 1;
4471        if(sheet->state == GTK_SHEET_COLUMN_SELECTED)
4472          {
4473              y = ROW_TOP_YPIXEL(sheet, sheet->view.row0)+3;
4474              width = 3;
4475          }
4476        gdk_draw_pixmap(sheet->sheet_window,
4477                        GTK_WIDGET(sheet)->style->fg_gc[GTK_STATE_NORMAL],
4478                        sheet->pixmap,
4479                        x-width,
4480                        y-width,
4481                        x-width,
4482                        y-width,
4483                        2*width+1,
4484                        2*width+1);         
4485        gdk_draw_rectangle (sheet->sheet_window,
4486                            sheet->xor_gc,
4487                            TRUE,
4488                            x-width+width/2,y-width+width/2,
4489                            2+width,2+width);
4490   }
4491
4492   if(gtk_sheet_cell_isvisible(sheet, range.rowi, range.col0) ||
4493      sheet->state == GTK_SHEET_ROW_SELECTED){
4494        x=COLUMN_LEFT_XPIXEL(sheet,range.col0);
4495        y=ROW_TOP_YPIXEL(sheet,range.rowi)+
4496          yyy_row_height(sheet, range.rowi);
4497        width = 1;
4498        if(sheet->state == GTK_SHEET_ROW_SELECTED) 
4499          {
4500              x = COLUMN_LEFT_XPIXEL(sheet, sheet->view.col0)+3;
4501              width = 3;
4502          }
4503        gdk_draw_pixmap(sheet->sheet_window,
4504                        GTK_WIDGET(sheet)->style->fg_gc[GTK_STATE_NORMAL],
4505                        sheet->pixmap,
4506                        x-width,
4507                        y-width,
4508                        x-width,
4509                        y-width,
4510                        2*width+1,
4511                        2*width+1);         
4512        gdk_draw_rectangle (sheet->sheet_window,
4513                            sheet->xor_gc,
4514                            TRUE,
4515                            x-width+width/2,y-width+width/2,
4516                            2+width,2+width);
4517   }
4518
4519   if(gtk_sheet_cell_isvisible(sheet, range.rowi, range.coli)){
4520        x=COLUMN_LEFT_XPIXEL(sheet,range.coli)+
4521          xxx_column_width(sheet, range.coli);
4522        y=ROW_TOP_YPIXEL(sheet,range.rowi)+
4523          yyy_row_height(sheet, range.rowi);
4524        width = 1;
4525        if(sheet->state == GTK_SHEET_RANGE_SELECTED) width = 3;
4526        if(sheet->state == GTK_SHEET_NORMAL) width = 3;
4527        gdk_draw_pixmap(sheet->sheet_window,
4528                        GTK_WIDGET(sheet)->style->fg_gc[GTK_STATE_NORMAL],
4529                        sheet->pixmap,
4530                        x-width,
4531                        y-width,
4532                        x-width,
4533                        y-width,
4534                        2*width+1,
4535                        2*width+1);         
4536        gdk_draw_rectangle (sheet->sheet_window,
4537                            sheet->xor_gc,
4538                            TRUE,
4539                            x-width+width/2,y-width+width/2,
4540                            2+width,2+width);
4541
4542   }
4543
4544 }
4545
4546
4547 static void
4548 gtk_sheet_real_select_range (GtkSheet * sheet,
4549                              GtkSheetRange * range)
4550 {
4551   gint state;
4552
4553   g_return_if_fail (sheet != NULL);
4554
4555   if(range==NULL) range=&sheet->range;
4556
4557   if(range->row0 < 0 || range->rowi < 0) return;
4558   if(range->col0 < 0 || range->coli < 0) return;
4559
4560   state=sheet->state;
4561
4562 #if 0
4563   if(state==GTK_SHEET_COLUMN_SELECTED || state==GTK_SHEET_RANGE_SELECTED){
4564    for(i=sheet->range.col0; i< range->col0; i++)
4565     column_button_release(sheet, i);
4566    for(i=range->coli+1; i<= sheet->range.coli; i++)
4567     column_button_release(sheet, i);
4568    for(i=range->col0; i<=range->coli; i++){
4569     column_button_set(sheet, i);
4570    }
4571   }
4572  
4573   if(state==GTK_SHEET_ROW_SELECTED || state==GTK_SHEET_RANGE_SELECTED){
4574    for(i=sheet->range.row0; i< range->row0; i++)
4575     row_button_release(sheet, i);
4576    for(i=range->rowi+1; i<= sheet->range.rowi; i++)
4577     row_button_release(sheet, i);
4578    for(i=range->row0; i<=range->rowi; i++){
4579     row_button_set(sheet, i);
4580    }
4581   }
4582 #endif
4583
4584   if(range->coli != sheet->range.coli || range->col0 != sheet->range.col0 ||
4585      range->rowi != sheet->range.rowi || range->row0 != sheet->range.row0)
4586          {
4587
4588            gtk_sheet_new_selection(sheet, range);
4589
4590            sheet->range.col0=range->col0;
4591            sheet->range.coli=range->coli;
4592            sheet->range.row0=range->row0;
4593            sheet->range.rowi=range->rowi;
4594
4595          }
4596   else
4597          {
4598            gtk_sheet_draw_backing_pixmap(sheet, sheet->range);
4599            gtk_sheet_range_draw_selection(sheet, sheet->range);
4600          }
4601
4602   gtk_signal_emit(GTK_OBJECT(sheet), sheet_signals[SELECT_RANGE], range);
4603 }
4604
4605 void
4606 gtk_sheet_select_range(GtkSheet * sheet, const GtkSheetRange *range)
4607 {
4608   g_return_if_fail (sheet != NULL);
4609
4610   if(range==NULL) range=&sheet->range;
4611
4612   if(range->row0 < 0 || range->rowi < 0) return;
4613   if(range->col0 < 0 || range->coli < 0) return;
4614
4615   if(sheet->state != GTK_SHEET_NORMAL) 
4616        gtk_sheet_real_unselect_range(sheet, NULL);
4617   else
4618   {
4619      gboolean veto = TRUE;
4620      veto = gtk_sheet_deactivate_cell(sheet);
4621      if(!veto) return;
4622   }
4623
4624   sheet->range.row0=range->row0;
4625   sheet->range.rowi=range->rowi;
4626   sheet->range.col0=range->col0;
4627   sheet->range.coli=range->coli;
4628   sheet->active_cell.row=range->row0;
4629   sheet->active_cell.col=range->col0;
4630   sheet->selection_cell.row=range->rowi;
4631   sheet->selection_cell.col=range->coli;
4632
4633   sheet->state = GTK_SHEET_RANGE_SELECTED;
4634   gtk_sheet_real_select_range(sheet, NULL);
4635
4636 }
4637
4638 void
4639 gtk_sheet_unselect_range (GtkSheet * sheet)
4640 {
4641   gtk_sheet_real_unselect_range(sheet, NULL);
4642   sheet->state = GTK_STATE_NORMAL;
4643   gtk_sheet_activate_cell(sheet, sheet->active_cell.row, sheet->active_cell.col);
4644 }
4645
4646
4647 static void
4648 gtk_sheet_real_unselect_range (GtkSheet * sheet,
4649                                const GtkSheetRange *range)
4650 {
4651   g_return_if_fail (sheet != NULL);
4652   g_return_if_fail (GTK_WIDGET_REALIZED(GTK_WIDGET(sheet)));
4653
4654   if(range==NULL){
4655      range=&sheet->range;
4656   }
4657
4658   if(range->row0 < 0 || range->rowi < 0) return;
4659   if(range->col0 < 0 || range->coli < 0) return;
4660
4661   if (gtk_sheet_range_isvisible (sheet, *range)){
4662     gtk_sheet_draw_backing_pixmap(sheet, *range);
4663   }
4664
4665 #if 0
4666   for(i=range->col0; i<=range->coli; i++){
4667      column_button_release(sheet, i);
4668   }
4669
4670   for(i=range->row0; i<=range->rowi; i++){
4671      row_button_release(sheet, i);
4672   }
4673 #endif
4674
4675   gtk_sheet_position_children(sheet);
4676 }
4677
4678
4679 static gint
4680 gtk_sheet_expose (GtkWidget * widget,
4681                   GdkEventExpose * event)
4682 {
4683   GtkSheet *sheet;
4684   GtkSheetRange range;
4685
4686   g_return_val_if_fail (widget != NULL, FALSE);
4687   g_return_val_if_fail (GTK_IS_SHEET (widget), FALSE);
4688   g_return_val_if_fail (event != NULL, FALSE);
4689
4690   sheet = GTK_SHEET (widget);
4691
4692   if (GTK_WIDGET_DRAWABLE (widget))
4693   {
4694       range.row0=ROW_FROM_YPIXEL(sheet,event->area.y);
4695       range.col0=COLUMN_FROM_XPIXEL(sheet,event->area.x);
4696       range.rowi=ROW_FROM_YPIXEL(sheet,event->area.y+event->area.height);
4697       range.coli=COLUMN_FROM_XPIXEL(sheet,event->area.x+event->area.width);
4698
4699       /* exposure events on the sheet */
4700  
4701       if(event->window == sheet->row_title_window && sheet->row_titles_visible){
4702          gint i;
4703          for(i = MIN_VISIBLE_ROW(sheet); i <= MAX_VISIBLE_ROW(sheet); i++)
4704            gtk_sheet_button_draw(sheet,i,-1);
4705       }
4706
4707       if(event->window == sheet->column_title_window && sheet->column_titles_visible){
4708          gint i;
4709          for(i = MIN_VISIBLE_COLUMN(sheet); i <= MAX_VISIBLE_COLUMN(sheet); i++)
4710            gtk_sheet_button_draw(sheet,-1,i);
4711       }
4712
4713       if (event->window == sheet->sheet_window){
4714         gtk_sheet_draw_backing_pixmap(sheet, range);
4715               
4716         if(sheet->state != GTK_SHEET_NORMAL){
4717                 if(gtk_sheet_range_isvisible(sheet, sheet->range))          
4718                    gtk_sheet_draw_backing_pixmap(sheet, sheet->range);
4719                 if(GTK_SHEET_IN_RESIZE(sheet) || GTK_SHEET_IN_DRAG(sheet))
4720                    gtk_sheet_draw_backing_pixmap(sheet, sheet->drag_range);
4721
4722                 if(gtk_sheet_range_isvisible(sheet, sheet->range))          
4723                    gtk_sheet_range_draw_selection(sheet, sheet->range);
4724                 if(GTK_SHEET_IN_RESIZE(sheet) || GTK_SHEET_IN_DRAG(sheet))
4725                    draw_xor_rectangle(sheet, sheet->drag_range);
4726         }
4727
4728         if((!GTK_SHEET_IN_XDRAG(sheet)) && (!GTK_SHEET_IN_YDRAG(sheet))){
4729              if(sheet->state == GTK_SHEET_NORMAL){ 
4730                  gtk_sheet_draw_active_cell(sheet);
4731                  if(!GTK_SHEET_IN_SELECTION(sheet))
4732                          gtk_widget_queue_draw(sheet->sheet_entry);
4733              }
4734         }
4735
4736
4737       }
4738
4739   }
4740
4741   if(sheet->state != GTK_SHEET_NORMAL && GTK_SHEET_IN_SELECTION(sheet))
4742      gtk_widget_grab_focus(GTK_WIDGET(sheet));
4743
4744   (* GTK_WIDGET_CLASS (parent_class)->expose_event) (widget, event);
4745
4746   return FALSE;
4747 }
4748
4749
4750 static gint
4751 gtk_sheet_button_press (GtkWidget * widget,
4752                         GdkEventButton * event)
4753 {
4754   GtkSheet *sheet;
4755   GdkModifierType mods;
4756   gint x, y, row, column;
4757   gboolean veto;
4758
4759   g_return_val_if_fail (widget != NULL, FALSE);
4760   g_return_val_if_fail (GTK_IS_SHEET (widget), FALSE);
4761   g_return_val_if_fail (event != NULL, FALSE);
4762
4763   sheet = GTK_SHEET (widget);
4764
4765   if ( event->type == GDK_2BUTTON_PRESS)
4766     {
4767       gtk_widget_get_pointer (widget, &x, &y);
4768       gtk_sheet_get_pixel_info (sheet, x, y, &row, &column);
4769
4770       if (event->window == sheet->column_title_window ) 
4771         {
4772           gtk_signal_emit (GTK_OBJECT (sheet), 
4773                            sheet_signals[DOUBLE_CLICK_COLUMN], column);
4774         }
4775       else if (event->window == sheet->row_title_window ) 
4776         {
4777           gtk_signal_emit (GTK_OBJECT (sheet), 
4778                            sheet_signals[DOUBLE_CLICK_ROW], row);
4779         }
4780     }
4781
4782   
4783 /*
4784   if(event->type != GDK_BUTTON_PRESS) return TRUE;
4785 */
4786   gdk_window_get_pointer(widget->window, NULL, NULL, &mods);
4787
4788   if(!(mods & GDK_BUTTON1_MASK)) return TRUE;
4789
4790
4791   /* press on resize windows */
4792   if (event->window == sheet->column_title_window &&
4793       gtk_sheet_columns_resizable(sheet))
4794       {
4795         gtk_widget_get_pointer (widget, &sheet->x_drag, NULL);
4796         if(POSSIBLE_XDRAG(sheet, sheet->x_drag, &sheet->drag_cell.col)){
4797           guint req;
4798           if (event->type == GDK_2BUTTON_PRESS){
4799             gtk_sheet_autoresize_column (sheet, sheet->drag_cell.col);
4800             GTK_SHEET_UNSET_FLAGS(sheet, GTK_SHEET_IN_XDRAG);
4801             return TRUE;
4802           }
4803           gtk_sheet_column_size_request(sheet, sheet->drag_cell.col, &req);
4804           GTK_SHEET_SET_FLAGS (sheet, GTK_SHEET_IN_XDRAG);
4805           gdk_pointer_grab (sheet->column_title_window, FALSE,
4806                             GDK_POINTER_MOTION_HINT_MASK |
4807                             GDK_BUTTON1_MOTION_MASK |
4808                             GDK_BUTTON_RELEASE_MASK,
4809                             NULL, NULL, event->time);
4810
4811           draw_xor_vline (sheet);
4812           return TRUE;
4813         }
4814       }
4815
4816   if (event->window == sheet->row_title_window && gtk_sheet_rows_resizable(sheet))
4817       {
4818         gtk_widget_get_pointer (widget, NULL, &sheet->y_drag);
4819
4820         if(POSSIBLE_YDRAG(sheet, sheet->y_drag, &sheet->drag_cell.row)){
4821           guint req;
4822           gtk_sheet_row_size_request(sheet, sheet->drag_cell.row, &req);
4823           GTK_SHEET_SET_FLAGS (sheet, GTK_SHEET_IN_YDRAG);
4824           gdk_pointer_grab (sheet->row_title_window, FALSE,
4825                             GDK_POINTER_MOTION_HINT_MASK |
4826                             GDK_BUTTON1_MOTION_MASK |
4827                             GDK_BUTTON_RELEASE_MASK,
4828                             NULL, NULL, event->time);
4829
4830           draw_xor_hline (sheet);
4831           return TRUE;
4832         }
4833       }
4834
4835   /* the sheet itself does not handle other than single click events */
4836   if(event->type != GDK_BUTTON_PRESS) return FALSE;
4837
4838   /* selections on the sheet */
4839     if(event->window == sheet->sheet_window){
4840      gtk_widget_get_pointer (widget, &x, &y);
4841      gtk_sheet_get_pixel_info (sheet, x, y, &row, &column);
4842      gdk_pointer_grab (sheet->sheet_window, FALSE,
4843                        GDK_POINTER_MOTION_HINT_MASK |
4844                        GDK_BUTTON1_MOTION_MASK |
4845                        GDK_BUTTON_RELEASE_MASK,
4846                        NULL, NULL, event->time);
4847      gtk_grab_add(GTK_WIDGET(sheet));
4848      sheet->timer=gtk_timeout_add(TIMEOUT_SCROLL, gtk_sheet_scroll, sheet); 
4849      gtk_widget_grab_focus(GTK_WIDGET(sheet));
4850
4851      if(sheet->selection_mode != GTK_SELECTION_SINGLE &&
4852         sheet->cursor_drag->type==GDK_SIZING &&
4853         !GTK_SHEET_IN_SELECTION(sheet) && !GTK_SHEET_IN_RESIZE(sheet)){
4854         if(sheet->state==GTK_STATE_NORMAL) {
4855           row=sheet->active_cell.row;
4856           column=sheet->active_cell.col;
4857           if(!gtk_sheet_deactivate_cell(sheet)) return FALSE;
4858           sheet->active_cell.row=row;
4859           sheet->active_cell.col=column;
4860           sheet->drag_range=sheet->range;
4861           sheet->state=GTK_SHEET_RANGE_SELECTED;
4862           gtk_sheet_select_range(sheet, &sheet->drag_range);
4863         }
4864         sheet->x_drag=x;
4865         sheet->y_drag=y;
4866         if(row > sheet->range.rowi) row--;
4867         if(column > sheet->range.coli) column--;
4868         sheet->drag_cell.row = row;
4869         sheet->drag_cell.col = column;
4870         sheet->drag_range=sheet->range;
4871         draw_xor_rectangle(sheet, sheet->drag_range);
4872         GTK_SHEET_SET_FLAGS(sheet, GTK_SHEET_IN_RESIZE);
4873      }
4874      else if(sheet->cursor_drag->type==GDK_TOP_LEFT_ARROW &&
4875             !GTK_SHEET_IN_SELECTION(sheet) && !GTK_SHEET_IN_DRAG(sheet)) {
4876             if(sheet->state==GTK_STATE_NORMAL) {
4877               row=sheet->active_cell.row;
4878               column=sheet->active_cell.col;
4879               if(!gtk_sheet_deactivate_cell(sheet)) return FALSE;
4880               sheet->active_cell.row=row;
4881               sheet->active_cell.col=column;
4882               sheet->drag_range=sheet->range;
4883               sheet->state=GTK_SHEET_RANGE_SELECTED;
4884               gtk_sheet_select_range(sheet, &sheet->drag_range);
4885             }
4886             sheet->x_drag=x;
4887             sheet->y_drag=y;
4888             if(row < sheet->range.row0) row++;
4889             if(row > sheet->range.rowi) row--;
4890             if(column < sheet->range.col0) column++;
4891             if(column > sheet->range.coli) column--;
4892             sheet->drag_cell.row=row;
4893             sheet->drag_cell.col=column;
4894             sheet->drag_range=sheet->range;
4895             draw_xor_rectangle(sheet, sheet->drag_range);
4896             GTK_SHEET_SET_FLAGS(sheet, GTK_SHEET_IN_DRAG);
4897           }
4898           else 
4899           {
4900            gtk_sheet_click_cell(sheet, row, column, &veto);
4901            if(veto) GTK_SHEET_SET_FLAGS(sheet, GTK_SHEET_IN_SELECTION);
4902           }
4903
4904     }
4905
4906     if(event->window == sheet->column_title_window){
4907      gtk_widget_get_pointer (widget, &x, &y);
4908      column = COLUMN_FROM_XPIXEL(sheet, x);
4909      if(xxx_column_is_sensitive(sheet, column)){
4910        gtk_sheet_click_cell(sheet, -1, column, &veto);
4911        gtk_grab_add(GTK_WIDGET(sheet));
4912        sheet->timer=gtk_timeout_add(TIMEOUT_SCROLL, gtk_sheet_scroll, sheet); 
4913        gtk_widget_grab_focus(GTK_WIDGET(sheet));
4914        GTK_SHEET_SET_FLAGS(sheet, GTK_SHEET_IN_SELECTION);
4915      }
4916     }
4917
4918     if(event->window == sheet->row_title_window){
4919      gtk_widget_get_pointer (widget, &x, &y);
4920      row = ROW_FROM_YPIXEL(sheet, y);
4921      if(yyy_row_is_sensitive(sheet, row)){
4922        gtk_sheet_click_cell(sheet, row, -1, &veto);
4923        gtk_grab_add(GTK_WIDGET(sheet));
4924        sheet->timer=gtk_timeout_add(TIMEOUT_SCROLL, gtk_sheet_scroll, sheet); 
4925        gtk_widget_grab_focus(GTK_WIDGET(sheet));
4926        GTK_SHEET_SET_FLAGS(sheet, GTK_SHEET_IN_SELECTION);
4927      }
4928     }
4929
4930     return TRUE;
4931 }
4932
4933 static gint
4934 gtk_sheet_scroll(gpointer data)
4935 {
4936  GtkSheet *sheet;
4937  gint x,y,row,column;
4938  gint move;
4939   
4940  sheet=GTK_SHEET(data);
4941
4942  GDK_THREADS_ENTER();
4943
4944  gtk_widget_get_pointer (GTK_WIDGET(sheet), &x, &y);
4945  gtk_sheet_get_pixel_info (sheet, x, y, &row, &column);
4946
4947  move=TRUE;
4948
4949  if(GTK_SHEET_IN_SELECTION(sheet))
4950       gtk_sheet_extend_selection(sheet, row, column);
4951
4952  if(GTK_SHEET_IN_DRAG(sheet) || GTK_SHEET_IN_RESIZE(sheet)){
4953        move=gtk_sheet_move_query(sheet, row, column);
4954        if(move) draw_xor_rectangle(sheet, sheet->drag_range);      
4955  }       
4956
4957  GDK_THREADS_LEAVE();
4958
4959  return TRUE;
4960       
4961 }
4962
4963 static void
4964 gtk_sheet_click_cell(GtkSheet *sheet, gint row, gint column, gboolean *veto)
4965 {
4966       *veto = TRUE;
4967
4968       if(row >= yyy_row_count(sheet) || column >= xxx_column_count(sheet)){
4969           *veto = FALSE;
4970           return;
4971       }
4972
4973       if(column >= 0 && row >= 0)
4974        if(! xxx_column_is_visible(sheet, column) || !yyy_row_is_visible(sheet, row)) 
4975          {
4976            *veto = FALSE;
4977            return;
4978          }
4979
4980       _gtkextra_signal_emit(GTK_OBJECT(sheet), sheet_signals[TRAVERSE],
4981                             sheet->active_cell.row, sheet->active_cell.col, 
4982                             &row, &column, veto);
4983
4984       if(!*veto){
4985            if(sheet->state == GTK_STATE_NORMAL) return;
4986
4987            row = sheet->active_cell.row;
4988            column = sheet->active_cell.col;
4989
4990            gtk_sheet_activate_cell(sheet, row, column);
4991            return;
4992       }
4993
4994       if(row == -1 && column >= 0){
4995           if(gtk_sheet_autoscroll(sheet))
4996             gtk_sheet_move_query(sheet, row, column);
4997           gtk_sheet_select_column(sheet, column);
4998           return;
4999       }
5000       if(column == -1 && row >= 0){
5001           if(gtk_sheet_autoscroll(sheet))
5002             gtk_sheet_move_query(sheet, row, column);
5003           gtk_sheet_select_row(sheet, row);
5004           return;
5005       }
5006
5007       if(row==-1 && column ==-1){
5008           sheet->range.row0=0;
5009           sheet->range.col0=0;
5010           sheet->range.rowi = yyy_row_count(sheet) - 1;
5011           sheet->range.coli = xxx_column_count(sheet) - 1;
5012           sheet->active_cell.row=0;
5013           sheet->active_cell.col=0;
5014           gtk_sheet_select_range(sheet, NULL);
5015           return;
5016       }
5017
5018       if(row!=-1 && column !=-1){
5019           if(sheet->state != GTK_SHEET_NORMAL){
5020             sheet->state = GTK_SHEET_NORMAL;
5021             gtk_sheet_real_unselect_range(sheet, NULL);
5022           }
5023           else
5024           {
5025             if(!gtk_sheet_deactivate_cell(sheet)){
5026               *veto = FALSE;
5027               return;
5028             }
5029           }
5030
5031           if(gtk_sheet_autoscroll(sheet))
5032             gtk_sheet_move_query(sheet, row, column);
5033           sheet->active_cell.row=row;
5034           sheet->active_cell.col=column;
5035           sheet->selection_cell.row=row;
5036           sheet->selection_cell.col=column;
5037           sheet->range.row0=row;
5038           sheet->range.col0=column;
5039           sheet->range.rowi=row;
5040           sheet->range.coli=column;
5041           sheet->state=GTK_SHEET_NORMAL;
5042           GTK_SHEET_SET_FLAGS(sheet, GTK_SHEET_IN_SELECTION);
5043           gtk_sheet_draw_active_cell(sheet);
5044           return;
5045       }
5046
5047       g_assert_not_reached();
5048       gtk_sheet_activate_cell(sheet, sheet->active_cell.row,
5049                                      sheet->active_cell.col);
5050 }
5051
5052 static gint
5053 gtk_sheet_button_release (GtkWidget * widget,
5054                         GdkEventButton * event)
5055 {
5056   GtkSheet *sheet;
5057   gint x,y;
5058  
5059   sheet=GTK_SHEET(widget);
5060
5061   /* release on resize windows */
5062   if (GTK_SHEET_IN_XDRAG (sheet)){
5063           GTK_SHEET_UNSET_FLAGS (sheet, GTK_SHEET_IN_XDRAG);
5064           GTK_SHEET_UNSET_FLAGS (sheet, GTK_SHEET_IN_SELECTION);
5065           gtk_widget_get_pointer (widget, &x, NULL);
5066           gdk_pointer_ungrab (event->time);
5067           draw_xor_vline (sheet);
5068           
5069           gtk_sheet_set_column_width (sheet, sheet->drag_cell.col, new_column_width (sheet, sheet->drag_cell.col, &x));
5070           sheet->old_hadjustment = -1.;
5071           gtk_signal_emit_by_name (GTK_OBJECT (sheet->hadjustment), "value_changed");
5072           return TRUE;
5073   }
5074
5075   if (GTK_SHEET_IN_YDRAG (sheet)){
5076           GTK_SHEET_UNSET_FLAGS (sheet, GTK_SHEET_IN_YDRAG);
5077           GTK_SHEET_UNSET_FLAGS (sheet, GTK_SHEET_IN_SELECTION);
5078           gtk_widget_get_pointer (widget, NULL, &y);
5079           gdk_pointer_ungrab (event->time);
5080           draw_xor_hline (sheet);
5081           
5082           gtk_sheet_set_row_height (sheet, sheet->drag_cell.row, new_row_height (sheet, sheet->drag_cell.row, &y));
5083           sheet->old_vadjustment = -1.;
5084           gtk_signal_emit_by_name (GTK_OBJECT (sheet->vadjustment), "value_changed");
5085           return TRUE;
5086   }
5087
5088   
5089   if (GTK_SHEET_IN_DRAG(sheet)){
5090       GtkSheetRange old_range;
5091       draw_xor_rectangle(sheet, sheet->drag_range);
5092       GTK_SHEET_UNSET_FLAGS(sheet, GTK_SHEET_IN_DRAG);
5093       gdk_pointer_ungrab (event->time);
5094
5095       gtk_sheet_real_unselect_range(sheet, NULL);
5096       
5097       sheet->active_cell.row = sheet->active_cell.row +
5098                                (sheet->drag_range.row0 - sheet->range.row0);
5099       sheet->active_cell.col = sheet->active_cell.col +
5100                                (sheet->drag_range.col0 - sheet->range.col0);
5101       sheet->selection_cell.row = sheet->selection_cell.row +
5102                                   (sheet->drag_range.row0 - sheet->range.row0);
5103       sheet->selection_cell.col = sheet->selection_cell.col +
5104                                   (sheet->drag_range.col0 - sheet->range.col0);
5105       old_range=sheet->range;
5106       sheet->range=sheet->drag_range;
5107       sheet->drag_range=old_range;
5108       gtk_signal_emit(GTK_OBJECT(sheet),sheet_signals[MOVE_RANGE],
5109                       &sheet->drag_range, &sheet->range);
5110       gtk_sheet_select_range(sheet, &sheet->range);
5111   }
5112
5113   if (GTK_SHEET_IN_RESIZE(sheet)){
5114       GtkSheetRange old_range;
5115       draw_xor_rectangle(sheet, sheet->drag_range);
5116       GTK_SHEET_UNSET_FLAGS(sheet, GTK_SHEET_IN_RESIZE);
5117       gdk_pointer_ungrab (event->time);
5118
5119       gtk_sheet_real_unselect_range(sheet, NULL);
5120       
5121       sheet->active_cell.row = sheet->active_cell.row +
5122                                (sheet->drag_range.row0 - sheet->range.row0);
5123       sheet->active_cell.col = sheet->active_cell.col +
5124                                (sheet->drag_range.col0 - sheet->range.col0);
5125       if(sheet->drag_range.row0 < sheet->range.row0)
5126                      sheet->selection_cell.row = sheet->drag_range.row0;
5127       if(sheet->drag_range.rowi >= sheet->range.rowi)
5128                      sheet->selection_cell.row = sheet->drag_range.rowi;
5129       if(sheet->drag_range.col0 < sheet->range.col0)
5130                      sheet->selection_cell.col = sheet->drag_range.col0;
5131       if(sheet->drag_range.coli >= sheet->range.coli)
5132                      sheet->selection_cell.col = sheet->drag_range.coli;
5133       old_range = sheet->range;
5134       sheet->range = sheet->drag_range;
5135       sheet->drag_range = old_range;
5136
5137       if(sheet->state==GTK_STATE_NORMAL) sheet->state=GTK_SHEET_RANGE_SELECTED;
5138       gtk_signal_emit(GTK_OBJECT(sheet),sheet_signals[RESIZE_RANGE],
5139                       &sheet->drag_range, &sheet->range);
5140       gtk_sheet_select_range(sheet, &sheet->range);
5141   }
5142
5143   if(sheet->state == GTK_SHEET_NORMAL && GTK_SHEET_IN_SELECTION(sheet)){
5144       GTK_SHEET_UNSET_FLAGS(sheet, GTK_SHEET_IN_SELECTION);
5145       gdk_pointer_ungrab (event->time);
5146       gtk_sheet_activate_cell(sheet, sheet->active_cell.row, 
5147                                      sheet->active_cell.col);
5148   }
5149
5150   if(GTK_SHEET_IN_SELECTION)
5151          gdk_pointer_ungrab (event->time);
5152   if(sheet->timer)
5153          gtk_timeout_remove(sheet->timer);
5154   gtk_grab_remove(GTK_WIDGET(sheet));
5155
5156   GTK_SHEET_UNSET_FLAGS(sheet, GTK_SHEET_IN_SELECTION);
5157
5158   return TRUE;
5159 }
5160
5161 static gint
5162 gtk_sheet_motion (GtkWidget * widget,
5163                   GdkEventMotion * event)
5164 {
5165   GtkSheet *sheet;
5166   GdkModifierType mods;
5167   GdkCursorType new_cursor;
5168   gint x, y, row, column;
5169
5170   g_return_val_if_fail (widget != NULL, FALSE);
5171   g_return_val_if_fail (GTK_IS_SHEET (widget), FALSE);
5172   g_return_val_if_fail (event != NULL, FALSE);
5173
5174
5175   sheet = GTK_SHEET (widget);
5176
5177   /* selections on the sheet */
5178   x = event->x;
5179   y = event->y;
5180
5181   if(event->window == sheet->column_title_window && gtk_sheet_columns_resizable(sheet)){
5182     gtk_widget_get_pointer(widget, &x, &y);
5183     if(!GTK_SHEET_IN_SELECTION(sheet) && POSSIBLE_XDRAG(sheet, x, &column)){
5184       new_cursor=GDK_SB_H_DOUBLE_ARROW;
5185       if(new_cursor != sheet->cursor_drag->type){
5186         gdk_cursor_destroy(sheet->cursor_drag);
5187         sheet->cursor_drag=gdk_cursor_new(GDK_SB_H_DOUBLE_ARROW);
5188         gdk_window_set_cursor(sheet->column_title_window,sheet->cursor_drag);
5189       }
5190     }else{
5191       new_cursor=GDK_TOP_LEFT_ARROW;
5192       if(!GTK_SHEET_IN_XDRAG(sheet) && new_cursor != sheet->cursor_drag->type){
5193         gdk_cursor_destroy(sheet->cursor_drag);
5194         sheet->cursor_drag=gdk_cursor_new(GDK_TOP_LEFT_ARROW);
5195         gdk_window_set_cursor(sheet->column_title_window,sheet->cursor_drag);
5196       }
5197     }
5198   }      
5199
5200   if(event->window == sheet->row_title_window && gtk_sheet_rows_resizable(sheet)){
5201     gtk_widget_get_pointer(widget, &x, &y);
5202     if(!GTK_SHEET_IN_SELECTION(sheet) && POSSIBLE_YDRAG(sheet,y, &column)){
5203       new_cursor=GDK_SB_V_DOUBLE_ARROW;
5204       if(new_cursor != sheet->cursor_drag->type){
5205         gdk_cursor_destroy(sheet->cursor_drag);
5206         sheet->cursor_drag=gdk_cursor_new(GDK_SB_V_DOUBLE_ARROW);
5207         gdk_window_set_cursor(sheet->row_title_window,sheet->cursor_drag);
5208       }
5209     }else{
5210       new_cursor=GDK_TOP_LEFT_ARROW;
5211       if(!GTK_SHEET_IN_YDRAG(sheet) && new_cursor != sheet->cursor_drag->type){
5212         gdk_cursor_destroy(sheet->cursor_drag);
5213         sheet->cursor_drag=gdk_cursor_new(GDK_TOP_LEFT_ARROW);
5214         gdk_window_set_cursor(sheet->row_title_window,sheet->cursor_drag);
5215       }
5216     }
5217   }      
5218
5219   new_cursor=GDK_PLUS;
5220   if(!POSSIBLE_DRAG(sheet,x,y,&row,&column) && !GTK_SHEET_IN_DRAG(sheet) &&
5221      !POSSIBLE_RESIZE(sheet,x,y,&row,&column) && !GTK_SHEET_IN_RESIZE(sheet) &&
5222      event->window == sheet->sheet_window && 
5223      new_cursor != sheet->cursor_drag->type){
5224          gdk_cursor_destroy(sheet->cursor_drag);
5225          sheet->cursor_drag=gdk_cursor_new(GDK_PLUS);
5226          gdk_window_set_cursor(sheet->sheet_window,sheet->cursor_drag);
5227   }
5228
5229   new_cursor=GDK_TOP_LEFT_ARROW;
5230   if(!(POSSIBLE_RESIZE(sheet,x,y,&row,&column) || GTK_SHEET_IN_RESIZE(sheet)) &&
5231      (POSSIBLE_DRAG(sheet, x,y,&row,&column) || GTK_SHEET_IN_DRAG(sheet)) && 
5232      event->window == sheet->sheet_window && 
5233      new_cursor != sheet->cursor_drag->type){
5234          gdk_cursor_destroy(sheet->cursor_drag);
5235          sheet->cursor_drag=gdk_cursor_new(GDK_TOP_LEFT_ARROW);
5236          gdk_window_set_cursor(sheet->sheet_window,sheet->cursor_drag);
5237   }
5238
5239   new_cursor=GDK_SIZING;
5240   if(!GTK_SHEET_IN_DRAG(sheet) &&
5241      (POSSIBLE_RESIZE(sheet,x,y,&row,&column) || GTK_SHEET_IN_RESIZE(sheet)) &&
5242      event->window == sheet->sheet_window && 
5243      new_cursor != sheet->cursor_drag->type){
5244          gdk_cursor_destroy(sheet->cursor_drag);
5245          sheet->cursor_drag=gdk_cursor_new(GDK_SIZING);
5246          gdk_window_set_cursor(sheet->sheet_window,sheet->cursor_drag);
5247   }
5248
5249   gdk_window_get_pointer (widget->window, &x, &y, &mods);
5250   if(!(mods & GDK_BUTTON1_MASK)) return FALSE;
5251
5252   if (GTK_SHEET_IN_XDRAG (sheet)){
5253         if (event->is_hint || event->window != widget->window)
5254             gtk_widget_get_pointer (widget, &x, NULL);
5255           else
5256             x = event->x;
5257
5258           new_column_width (sheet, sheet->drag_cell.col, &x);
5259           if (x != sheet->x_drag)
5260             {
5261               draw_xor_vline (sheet);
5262               sheet->x_drag = x;
5263               draw_xor_vline (sheet);
5264             }
5265           return TRUE;
5266   }
5267
5268   if (GTK_SHEET_IN_YDRAG (sheet)){
5269           if (event->is_hint || event->window != widget->window)
5270             gtk_widget_get_pointer (widget, NULL, &y);
5271           else
5272             y = event->y;
5273
5274           new_row_height (sheet, sheet->drag_cell.row, &y);
5275           if (y != sheet->y_drag)
5276             {
5277               draw_xor_hline (sheet);
5278               sheet->y_drag = y;
5279               draw_xor_hline (sheet);
5280             }
5281           return TRUE;
5282   }
5283
5284   if (GTK_SHEET_IN_DRAG(sheet)){
5285        GtkSheetRange aux;
5286        column=COLUMN_FROM_XPIXEL(sheet,x)-sheet->drag_cell.col;
5287        row=ROW_FROM_YPIXEL(sheet,y)-sheet->drag_cell.row;
5288        if(sheet->state==GTK_SHEET_COLUMN_SELECTED) row=0;
5289        if(sheet->state==GTK_SHEET_ROW_SELECTED) column=0;
5290        sheet->x_drag=x;
5291        sheet->y_drag=y;
5292        aux=sheet->range;
5293        if(aux.row0+row >= 0 && aux.rowi+row < yyy_row_count(sheet) &&
5294           aux.col0+column >= 0 && aux.coli+column < xxx_column_count(sheet)){
5295              aux=sheet->drag_range;
5296              sheet->drag_range.row0=sheet->range.row0+row;
5297              sheet->drag_range.col0=sheet->range.col0+column;
5298              sheet->drag_range.rowi=sheet->range.rowi+row;
5299              sheet->drag_range.coli=sheet->range.coli+column;
5300              if(aux.row0 != sheet->drag_range.row0 ||
5301                 aux.col0 != sheet->drag_range.col0){
5302                 draw_xor_rectangle (sheet, aux);
5303                 draw_xor_rectangle (sheet, sheet->drag_range);
5304              }
5305        }
5306        return TRUE;
5307   }
5308
5309   if (GTK_SHEET_IN_RESIZE(sheet)){
5310        GtkSheetRange aux;
5311        gint v_h, current_col, current_row, col_threshold, row_threshold;
5312        v_h=1;
5313
5314        if(abs(x-COLUMN_LEFT_XPIXEL(sheet,sheet->drag_cell.col)) >
5315           abs(y-ROW_TOP_YPIXEL(sheet,sheet->drag_cell.row))) v_h=2;
5316         
5317        current_col = COLUMN_FROM_XPIXEL(sheet,x);
5318        current_row = ROW_FROM_YPIXEL(sheet,y);
5319        column = current_col-sheet->drag_cell.col;
5320        row    = current_row-sheet->drag_cell.row;
5321
5322        /*use half of column width resp. row height as threshold to expand selection*/
5323        col_threshold = COLUMN_LEFT_XPIXEL(sheet,current_col)+xxx_column_width (sheet,current_col)/2;
5324        if (column > 0){
5325          if (x < col_threshold)
5326            column-=1;
5327        }
5328        else if (column < 0){
5329          if (x > col_threshold) 
5330            column+=1;
5331        }
5332        row_threshold = ROW_TOP_YPIXEL(sheet,current_row)+yyy_row_height (sheet, current_row)/2;
5333        if (row > 0){
5334          if(y < row_threshold)
5335            row-=1;
5336        }
5337        else if (row < 0){
5338          if(y > row_threshold)
5339            row+=1;       
5340        }
5341
5342        if(sheet->state==GTK_SHEET_COLUMN_SELECTED) row=0;
5343        if(sheet->state==GTK_SHEET_ROW_SELECTED) column=0;
5344        sheet->x_drag=x;
5345        sheet->y_drag=y;
5346        aux=sheet->range;
5347
5348        if(v_h==1) 
5349            column=0;
5350        else
5351            row=0;
5352
5353        if(aux.row0+row >= 0 && aux.rowi+row < yyy_row_count(sheet) &&
5354           aux.col0+column >= 0 && aux.coli+column < xxx_column_count(sheet)){
5355
5356              aux=sheet->drag_range;
5357              sheet->drag_range=sheet->range;
5358
5359              if(row<0) sheet->drag_range.row0=sheet->range.row0+row;
5360              if(row>0) sheet->drag_range.rowi=sheet->range.rowi+row;
5361              if(column<0) sheet->drag_range.col0=sheet->range.col0+column;
5362              if(column>0) sheet->drag_range.coli=sheet->range.coli+column;
5363              
5364              if(aux.row0 != sheet->drag_range.row0 ||
5365                 aux.rowi != sheet->drag_range.rowi ||
5366                 aux.col0 != sheet->drag_range.col0 ||
5367                 aux.coli != sheet->drag_range.coli){
5368                      draw_xor_rectangle (sheet, aux);
5369                      draw_xor_rectangle (sheet, sheet->drag_range);
5370              }
5371        }
5372        return TRUE;
5373   }
5374
5375   
5376
5377   gtk_sheet_get_pixel_info (sheet, x, y, &row, &column);
5378
5379   if(sheet->state==GTK_SHEET_NORMAL && row==sheet->active_cell.row &&
5380      column==sheet->active_cell.col) return TRUE;
5381
5382   if(GTK_SHEET_IN_SELECTION(sheet) && mods&GDK_BUTTON1_MASK)
5383                           gtk_sheet_extend_selection(sheet, row, column);
5384
5385   return TRUE;
5386 }
5387
5388 static gint
5389 gtk_sheet_move_query(GtkSheet *sheet, gint row, gint column)
5390 {
5391   gint row_move, column_move;
5392   gfloat row_align, col_align;
5393   guint height, width;
5394   gint new_row = row;
5395   gint new_col = column;
5396
5397   row_move=FALSE;
5398   column_move=FALSE;
5399   row_align=-1.;
5400   col_align=-1.;
5401
5402   height = sheet->sheet_window_height;
5403   width = sheet->sheet_window_width;
5404
5405   if(row>=MAX_VISIBLE_ROW(sheet) && sheet->state!=GTK_SHEET_COLUMN_SELECTED) {
5406           row_align = 1.;
5407           new_row = MIN(yyy_row_count(sheet), row + 1);
5408           row_move = TRUE;
5409           if(MAX_VISIBLE_ROW(sheet) == yyy_row_count(sheet) - 1 &&
5410              ROW_TOP_YPIXEL(sheet, yyy_row_count(sheet)-1) + 
5411              yyy_row_height(sheet, yyy_row_count(sheet)-1) < height){
5412                  row_move = FALSE;
5413                  row_align = -1.;
5414           }
5415   }
5416   if(row<MIN_VISIBLE_ROW(sheet) && sheet->state!=GTK_SHEET_COLUMN_SELECTED) {
5417           row_align= 0.;
5418           row_move = TRUE;
5419   }
5420   if(column>=MAX_VISIBLE_COLUMN(sheet) && sheet->state!=GTK_SHEET_ROW_SELECTED) {
5421           col_align = 1.;
5422           new_col = MIN(xxx_column_count(sheet) - 1, column + 1);
5423           column_move = TRUE;
5424           if(MAX_VISIBLE_COLUMN(sheet) == (xxx_column_count(sheet) - 1) &&
5425              COLUMN_LEFT_XPIXEL(sheet, xxx_column_count(sheet) - 1) + 
5426              xxx_column_width(sheet, xxx_column_count(sheet) - 1) < width)
5427             {
5428               column_move = FALSE;
5429               col_align = -1.;
5430             }
5431   } 
5432   if(column<MIN_VISIBLE_COLUMN(sheet) && sheet->state!=GTK_SHEET_ROW_SELECTED) {
5433           col_align = 0.;
5434           column_move = TRUE;
5435   }
5436
5437   if(row_move || column_move){
5438         gtk_sheet_moveto(sheet, new_row, new_col, row_align, col_align);
5439   }
5440
5441   return(row_move || column_move);
5442 }
5443
5444 static void
5445 gtk_sheet_extend_selection(GtkSheet *sheet, gint row, gint column)
5446 {
5447    GtkSheetRange range;
5448    gint state;
5449    gint r,c;
5450
5451    if(row == sheet->selection_cell.row && column == sheet->selection_cell.col)
5452         return;
5453
5454    if(sheet->selection_mode == GTK_SELECTION_SINGLE) return;
5455
5456    gtk_sheet_move_query(sheet, row, column);
5457    gtk_widget_grab_focus(GTK_WIDGET(sheet));
5458
5459    if(GTK_SHEET_IN_DRAG(sheet)) return;
5460
5461    state=sheet->state;
5462
5463    switch(sheet->state){
5464     case GTK_SHEET_ROW_SELECTED:
5465          column = xxx_column_count(sheet) - 1;
5466          break;
5467     case GTK_SHEET_COLUMN_SELECTED:
5468          row = yyy_row_count(sheet) - 1;
5469          break; 
5470     case GTK_SHEET_NORMAL:
5471          sheet->state=GTK_SHEET_RANGE_SELECTED;
5472          r=sheet->active_cell.row;
5473          c=sheet->active_cell.col;
5474          sheet->range.col0=c;
5475          sheet->range.row0=r;
5476          sheet->range.coli=c;
5477          sheet->range.rowi=r;
5478          gdk_draw_pixmap(sheet->sheet_window,
5479                    GTK_WIDGET(sheet)->style->fg_gc[GTK_STATE_NORMAL],
5480                    sheet->pixmap,
5481                    COLUMN_LEFT_XPIXEL(sheet,c)-1,
5482                    ROW_TOP_YPIXEL(sheet,r)-1,
5483                    COLUMN_LEFT_XPIXEL(sheet,c)-1,
5484                    ROW_TOP_YPIXEL(sheet,r)-1,
5485                    xxx_column_width(sheet, c)+4,
5486                    yyy_row_height(sheet, r)+4);   
5487          gtk_sheet_range_draw_selection(sheet, sheet->range);
5488     case GTK_SHEET_RANGE_SELECTED:
5489          sheet->state=GTK_SHEET_RANGE_SELECTED;
5490    }
5491
5492    sheet->selection_cell.row = row;
5493    sheet->selection_cell.col = column;
5494
5495    range.col0=MIN(column,sheet->active_cell.col);
5496    range.coli=MAX(column,sheet->active_cell.col);
5497    range.row0=MIN(row,sheet->active_cell.row);
5498    range.rowi=MAX(row,sheet->active_cell.row);
5499
5500    if(range.row0 != sheet->range.row0 || range.rowi != sheet->range.rowi ||
5501       range.col0 != sheet->range.col0 || range.coli != sheet->range.coli ||
5502       state==GTK_SHEET_NORMAL)
5503                gtk_sheet_real_select_range(sheet, &range);
5504
5505 }
5506
5507 static gint
5508 gtk_sheet_entry_key_press(GtkWidget *widget,
5509                           GdkEventKey *key)
5510 {
5511   gboolean focus;
5512   gtk_signal_emit_by_name(GTK_OBJECT(widget), "key_press_event", key, &focus);
5513   return focus;
5514 }
5515
5516 static gint
5517 gtk_sheet_key_press(GtkWidget *widget,
5518                     GdkEventKey *key)
5519 {
5520   GtkSheet *sheet;
5521   gint row, col;
5522   gint state;
5523   gboolean extend_selection = FALSE;
5524   gboolean force_move = FALSE;
5525   gboolean in_selection = FALSE;
5526   gboolean veto = TRUE;
5527   gint scroll = 1;
5528
5529   sheet = GTK_SHEET(widget);
5530
5531   if(key->state & GDK_CONTROL_MASK || key->keyval==GDK_Control_L ||
5532      key->keyval==GDK_Control_R) return FALSE;
5533
5534 /*
5535   {
5536     if(key->keyval=='c' || key->keyval == 'C' && sheet->state != GTK_STATE_NORMAL)
5537             gtk_sheet_clip_range(sheet, sheet->range);
5538     if(key->keyval=='x' || key->keyval == 'X')
5539             gtk_sheet_unclip_range(sheet);    
5540     return FALSE;
5541   }
5542 */
5543
5544   extend_selection = (key->state & GDK_SHIFT_MASK) || key->keyval==GDK_Shift_L 
5545 || key->keyval==GDK_Shift_R;
5546
5547   state=sheet->state;
5548   in_selection = GTK_SHEET_IN_SELECTION(sheet);
5549   GTK_SHEET_UNSET_FLAGS(sheet, GTK_SHEET_IN_SELECTION);
5550
5551   switch(key->keyval){
5552     case GDK_Return: case GDK_KP_Enter:
5553       if(sheet->state == GTK_SHEET_NORMAL && 
5554          !GTK_SHEET_IN_SELECTION(sheet))
5555          gtk_signal_emit_stop_by_name(GTK_OBJECT(gtk_sheet_get_entry(sheet)), 
5556                                      "key_press_event");
5557       row = sheet->active_cell.row;
5558       col = sheet->active_cell.col;
5559       if(sheet->state == GTK_SHEET_COLUMN_SELECTED)
5560            row = MIN_VISIBLE_ROW(sheet)-1;
5561       if(sheet->state == GTK_SHEET_ROW_SELECTED)
5562            col = MIN_VISIBLE_COLUMN(sheet);
5563       if(row < yyy_row_count(sheet) - 1){
5564            row = row + scroll;
5565            while(!yyy_row_is_visible(sheet, row) && row<yyy_row_count(sheet)-1) 
5566              row++;
5567       }
5568       gtk_sheet_click_cell(sheet, row, col, &veto);
5569       extend_selection = FALSE;
5570       break;
5571    case GDK_ISO_Left_Tab:
5572       row = sheet->active_cell.row;
5573       col = sheet->active_cell.col;
5574       if(sheet->state == GTK_SHEET_ROW_SELECTED) 
5575            col = MIN_VISIBLE_COLUMN(sheet)-1;
5576       if(sheet->state == GTK_SHEET_COLUMN_SELECTED) 
5577            row = MIN_VISIBLE_ROW(sheet);
5578       if(col > 0){
5579            col = col - scroll; 
5580            while(! xxx_column_is_visible(sheet, col) && col>0) col--;
5581            col=MAX(0, col);
5582       }       
5583       gtk_sheet_click_cell(sheet, row, col, &veto);
5584       extend_selection = FALSE;
5585       break;
5586    case GDK_Tab:
5587       row = sheet->active_cell.row;
5588       col = sheet->active_cell.col;
5589       if(sheet->state == GTK_SHEET_ROW_SELECTED) 
5590            col = MIN_VISIBLE_COLUMN(sheet)-1;
5591       if(sheet->state == GTK_SHEET_COLUMN_SELECTED) 
5592            row = MIN_VISIBLE_ROW(sheet);
5593       if(col < xxx_column_count(sheet) - 1)
5594         {
5595           col = col + scroll; 
5596           while(! xxx_column_is_visible(sheet, col) && 
5597                 col < xxx_column_count(sheet) - 1) 
5598             col++;
5599         }       
5600       gtk_sheet_click_cell(sheet, row, col, &veto);
5601       extend_selection = FALSE;
5602       break;
5603 /*    case GDK_BackSpace:
5604       if(sheet->active_cell.row >= 0 && sheet->active_cell.col >= 0){
5605        if(sheet->active_cell.col > 0){
5606             col = sheet->active_cell.col - scroll; 
5607             row = sheet->active_cell.row;
5608             while(!sheet->column[col].is_visible && col > 0) col--;
5609        }       
5610       }
5611       gtk_sheet_click_cell(sheet, row, col, &veto);
5612       extend_selection = FALSE;
5613       break;
5614 */
5615     case GDK_Page_Up:
5616       scroll=MAX_VISIBLE_ROW(sheet)-MIN_VISIBLE_ROW(sheet)+1;
5617     case GDK_Up:
5618       if(extend_selection){
5619         if(state==GTK_STATE_NORMAL){
5620            row=sheet->active_cell.row;
5621            col=sheet->active_cell.col;
5622            gtk_sheet_click_cell(sheet, row, col, &veto);
5623            if(!veto) break;
5624         }
5625         if(sheet->selection_cell.row > 0){
5626           row = sheet->selection_cell.row - scroll;
5627           while(!yyy_row_is_visible(sheet, row) && row > 0) row--;
5628           row = MAX(0, row);
5629           gtk_sheet_extend_selection(sheet, row, sheet->selection_cell.col);
5630         }
5631         return TRUE;
5632       }
5633       col = sheet->active_cell.col;
5634       row = sheet->active_cell.row;
5635       if(state==GTK_SHEET_COLUMN_SELECTED) 
5636              row = MIN_VISIBLE_ROW(sheet);
5637       if(state==GTK_SHEET_ROW_SELECTED) 
5638              col = MIN_VISIBLE_COLUMN(sheet);
5639       row = row - scroll;
5640       while(!yyy_row_is_visible(sheet, row) && row > 0) row--;
5641       row = MAX(0,row);
5642       gtk_sheet_click_cell(sheet, row, col, &veto);
5643       extend_selection = FALSE;
5644       break;
5645     case GDK_Page_Down:
5646       scroll=MAX_VISIBLE_ROW(sheet)-MIN_VISIBLE_ROW(sheet)+1;
5647     case GDK_Down:
5648       if(extend_selection){
5649         if(state==GTK_STATE_NORMAL){
5650            row=sheet->active_cell.row;
5651            col=sheet->active_cell.col;
5652            gtk_sheet_click_cell(sheet, row, col, &veto);
5653            if(!veto) break;
5654         }
5655         if(sheet->selection_cell.row < yyy_row_count(sheet)-1){
5656           row = sheet->selection_cell.row + scroll;
5657           while(!yyy_row_is_visible(sheet, row) && row < yyy_row_count(sheet)-1) row++;
5658           row = MIN(yyy_row_count(sheet)-1, row);
5659           gtk_sheet_extend_selection(sheet, row, sheet->selection_cell.col);
5660         }
5661         return TRUE;
5662       }
5663       col = sheet->active_cell.col;
5664       row = sheet->active_cell.row;
5665       if(sheet->active_cell.row < yyy_row_count(sheet)-1){
5666            if(state==GTK_SHEET_COLUMN_SELECTED) 
5667                 row = MIN_VISIBLE_ROW(sheet)-1;
5668            if(state==GTK_SHEET_ROW_SELECTED) 
5669                 col = MIN_VISIBLE_COLUMN(sheet);
5670            row = row + scroll;
5671            while(!yyy_row_is_visible(sheet, row) && row < yyy_row_count(sheet)-1) row++;
5672            row = MIN(yyy_row_count(sheet)-1, row);
5673       }
5674       gtk_sheet_click_cell(sheet, row, col, &veto);
5675       extend_selection = FALSE;
5676       break;
5677     case GDK_Right:
5678       if(extend_selection){
5679         if(state==GTK_STATE_NORMAL){
5680            row=sheet->active_cell.row;
5681            col=sheet->active_cell.col;
5682            gtk_sheet_click_cell(sheet, row, col, &veto);
5683            if(!veto) break;
5684         }
5685         if(sheet->selection_cell.col < xxx_column_count(sheet) - 1)
5686           {
5687             col = sheet->selection_cell.col + 1;
5688             while(! xxx_column_is_visible(sheet, col) && col < xxx_column_count(sheet) - 1) 
5689               col++;
5690             gtk_sheet_extend_selection(sheet, sheet->selection_cell.row, col);
5691           }
5692         return TRUE;
5693       }
5694       col = sheet->active_cell.col;
5695       row = sheet->active_cell.row;
5696       if(sheet->active_cell.col < xxx_column_count(sheet) - 1){
5697            col ++;
5698            if(state==GTK_SHEET_ROW_SELECTED) 
5699                 col = MIN_VISIBLE_COLUMN(sheet)-1;
5700            if(state==GTK_SHEET_COLUMN_SELECTED) 
5701                 row = MIN_VISIBLE_ROW(sheet);
5702            while(! xxx_column_is_visible(sheet, col) && col < xxx_column_count(sheet) - 1) col++;
5703            if(strlen(gtk_entry_get_text(GTK_ENTRY(gtk_sheet_get_entry(sheet)))) == 0 
5704               || force_move) {
5705                 gtk_sheet_click_cell(sheet, row, col, &veto);
5706            }
5707            else
5708               return FALSE;
5709       }
5710       extend_selection = FALSE;
5711       break;
5712     case GDK_Left:
5713       if(extend_selection){
5714         if(state==GTK_STATE_NORMAL){
5715            row=sheet->active_cell.row;
5716            col=sheet->active_cell.col;
5717            gtk_sheet_click_cell(sheet, row, col, &veto);
5718            if(!veto) break;
5719         }
5720         if(sheet->selection_cell.col > 0){
5721           col = sheet->selection_cell.col - 1;
5722           while(! xxx_column_is_visible(sheet, col) && col > 0) col--;          
5723           gtk_sheet_extend_selection(sheet, sheet->selection_cell.row, col);
5724         }
5725         return TRUE;
5726       }
5727       col = sheet->active_cell.col - 1;
5728       row = sheet->active_cell.row;
5729       if(state==GTK_SHEET_ROW_SELECTED) 
5730                 col = MIN_VISIBLE_COLUMN(sheet)-1;
5731       if(state==GTK_SHEET_COLUMN_SELECTED) 
5732                 row = MIN_VISIBLE_ROW(sheet);
5733       while(! xxx_column_is_visible(sheet, col) && col > 0) col--;
5734       col = MAX(0, col);
5735
5736       if(strlen(gtk_entry_get_text(GTK_ENTRY(gtk_sheet_get_entry(sheet)))) == 0
5737          || force_move){
5738                 gtk_sheet_click_cell(sheet, row, col, &veto);
5739       }
5740       else
5741          return FALSE;
5742       extend_selection = FALSE;
5743       break;
5744     case GDK_Home:
5745       row=0;
5746       while(!yyy_row_is_visible(sheet, row) && row < yyy_row_count(sheet)-1) row++;
5747       gtk_sheet_click_cell(sheet, row, sheet->active_cell.col, &veto);
5748       extend_selection = FALSE;
5749       break;
5750     case GDK_End:
5751       row=yyy_row_count(sheet)-1;
5752       while(!yyy_row_is_visible(sheet, row) && row > 0) row--;
5753       gtk_sheet_click_cell(sheet, row, sheet->active_cell.col, &veto);
5754       extend_selection = FALSE;
5755       break;
5756     default:
5757       if(in_selection) {
5758         GTK_SHEET_SET_FLAGS(sheet, GTK_SHEET_IN_SELECTION);
5759         if(extend_selection) return TRUE;
5760       }
5761       if(state == GTK_SHEET_ROW_SELECTED) 
5762         sheet->active_cell.col=MIN_VISIBLE_COLUMN(sheet);
5763       if(state == GTK_SHEET_COLUMN_SELECTED)
5764         sheet->active_cell.row=MIN_VISIBLE_ROW(sheet);
5765       return FALSE;
5766   }
5767
5768   if(extend_selection) return TRUE;
5769
5770   gtk_sheet_activate_cell(sheet, sheet->active_cell.row,
5771                                  sheet->active_cell.col);
5772
5773   return TRUE;
5774
5775
5776 static void
5777 gtk_sheet_size_request (GtkWidget * widget,
5778                         GtkRequisition * requisition)
5779 {
5780   GtkSheet *sheet;
5781   GList *children;
5782   GtkSheetChild *child;
5783   GtkRequisition child_requisition;
5784
5785   g_return_if_fail (widget != NULL);
5786   g_return_if_fail (GTK_IS_SHEET (widget));
5787   g_return_if_fail (requisition != NULL);
5788
5789   sheet = GTK_SHEET (widget);
5790
5791   requisition->width = 3*DEFAULT_COLUMN_WIDTH;
5792   requisition->height = 3*DEFAULT_ROW_HEIGHT(widget);
5793
5794   /* compute the size of the column title area */
5795   if(sheet->column_titles_visible) 
5796      requisition->height += sheet->column_title_area.height;
5797
5798   /* compute the size of the row title area */
5799   if(sheet->row_titles_visible) 
5800      requisition->width += sheet->row_title_area.width;
5801
5802   sheet->view.row0=ROW_FROM_YPIXEL(sheet, sheet->column_title_area.height+1);
5803   sheet->view.rowi=ROW_FROM_YPIXEL(sheet, sheet->sheet_window_height-1);
5804   sheet->view.col0=COLUMN_FROM_XPIXEL(sheet, sheet->row_title_area.width+1);
5805   sheet->view.coli=COLUMN_FROM_XPIXEL(sheet, sheet->sheet_window_width);
5806
5807   if(!sheet->column_titles_visible) 
5808      sheet->view.row0=ROW_FROM_YPIXEL(sheet, 1);
5809
5810   if(!sheet->row_titles_visible) 
5811      sheet->view.col0=COLUMN_FROM_XPIXEL(sheet, 1);
5812
5813   children = sheet->children;
5814   while (children)
5815   {
5816     child = children->data;
5817     children = children->next;
5818
5819     gtk_widget_size_request(child->widget, &child_requisition);
5820   }
5821 }
5822
5823  
5824 static void
5825 gtk_sheet_size_allocate (GtkWidget * widget,
5826                          GtkAllocation * allocation)
5827 {
5828   GtkSheet *sheet;
5829   GtkAllocation sheet_allocation;
5830   gint border_width;
5831
5832   g_return_if_fail (widget != NULL);
5833   g_return_if_fail (GTK_IS_SHEET (widget));
5834   g_return_if_fail (allocation != NULL);
5835
5836   sheet = GTK_SHEET (widget);
5837   widget->allocation = *allocation;
5838   border_width = GTK_CONTAINER(widget)->border_width;
5839
5840   if (GTK_WIDGET_REALIZED (widget))
5841     gdk_window_move_resize (widget->window,
5842                             allocation->x + border_width,
5843                             allocation->y + border_width,
5844                             allocation->width - 2*border_width,
5845                             allocation->height - 2*border_width);
5846
5847   /* use internal allocation structure for all the math
5848    * because it's easier than always subtracting the container
5849    * border width */
5850   sheet->internal_allocation.x = 0;
5851   sheet->internal_allocation.y = 0;
5852   sheet->internal_allocation.width = allocation->width - 2*border_width;
5853   sheet->internal_allocation.height = allocation->height - 2*border_width;
5854         
5855   sheet_allocation.x = 0;
5856   sheet_allocation.y = 0;
5857   sheet_allocation.width = allocation->width - 2*border_width;
5858   sheet_allocation.height = allocation->height - 2*border_width;
5859
5860   sheet->sheet_window_width = sheet_allocation.width;
5861   sheet->sheet_window_height = sheet_allocation.height;
5862
5863   if (GTK_WIDGET_REALIZED (widget))
5864     gdk_window_move_resize (sheet->sheet_window,
5865                             sheet_allocation.x,
5866                             sheet_allocation.y,
5867                             sheet_allocation.width,
5868                             sheet_allocation.height);
5869
5870     /* position the window which holds the column title buttons */
5871   sheet->column_title_area.x = 0;
5872   sheet->column_title_area.y = 0;
5873   if(sheet->row_titles_visible)
5874        sheet->column_title_area.x = sheet->row_title_area.width;
5875   sheet->column_title_area.width = sheet_allocation.width - 
5876                                      sheet->column_title_area.x;
5877   if(GTK_WIDGET_REALIZED(widget) && sheet->column_titles_visible)
5878       gdk_window_move_resize (sheet->column_title_window,
5879                               sheet->column_title_area.x,
5880                               sheet->column_title_area.y,
5881                               sheet->column_title_area.width,
5882                               sheet->column_title_area.height);
5883
5884   sheet->sheet_window_width = sheet_allocation.width;
5885   sheet->sheet_window_height = sheet_allocation.height;
5886
5887   /* column button allocation */
5888   size_allocate_column_title_buttons (sheet);
5889
5890   /* position the window which holds the row title buttons */
5891   sheet->row_title_area.x = 0;
5892   sheet->row_title_area.y = 0;
5893   if(sheet->column_titles_visible)
5894        sheet->row_title_area.y = sheet->column_title_area.height;
5895   sheet->row_title_area.height = sheet_allocation.height -
5896                                    sheet->row_title_area.y;
5897
5898   if(GTK_WIDGET_REALIZED(widget) && sheet->row_titles_visible)
5899       gdk_window_move_resize (sheet->row_title_window,
5900                               sheet->row_title_area.x,
5901                               sheet->row_title_area.y,
5902                               sheet->row_title_area.width,
5903                               sheet->row_title_area.height);
5904
5905
5906   /* row button allocation */
5907   size_allocate_row_title_buttons (sheet);
5908
5909   sheet->view.row0=ROW_FROM_YPIXEL(sheet, sheet->column_title_area.height+1);
5910   sheet->view.rowi=ROW_FROM_YPIXEL(sheet, sheet->sheet_window_height-1);
5911   sheet->view.col0=COLUMN_FROM_XPIXEL(sheet, sheet->row_title_area.width+1);
5912   sheet->view.coli=COLUMN_FROM_XPIXEL(sheet, sheet->sheet_window_width);
5913
5914   if(!sheet->column_titles_visible)
5915        sheet->view.row0=ROW_FROM_YPIXEL(sheet, 1);
5916       
5917   if(!sheet->row_titles_visible)
5918        sheet->view.col0=COLUMN_FROM_XPIXEL(sheet, 1);
5919
5920   size_allocate_column_title_buttons(sheet);
5921   size_allocate_row_title_buttons(sheet);
5922
5923   /* re-scale backing pixmap */
5924   gtk_sheet_make_backing_pixmap(sheet, 0, 0); 
5925   gtk_sheet_position_children(sheet);
5926
5927   /* set the scrollbars adjustments */
5928   adjust_scrollbars (sheet);
5929 }
5930
5931 static void
5932 size_allocate_column_title_buttons (GtkSheet * sheet)
5933 {
5934   gint i;
5935   gint x,width;
5936
5937   if (!sheet->column_titles_visible) return;
5938   if (!GTK_WIDGET_REALIZED (sheet))
5939     return;
5940
5941   width = sheet->sheet_window_width;
5942   x = 0;
5943
5944   if(sheet->row_titles_visible)
5945     {
5946       width -= sheet->row_title_area.width;
5947       x = sheet->row_title_area.width;
5948     }
5949
5950   if(sheet->column_title_area.width != width || sheet->column_title_area.x != x)
5951   {
5952      sheet->column_title_area.width = width;
5953      sheet->column_title_area.x = x;
5954      gdk_window_move_resize (sheet->column_title_window,
5955                              sheet->column_title_area.x,
5956                              sheet->column_title_area.y,
5957                              sheet->column_title_area.width,
5958                              sheet->column_title_area.height);
5959   }
5960
5961
5962   if(MAX_VISIBLE_COLUMN(sheet) == xxx_column_count(sheet) - 1)
5963      gdk_window_clear_area (sheet->column_title_window,
5964                             0,0,
5965                             sheet->column_title_area.width, 
5966                             sheet->column_title_area.height);
5967
5968   if(!GTK_WIDGET_DRAWABLE(sheet)) return;
5969
5970   for (i = MIN_VISIBLE_COLUMN(sheet); i <= MAX_VISIBLE_COLUMN(sheet); i++)
5971       gtk_sheet_button_draw(sheet,-1,i);
5972 }
5973         
5974 static void
5975 size_allocate_row_title_buttons (GtkSheet * sheet)
5976 {
5977   gint i;
5978   gint y, height;
5979
5980   if (!sheet->row_titles_visible) return;
5981   if (!GTK_WIDGET_REALIZED (sheet))
5982     return;
5983
5984   height = sheet->sheet_window_height;
5985   y = 0;
5986
5987   if(sheet->column_titles_visible)
5988     {
5989       height -= sheet->column_title_area.height;
5990       y = sheet->column_title_area.height;
5991     }
5992     
5993   if(sheet->row_title_area.height != height || sheet->row_title_area.y != y)
5994     {
5995       sheet->row_title_area.y = y;
5996       sheet->row_title_area.height = height;
5997       gdk_window_move_resize (sheet->row_title_window,
5998                               sheet->row_title_area.x,
5999                               sheet->row_title_area.y,
6000                               sheet->row_title_area.width,
6001                               sheet->row_title_area.height);
6002     }
6003   if(MAX_VISIBLE_ROW(sheet) == yyy_row_count(sheet)-1)
6004     gdk_window_clear_area (sheet->row_title_window,
6005                            0,0,
6006                            sheet->row_title_area.width, 
6007                            sheet->row_title_area.height);
6008
6009   if(!GTK_WIDGET_DRAWABLE(sheet)) return;
6010
6011   for(i = MIN_VISIBLE_ROW(sheet); i <= MAX_VISIBLE_ROW(sheet); i++)
6012       gtk_sheet_button_draw(sheet,i,-1);
6013 }
6014           
6015
6016 static void
6017 gtk_sheet_size_allocate_entry(GtkSheet *sheet)
6018 {
6019  GtkAllocation shentry_allocation;
6020  GtkSheetCellAttr attributes;
6021  GtkEntry *sheet_entry;
6022  GtkStyle *style = NULL, *previous_style = NULL;
6023  gint row, col;
6024  gint size, max_size, text_size, column_width;
6025  const gchar *text;
6026
6027  if(!GTK_WIDGET_REALIZED(GTK_WIDGET(sheet))) return;
6028  if(!GTK_WIDGET_MAPPED(GTK_WIDGET(sheet))) return;
6029
6030  sheet_entry = GTK_ENTRY(gtk_sheet_get_entry(sheet));
6031
6032  gtk_sheet_get_attributes(sheet, sheet->active_cell.row, sheet->active_cell.col, &attributes); 
6033
6034  if(GTK_WIDGET_REALIZED(sheet->sheet_entry)){
6035
6036   if(!GTK_WIDGET(sheet_entry)->style) 
6037         gtk_widget_ensure_style(GTK_WIDGET(sheet_entry));
6038
6039   previous_style = GTK_WIDGET(sheet_entry)->style;
6040
6041   style = gtk_style_copy(previous_style);
6042   style->bg[GTK_STATE_NORMAL] = attributes.background;
6043   style->fg[GTK_STATE_NORMAL] = attributes.foreground;
6044   style->text[GTK_STATE_NORMAL] = attributes.foreground;
6045   style->bg[GTK_STATE_ACTIVE] = attributes.background;
6046   style->fg[GTK_STATE_ACTIVE] = attributes.foreground;
6047   style->text[GTK_STATE_ACTIVE] = attributes.foreground;
6048
6049   pango_font_description_free(style->font_desc);
6050   style->font_desc = pango_font_description_copy(attributes.font_desc);
6051
6052   GTK_WIDGET(sheet_entry)->style = style;
6053   gtk_widget_size_request(sheet->sheet_entry, NULL);
6054   GTK_WIDGET(sheet_entry)->style = previous_style;
6055
6056   if(style != previous_style){
6057     if(!GTK_IS_ITEM_ENTRY(sheet->sheet_entry)){
6058       style->bg[GTK_STATE_NORMAL] = previous_style->bg[GTK_STATE_NORMAL];
6059       style->fg[GTK_STATE_NORMAL] = previous_style->fg[GTK_STATE_NORMAL];
6060       style->bg[GTK_STATE_ACTIVE] = previous_style->bg[GTK_STATE_ACTIVE];
6061       style->fg[GTK_STATE_ACTIVE] = previous_style->fg[GTK_STATE_ACTIVE];
6062     }
6063     gtk_widget_set_style(GTK_WIDGET(sheet_entry), style);
6064   }
6065  }
6066
6067  if(GTK_IS_ITEM_ENTRY(sheet_entry))
6068     max_size = GTK_ITEM_ENTRY(sheet_entry)->text_max_size;
6069  else
6070     max_size = 0;
6071
6072  text_size = 0;
6073  text = gtk_entry_get_text(GTK_ENTRY(sheet_entry));
6074  if(text && strlen(text) > 0){ 
6075      text_size = STRING_WIDTH(GTK_WIDGET(sheet), attributes.font_desc, text);
6076  }
6077
6078  column_width=xxx_column_width(sheet, sheet->active_cell.col);
6079
6080  size=MIN(text_size, max_size);
6081  size=MAX(size,column_width-2*CELLOFFSET);
6082
6083  row=sheet->active_cell.row;
6084  col=sheet->active_cell.col;
6085
6086  shentry_allocation.x = COLUMN_LEFT_XPIXEL(sheet,sheet->active_cell.col);
6087  shentry_allocation.y = ROW_TOP_YPIXEL(sheet,sheet->active_cell.row);
6088  shentry_allocation.width = column_width;
6089  shentry_allocation.height = yyy_row_height(sheet, sheet->active_cell.row);
6090
6091  if(GTK_IS_ITEM_ENTRY(sheet->sheet_entry)){
6092
6093    shentry_allocation.height -= 2*CELLOFFSET;
6094    shentry_allocation.y += CELLOFFSET;
6095    if(gtk_sheet_clip_text(sheet))
6096      shentry_allocation.width = column_width - 2*CELLOFFSET;
6097    else
6098      shentry_allocation.width = size;
6099
6100    switch(GTK_ITEM_ENTRY(sheet_entry)->justification){
6101      case GTK_JUSTIFY_CENTER:
6102        shentry_allocation.x += (column_width)/2 - size/2;
6103        break;
6104      case GTK_JUSTIFY_RIGHT:
6105        shentry_allocation.x += column_width - size - CELLOFFSET;
6106        break;
6107      case GTK_JUSTIFY_LEFT:
6108      case GTK_JUSTIFY_FILL:
6109        shentry_allocation.x += CELLOFFSET;
6110        break;
6111     }
6112
6113  }
6114
6115  if(!GTK_IS_ITEM_ENTRY(sheet->sheet_entry)){
6116    shentry_allocation.x += 2;
6117    shentry_allocation.y += 2;
6118    shentry_allocation.width -= MIN(shentry_allocation.width, 3);
6119    shentry_allocation.height -= MIN(shentry_allocation.height, 3);
6120  }
6121
6122  gtk_widget_size_allocate(sheet->sheet_entry, &shentry_allocation);
6123
6124  if(previous_style == style) gtk_style_unref(previous_style);
6125 }
6126
6127 static void
6128 gtk_sheet_entry_set_max_size(GtkSheet *sheet)
6129 {
6130  gint i;
6131  gint size=0;
6132  gint sizel=0, sizer=0;
6133  gint row,col;
6134  GtkJustification justification;
6135
6136  row=sheet->active_cell.row;
6137  col=sheet->active_cell.col;
6138
6139  if(!GTK_IS_ITEM_ENTRY(sheet->sheet_entry) || gtk_sheet_clip_text(sheet)) return;
6140
6141  justification = GTK_ITEM_ENTRY(sheet->sheet_entry)->justification;
6142
6143  switch(justification){
6144   case GTK_JUSTIFY_FILL:
6145   case GTK_JUSTIFY_LEFT:
6146     for(i=col+1; i<=MAX_VISIBLE_COLUMN(sheet); i++){
6147      if(gtk_sheet_cell_get_text(sheet, row, i)) break;
6148      size+=xxx_column_width(sheet, i);
6149     }
6150     size = MIN(size, sheet->sheet_window_width - COLUMN_LEFT_XPIXEL(sheet, col));
6151     break;
6152   case GTK_JUSTIFY_RIGHT:
6153     for(i=col-1; i>=MIN_VISIBLE_COLUMN(sheet); i--){
6154      if(gtk_sheet_cell_get_text(sheet, row, i)) break;
6155      size+=xxx_column_width(sheet, i);
6156     }
6157     break;
6158   case GTK_JUSTIFY_CENTER:
6159     for(i=col+1; i<=MAX_VISIBLE_COLUMN(sheet); i++){
6160 /*     if(gtk_sheet_cell_get_text(sheet, row, i)) break;
6161 */
6162      sizer+=xxx_column_width(sheet, i);
6163     }
6164     for(i=col-1; i>=MIN_VISIBLE_COLUMN(sheet); i--){
6165      if(gtk_sheet_cell_get_text(sheet, row, i)) break;
6166      sizel+=xxx_column_width(sheet, i);
6167     }
6168     size=2*MIN(sizel, sizer);
6169     break;
6170  }
6171
6172  if(size!=0) size+=xxx_column_width(sheet, col);
6173  GTK_ITEM_ENTRY(sheet->sheet_entry)->text_max_size=size;
6174
6175 }
6176
6177 static void
6178 create_sheet_entry(GtkSheet *sheet)
6179 {
6180  GtkWidget *widget;
6181  GtkWidget *parent;
6182  GtkWidget *entry;
6183  gint found_entry = FALSE;
6184
6185  widget = GTK_WIDGET(sheet);
6186
6187  if(sheet->sheet_entry){
6188     /* avoids warnings */
6189     gtk_widget_ref(sheet->sheet_entry);
6190     gtk_widget_unparent(sheet->sheet_entry);
6191     gtk_widget_destroy(sheet->sheet_entry);
6192  }
6193
6194  if(sheet->entry_type){
6195
6196    if(!g_type_is_a (sheet->entry_type, GTK_TYPE_ENTRY)){
6197
6198      parent = GTK_WIDGET(gtk_type_new(sheet->entry_type));
6199
6200      sheet->sheet_entry = parent;
6201
6202      entry = gtk_sheet_get_entry (sheet);
6203      if(GTK_IS_ENTRY(entry)) found_entry = TRUE;
6204
6205    } else {
6206
6207      parent = GTK_WIDGET(gtk_type_new(sheet->entry_type));
6208      entry = parent;
6209      found_entry = TRUE;
6210
6211    }             
6212                                     
6213    if(!found_entry){
6214
6215      g_warning ("Entry type must be GtkEntry subclass, using default");
6216      entry = gtk_item_entry_new();
6217      sheet->sheet_entry = entry;
6218
6219    } else {
6220
6221      sheet->sheet_entry = parent;
6222
6223    }
6224
6225
6226  } else {
6227
6228      entry = gtk_item_entry_new();
6229      sheet->sheet_entry = entry;
6230
6231  }
6232  
6233  gtk_widget_size_request(sheet->sheet_entry, NULL);
6234  
6235  if(GTK_WIDGET_REALIZED(sheet))
6236    {
6237       gtk_widget_set_parent_window (sheet->sheet_entry, sheet->sheet_window);
6238       gtk_widget_set_parent(sheet->sheet_entry, GTK_WIDGET(sheet));
6239       gtk_widget_realize(sheet->sheet_entry);
6240    }
6241
6242  gtk_signal_connect_object(GTK_OBJECT(entry),"key_press_event",
6243                            (GtkSignalFunc) gtk_sheet_entry_key_press,
6244                            GTK_OBJECT(sheet)); 
6245
6246  gtk_widget_show (sheet->sheet_entry); 
6247 }
6248
6249
6250 /* Finds the last child widget that happens to be of type GtkEntry */
6251 static void
6252 find_entry(GtkWidget *w, gpointer user_data)
6253 {
6254   GtkWidget **entry = user_data;
6255   if ( GTK_IS_ENTRY(w))
6256     {
6257       *entry = w;
6258     }
6259 }
6260
6261 GtkWidget * 
6262 gtk_sheet_get_entry(GtkSheet *sheet)
6263 {
6264  GtkWidget *parent;
6265  GtkWidget *entry = NULL;
6266  GtkTableChild *table_child;
6267  GtkBoxChild *box_child;
6268  GList *children = NULL;
6269
6270  g_return_val_if_fail (sheet != NULL, NULL);
6271  g_return_val_if_fail (GTK_IS_SHEET (sheet), NULL);
6272  g_return_val_if_fail (sheet->sheet_entry != NULL, NULL);
6273
6274  if(GTK_IS_ENTRY(sheet->sheet_entry)) return (sheet->sheet_entry);
6275
6276  parent = GTK_WIDGET(sheet->sheet_entry);
6277
6278  if(GTK_IS_TABLE(parent)) children = GTK_TABLE(parent)->children;
6279  if(GTK_IS_BOX(parent)) children = GTK_BOX(parent)->children;
6280
6281  if(GTK_IS_CONTAINER(parent)) 
6282    {
6283      gtk_container_forall(GTK_CONTAINER(parent), find_entry, &entry);
6284      
6285      if(GTK_IS_ENTRY(entry))  
6286        return entry;
6287    }
6288
6289  if(!children) return NULL;
6290
6291  while(children){
6292       if(GTK_IS_TABLE(parent)) {
6293                  table_child = children->data;
6294                  entry = table_child->widget;
6295       }
6296       if(GTK_IS_BOX(parent)){
6297                  box_child = children->data; 
6298                  entry = box_child->widget;
6299       }
6300
6301       if(GTK_IS_ENTRY(entry))  
6302                                 break;
6303       children = children->next;                        
6304  } 
6305
6306
6307  if(!GTK_IS_ENTRY(entry))   return NULL;
6308
6309  return (entry);
6310
6311 }
6312
6313 GtkWidget * 
6314 gtk_sheet_get_entry_widget(GtkSheet *sheet)
6315 {
6316  g_return_val_if_fail (sheet != NULL, NULL);
6317  g_return_val_if_fail (GTK_IS_SHEET (sheet), NULL);
6318  g_return_val_if_fail (sheet->sheet_entry != NULL, NULL);
6319
6320  return (sheet->sheet_entry);
6321 }
6322
6323 #if 0
6324 /* BUTTONS */
6325 static void
6326 row_button_set (GtkSheet *sheet, gint row)
6327 {
6328   if(sheet->row[row].button.state == GTK_STATE_ACTIVE) return;
6329
6330   sheet->row[row].button.state = GTK_STATE_ACTIVE;
6331   gtk_sheet_button_draw(sheet, row, -1);
6332  
6333 }
6334
6335 static void
6336 row_button_release (GtkSheet *sheet, gint row)
6337 {
6338   if(sheet->row[row].button.state == GTK_STATE_NORMAL) return;
6339
6340   sheet->row[row].button.state = GTK_STATE_NORMAL;
6341   gtk_sheet_button_draw(sheet, row, -1);
6342 }
6343 #endif
6344
6345 static void
6346 gtk_sheet_button_draw (GtkSheet *sheet, gint row, gint column)
6347 {
6348   GdkWindow *window = NULL;
6349   GtkShadowType shadow_type;
6350   guint width = 0, height = 0;
6351   gint x = 0, y = 0;
6352   gint index = 0;
6353   gint text_width = 0, text_height = 0;
6354   const GtkSheetButton *button = NULL;
6355   GtkSheetChild *child = NULL;
6356   GdkRectangle allocation;
6357   gboolean is_sensitive = FALSE;
6358   gint state = 0;
6359   gint len = 0;
6360   gchar *line = 0;
6361
6362   PangoAlignment align = PANGO_ALIGN_LEFT; 
6363   gboolean rtl;
6364
6365   rtl = gtk_widget_get_direction(GTK_WIDGET(sheet)) == GTK_TEXT_DIR_RTL;
6366
6367   if(!GTK_WIDGET_REALIZED(GTK_WIDGET(sheet))) return;
6368
6369   if(row >= 0 && !yyy_row_is_visible(sheet, row)) return;
6370   if(column >= 0 && ! xxx_column_is_visible(sheet, column)) return;
6371   if(row >= 0 && !sheet->row_titles_visible) return;
6372   if(column >= 0 && !sheet->column_titles_visible) return;
6373   if(column>=0 && column < MIN_VISIBLE_COLUMN(sheet)) return;
6374   if(column>=0 && column > MAX_VISIBLE_COLUMN(sheet)) return;
6375   if(row>=0 && row < MIN_VISIBLE_ROW(sheet)) return;
6376   if(row>=0 && row > MAX_VISIBLE_ROW(sheet)) return;
6377   if( (row == -1) && (column == -1) ) return; 
6378
6379   if(row==-1){
6380      window=sheet->column_title_window;
6381      button= xxx_column_button(sheet, column);
6382      index=column;
6383      x = COLUMN_LEFT_XPIXEL(sheet, column)+CELL_SPACING;
6384      if(sheet->row_titles_visible) x -= sheet->row_title_area.width;
6385      y = 0;
6386      width = xxx_column_width(sheet, column);
6387      height = sheet->column_title_area.height;
6388      is_sensitive=xxx_column_is_sensitive(sheet, column);
6389   }
6390   if(column==-1){
6391      window=sheet->row_title_window;
6392      button = yyy_row_button(sheet, row);
6393      index=row;
6394      x = 0;
6395      y = ROW_TOP_YPIXEL(sheet, row)+CELL_SPACING;
6396      if(sheet->column_titles_visible) y-=sheet->column_title_area.height;
6397      width = sheet->row_title_area.width;
6398      height = yyy_row_height(sheet, row);
6399      is_sensitive=yyy_row_is_sensitive(sheet, row);
6400   }
6401
6402   allocation.x = x;
6403   allocation.y = y;
6404   allocation.width = width;
6405   allocation.height = height;
6406  
6407   gdk_window_clear_area (window,
6408                          x, y,
6409                          width, height);
6410
6411   gtk_paint_box (sheet->button->style, window,
6412                  GTK_STATE_NORMAL, GTK_SHADOW_OUT, 
6413                  &allocation, GTK_WIDGET(sheet->button),
6414                  "buttondefault", x, y, width, height);
6415
6416   state = button->state;
6417   if(!is_sensitive) state=GTK_STATE_INSENSITIVE;
6418
6419   if (state == GTK_STATE_ACTIVE)
6420      shadow_type = GTK_SHADOW_IN;
6421   else
6422      shadow_type = GTK_SHADOW_OUT;
6423
6424   if(state != GTK_STATE_NORMAL && state != GTK_STATE_INSENSITIVE)
6425   gtk_paint_box (sheet->button->style, window,
6426                  button->state, shadow_type, 
6427                  &allocation, GTK_WIDGET(sheet->button),
6428                  "button", x, y, width, height);
6429
6430   if(button->label_visible){
6431
6432     text_height=DEFAULT_ROW_HEIGHT(GTK_WIDGET(sheet))-2*CELLOFFSET;
6433
6434     gdk_gc_set_clip_rectangle(GTK_WIDGET(sheet)->style->fg_gc[button->state], 
6435                               &allocation);
6436     gdk_gc_set_clip_rectangle(GTK_WIDGET(sheet)->style->white_gc, &allocation);
6437
6438     y += 2*sheet->button->style->ythickness;
6439
6440
6441     if(button->label && strlen(button->label)>0){
6442            gchar *words = 0;
6443            PangoLayout *layout = NULL;
6444            gint real_x = x, real_y = y;
6445
6446            words=button->label;
6447            line = g_new(gchar, 1);
6448            line[0]='\0';
6449
6450            while(words && *words != '\0'){
6451              if(*words != '\n'){
6452                 len=strlen(line);
6453                 line=g_realloc(line, len+2);
6454                 line[len]=*words;
6455                 line[len+1]='\0';
6456              }
6457              if(*words == '\n' || *(words+1) == '\0'){
6458                text_width = STRING_WIDTH(GTK_WIDGET(sheet), GTK_WIDGET(sheet)->style->font_desc, line);
6459
6460                layout = gtk_widget_create_pango_layout (GTK_WIDGET(sheet), line);
6461                switch(button->justification){
6462                  case GTK_JUSTIFY_LEFT:
6463                    real_x = x + CELLOFFSET;
6464                    align = rtl ? PANGO_ALIGN_RIGHT : PANGO_ALIGN_LEFT;
6465                    break;
6466                  case GTK_JUSTIFY_RIGHT:
6467                    real_x = x + width - text_width - CELLOFFSET;
6468                    align = rtl ? PANGO_ALIGN_LEFT : PANGO_ALIGN_RIGHT;
6469                    break;
6470                  case GTK_JUSTIFY_CENTER:
6471                  default:
6472                    real_x = x + (width - text_width)/2;
6473                    align = rtl ? PANGO_ALIGN_RIGHT : PANGO_ALIGN_LEFT;
6474                    pango_layout_set_justify (layout, TRUE);
6475                }
6476                pango_layout_set_alignment (layout, align);
6477                gtk_paint_layout (GTK_WIDGET(sheet)->style,
6478                                  window,
6479                                  state,
6480                                  FALSE,
6481                                  &allocation,
6482                                  GTK_WIDGET(sheet),
6483                                  "label",
6484                                  real_x, real_y,
6485                                  layout);
6486                g_object_unref(G_OBJECT(layout));
6487
6488                real_y += text_height + 2;
6489
6490                g_free(line);
6491                line = g_new(gchar, 1);
6492                line[0]='\0';
6493              }
6494              words++;
6495            }
6496            g_free(line);
6497     }
6498     if(button->label && strlen(button->label) > 0){
6499       PangoLayout *layout = NULL;
6500       gint real_x = x, real_y = y;
6501
6502       text_width = STRING_WIDTH(GTK_WIDGET(sheet), GTK_WIDGET(sheet)->style->font_desc, button->label);
6503
6504       layout = gtk_widget_create_pango_layout (GTK_WIDGET(sheet), button->label);
6505       switch(button->justification){
6506       case GTK_JUSTIFY_LEFT:
6507         real_x = x + CELLOFFSET;
6508         align = rtl ? PANGO_ALIGN_RIGHT : PANGO_ALIGN_LEFT;
6509         break;
6510       case GTK_JUSTIFY_RIGHT:
6511         real_x = x + width - text_width - CELLOFFSET;
6512         align = rtl ? PANGO_ALIGN_LEFT : PANGO_ALIGN_RIGHT;
6513         break;
6514       case GTK_JUSTIFY_CENTER:
6515       default:
6516         real_x = x + (width - text_width)/2;
6517         align = rtl ? PANGO_ALIGN_RIGHT : PANGO_ALIGN_LEFT;
6518         pango_layout_set_justify (layout, TRUE);
6519       }
6520       pango_layout_set_alignment (layout, align);
6521       gtk_paint_layout (GTK_WIDGET(sheet)->style,
6522                         window,
6523                         state,
6524                         FALSE,
6525                         &allocation,
6526                         GTK_WIDGET(sheet),
6527                         "label",
6528                         real_x, real_y,
6529                         layout);
6530       g_object_unref(G_OBJECT(layout));
6531     }
6532
6533     gdk_gc_set_clip_rectangle(GTK_WIDGET(sheet)->style->fg_gc[button->state],
6534                             NULL);
6535     gdk_gc_set_clip_rectangle(GTK_WIDGET(sheet)->style->white_gc, NULL);
6536
6537   }
6538
6539   if((child = button->child) && (child->widget)){
6540       child->x = allocation.x;
6541       child->y = allocation.y;
6542
6543       child->x += (width - child->widget->requisition.width) / 2; 
6544       child->y += (height - child->widget->requisition.height) / 2;
6545       allocation.x = child->x;
6546       allocation.y = child->y;
6547       allocation.width = child->widget->requisition.width;
6548       allocation.height = child->widget->requisition.height;
6549
6550       x = child->x;
6551       y = child->y;
6552
6553       gtk_widget_set_state(child->widget, button->state);
6554
6555       if(GTK_WIDGET_REALIZED(GTK_WIDGET(sheet)) &&
6556          GTK_WIDGET_MAPPED(child->widget))
6557             {
6558               gtk_widget_size_allocate(child->widget, 
6559                                        &allocation);
6560               gtk_widget_queue_draw(child->widget);
6561             }
6562   }
6563    
6564 }
6565
6566
6567 /* SCROLLBARS
6568  *
6569  * functions:
6570  *   adjust_scrollbars
6571  *   vadjustment_changed
6572  *   hadjustment_changed
6573  *   vadjustment_value_changed
6574  *   hadjustment_value_changed */
6575
6576 static void
6577 adjust_scrollbars (GtkSheet * sheet)
6578 {
6579
6580  if(sheet->vadjustment){ 
6581   sheet->vadjustment->page_size = sheet->sheet_window_height;
6582   sheet->vadjustment->page_increment = sheet->sheet_window_height / 2;
6583   sheet->vadjustment->step_increment = DEFAULT_ROW_HEIGHT(GTK_WIDGET(sheet));
6584   sheet->vadjustment->lower = 0;
6585   sheet->vadjustment->upper = SHEET_HEIGHT (sheet) + 80;
6586 /*
6587   if (sheet->sheet_window_height - sheet->voffset > SHEET_HEIGHT (sheet))
6588     {
6589       sheet->vadjustment->value = MAX(0, SHEET_HEIGHT (sheet) - 
6590         sheet->sheet_window_height);
6591       gtk_signal_emit_by_name (GTK_OBJECT (sheet->vadjustment), 
6592                                "value_changed");
6593     }
6594 */
6595     gtk_signal_emit_by_name (GTK_OBJECT(sheet->vadjustment), "changed");
6596
6597  }
6598
6599  if(sheet->hadjustment){
6600   sheet->hadjustment->page_size = sheet->sheet_window_width;
6601   sheet->hadjustment->page_increment = sheet->sheet_window_width / 2;
6602   sheet->hadjustment->step_increment = DEFAULT_COLUMN_WIDTH;
6603   sheet->hadjustment->lower = 0;
6604   sheet->hadjustment->upper = SHEET_WIDTH (sheet)+ 80;
6605 /*
6606   if (sheet->sheet_window_width - sheet->hoffset > SHEET_WIDTH (sheet))
6607     {
6608       sheet->hadjustment->value = MAX(0, SHEET_WIDTH (sheet) - 
6609         sheet->sheet_window_width);
6610       gtk_signal_emit_by_name (GTK_OBJECT(sheet->hadjustment), 
6611                                "value_changed");
6612     }
6613 */
6614     gtk_signal_emit_by_name (GTK_OBJECT(sheet->hadjustment), "changed");
6615
6616  }
6617 /*
6618  if(GTK_WIDGET_REALIZED(sheet)) 
6619    {
6620      if(sheet->row_titles_visible){
6621                  size_allocate_row_title_buttons(sheet);
6622                  gdk_window_show(sheet->row_title_window);
6623      }
6624
6625      if(sheet->column_titles_visible){
6626                  size_allocate_column_title_buttons(sheet);
6627                  gdk_window_show(sheet->column_title_window);
6628      }
6629
6630      gtk_sheet_range_draw(sheet, NULL);
6631    }
6632 */
6633 }
6634
6635
6636 static void
6637 vadjustment_changed (GtkAdjustment * adjustment,
6638                                gpointer data)
6639 {
6640   GtkSheet *sheet;
6641
6642   g_return_if_fail (adjustment != NULL);
6643   g_return_if_fail (data != NULL);
6644
6645   sheet = GTK_SHEET (data);
6646
6647 }
6648
6649 static void
6650 hadjustment_changed (GtkAdjustment * adjustment,
6651                                gpointer data)
6652 {
6653   GtkSheet *sheet;
6654
6655   g_return_if_fail (adjustment != NULL);
6656   g_return_if_fail (data != NULL);
6657
6658   sheet = GTK_SHEET (data);
6659 }
6660
6661
6662 static void
6663 vadjustment_value_changed (GtkAdjustment * adjustment,
6664                                      gpointer data)
6665 {
6666   GtkSheet *sheet;
6667   gint diff, value, old_value;
6668   gint i;
6669   gint row, new_row;
6670   gint y=0;
6671
6672   g_return_if_fail (adjustment != NULL);
6673   g_return_if_fail (data != NULL);
6674   g_return_if_fail (GTK_IS_SHEET (data));
6675
6676   sheet = GTK_SHEET (data);
6677
6678   if(GTK_SHEET_IS_FROZEN(sheet)) return;
6679
6680   row=ROW_FROM_YPIXEL(sheet,sheet->column_title_area.height + CELL_SPACING);
6681   if(!sheet->column_titles_visible)
6682      row=ROW_FROM_YPIXEL(sheet,CELL_SPACING);
6683     
6684   old_value = -sheet->voffset;
6685
6686   new_row = g_sheet_row_pixel_to_row(sheet->row_geometry,
6687                                      adjustment->value,sheet);
6688
6689   y = g_sheet_row_start_pixel(sheet->row_geometry, new_row, sheet);
6690
6691   if (adjustment->value > sheet->old_vadjustment && sheet->old_vadjustment > 0. &&
6692       yyy_row_height(sheet, i) > sheet->vadjustment->step_increment){
6693 /* This avoids embarrassing twitching */
6694           if(row == new_row && row != yyy_row_count(sheet) - 1 &&
6695              adjustment->value - sheet->old_vadjustment >= 
6696                           sheet->vadjustment->step_increment &&
6697              new_row + 1 != MIN_VISIBLE_ROW(sheet)){
6698                 new_row+=1;
6699                 y=y+yyy_row_height(sheet, row);
6700           }
6701   }
6702
6703 /* Negative old_adjustment enforces the redraw, otherwise avoid spureous redraw */
6704   if(sheet->old_vadjustment >= 0. && row == new_row){
6705       sheet->old_vadjustment = sheet->vadjustment->value;
6706       return;
6707   }
6708
6709   sheet->old_vadjustment = sheet->vadjustment->value;
6710   adjustment->value=y;
6711
6712  
6713   if(new_row == 0){
6714    sheet->vadjustment->step_increment=  yyy_row_height(sheet, 0);
6715   }else{
6716    sheet->vadjustment->step_increment=
6717    MIN(yyy_row_height(sheet, new_row), yyy_row_height(sheet, new_row-1));
6718   }
6719
6720   sheet->vadjustment->value=adjustment->value;
6721
6722   value = adjustment->value;
6723
6724   if (value >= -sheet->voffset)
6725         {
6726           /* scroll down */
6727           diff = value + sheet->voffset;
6728         }
6729   else
6730         {
6731           /* scroll up */
6732           diff = -sheet->voffset - value;
6733         }
6734
6735       sheet->voffset = -value;
6736  
6737   sheet->view.row0=ROW_FROM_YPIXEL(sheet, sheet->column_title_area.height+1);
6738   sheet->view.rowi=ROW_FROM_YPIXEL(sheet, sheet->sheet_window_height-1);
6739   if(!sheet->column_titles_visible)
6740      sheet->view.row0=ROW_FROM_YPIXEL(sheet, 1);
6741
6742   if(GTK_WIDGET_REALIZED(sheet->sheet_entry) &&
6743      sheet->state == GTK_SHEET_NORMAL && 
6744      sheet->active_cell.row >= 0 && sheet->active_cell.col >= 0 &&
6745      !gtk_sheet_cell_isvisible(sheet, sheet->active_cell.row,
6746                                       sheet->active_cell.col))
6747     {
6748       const gchar *text;
6749
6750       text = gtk_entry_get_text(GTK_ENTRY(gtk_sheet_get_entry(sheet)));
6751
6752       if(!text || strlen(text)==0) 
6753              gtk_sheet_cell_clear(sheet,
6754                                   sheet->active_cell.row,
6755                                   sheet->active_cell.col);
6756        gtk_widget_unmap(sheet->sheet_entry);
6757     }
6758
6759   gtk_sheet_position_children(sheet);
6760
6761   gtk_sheet_range_draw(sheet, NULL);
6762   size_allocate_row_title_buttons(sheet);
6763   size_allocate_global_button(sheet);
6764 }
6765
6766 static void
6767 hadjustment_value_changed (GtkAdjustment * adjustment,
6768                            gpointer data)
6769 {
6770   GtkSheet *sheet;
6771   gint i, diff, value, old_value;
6772   gint column, new_column;
6773   gint x=0;
6774
6775   g_return_if_fail (adjustment != NULL);
6776   g_return_if_fail (data != NULL);
6777   g_return_if_fail (GTK_IS_SHEET (data));
6778
6779   sheet = GTK_SHEET (data);
6780
6781   if(GTK_SHEET_IS_FROZEN(sheet)) return;
6782
6783   column=COLUMN_FROM_XPIXEL(sheet,sheet->row_title_area.width + CELL_SPACING);
6784   if(!sheet->row_titles_visible)
6785      column=COLUMN_FROM_XPIXEL(sheet, CELL_SPACING);
6786
6787   old_value = -sheet->hoffset;
6788
6789   for(i=0; i < xxx_column_count(sheet); i++)
6790     {
6791       if(xxx_column_is_visible(sheet, i)) x += xxx_column_width(sheet, i);
6792       if(x > adjustment->value) break;
6793     }
6794   x-=xxx_column_width(sheet, i);
6795   new_column=i;
6796
6797   if (adjustment->value > sheet->old_hadjustment && sheet->old_hadjustment > 0 &&
6798       xxx_column_width(sheet, i) > sheet->hadjustment->step_increment){
6799 /* This avoids embarrassing twitching */
6800           if(column == new_column && column != xxx_column_count(sheet) - 1 &&
6801              adjustment->value - sheet->old_hadjustment >= 
6802                           sheet->hadjustment->step_increment &&
6803              new_column + 1 != MIN_VISIBLE_COLUMN(sheet)){
6804              new_column+=1;
6805              x=x+xxx_column_width(sheet, column);
6806           }
6807   }
6808
6809 /* Negative old_adjustment enforces the redraw, otherwise avoid spureous redraw */
6810   if(sheet->old_hadjustment >= 0. && new_column == column){
6811      sheet->old_hadjustment = sheet->hadjustment->value;
6812      return;
6813   }
6814
6815   sheet->old_hadjustment = sheet->hadjustment->value;
6816   adjustment->value=x;
6817
6818   if(new_column == 0){
6819    sheet->hadjustment->step_increment=
6820    xxx_column_width(sheet, 0);
6821   }else{
6822    sheet->hadjustment->step_increment=
6823    MIN(xxx_column_width(sheet, new_column), xxx_column_width(sheet, new_column-1));
6824   }
6825
6826
6827   sheet->hadjustment->value=adjustment->value;
6828
6829   value = adjustment->value;
6830
6831   if (value >= -sheet->hoffset)
6832         {
6833           /* scroll right */
6834           diff = value + sheet->hoffset;
6835         }
6836   else
6837         {
6838           /* scroll left */
6839           diff = -sheet->hoffset - value;
6840         }
6841
6842   sheet->hoffset = -value;
6843
6844   sheet->view.col0=COLUMN_FROM_XPIXEL(sheet, sheet->row_title_area.width+1);
6845   sheet->view.coli=COLUMN_FROM_XPIXEL(sheet, sheet->sheet_window_width);
6846   if(!sheet->row_titles_visible)
6847     sheet->view.col0=COLUMN_FROM_XPIXEL(sheet, 1);
6848
6849   if(GTK_WIDGET_REALIZED(sheet->sheet_entry) &&
6850      sheet->state == GTK_SHEET_NORMAL && 
6851      sheet->active_cell.row >= 0 && sheet->active_cell.col >= 0 &&
6852      !gtk_sheet_cell_isvisible(sheet, sheet->active_cell.row,
6853                                       sheet->active_cell.col))
6854     {
6855       const gchar *text;
6856
6857       text = gtk_entry_get_text(GTK_ENTRY(gtk_sheet_get_entry(sheet)));
6858       if(!text || strlen(text)==0) 
6859              gtk_sheet_cell_clear(sheet,
6860                                   sheet->active_cell.row,
6861                                   sheet->active_cell.col);
6862
6863       gtk_widget_unmap(sheet->sheet_entry);
6864     }
6865
6866   gtk_sheet_position_children(sheet);
6867
6868   gtk_sheet_range_draw(sheet, NULL);
6869   size_allocate_column_title_buttons(sheet);
6870 }
6871         
6872
6873 /* COLUMN RESIZING */
6874 static void                          
6875 draw_xor_vline (GtkSheet * sheet)
6876 {
6877   GtkWidget *widget;
6878   
6879   g_return_if_fail (sheet != NULL);
6880   
6881   widget = GTK_WIDGET (sheet);
6882
6883   gdk_draw_line (widget->window, sheet->xor_gc,  
6884                  sheet->x_drag,                                       
6885                  sheet->column_title_area.height,                               
6886                  sheet->x_drag,                                             
6887                  sheet->sheet_window_height + 1);
6888 }
6889
6890 /* ROW RESIZING */
6891 static void                          
6892 draw_xor_hline (GtkSheet * sheet)
6893 {
6894   GtkWidget *widget;
6895   
6896   g_return_if_fail (sheet != NULL);
6897   
6898   widget = GTK_WIDGET (sheet);
6899
6900   gdk_draw_line (widget->window, sheet->xor_gc,  
6901                  sheet->row_title_area.width,
6902                  sheet->y_drag,                                       
6903                         
6904                  sheet->sheet_window_width + 1,                      
6905                  sheet->y_drag);                                             
6906 }
6907
6908 /* SELECTED RANGE */
6909 static void
6910 draw_xor_rectangle(GtkSheet *sheet, GtkSheetRange range)
6911 {
6912    gint i;
6913    GdkRectangle clip_area, area;
6914    GdkGCValues values;
6915
6916    area.x=COLUMN_LEFT_XPIXEL(sheet, range.col0);
6917    area.y=ROW_TOP_YPIXEL(sheet, range.row0);
6918    area.width=COLUMN_LEFT_XPIXEL(sheet, range.coli)-area.x+
6919                                         xxx_column_width(sheet, range.coli);
6920    area.height=ROW_TOP_YPIXEL(sheet, range.rowi)-area.y+
6921                                         yyy_row_height(sheet, range.rowi);
6922
6923    clip_area.x=sheet->row_title_area.width;
6924    clip_area.y=sheet->column_title_area.height;
6925    clip_area.width=sheet->sheet_window_width;
6926    clip_area.height=sheet->sheet_window_height;
6927
6928    if(!sheet->row_titles_visible) clip_area.x = 0;
6929    if(!sheet->column_titles_visible) clip_area.y = 0;
6930
6931    if(area.x<0) {
6932       area.width=area.width+area.x;
6933       area.x=0;
6934    }
6935    if(area.width>clip_area.width) area.width=clip_area.width+10;
6936    if(area.y<0) {
6937       area.height=area.height+area.y;
6938       area.y=0;
6939    }
6940    if(area.height>clip_area.height) area.height=clip_area.height+10;
6941
6942    clip_area.x--;
6943    clip_area.y--;
6944    clip_area.width+=3;
6945    clip_area.height+=3;
6946
6947    gdk_gc_get_values(sheet->xor_gc, &values);
6948
6949    gdk_gc_set_clip_rectangle(sheet->xor_gc, &clip_area);
6950
6951    for(i=-1;i<=1;++i)
6952      gdk_draw_rectangle(sheet->sheet_window,
6953                         sheet->xor_gc,
6954                         FALSE,
6955                         area.x+i, area.y+i,
6956                         area.width-2*i, area.height-2*i);
6957
6958
6959    gdk_gc_set_clip_rectangle(sheet->xor_gc, NULL);
6960
6961    gdk_gc_set_foreground(sheet->xor_gc, &values.foreground);
6962
6963 }                      
6964
6965   
6966 /* this function returns the new width of the column being resized given
6967  * the column and x position of the cursor; the x cursor position is passed
6968  * in as a pointer and automaticaly corrected if it's beyond min/max limits */
6969 static guint
6970 new_column_width (GtkSheet * sheet,
6971                   gint column,
6972                   gint * x)
6973 {
6974   gint cx, width;
6975   guint min_width;
6976
6977   cx = *x;
6978
6979   min_width = sheet->column_requisition;
6980
6981   /* you can't shrink a column to less than its minimum width */
6982   if (cx < COLUMN_LEFT_XPIXEL (sheet, column) + min_width)
6983     {
6984       *x = cx = COLUMN_LEFT_XPIXEL (sheet, column) + min_width;
6985     }
6986
6987   /* don't grow past the end of the window */
6988   /*
6989   if (cx > sheet->sheet_window_width)
6990     {
6991       *x = cx = sheet->sheet_window_width;
6992     }
6993     */
6994   /* calculate new column width making sure it doesn't end up
6995    * less than the minimum width */
6996   width = cx - COLUMN_LEFT_XPIXEL (sheet, column);
6997   if (width < min_width)
6998     width = min_width;
6999
7000   xxx_set_column_width(sheet, column, width);
7001   sheet->view.coli=COLUMN_FROM_XPIXEL(sheet, sheet->sheet_window_width);
7002   size_allocate_column_title_buttons (sheet);
7003   
7004   return width;
7005 }
7006
7007 /* this function returns the new height of the row being resized given
7008  * the row and y position of the cursor; the y cursor position is passed
7009  * in as a pointer and automaticaly corrected if it's beyond min/max limits */
7010 static guint
7011 new_row_height (GtkSheet * sheet,
7012                 gint row,
7013                 gint * y)
7014 {
7015   gint cy, height;
7016   guint min_height;
7017
7018   cy = *y;
7019   min_height = sheet->row_requisition;
7020
7021   /* you can't shrink a row to less than its minimum height */
7022   if (cy < ROW_TOP_YPIXEL (sheet, row) + min_height)
7023
7024     {
7025       *y = cy = ROW_TOP_YPIXEL (sheet, row) + min_height;
7026     }
7027
7028   /* don't grow past the end of the window */
7029   /*
7030   if (cy > sheet->sheet_window_height)
7031     {
7032       *y = cy = sheet->sheet_window_height;
7033     }
7034     */
7035   /* calculate new row height making sure it doesn't end up
7036    * less than the minimum height */
7037   height = (cy - ROW_TOP_YPIXEL (sheet, row));
7038   if (height < min_height)
7039     height = min_height;
7040
7041   yyy_set_row_height(sheet, row, height);
7042   sheet->view.rowi=ROW_FROM_YPIXEL(sheet, sheet->sheet_window_height-1);
7043   size_allocate_row_title_buttons (sheet);
7044
7045   return height;
7046 }
7047
7048 static void
7049 gtk_sheet_set_column_width (GtkSheet * sheet,
7050                             gint column,
7051                             guint width)
7052 {
7053   guint min_width;
7054
7055   g_return_if_fail (sheet != NULL);
7056   g_return_if_fail (GTK_IS_SHEET (sheet));
7057
7058   if (column < 0 || column >= xxx_column_count(sheet))
7059     return;
7060
7061   gtk_sheet_column_size_request(sheet, column, &min_width);
7062   if(width < min_width) return;
7063
7064   xxx_set_column_width(sheet, column, width);
7065
7066   if(GTK_WIDGET_REALIZED(GTK_WIDGET(sheet)) && !GTK_SHEET_IS_FROZEN(sheet)){
7067     size_allocate_column_title_buttons (sheet);
7068     adjust_scrollbars (sheet);
7069     gtk_sheet_size_allocate_entry(sheet);
7070     gtk_sheet_range_draw (sheet, NULL);
7071   } else
7072
7073   gtk_signal_emit(GTK_OBJECT(sheet), sheet_signals[CHANGED], -1, column);
7074   gtk_signal_emit(GTK_OBJECT(sheet), sheet_signals[NEW_COL_WIDTH], column, width);
7075
7076 }
7077
7078
7079
7080 void
7081 gtk_sheet_set_row_height (GtkSheet * sheet,
7082                             gint row,
7083                             guint height)
7084 {
7085   guint min_height;
7086
7087   g_return_if_fail (sheet != NULL);
7088   g_return_if_fail (GTK_IS_SHEET (sheet));
7089
7090   if (row < 0 || row >= yyy_row_count(sheet))
7091     return;
7092
7093   gtk_sheet_row_size_request(sheet, row, &min_height);
7094   if(height < min_height) return;
7095
7096   yyy_set_row_height(sheet, row, height);
7097
7098   if(GTK_WIDGET_REALIZED(GTK_WIDGET(sheet)) && !GTK_SHEET_IS_FROZEN(sheet)){
7099     size_allocate_row_title_buttons (sheet);
7100     adjust_scrollbars (sheet);
7101     gtk_sheet_size_allocate_entry(sheet);
7102     gtk_sheet_range_draw (sheet, NULL);
7103   }
7104
7105   gtk_signal_emit(GTK_OBJECT(sheet), sheet_signals[CHANGED], row, -1);
7106   gtk_signal_emit(GTK_OBJECT(sheet), sheet_signals[NEW_ROW_HEIGHT], row, height);
7107
7108 }
7109
7110
7111 gboolean
7112 gtk_sheet_get_attributes(GtkSheet *sheet, gint row, gint col, GtkSheetCellAttr *attributes)
7113 {
7114  g_return_val_if_fail (sheet != NULL, FALSE);
7115  g_return_val_if_fail (GTK_IS_SHEET (sheet), FALSE);
7116
7117  if(row < 0 || col < 0) return FALSE;
7118
7119  init_attributes(sheet, col, attributes);
7120
7121  if ( !sheet->model) 
7122          return FALSE;
7123
7124  attributes->is_editable = g_sheet_model_is_editable(sheet->model, row, col);
7125  attributes->is_visible = g_sheet_model_is_visible(sheet->model, row, col);
7126
7127  const GdkColor *fg = g_sheet_model_get_foreground(sheet->model, row, col);
7128  if ( fg ) 
7129    attributes->foreground =  *fg;
7130
7131  const GdkColor *bg = g_sheet_model_get_background(sheet->model, row, col);
7132  if ( bg ) 
7133    attributes->background =  *bg;
7134
7135  const GtkJustification *j = g_sheet_model_get_justification(sheet->model,
7136                                                                row, col);
7137  if (j)   attributes->justification = *j;
7138
7139  const PangoFontDescription *font_desc = 
7140    g_sheet_model_get_font_desc(sheet->model, row, col);
7141  if ( font_desc )  attributes->font_desc = font_desc;
7142
7143  const GtkSheetCellBorder *border = 
7144   g_sheet_model_get_cell_border(sheet->model, row, col);
7145
7146  if ( border )    attributes->border = *border;
7147
7148  return TRUE;
7149 }
7150
7151 static void
7152 init_attributes(GtkSheet *sheet, gint col, GtkSheetCellAttr *attributes)
7153 {
7154  /* DEFAULT VALUES */    
7155  attributes->foreground = GTK_WIDGET(sheet)->style->black;
7156  attributes->background = sheet->bg_color;
7157  if(!GTK_WIDGET_REALIZED(GTK_WIDGET(sheet))){
7158    GdkColormap *colormap;
7159    colormap=gdk_colormap_get_system();
7160    gdk_color_black(colormap, &attributes->foreground);
7161    attributes->background = sheet->bg_color;
7162  }
7163  attributes->justification = xxx_column_justification(sheet, col);
7164  attributes->border.width = 0;
7165  attributes->border.line_style = GDK_LINE_SOLID;
7166  attributes->border.cap_style = GDK_CAP_NOT_LAST;
7167  attributes->border.join_style = GDK_JOIN_MITER;
7168  attributes->border.mask = 0;
7169  attributes->border.color = GTK_WIDGET(sheet)->style->black;
7170  attributes->is_editable = TRUE;
7171  attributes->is_visible = TRUE;
7172  attributes->font_desc = GTK_WIDGET(sheet)->style->font_desc;
7173
7174 }       
7175  
7176
7177
7178 /********************************************************************
7179  * Container Functions:
7180  * gtk_sheet_add
7181  * gtk_sheet_put
7182  * gtk_sheet_attach
7183  * gtk_sheet_remove
7184  * gtk_sheet_move_child
7185  * gtk_sheet_position_child
7186  * gtk_sheet_position_children 
7187  * gtk_sheet_realize_child
7188  * gtk_sheet_get_child_at
7189  ********************************************************************/ 
7190
7191 GtkSheetChild *
7192 gtk_sheet_put(GtkSheet *sheet, GtkWidget *child, gint x, gint y)
7193 {
7194   GtkRequisition child_requisition;
7195   GtkSheetChild *child_info;
7196
7197   g_return_val_if_fail(sheet != NULL, NULL);
7198   g_return_val_if_fail(GTK_IS_SHEET(sheet), NULL);
7199   g_return_val_if_fail(child != NULL, NULL);
7200   g_return_val_if_fail(child->parent == NULL, NULL);
7201
7202   child_info = g_new (GtkSheetChild, 1);
7203   child_info->widget = child;
7204   child_info->x = x;  
7205   child_info->y = y;
7206   child_info->attached_to_cell = FALSE;
7207   child_info->floating = TRUE;
7208   child_info->xpadding = child_info->ypadding = 0;
7209   child_info->xexpand = child_info->yexpand = FALSE;
7210   child_info->xshrink = child_info->yshrink = FALSE;
7211   child_info->xfill = child_info->yfill = FALSE;
7212
7213   sheet->children = g_list_append(sheet->children, child_info);
7214
7215   gtk_widget_set_parent (child, GTK_WIDGET(sheet));
7216
7217   gtk_widget_size_request(child, &child_requisition);
7218
7219   if (GTK_WIDGET_VISIBLE(GTK_WIDGET(sheet)))
7220     {
7221        if(GTK_WIDGET_REALIZED(GTK_WIDGET(sheet)) && 
7222           (!GTK_WIDGET_REALIZED(child) || GTK_WIDGET_NO_WINDOW(child)))
7223         gtk_sheet_realize_child(sheet, child_info);
7224
7225        if(GTK_WIDGET_MAPPED(GTK_WIDGET(sheet)) && 
7226           !GTK_WIDGET_MAPPED(child))
7227         gtk_widget_map(child);
7228     }
7229
7230   gtk_sheet_position_child(sheet, child_info);
7231
7232 /* This will avoid drawing on the titles */
7233
7234   if(GTK_WIDGET_REALIZED(GTK_WIDGET(sheet)))
7235    {
7236       if(sheet->row_titles_visible)
7237              gdk_window_show(sheet->row_title_window);
7238       if(sheet->column_titles_visible)
7239              gdk_window_show(sheet->column_title_window);
7240    }
7241
7242   return (child_info);
7243 }
7244
7245 void
7246 gtk_sheet_attach_floating       (GtkSheet *sheet,
7247                                  GtkWidget *widget,
7248                                  gint row, gint col)
7249 {
7250   GdkRectangle area;
7251   GtkSheetChild *child;
7252
7253   if(row < 0 || col < 0){
7254     gtk_sheet_button_attach(sheet, widget, row, col);
7255     return;
7256   }
7257
7258   gtk_sheet_get_cell_area(sheet, row, col, &area);
7259   child = gtk_sheet_put(sheet, widget, area.x, area.y);
7260   child->attached_to_cell = TRUE;
7261   child->row = row;
7262   child->col = col;
7263 }
7264
7265 void
7266 gtk_sheet_attach_default        (GtkSheet *sheet,
7267                                  GtkWidget *widget,
7268                                  gint row, gint col)
7269 {
7270   if(row < 0 || col < 0){
7271     gtk_sheet_button_attach(sheet, widget, row, col);
7272     return;
7273   }
7274
7275   gtk_sheet_attach(sheet, widget, row, col, GTK_EXPAND|GTK_FILL, GTK_EXPAND|GTK_FILL, 0, 0);
7276 }
7277
7278 void
7279 gtk_sheet_attach        (GtkSheet *sheet,
7280                          GtkWidget *widget,
7281                          gint row, gint col,
7282                          gint xoptions,
7283                          gint yoptions,
7284                          gint xpadding,
7285                          gint ypadding)
7286 {
7287   GdkRectangle area;
7288   GtkSheetChild *child = NULL;
7289
7290   if(row < 0 || col < 0){
7291     gtk_sheet_button_attach(sheet, widget, row, col);
7292     return;
7293   }
7294
7295   child = g_new0(GtkSheetChild, 1);
7296   child->attached_to_cell = TRUE;
7297   child->floating = FALSE;
7298   child->widget = widget;
7299   child->row = row;
7300   child->col = col;
7301   child->xpadding = xpadding;
7302   child->ypadding = ypadding;
7303   child->xexpand = (xoptions & GTK_EXPAND) != 0;
7304   child->yexpand = (yoptions & GTK_EXPAND) != 0;
7305   child->xshrink = (xoptions & GTK_SHRINK) != 0;
7306   child->yshrink = (yoptions & GTK_SHRINK) != 0;
7307   child->xfill = (xoptions & GTK_FILL) != 0;
7308   child->yfill = (yoptions & GTK_FILL) != 0;
7309
7310   sheet->children = g_list_append(sheet->children, child);
7311
7312   gtk_sheet_get_cell_area(sheet, row, col, &area);
7313
7314   child->x = area.x + child->xpadding;
7315   child->y = area.y + child->ypadding;
7316
7317   if (GTK_WIDGET_VISIBLE(GTK_WIDGET(sheet)))
7318     {
7319        if(GTK_WIDGET_REALIZED(GTK_WIDGET(sheet)) &&
7320           (!GTK_WIDGET_REALIZED(widget) || GTK_WIDGET_NO_WINDOW(widget)))
7321         gtk_sheet_realize_child(sheet, child);
7322
7323        if(GTK_WIDGET_MAPPED(GTK_WIDGET(sheet)) &&
7324           !GTK_WIDGET_MAPPED(widget))
7325         gtk_widget_map(widget);
7326     }
7327
7328   gtk_sheet_position_child(sheet, child);
7329
7330 /* This will avoid drawing on the titles */
7331
7332   if(GTK_WIDGET_REALIZED(GTK_WIDGET(sheet)))
7333    {
7334       if(GTK_SHEET_ROW_TITLES_VISIBLE(sheet))
7335              gdk_window_show(sheet->row_title_window);
7336       if(GTK_SHEET_COL_TITLES_VISIBLE(sheet))
7337              gdk_window_show(sheet->column_title_window);
7338    }
7339
7340 }
7341
7342 void
7343 gtk_sheet_button_attach         (GtkSheet *sheet, 
7344                                  GtkWidget *widget, 
7345                                  gint row, gint col)
7346 {
7347   GtkSheetButton *button;
7348   GtkSheetChild *child;
7349   GtkRequisition button_requisition;
7350
7351   if(row >= 0 && col >= 0) return;
7352   if(row < 0 && col < 0) return;
7353
7354   child = g_new (GtkSheetChild, 1);
7355   child->widget = widget;
7356   child->x = 0;  
7357   child->y = 0;  
7358   child->attached_to_cell = TRUE;
7359   child->floating = FALSE;
7360   child->row = row;
7361   child->col = col;
7362   child->xpadding = child->ypadding = 0;
7363   child->xshrink = child->yshrink = FALSE;
7364   child->xfill = child->yfill = FALSE;
7365
7366
7367   sheet->children = g_list_append(sheet->children, child);
7368
7369   gtk_sheet_button_size_request(sheet, button, &button_requisition);
7370
7371
7372   if (GTK_WIDGET_VISIBLE(GTK_WIDGET(sheet)))
7373     {
7374        if(GTK_WIDGET_REALIZED(GTK_WIDGET(sheet)) && 
7375           (!GTK_WIDGET_REALIZED(widget) || GTK_WIDGET_NO_WINDOW(widget)))
7376         gtk_sheet_realize_child(sheet, child);
7377
7378        if(GTK_WIDGET_MAPPED(GTK_WIDGET(sheet)) && 
7379           !GTK_WIDGET_MAPPED(widget))
7380         gtk_widget_map(widget);
7381     }
7382
7383   if(row == -1) size_allocate_column_title_buttons(sheet);
7384   if(col == -1) size_allocate_row_title_buttons(sheet);
7385
7386 }
7387
7388 static void
7389 label_size_request(GtkSheet *sheet, gchar *label, GtkRequisition *req)
7390 {
7391   gchar *words;
7392   gchar word[1000];
7393   gint n = 0;
7394   gint row_height = DEFAULT_ROW_HEIGHT(GTK_WIDGET(sheet)) - 2*CELLOFFSET + 2;
7395
7396   req->height = 0;
7397   req->width = 0;
7398   words=label;
7399
7400   while(words && *words != '\0'){
7401     if(*words == '\n' || *(words+1) == '\0'){
7402       req->height += row_height;
7403
7404       word[n] = '\0';
7405       req->width = MAX(req->width, STRING_WIDTH(GTK_WIDGET(sheet), GTK_WIDGET(sheet)->style->font_desc, word));
7406       n = 0;
7407     } else {
7408       word[n++] = *words;
7409     }
7410     words++;
7411   }
7412  
7413   if(n > 0) req->height -= 2;
7414 }
7415
7416 static void
7417 gtk_sheet_button_size_request   (GtkSheet *sheet,
7418                                  const GtkSheetButton *button, 
7419                                  GtkRequisition *button_requisition)
7420 {
7421   GtkRequisition requisition;
7422   GtkRequisition label_requisition;
7423
7424   if(gtk_sheet_autoresize(sheet) && button->label && strlen(button->label) > 0){
7425      label_size_request(sheet, button->label, &label_requisition);
7426      label_requisition.width += 2*CELLOFFSET;
7427      label_requisition.height += 2*CELLOFFSET;
7428   } else {
7429      label_requisition.height = DEFAULT_ROW_HEIGHT(GTK_WIDGET(sheet));
7430      label_requisition.width = COLUMN_MIN_WIDTH;
7431   } 
7432
7433   if(button->child)
7434   {
7435      gtk_widget_size_request(button->child->widget, &requisition);
7436      requisition.width += 2*button->child->xpadding;
7437      requisition.height += 2*button->child->ypadding;
7438      requisition.width += 2*sheet->button->style->xthickness;
7439      requisition.height += 2*sheet->button->style->ythickness;
7440   }
7441   else
7442   {
7443      requisition.height = DEFAULT_ROW_HEIGHT(GTK_WIDGET(sheet));
7444      requisition.width = COLUMN_MIN_WIDTH;
7445   }
7446
7447   *button_requisition = requisition;
7448   button_requisition->width = MAX(requisition.width, label_requisition.width);
7449   button_requisition->height = MAX(requisition.height, label_requisition.height);
7450  
7451 }
7452
7453 static void
7454 gtk_sheet_row_size_request      (GtkSheet *sheet,
7455                                  gint row,
7456                                  guint *requisition)
7457 {
7458   GtkRequisition button_requisition;
7459   GList *children;
7460
7461   gtk_sheet_button_size_request(sheet, 
7462                                 yyy_row_button(sheet, row),
7463                                 &button_requisition);
7464
7465   *requisition = button_requisition.height;
7466
7467   children = sheet->children;
7468   while(children){
7469     GtkSheetChild *child = (GtkSheetChild *)children->data;
7470     GtkRequisition child_requisition;
7471
7472     if(child->attached_to_cell && child->row == row && child->col != -1 && !child->floating && !child->yshrink){
7473       gtk_widget_get_child_requisition(child->widget, &child_requisition);
7474
7475       if(child_requisition.height + 2 * child->ypadding > *requisition)
7476         *requisition = child_requisition.height + 2 * child->ypadding;
7477     }
7478     children = children->next;
7479   }
7480
7481   sheet->row_requisition = * requisition;
7482 }
7483
7484 static void
7485 gtk_sheet_column_size_request   (GtkSheet *sheet,
7486                                  gint col,
7487                                  guint *requisition)
7488 {
7489   GtkRequisition button_requisition;
7490   GList *children;
7491
7492   gtk_sheet_button_size_request(sheet, 
7493                                 xxx_column_button(sheet, col),
7494                                 &button_requisition);
7495
7496   *requisition = button_requisition.width;
7497
7498   children = sheet->children;
7499   while(children){
7500     GtkSheetChild *child = (GtkSheetChild *)children->data;
7501     GtkRequisition child_requisition;
7502
7503     if(child->attached_to_cell && child->col == col && child->row != -1 && !child->floating && !child->xshrink){
7504       gtk_widget_get_child_requisition(child->widget, &child_requisition);
7505
7506       if(child_requisition.width + 2 * child->xpadding > *requisition)
7507         *requisition = child_requisition.width + 2 * child->xpadding;
7508     }
7509     children = children->next;
7510   }
7511
7512   sheet->column_requisition = *requisition;
7513 }
7514
7515 void
7516 gtk_sheet_move_child(GtkSheet *sheet, GtkWidget *widget, gint x, gint y)
7517 {
7518   GtkSheetChild *child;
7519   GList *children;
7520
7521   g_return_if_fail(sheet != NULL);
7522   g_return_if_fail(GTK_IS_SHEET(sheet));
7523
7524   children = sheet->children;
7525   while(children)
7526     {
7527        child = children->data;
7528
7529        if(child->widget == widget){
7530          child->x = x;
7531          child->y = y;
7532          child->row = ROW_FROM_YPIXEL(sheet, y);
7533          child->col = COLUMN_FROM_XPIXEL(sheet, x);
7534          gtk_sheet_position_child(sheet, child);
7535          return;
7536        }
7537
7538        children = children->next;
7539     }
7540
7541   g_warning("Widget must be a GtkSheet child"); 
7542
7543 }
7544
7545 static void
7546 gtk_sheet_position_child(GtkSheet *sheet, GtkSheetChild *child)
7547 {
7548    GtkRequisition child_requisition;
7549    GtkAllocation child_allocation;
7550    gint xoffset = 0; 
7551    gint yoffset = 0;
7552    gint x = 0, y = 0;
7553    GdkRectangle area;
7554
7555    gtk_widget_get_child_requisition(child->widget, &child_requisition);
7556
7557    if(sheet->column_titles_visible) 
7558              yoffset = sheet->column_title_area.height;
7559
7560    if(sheet->row_titles_visible)
7561              xoffset = sheet->row_title_area.width;
7562
7563    if(child->attached_to_cell){
7564 /*
7565       child->x = COLUMN_LEFT_XPIXEL(sheet, child->col);
7566       child->y = ROW_TOP_YPIXEL(sheet, child->row);
7567
7568       if(sheet->row_titles_visible) 
7569                                     child->x-=sheet->row_title_area.width;
7570       if(sheet->column_titles_visible) 
7571                                     child->y-=sheet->column_title_area.height;
7572
7573       width = xxx_column_width(sheet, child->col);
7574       height = yyy_row_height(sheet, child->row);
7575 */
7576       
7577       gtk_sheet_get_cell_area(sheet, child->row, child->col, &area);
7578       child->x = area.x + child->xpadding;
7579       child->y = area.y + child->ypadding;
7580
7581       if(!child->floating){
7582         if(child_requisition.width + 2*child->xpadding <= xxx_column_width(sheet, child->col)){
7583           if(child->xfill){
7584             child_requisition.width = child_allocation.width = xxx_column_width(sheet, child->col) - 2*child->xpadding;
7585           } else {
7586             if(child->xexpand){
7587               child->x = area.x + xxx_column_width(sheet, child->col) / 2 -
7588                                   child_requisition.width / 2;
7589             }
7590             child_allocation.width = child_requisition.width;
7591           }
7592         } else {
7593           if(!child->xshrink){
7594             gtk_sheet_set_column_width(sheet, child->col, child_requisition.width + 2 * child->xpadding);
7595           }
7596           child_allocation.width = xxx_column_width(sheet, child->col) - 2*child->xpadding;
7597         }
7598
7599         if(child_requisition.height + 2*child->ypadding <= yyy_row_height(sheet, child->row)){
7600           if(child->yfill){
7601             child_requisition.height = child_allocation.height = yyy_row_height(sheet, child->row) - 2*child->ypadding;
7602           } else {
7603             if(child->yexpand){
7604               child->y = area.y + yyy_row_height(sheet, child->row) / 2 -
7605                                   child_requisition.height / 2;
7606             }
7607             child_allocation.height = child_requisition.height;
7608           }
7609         } else {
7610           if(!child->yshrink){
7611             gtk_sheet_set_row_height(sheet, child->row, child_requisition.height + 2 * child->ypadding);
7612           }
7613           child_allocation.height = yyy_row_height(sheet, child->row) - 2*child->ypadding;
7614         }
7615       } else {
7616         child_allocation.width = child_requisition.width;
7617         child_allocation.height = child_requisition.height;
7618       }
7619
7620       x = child_allocation.x = child->x + xoffset;
7621       y = child_allocation.y = child->y + yoffset;
7622    }
7623    else
7624    {
7625       x = child_allocation.x = child->x + sheet->hoffset + xoffset;   
7626       x = child_allocation.x = child->x + xoffset;   
7627       y = child_allocation.y = child->y + sheet->voffset + yoffset;
7628       y = child_allocation.y = child->y + yoffset;
7629       child_allocation.width = child_requisition.width;
7630       child_allocation.height = child_requisition.height;
7631    }
7632
7633    gtk_widget_size_allocate(child->widget, &child_allocation);
7634    gtk_widget_queue_draw(child->widget);
7635 }
7636
7637 static void
7638 gtk_sheet_forall (GtkContainer *container,
7639                   gboolean      include_internals,
7640                   GtkCallback   callback,
7641                   gpointer      callback_data)
7642 {
7643   GtkSheet *sheet;
7644   GtkSheetChild *child;
7645   GList *children;
7646
7647   g_return_if_fail (GTK_IS_SHEET (container));
7648   g_return_if_fail (callback != NULL);
7649
7650   sheet = GTK_SHEET (container);
7651   children = sheet->children;
7652   while (children)
7653     {
7654       child = children->data;
7655       children = children->next;
7656
7657       (* callback) (child->widget, callback_data);
7658     }
7659   if(sheet->button)
7660      (* callback) (sheet->button, callback_data);
7661   if(sheet->sheet_entry)
7662      (* callback) (sheet->sheet_entry, callback_data);
7663 }
7664
7665
7666 static void
7667 gtk_sheet_position_children(GtkSheet *sheet)
7668 {
7669   GList *children;
7670   GtkSheetChild *child;
7671
7672   children = sheet->children;
7673
7674   while(children)
7675    {
7676      child = (GtkSheetChild *)children->data;
7677
7678      if(child->col !=-1 && child->row != -1)
7679            gtk_sheet_position_child(sheet, child);
7680
7681      if(child->row == -1){
7682         if(child->col < MIN_VISIBLE_COLUMN(sheet) || 
7683            child->col > MAX_VISIBLE_COLUMN(sheet))
7684               gtk_sheet_child_hide(child);
7685         else
7686               gtk_sheet_child_show(child);
7687      }
7688      if(child->col == -1){
7689         if(child->row < MIN_VISIBLE_ROW(sheet) ||
7690            child->row > MAX_VISIBLE_ROW(sheet))
7691               gtk_sheet_child_hide(child);
7692         else
7693               gtk_sheet_child_show(child);
7694      }
7695  
7696      children = children->next;
7697    }
7698     
7699 }
7700
7701 static void
7702 gtk_sheet_remove (GtkContainer *container, GtkWidget *widget)
7703 {
7704   GtkSheet *sheet;
7705   GList *children;
7706   GtkSheetChild *child = 0;
7707
7708   g_return_if_fail(container != NULL);
7709   g_return_if_fail(GTK_IS_SHEET(container));
7710
7711   sheet = GTK_SHEET(container);
7712
7713   children = sheet->children;
7714
7715   while(children)
7716    {
7717      child = (GtkSheetChild *)children->data;
7718
7719      if(child->widget == widget) break;
7720
7721      children = children->next;
7722    }
7723
7724   if (children)
7725    {
7726      gtk_widget_unparent (widget);
7727      child->widget = NULL;
7728
7729      sheet->children = g_list_remove_link (sheet->children, children);
7730      g_list_free_1 (children);
7731      g_free(child);
7732    }
7733
7734 }
7735
7736 static void
7737 gtk_sheet_realize_child(GtkSheet *sheet, GtkSheetChild *child)
7738 {
7739   GtkWidget *widget;
7740
7741   widget = GTK_WIDGET(sheet);
7742
7743   if(GTK_WIDGET_REALIZED(widget)){
7744     if(child->row == -1)
7745       gtk_widget_set_parent_window(child->widget, sheet->column_title_window);
7746     else if(child->col == -1)
7747       gtk_widget_set_parent_window(child->widget, sheet->row_title_window);
7748     else
7749       gtk_widget_set_parent_window(child->widget, sheet->sheet_window);
7750   }
7751
7752   gtk_widget_set_parent(child->widget, widget);
7753 }
7754
7755
7756    
7757 GtkSheetChild *
7758 gtk_sheet_get_child_at(GtkSheet *sheet, gint row, gint col)
7759 {
7760   GList *children;
7761   GtkSheetChild *child = 0;
7762
7763   g_return_val_if_fail(sheet != NULL, NULL);
7764   g_return_val_if_fail(GTK_IS_SHEET(sheet), NULL);
7765
7766   children = sheet->children;
7767
7768   while(children)
7769    {
7770      child = (GtkSheetChild *)children->data;
7771
7772      if(child->attached_to_cell)
7773         if(child->row == row && child->col == col) break; 
7774      
7775      children = children->next;
7776    }
7777
7778   if(children) return child; 
7779
7780   return NULL;
7781 }
7782
7783 static void
7784 gtk_sheet_child_hide(GtkSheetChild *child) 
7785 {
7786   g_return_if_fail(child != NULL);
7787   gtk_widget_hide(child->widget);
7788 }
7789
7790 static void
7791 gtk_sheet_child_show(GtkSheetChild *child) 
7792 {
7793   g_return_if_fail(child != NULL);
7794
7795   gtk_widget_show(child->widget);
7796 }
7797
7798 GSheetModel *
7799 gtk_sheet_get_model(const GtkSheet *sheet)
7800 {
7801   g_return_val_if_fail (GTK_IS_SHEET (sheet), NULL);
7802
7803   return sheet->model;
7804 }
7805