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