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