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