gattrib

gtksheet_2_2.c

Go to the documentation of this file.
00001 /* GtkSheet widget for Gtk+.
00002  * Copyright (C) 1999-2001 Adrian E. Feiguin <adrian@ifir.ifir.edu.ar>
00003  *
00004  * Based on GtkClist widget by Jay Painter, but major changes.
00005  * Memory allocation routines inspired on SC (Spreadsheet Calculator)
00006  *
00007  * This library is free software; you can redistribute it and/or
00008  * modify it under the terms of the GNU Library General Public
00009  * License as published by the Free Software Foundation; either
00010  * version 2 of the License, or (at your option) any later version.
00011  *
00012  * This library is distributed in the hope that it will be useful,
00013  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00014  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00015  * Library General Public License for more details.
00016  *
00017  * You should have received a copy of the GNU Library General Public
00018  * License along with this library; if not, write to the
00019  * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
00020  * Boston, MA 02110-1301 USA
00021  */
00022 
00023 #ifdef HAVE_CONFIG_H
00024 #include "config.h"
00025 #endif
00026 
00027 #include <string.h>
00028 #include <stdio.h>
00029 #include <stdlib.h>
00030 #include <glib.h>
00031 #include <glib-object.h>
00032 #include <gobject/gvaluecollector.h>
00033 #include <gdk/gdk.h>
00034 #include <gdk/gdkkeysyms.h>
00035 #include <gtk/gtksignal.h>
00036 #include <gtk/gtklabel.h>
00037 #include <gtk/gtkbutton.h>
00038 #include <gtk/gtkadjustment.h>
00039 #include <gtk/gtktable.h>
00040 #include <gtk/gtkbox.h>
00041 #include <gtk/gtkmain.h>
00042 #include <gtk/gtktypeutils.h>
00043 #include <gtk/gtkentry.h>
00044 #include <gtk/gtkcontainer.h>
00045 #include <gtk/gtkpixmap.h>
00046 #include <pango/pango.h>
00047 #include "gtksheet_2_2.h"
00048 #include "gtkextra-marshal.h"
00049 
00050 /*------------------------------------------------------------------
00051  * Gattrib specific includes -- stuff dealing with gattrib data structs.
00052  * Included here in order to grab sheet_head->CHANGED, which is set
00053  * when the user puts a new value in a cell.
00054  *------------------------------------------------------------------*/
00055 #include <libgeda/libgeda.h>       /* geda library fcns  */
00056 #include "../include/struct.h"     /* typdef and struct declarations */
00057 #include "../include/prototype.h"  /* function prototypes */
00058 #include "../include/globals.h"
00059 
00060 #ifdef HAVE_LIBDMALLOC
00061 #include <dmalloc.h>
00062 #endif
00063 
00064 
00065 /* sheet flags */
00066 enum
00067 { 
00068   GTK_SHEET_IS_LOCKED       = 1 << 0,
00069   GTK_SHEET_IS_FROZEN       = 1 << 1,
00070   GTK_SHEET_IN_XDRAG        = 1 << 2,
00071   GTK_SHEET_IN_YDRAG        = 1 << 3,
00072   GTK_SHEET_IN_DRAG         = 1 << 4,
00073   GTK_SHEET_IN_SELECTION    = 1 << 5,
00074   GTK_SHEET_IN_RESIZE       = 1 << 6,
00075   GTK_SHEET_IN_CLIP         = 1 << 7,
00076   GTK_SHEET_REDRAW_PENDING  = 1 << 8,
00077 };
00078 
00079 #define GTK_SHEET_FLAGS(sheet)             (GTK_SHEET (sheet)->flags)
00080 #define GTK_SHEET_SET_FLAGS(sheet,flag)    (GTK_SHEET_FLAGS (sheet) |= (flag))
00081 #define GTK_SHEET_UNSET_FLAGS(sheet,flag)  (GTK_SHEET_FLAGS (sheet) &= ~(flag))
00082 
00083 #define GTK_SHEET_IS_FROZEN(sheet)   (GTK_SHEET_FLAGS (sheet) & GTK_SHEET_IS_FROZEN)
00084 #define GTK_SHEET_IN_XDRAG(sheet)    (GTK_SHEET_FLAGS (sheet) & GTK_SHEET_IN_XDRAG)
00085 #define GTK_SHEET_IN_YDRAG(sheet)    (GTK_SHEET_FLAGS (sheet) & GTK_SHEET_IN_YDRAG)
00086 #define GTK_SHEET_IN_DRAG(sheet)     (GTK_SHEET_FLAGS (sheet) & GTK_SHEET_IN_DRAG)
00087 #define GTK_SHEET_IN_SELECTION(sheet) (GTK_SHEET_FLAGS (sheet) & GTK_SHEET_IN_SELECTION)
00088 #define GTK_SHEET_IN_RESIZE(sheet) (GTK_SHEET_FLAGS (sheet) & GTK_SHEET_IN_RESIZE)
00089 #define GTK_SHEET_IN_CLIP(sheet) (GTK_SHEET_FLAGS (sheet) & GTK_SHEET_IN_CLIP)
00090 #define GTK_SHEET_REDRAW_PENDING(sheet)   (GTK_SHEET_FLAGS (sheet) & GTK_SHEET_REDRAW_PENDING)
00091  
00092 #define CELL_SPACING 1
00093 #define DRAG_WIDTH 6
00094 #define TIMEOUT_SCROLL 20
00095 #define TIMEOUT_FLASH 200
00096 #define TIME_INTERVAL 8
00097 #define COLUMN_MIN_WIDTH 10
00098 #define MINROWS 1
00099 #define MINCOLS 1
00100 #define MAXLENGTH 30
00101 #define CELLOFFSET 4
00102 #define DEFAULT_COLUMN_WIDTH 80
00103 
00104 static inline guint DEFAULT_ROW_HEIGHT(GtkWidget *widget) 
00105 { 
00106   if(!widget->style->font_desc) return 24;
00107   else {
00108     PangoContext *context = gtk_widget_get_pango_context(widget); 
00109     PangoFontMetrics *metrics = pango_context_get_metrics(context,
00110                                   widget->style->font_desc,
00111                                   pango_context_get_language(context)); 
00112     guint val = pango_font_metrics_get_descent(metrics) + 
00113                 pango_font_metrics_get_ascent(metrics);
00114     pango_font_metrics_unref(metrics);
00115     return PANGO_PIXELS(val)+2*CELLOFFSET;
00116   }
00117 }
00118 static inline guint DEFAULT_FONT_ASCENT(GtkWidget *widget) 
00119 { 
00120   if(!widget->style->font_desc) return 12;
00121   else {
00122     PangoContext *context = gtk_widget_get_pango_context(widget); 
00123     PangoFontMetrics *metrics = pango_context_get_metrics(context,
00124                                   widget->style->font_desc,
00125                                   pango_context_get_language(context)); 
00126     guint val = pango_font_metrics_get_ascent(metrics);
00127     pango_font_metrics_unref(metrics);
00128     return PANGO_PIXELS(val);
00129   }
00130 }
00131 static inline guint STRING_WIDTH(GtkWidget *widget,
00132                                  PangoFontDescription *font, const gchar *text)
00133 {
00134   PangoRectangle rect;
00135   PangoLayout *layout;
00136 
00137   layout = gtk_widget_create_pango_layout (widget, text);
00138   pango_layout_set_font_description (layout, font);
00139 
00140   pango_layout_get_extents (layout, NULL, &rect);
00141 
00142   g_object_unref(G_OBJECT(layout));
00143   return PANGO_PIXELS(rect.width);
00144 }
00145 
00146 static inline guint DEFAULT_FONT_DESCENT(GtkWidget *widget) 
00147 { 
00148   if(!widget->style->font_desc) return 12;
00149   else {
00150     PangoContext *context = gtk_widget_get_pango_context(widget); 
00151     PangoFontMetrics *metrics = pango_context_get_metrics(context,
00152                                   widget->style->font_desc,
00153                                   pango_context_get_language(context)); 
00154     guint val =  pango_font_metrics_get_descent(metrics);
00155     pango_font_metrics_unref(metrics);
00156     return PANGO_PIXELS(val);
00157   }
00158 }
00159 
00164 static inline gint
00165 ROW_TOP_YPIXEL(GtkSheet *sheet, gint nrow)
00166 {
00167    return (sheet->voffset + sheet->row[nrow].top_ypixel);
00168 }
00169 
00170 
00175 static inline gint 
00176 ROW_FROM_YPIXEL(GtkSheet *sheet, gint y)
00177 {
00178   gint i, cy;
00179 
00180   cy = sheet->voffset;
00181   if(sheet->column_titles_visible) cy += sheet->column_title_area.height;
00182   if(y < cy) return 0;
00183   for (i = 0; i <= sheet->maxrow; i++)
00184     {
00185       if (y >= cy  && y <= (cy + sheet->row[i].height) && sheet->row[i].is_visible)
00186     return i;
00187       if(sheet->row[i].is_visible) cy += sheet->row[i].height;
00188 
00189     }
00190 
00191   /* no match */
00192   return sheet->maxrow;
00193 }
00194 
00195 
00200 static inline gint
00201 COLUMN_LEFT_XPIXEL(GtkSheet *sheet, gint ncol)
00202 {
00203    return (sheet->hoffset + sheet->column[ncol].left_xpixel);
00204 }
00205 
00210 static inline gint
00211 COLUMN_FROM_XPIXEL (GtkSheet * sheet,
00212             gint x)
00213 {
00214   gint i, cx;
00215 
00216   cx = sheet->hoffset;
00217   if(sheet->row_titles_visible) cx += sheet->row_title_area.width;
00218   if(x < cx) return 0;
00219   for (i = 0; i <= sheet->maxcol; i++)
00220     {
00221       if (x >= cx  && x <= (cx + sheet->column[i].width) && sheet->column[i].is_visible)
00222     return i;
00223       if(sheet->column[i].is_visible) cx += sheet->column[i].width;
00224 
00225     }
00226 
00227   /* no match */
00228   return sheet->maxcol;
00229 }
00230 
00234 static inline gint SHEET_HEIGHT(GtkSheet *sheet)
00235 {
00236   gint i,cx;
00237  
00238   cx = 0;
00239   if(sheet->column_titles_visible) cx += sheet->column_title_area.height;
00240   for (i=0;i<=sheet->maxrow; i++)
00241    if(sheet->row[i].is_visible) cx += sheet->row[i].height;
00242   
00243   return cx;
00244 }
00245 
00246 
00250 static inline gint SHEET_WIDTH(GtkSheet *sheet)
00251 {
00252   gint i,cx;
00253  
00254   cx = 0;
00255   if(sheet->row_titles_visible) cx += sheet->row_title_area.width;
00256   for (i=0;i<=sheet->maxcol; i++)
00257    if(sheet->column[i].is_visible) cx += sheet->column[i].width;
00258   
00259   return cx;
00260 }
00261 
00262 #define MIN_VISIBLE_ROW(sheet) sheet->view.row0
00263 #define MAX_VISIBLE_ROW(sheet) sheet->view.rowi
00264 #define MIN_VISIBLE_COLUMN(sheet) sheet->view.col0
00265 #define MAX_VISIBLE_COLUMN(sheet) sheet->view.coli
00266 
00267 
00268 static inline gint
00269 POSSIBLE_XDRAG(GtkSheet *sheet, gint x, gint *drag_column)
00270 {
00271  gint column, xdrag;
00272 
00273  column=COLUMN_FROM_XPIXEL(sheet, x);
00274  *drag_column=column;
00275 
00276  xdrag=COLUMN_LEFT_XPIXEL(sheet,column)+CELL_SPACING;
00277  if(x <= xdrag+DRAG_WIDTH/2 && column != 0){
00278    while(!sheet->column[column-1].is_visible && column>0) column--;
00279    *drag_column=column-1;
00280    return sheet->column[column-1].is_sensitive;
00281  }
00282 
00283  xdrag+=sheet->column[column].width;
00284  if(x >= xdrag-DRAG_WIDTH/2 && x <= xdrag+DRAG_WIDTH/2)
00285    return sheet->column[column].is_sensitive;
00286 
00287  return FALSE;
00288 } 
00289 
00290 static inline gint
00291 POSSIBLE_YDRAG(GtkSheet *sheet, gint y, gint *drag_row)
00292 {
00293  gint row, ydrag;
00294 
00295  row=ROW_FROM_YPIXEL(sheet, y);
00296  *drag_row=row;
00297 
00298  ydrag=ROW_TOP_YPIXEL(sheet,row)+CELL_SPACING;
00299  if(y <= ydrag+DRAG_WIDTH/2 && row != 0){
00300    while(!sheet->row[row-1].is_visible && row>0) row--;
00301    *drag_row=row-1;
00302    return sheet->row[row-1].is_sensitive;
00303  }
00304 
00305  ydrag+=sheet->row[row].height;
00306 
00307  if(y >= ydrag-DRAG_WIDTH/2 && y <= ydrag+DRAG_WIDTH/2)
00308    return sheet->row[row].is_sensitive;
00309  
00310  
00311  return FALSE;
00312 }        
00313 
00314 static inline gint POSSIBLE_DRAG(GtkSheet *sheet, gint x, gint y,
00315                             gint *drag_row, gint *drag_column)
00316 {
00317   gint ydrag, xdrag;
00318 
00319   *drag_column=COLUMN_FROM_XPIXEL(sheet,x);
00320   *drag_row=ROW_FROM_YPIXEL(sheet,y);
00321 
00322   if(x>=COLUMN_LEFT_XPIXEL(sheet,sheet->range.col0)-DRAG_WIDTH/2 &&
00323      x<=COLUMN_LEFT_XPIXEL(sheet,sheet->range.coli)+
00324         sheet->column[sheet->range.coli].width+DRAG_WIDTH/2){
00325      ydrag=ROW_TOP_YPIXEL(sheet,sheet->range.row0);
00326      if(y>=ydrag-DRAG_WIDTH/2 && y<=ydrag+DRAG_WIDTH/2){
00327         *drag_row=sheet->range.row0;
00328         return TRUE;
00329      }
00330      ydrag=ROW_TOP_YPIXEL(sheet,sheet->range.rowi)+
00331            sheet->row[sheet->range.rowi].height;
00332      if(y>=ydrag-DRAG_WIDTH/2 && y<=ydrag+DRAG_WIDTH/2){
00333         *drag_row=sheet->range.rowi;
00334         return TRUE;
00335      }
00336   }
00337 
00338   if(y>=ROW_TOP_YPIXEL(sheet,sheet->range.row0)-DRAG_WIDTH/2 &&
00339      y<=ROW_TOP_YPIXEL(sheet,sheet->range.rowi)+
00340         sheet->row[sheet->range.rowi].height+DRAG_WIDTH/2){
00341      xdrag=COLUMN_LEFT_XPIXEL(sheet,sheet->range.col0);
00342      if(x>=xdrag-DRAG_WIDTH/2 && x<=xdrag+DRAG_WIDTH/2){
00343         *drag_column=sheet->range.col0;
00344         return TRUE;
00345      }
00346      xdrag=COLUMN_LEFT_XPIXEL(sheet,sheet->range.coli)+
00347            sheet->column[sheet->range.coli].width;
00348      if(x>=xdrag-DRAG_WIDTH/2 && x<=xdrag+DRAG_WIDTH/2){
00349         *drag_column=sheet->range.coli;
00350         return TRUE;
00351      }
00352   }
00353   return FALSE;
00354 }
00355 
00356 static inline gint POSSIBLE_RESIZE(GtkSheet *sheet, gint x, gint y,
00357                             gint *drag_row, gint *drag_column)
00358 {
00359   gint xdrag, ydrag;
00360   
00361   xdrag=COLUMN_LEFT_XPIXEL(sheet,sheet->range.coli)+
00362            sheet->column[sheet->range.coli].width;
00363 
00364   ydrag=ROW_TOP_YPIXEL(sheet,sheet->range.rowi)+
00365            sheet->row[sheet->range.rowi].height;
00366 
00367   if(sheet->state == GTK_SHEET_COLUMN_SELECTED) 
00368         ydrag = ROW_TOP_YPIXEL(sheet, sheet->view.row0);
00369 
00370   if(sheet->state == GTK_SHEET_ROW_SELECTED)
00371         xdrag = COLUMN_LEFT_XPIXEL(sheet, sheet->view.col0);
00372 
00373   *drag_column=COLUMN_FROM_XPIXEL(sheet,x);
00374   *drag_row=ROW_FROM_YPIXEL(sheet,y);
00375 
00376   if(x>=xdrag-DRAG_WIDTH/2 && x<=xdrag+DRAG_WIDTH/2 &&
00377      y>=ydrag-DRAG_WIDTH/2 && y<=ydrag+DRAG_WIDTH/2) return TRUE;
00378 
00379   return FALSE;  
00380 }
00381 
00382 static void gtk_sheet_class_init        (GtkSheetClass * klass);
00383 static void gtk_sheet_init          (GtkSheet * sheet);
00384 static void gtk_sheet_destroy           (GtkObject * object);
00385 static void gtk_sheet_finalize          (GObject * object);
00386 static void gtk_sheet_style_set         (GtkWidget *widget,
00387                                  GtkStyle  *previous_style);
00388 static void gtk_sheet_realize           (GtkWidget * widget);
00389 static void gtk_sheet_unrealize         (GtkWidget * widget);
00390 static void gtk_sheet_map           (GtkWidget * widget);
00391 static void gtk_sheet_unmap             (GtkWidget * widget);
00392 static gint gtk_sheet_expose            (GtkWidget * widget,
00393                          GdkEventExpose * event);
00394 static void gtk_sheet_forall            (GtkContainer *container,
00395                                          gboolean include_internals,
00396                                          GtkCallback  callback, 
00397                                          gpointer  callback_data); 
00398 
00399 static void gtk_sheet_set_scroll_adjustments    (GtkSheet *sheet,
00400                          GtkAdjustment *hadjustment,
00401                          GtkAdjustment *vadjustment);
00402 
00403 static gint gtk_sheet_button_press      (GtkWidget * widget,
00404                          GdkEventButton * event);
00405 static gint gtk_sheet_button_release        (GtkWidget * widget,
00406                          GdkEventButton * event);
00407 static gint gtk_sheet_motion            (GtkWidget * widget,
00408                          GdkEventMotion * event);
00409 
00410 #if 0
00411 static gint gtk_sheet_entry_key_press       (GtkWidget *widget,
00412                                  GdkEventKey *key);
00413 #endif
00414 
00415 static gint gtk_sheet_key_press         (GtkWidget *widget,
00416                                  GdkEventKey *key);
00417 
00418 static void gtk_sheet_size_request      (GtkWidget * widget,
00419                                  GtkRequisition * requisition);
00420 static void gtk_sheet_size_allocate         (GtkWidget * widget,
00421                                  GtkAllocation * allocation);
00422 
00423 /* Sheet queries */
00424 
00425 static gint gtk_sheet_range_isvisible       (GtkSheet * sheet,
00426                          GtkSheetRange range);
00427 static gint gtk_sheet_cell_isvisible        (GtkSheet * sheet,
00428                          gint row, gint column);
00429 /* Clipped Range */
00430 
00431 static gint gtk_sheet_scroll            (gpointer data);
00432 static gint gtk_sheet_flash         (gpointer data);
00433 
00434 /* Drawing Routines */
00435 
00436 /* draw cell background and frame */
00437 static void gtk_sheet_cell_draw_default     (GtkSheet *sheet, 
00438                          gint row, gint column);
00439 
00440 /* draw cell border */
00441 static void gtk_sheet_cell_draw_border      (GtkSheet *sheet, 
00442                          gint row, gint column, 
00443                          gint mask);
00444 
00445 /* draw cell contents */
00446 static void gtk_sheet_cell_draw_label       (GtkSheet *sheet, 
00447                          gint row, gint column);
00448 
00449 /* draw visible part of range. If range==NULL then draw the whole screen */
00450 static void gtk_sheet_range_draw        (GtkSheet *sheet, 
00451                          const GtkSheetRange *range);
00452 
00453 /* highlight the visible part of the selected range */
00454 static void gtk_sheet_range_draw_selection  (GtkSheet *sheet, 
00455                          GtkSheetRange range);
00456 
00457 /* Selection */
00458 
00459 static gint gtk_sheet_move_query        (GtkSheet *sheet, 
00460                          gint row, gint column);
00461 static void gtk_sheet_real_select_range     (GtkSheet * sheet,
00462                                  GtkSheetRange * range);
00463 static void gtk_sheet_real_unselect_range   (GtkSheet * sheet,
00464                                  const GtkSheetRange * range);
00465 static void gtk_sheet_extend_selection      (GtkSheet *sheet, 
00466                          gint row, gint column);
00467 static void gtk_sheet_new_selection     (GtkSheet *sheet, 
00468                          GtkSheetRange *range);
00469 static void gtk_sheet_draw_border       (GtkSheet *sheet, 
00470                          GtkSheetRange range);
00471 static void gtk_sheet_draw_corners      (GtkSheet *sheet,
00472                          GtkSheetRange range);
00473 
00474 
00475 /* Active Cell handling */
00476 
00477 static void gtk_sheet_entry_changed     (GtkWidget *widget, 
00478                          gpointer data);
00479 static gboolean gtk_sheet_deactivate_cell   (GtkSheet *sheet);
00480 static void gtk_sheet_hide_active_cell      (GtkSheet *sheet);
00481 static gboolean gtk_sheet_activate_cell     (GtkSheet *sheet, 
00482                          gint row, gint col);
00483 static void gtk_sheet_draw_active_cell      (GtkSheet *sheet);
00484 static void gtk_sheet_show_active_cell      (GtkSheet *sheet);
00485 static void gtk_sheet_click_cell        (GtkSheet *sheet, 
00486                                          gint row, 
00487                                          gint column,
00488                                          gboolean *veto);
00489 
00490 /* Backing Pixmap */
00491 
00492 static void gtk_sheet_make_backing_pixmap   (GtkSheet *sheet, 
00493                          guint width, guint height);
00494 static void gtk_sheet_draw_backing_pixmap   (GtkSheet *sheet, 
00495                          GtkSheetRange range);
00496 /* Scrollbars */
00497 
00498 static void adjust_scrollbars           (GtkSheet * sheet);
00499 static void vadjustment_changed         (GtkAdjustment * adjustment,
00500                              gpointer data);
00501 static void hadjustment_changed         (GtkAdjustment * adjustment,
00502                              gpointer data);
00503 static void vadjustment_value_changed       (GtkAdjustment * adjustment,
00504                              gpointer data);
00505 static void hadjustment_value_changed       (GtkAdjustment * adjustment,
00506                              gpointer data);
00507 
00508 
00509 static void draw_xor_vline          (GtkSheet * sheet);
00510 static void draw_xor_hline          (GtkSheet * sheet);
00511 static void draw_xor_rectangle          (GtkSheet *sheet, 
00512                          GtkSheetRange range);
00513 static void gtk_sheet_draw_flashing_range   (GtkSheet *sheet, 
00514                          GtkSheetRange range);
00515 static guint new_column_width           (GtkSheet * sheet,
00516                          gint column,
00517                          gint * x);
00518 static guint new_row_height             (GtkSheet * sheet,
00519                          gint row,
00520                          gint * y);
00521 /* Sheet Button */
00522 
00523 static void create_global_button        (GtkSheet *sheet);
00524 static void global_button_clicked       (GtkWidget *widget, 
00525                          gpointer data);
00526 /* Sheet Entry */
00527 
00528 static void create_sheet_entry          (GtkSheet *sheet);
00529 static void gtk_sheet_size_allocate_entry   (GtkSheet *sheet);
00530 
00531 /* Sheet button gadgets */
00532 
00533 static void size_allocate_column_title_buttons  (GtkSheet * sheet);
00534 static void size_allocate_row_title_buttons     (GtkSheet * sheet);
00535 static void gtk_sheet_recalc_top_ypixels    (GtkSheet *sheet, 
00536                          gint row);
00537 static void gtk_sheet_recalc_left_xpixels   (GtkSheet *sheet, 
00538                          gint column);
00539 static void row_button_set          (GtkSheet *sheet, 
00540                          gint row);
00541 static void column_button_set           (GtkSheet *sheet, 
00542                          gint column);
00543 static void row_button_release          (GtkSheet *sheet, 
00544                          gint row);
00545 static void column_button_release       (GtkSheet *sheet, 
00546                          gint column);
00547 static void gtk_sheet_button_draw       (GtkSheet *sheet, 
00548                          gint row, gint column);
00549 static void size_allocate_global_button     (GtkSheet *sheet);
00550 static void gtk_sheet_button_size_request   (GtkSheet *sheet,
00551                                          GtkSheetButton *button, 
00552                                          GtkRequisition *requisition);
00553 
00554 /* Attributes routines */
00555 
00556 static void gtk_sheet_set_cell_attributes   (GtkSheet *sheet, 
00557                          gint row, gint col,
00558                          GtkSheetCellAttr attributes);
00559 
00560 static void init_attributes         (GtkSheet *sheet, gint col,  
00561                          GtkSheetCellAttr *attributes);
00562 /* Memory allocation routines */
00563 static void gtk_sheet_real_range_clear      (GtkSheet *sheet, 
00564                          const GtkSheetRange *range, 
00565                                          gboolean delete);
00566 static void gtk_sheet_real_cell_clear       (GtkSheet *sheet, 
00567                          gint row,
00568                          gint column,
00569                          gboolean delete);
00570 static GtkSheetCell * gtk_sheet_cell_new    (void);
00571 static gint AddRow              (GtkSheet *sheet, gint nrows);
00572 static gint AddColumn               (GtkSheet *sheet, gint ncols);
00573 static gint InsertRow               (GtkSheet *sheet, gint row, gint nrows);
00574 static gint InsertColumn            (GtkSheet *sheet, gint col, gint ncols);
00575 static gint DeleteRow               (GtkSheet *sheet, gint row, gint nrows);
00576 static gint DeleteColumn            (GtkSheet *sheet, gint col, gint ncols);
00577 static gint GrowSheet               (GtkSheet *sheet, 
00578                          gint newrows, gint newcols);
00579 static gint CheckBounds             (GtkSheet *sheet, 
00580                          gint row, gint col);
00581 
00582 /* Container Functions */
00583 static void gtk_sheet_remove            (GtkContainer *container,
00584                          GtkWidget *widget);
00585 static void gtk_sheet_realize_child     (GtkSheet *sheet,
00586                          GtkSheetChild *child);
00587 static void gtk_sheet_position_child        (GtkSheet *sheet,
00588                          GtkSheetChild *child);
00589 static void gtk_sheet_position_children     (GtkSheet *sheet);
00590 static void gtk_sheet_child_show        (GtkSheetChild *child); 
00591 static void gtk_sheet_child_hide        (GtkSheetChild *child); 
00592 static void gtk_sheet_column_size_request       (GtkSheet *sheet,
00593                                                  gint col,
00594                                                  guint *requisition);
00595 static void gtk_sheet_row_size_request          (GtkSheet *sheet,
00596                                                  gint row,
00597                                                  guint *requisition);
00598 
00599 
00600 /* Signals */
00601 
00602 /* \brief Imported from gtkextra.c  by SDB 7.22.2004  
00603  *
00604  */
00605 void
00606 _gtkextra_signal_emit(GtkObject *object, guint signal_id, ...)
00607 {
00608   gboolean *result;
00609   GValue ret = { 0, };
00610   GValue instance_and_params [10] = { {0, }, };
00611   va_list var_args;
00612   GSignalQuery query;
00613   gchar *error;
00614   int i;
00615 
00616   va_start (var_args, signal_id);
00617 
00618   g_value_init(instance_and_params + 0, GTK_OBJECT_TYPE(object));
00619   g_value_set_instance (instance_and_params + 0, G_OBJECT(object));
00620 
00621   g_signal_query(signal_id, &query);
00622 
00623   for (i = 0; i < query.n_params; i++)
00624     {
00625       gboolean static_scope = query.param_types[i]&~G_SIGNAL_TYPE_STATIC_SCOPE;
00626       g_value_init(instance_and_params + i + 1, query.param_types[i]);
00627 
00628 
00629       G_VALUE_COLLECT (instance_and_params + i + 1,
00630                        var_args,
00631                        static_scope ? G_VALUE_NOCOPY_CONTENTS : 0,
00632                        &error);
00633 
00634       if (error)
00635         {
00636           g_warning ("%s: %s", G_STRLOC, error);
00637           g_free (error);
00638           while (i-- > 0)
00639             g_value_unset (instance_and_params + i);
00640 
00641           va_end (var_args);
00642           return;
00643         }
00644   
00645 
00646     }
00647 
00648   g_value_init(&ret, query.return_type);
00649   result = va_arg(var_args,gboolean *);
00650   g_value_set_boolean(&ret, *result);    
00651   g_signal_emitv(instance_and_params, signal_id, 0, &ret);
00652   *result = g_value_get_boolean(&ret);    
00653   g_value_unset (&ret);
00654 
00655   for (i = 0; i < query.n_params; i++)
00656     g_value_unset (instance_and_params + 1 + i);
00657   g_value_unset (instance_and_params + 0);
00658 
00659   va_end (var_args);
00660 }
00661 
00662 
00663 enum {
00664       SELECT_ROW, 
00665       SELECT_COLUMN, 
00666       SELECT_RANGE,
00667       CLIP_RANGE,
00668       RESIZE_RANGE,
00669       MOVE_RANGE,
00670       TRAVERSE, 
00671       DEACTIVATE, 
00672       ACTIVATE,
00673       SET_CELL,
00674       CLEAR_CELL,
00675       CHANGED,
00676       NEW_COL_WIDTH,
00677       NEW_ROW_HEIGHT,
00678       LAST_SIGNAL
00679 };
00680 
00681 static GtkContainerClass *parent_class = NULL;
00682 static guint sheet_signals[LAST_SIGNAL] = {0};
00683 
00684 
00685 GType
00686 gtk_sheet_get_type ()
00687 {
00688   static GType sheet_type = 0;
00689                                                                                 
00690   if (!sheet_type)
00691     {
00692       static const GTypeInfo sheet_info =
00693       {
00694         sizeof (GtkSheetClass),
00695         NULL,
00696         NULL,
00697         (GClassInitFunc) gtk_sheet_class_init,
00698         NULL,        
00699         NULL,       
00700         sizeof (GtkSheet),
00701         0,         
00702         (GInstanceInitFunc) gtk_sheet_init,
00703         NULL,
00704       };
00705       sheet_type =
00706         g_type_register_static (GTK_TYPE_CONTAINER, "GtkSheet",
00707                                 &sheet_info, 0);
00708     }
00709   return sheet_type;
00710 }
00711 
00712 static GtkSheetRange*
00713 gtk_sheet_range_copy (const GtkSheetRange *range)
00714 {
00715   GtkSheetRange *new_range;
00716 
00717   g_return_val_if_fail (range != NULL, NULL);
00718 
00719   new_range = g_new (GtkSheetRange, 1);
00720 
00721   *new_range = *range;
00722 
00723   return new_range;
00724 }
00725 
00726 static void
00727 gtk_sheet_range_free (GtkSheetRange *range)
00728 {
00729   g_return_if_fail (range != NULL);
00730 
00731   g_free (range);
00732 }
00733 
00734 GType
00735 gtk_sheet_range_get_type (void)
00736 {
00737   static GType sheet_range_type;
00738 
00739   if(!sheet_range_type)
00740   {
00741     sheet_range_type = g_boxed_type_register_static("GtkSheetRange", (GBoxedCopyFunc)gtk_sheet_range_copy, (GBoxedFreeFunc)gtk_sheet_range_free);
00742   }
00743   return sheet_range_type;
00744 
00745 }
00746 
00747 static void
00748 gtk_sheet_class_init (GtkSheetClass * klass)
00749 {
00750   GtkObjectClass *object_class;
00751   GtkWidgetClass *widget_class;
00752   GtkContainerClass *container_class;
00753   GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
00754 
00755   object_class = (GtkObjectClass *) klass;
00756   widget_class = (GtkWidgetClass *) klass;
00757   container_class = (GtkContainerClass *) klass;
00758 
00759   parent_class = g_type_class_peek_parent (klass);
00760 
00761   sheet_signals[SELECT_ROW] =
00762     gtk_signal_new ("select_row",
00763             GTK_RUN_LAST,
00764             GTK_CLASS_TYPE(object_class),
00765             GTK_SIGNAL_OFFSET (GtkSheetClass, select_row),
00766             gtkextra_VOID__INT,
00767                     GTK_TYPE_NONE, 1, GTK_TYPE_INT);
00768 
00769   sheet_signals[SELECT_COLUMN] =
00770     gtk_signal_new ("select_column",
00771             GTK_RUN_LAST,
00772             GTK_CLASS_TYPE(object_class),
00773             GTK_SIGNAL_OFFSET (GtkSheetClass, select_column),
00774             gtkextra_VOID__INT,
00775                     GTK_TYPE_NONE, 1, GTK_TYPE_INT);
00776 
00777   sheet_signals[SELECT_RANGE] =
00778     gtk_signal_new ("select_range",
00779             GTK_RUN_LAST,
00780             GTK_CLASS_TYPE(object_class),
00781             GTK_SIGNAL_OFFSET (GtkSheetClass, select_range),
00782                     gtkextra_VOID__BOXED,
00783                 GTK_TYPE_NONE, 1, GTK_TYPE_SHEET_RANGE);
00784 
00785   sheet_signals[CLIP_RANGE] =
00786     gtk_signal_new ("clip_range",
00787             GTK_RUN_LAST,
00788             GTK_CLASS_TYPE(object_class),
00789             GTK_SIGNAL_OFFSET (GtkSheetClass, clip_range),
00790                     gtkextra_VOID__BOXED,
00791                 GTK_TYPE_NONE, 1, GTK_TYPE_SHEET_RANGE);
00792 
00793   sheet_signals[RESIZE_RANGE] =
00794     gtk_signal_new ("resize_range",
00795             GTK_RUN_LAST,
00796             GTK_CLASS_TYPE(object_class),
00797             GTK_SIGNAL_OFFSET (GtkSheetClass, resize_range),
00798             gtkextra_VOID__BOXED_BOXED,
00799                 GTK_TYPE_NONE, 2, GTK_TYPE_SHEET_RANGE, GTK_TYPE_SHEET_RANGE);
00800   sheet_signals[MOVE_RANGE] =
00801     gtk_signal_new ("move_range",
00802             GTK_RUN_LAST,
00803             GTK_CLASS_TYPE(object_class),
00804             GTK_SIGNAL_OFFSET (GtkSheetClass, move_range),
00805             gtkextra_VOID__BOXED_BOXED,
00806                     GTK_TYPE_NONE, 2, GTK_TYPE_SHEET_RANGE, GTK_TYPE_SHEET_RANGE);
00807   sheet_signals[TRAVERSE] =
00808     gtk_signal_new ("traverse",
00809             GTK_RUN_LAST,
00810             GTK_CLASS_TYPE(object_class),
00811             GTK_SIGNAL_OFFSET (GtkSheetClass, traverse),
00812                     gtkextra_BOOLEAN__INT_INT_POINTER_POINTER,
00813                 GTK_TYPE_BOOL, 4, GTK_TYPE_INT, GTK_TYPE_INT,
00814                                       GTK_TYPE_POINTER, GTK_TYPE_POINTER);
00815 
00816   sheet_signals[DEACTIVATE] =
00817     gtk_signal_new ("deactivate",
00818             GTK_RUN_LAST,
00819             GTK_CLASS_TYPE(object_class),
00820             GTK_SIGNAL_OFFSET (GtkSheetClass, deactivate),
00821                     gtkextra_BOOLEAN__INT_INT,
00822                 GTK_TYPE_BOOL, 2, GTK_TYPE_INT, GTK_TYPE_INT);
00823 
00824   sheet_signals[ACTIVATE] =
00825     gtk_signal_new ("activate",
00826             GTK_RUN_LAST,
00827             GTK_CLASS_TYPE(object_class),
00828             GTK_SIGNAL_OFFSET (GtkSheetClass, activate),
00829                     gtkextra_BOOLEAN__INT_INT,
00830                 GTK_TYPE_BOOL, 2, GTK_TYPE_INT, GTK_TYPE_INT);
00831 
00832   sheet_signals[SET_CELL] =
00833     gtk_signal_new ("set_cell",
00834             GTK_RUN_LAST,
00835             GTK_CLASS_TYPE(object_class),
00836             GTK_SIGNAL_OFFSET (GtkSheetClass, set_cell),
00837                     gtkextra_VOID__INT_INT,
00838                 GTK_TYPE_NONE, 2, GTK_TYPE_INT, GTK_TYPE_INT);
00839 
00840   sheet_signals[CLEAR_CELL] =
00841     gtk_signal_new ("clear_cell",
00842             GTK_RUN_LAST,
00843             GTK_CLASS_TYPE(object_class),
00844             GTK_SIGNAL_OFFSET (GtkSheetClass, clear_cell),
00845                     gtkextra_VOID__INT_INT,
00846                 GTK_TYPE_NONE, 2, GTK_TYPE_INT, GTK_TYPE_INT);
00847 
00848   sheet_signals[CHANGED] =
00849     gtk_signal_new ("changed",
00850             GTK_RUN_LAST,
00851             GTK_CLASS_TYPE(object_class),
00852             GTK_SIGNAL_OFFSET (GtkSheetClass, changed),
00853                     gtkextra_VOID__INT_INT,
00854                 GTK_TYPE_NONE, 2, GTK_TYPE_INT, GTK_TYPE_INT);
00855 
00856   sheet_signals[NEW_COL_WIDTH] =
00857     gtk_signal_new ("new_column_width",
00858             GTK_RUN_LAST,
00859             GTK_CLASS_TYPE(object_class),
00860             GTK_SIGNAL_OFFSET (GtkSheetClass, changed),
00861                     gtkextra_VOID__INT_INT,
00862                 GTK_TYPE_NONE, 2, GTK_TYPE_INT, GTK_TYPE_INT);
00863 
00864   sheet_signals[NEW_ROW_HEIGHT] =
00865     gtk_signal_new ("new_row_height",
00866             GTK_RUN_LAST,
00867             GTK_CLASS_TYPE(object_class),
00868             GTK_SIGNAL_OFFSET (GtkSheetClass, changed),
00869                     gtkextra_VOID__INT_INT,
00870                 GTK_TYPE_NONE, 2, GTK_TYPE_INT, GTK_TYPE_INT);
00871 
00872 
00873 
00874   widget_class->set_scroll_adjustments_signal =
00875     gtk_signal_new ("set_scroll_adjustments",
00876                     GTK_RUN_LAST,
00877                     GTK_CLASS_TYPE(object_class),
00878                     GTK_SIGNAL_OFFSET (GtkSheetClass, set_scroll_adjustments),
00879                     gtkextra_VOID__OBJECT_OBJECT,
00880                     GTK_TYPE_NONE, 2, GTK_TYPE_ADJUSTMENT, GTK_TYPE_ADJUSTMENT);
00881 
00882 
00883   container_class->add = NULL;
00884   container_class->remove = gtk_sheet_remove;
00885   container_class->forall = gtk_sheet_forall;
00886 
00887   object_class->destroy = gtk_sheet_destroy;
00888   gobject_class->finalize = gtk_sheet_finalize;
00889 
00890   widget_class->realize = gtk_sheet_realize;
00891   widget_class->unrealize = gtk_sheet_unrealize;
00892   widget_class->map = gtk_sheet_map;
00893   widget_class->unmap = gtk_sheet_unmap;
00894   widget_class->style_set = gtk_sheet_style_set;
00895   widget_class->button_press_event = gtk_sheet_button_press;
00896   widget_class->button_release_event = gtk_sheet_button_release;
00897   widget_class->motion_notify_event = gtk_sheet_motion;
00898   widget_class->key_press_event = gtk_sheet_key_press;
00899   widget_class->expose_event = gtk_sheet_expose;
00900   widget_class->size_request = gtk_sheet_size_request;
00901   widget_class->size_allocate = gtk_sheet_size_allocate;
00902   widget_class->focus_in_event = NULL;
00903   widget_class->focus_out_event = NULL;
00904 
00905   klass->set_scroll_adjustments = gtk_sheet_set_scroll_adjustments;
00906   klass->select_row = NULL;
00907   klass->select_column = NULL;
00908   klass->select_range = NULL;
00909   klass->clip_range = NULL;
00910   klass->resize_range = NULL;
00911   klass->move_range = NULL;
00912   klass->traverse = NULL;
00913   klass->deactivate = NULL;
00914   klass->activate = NULL;
00915   klass->set_cell = NULL;
00916   klass->clear_cell = NULL;
00917   klass->changed = NULL;
00918 
00919   gtk_widget_class_install_style_property (widget_class,
00920                        g_param_spec_boxed ("default-border",
00921                                    NULL, /* P_("Default Spacing"),*/
00922                                    NULL, /* P_("Extra space to add for CAN_DEFAULT buttons"), */
00923                                    GTK_TYPE_BORDER,
00924                                    G_PARAM_READABLE));
00925 
00926   gtk_widget_class_install_style_property (widget_class,
00927                        g_param_spec_boxed ("default-outside-border",
00928                                    NULL, /* P_("Default Outside Spacing"), */
00929                                    NULL, /* P_("Extra space to add for CAN_DEFAULT buttons that is always drawn outside the border"), */
00930                                    GTK_TYPE_BORDER,
00931                                    G_PARAM_READABLE));
00932 }
00933 
00934 static void 
00935 gtk_sheet_init (GtkSheet *sheet)
00936 {
00937   sheet->children = NULL;
00938 
00939   sheet->flags = 0;
00940   sheet->selection_mode = GTK_SELECTION_BROWSE;
00941   sheet->freeze_count = 0;
00942   sheet->state = GTK_SHEET_NORMAL;
00943 
00944   GTK_WIDGET_UNSET_FLAGS (sheet, GTK_NO_WINDOW);
00945   GTK_WIDGET_SET_FLAGS (sheet, GTK_CAN_FOCUS);
00946 
00947   sheet->maxrow = 0;
00948   sheet->maxcol = 0;
00949 
00950   sheet->view.row0 = 0;
00951   sheet->view.col0 = 0;
00952   sheet->view.rowi = 0;
00953   sheet->view.coli = 0;
00954 
00955   sheet->maxallocrow = 0;
00956   sheet->maxalloccol = 0;
00957 
00958   sheet->column_title_window=NULL;
00959   sheet->column_title_area.x=0;
00960   sheet->column_title_area.y=0;
00961   sheet->column_title_area.width=0;
00962   sheet->column_title_area.height=DEFAULT_ROW_HEIGHT(GTK_WIDGET(sheet));
00963  
00964   sheet->row_title_window=NULL;
00965   sheet->row_title_area.x=0;
00966   sheet->row_title_area.y=0;
00967   sheet->row_title_area.width=DEFAULT_COLUMN_WIDTH;
00968   sheet->row_title_area.height=0;
00969 
00970   sheet->active_cell.row=0;
00971   sheet->active_cell.col=0;
00972   sheet->selection_cell.row=0;
00973   sheet->selection_cell.col=0;
00974 
00975   sheet->sheet_entry=NULL;
00976   sheet->pixmap=NULL;
00977 
00978   sheet->range.row0=0;
00979   sheet->range.rowi=0;
00980   sheet->range.col0=0;
00981   sheet->range.coli=0;
00982 
00983   sheet->state=GTK_SHEET_NORMAL;
00984 
00985   sheet->sheet_window = NULL;
00986   sheet->sheet_window_width = 0;
00987   sheet->sheet_window_height = 0;
00988   sheet->sheet_entry = NULL;
00989   sheet->button = NULL;
00990 
00991   sheet->hoffset = 0;
00992   sheet->voffset = 0;
00993 
00994   sheet->hadjustment = NULL;
00995   sheet->vadjustment = NULL;
00996 
00997   sheet->cursor_drag = gdk_cursor_new(GDK_PLUS);
00998   sheet->xor_gc = NULL;
00999   sheet->fg_gc = NULL;
01000   sheet->bg_gc = NULL;
01001   sheet->x_drag = 0;
01002   sheet->y_drag = 0;
01003 
01004   gdk_color_white(gdk_colormap_get_system(), &sheet->bg_color);
01005   gdk_color_parse("gray", &sheet->grid_color);
01006   gdk_color_alloc(gdk_colormap_get_system(), &sheet->grid_color);
01007   sheet->show_grid = TRUE;
01008 }
01009 
01010 GtkWidget *
01011 gtk_sheet_new (guint rows, guint columns, const gchar *title)
01012 {
01013   GtkWidget *widget;
01014 
01015   /* sanity check */
01016   g_return_val_if_fail (columns >= MINCOLS, NULL);
01017   g_return_val_if_fail (rows >= MINROWS, NULL);
01018 
01019   widget = gtk_type_new (gtk_sheet_get_type ());
01020 
01021   gtk_sheet_construct(GTK_SHEET(widget), rows, columns, title);
01022 
01023   return widget;
01024 }
01025 
01026 void
01027 gtk_sheet_construct (GtkSheet *sheet, guint rows, guint columns, const gchar *title)
01028 {
01029   sheet->row=(GtkSheetRow *)g_malloc(sizeof(GtkSheetRow));
01030   sheet->column=(GtkSheetColumn *)g_malloc(sizeof(GtkSheetColumn));
01031   sheet->data=(GtkSheetCell ***)g_malloc(sizeof(GtkSheetCell **));
01032 
01033   sheet->data[0] = (GtkSheetCell **)g_malloc(sizeof(GtkSheetCell *)+sizeof(gdouble));
01034   sheet->data[0][0] = NULL;
01035 
01036   sheet->columns_resizable = TRUE;
01037   sheet->rows_resizable = TRUE;
01038   sheet->row_titles_visible = TRUE;
01039   sheet->column_titles_visible = TRUE;
01040   sheet->autoscroll = TRUE;
01041   sheet->justify_entry = TRUE;
01042   sheet->locked = FALSE;
01043 
01044   /* set number of rows and columns */
01045   GrowSheet(sheet, MINROWS, MINCOLS);
01046 
01047   /* Init row an column zero */
01048   AddRow(sheet,-1);
01049   AddColumn(sheet,-1);
01050 
01051   /* Add rows and columns */
01052   AddRow(sheet,rows-1);
01053   AddColumn(sheet,columns-1);
01054 
01055   /* create sheet entry */
01056   sheet->entry_type = 0;
01057   create_sheet_entry (sheet);
01058 
01059   /* create global selection button */
01060   create_global_button(sheet);
01061 
01062   if(title)
01063      sheet->name = g_strdup(title);
01064 
01065 }
01066 
01067 
01068 GtkWidget *
01069 gtk_sheet_new_browser(guint rows, guint columns, const gchar *title)
01070 {
01071   GtkWidget *widget;
01072   
01073   widget = gtk_type_new (gtk_sheet_get_type ());
01074 
01075   gtk_sheet_construct_browser(GTK_SHEET(widget), rows, columns, title);
01076  
01077   return widget;
01078 }
01079 
01080 void
01081 gtk_sheet_construct_browser(GtkSheet *sheet, guint rows, guint columns, 
01082                            const gchar *title)
01083 {
01084   gtk_sheet_construct(sheet, rows, columns, title);
01085 
01086   gtk_sheet_set_locked(sheet, TRUE);
01087   sheet->autoresize = TRUE;
01088 }
01089 
01090 GtkWidget *
01091 gtk_sheet_new_with_custom_entry (guint rows, guint columns, const gchar *title,
01092                                  GtkType entry_type)
01093 {
01094   GtkWidget *widget;
01095   
01096   widget = gtk_type_new (gtk_sheet_get_type ());
01097 
01098   gtk_sheet_construct_with_custom_entry(GTK_SHEET(widget), 
01099                                        rows, columns, title, entry_type);
01100  
01101   return widget;
01102 }
01103 
01104 void
01105 gtk_sheet_construct_with_custom_entry (GtkSheet *sheet, 
01106                                       guint rows, guint columns, 
01107                                       const gchar *title,
01108                                       GtkType entry_type)
01109 {
01110   gtk_sheet_construct(sheet, rows, columns, title);
01111 
01112   sheet->entry_type = entry_type;
01113   create_sheet_entry(sheet);
01114 }
01115 
01116 
01117 void
01118 gtk_sheet_change_entry(GtkSheet *sheet, GtkType entry_type)
01119 {
01120   gint state;
01121 
01122   g_return_if_fail (sheet != NULL);
01123   g_return_if_fail (GTK_IS_SHEET (sheet));
01124 
01125   state = sheet->state;
01126 
01127   if(sheet->state == GTK_SHEET_NORMAL)
01128       gtk_sheet_hide_active_cell(sheet);
01129 
01130   sheet->entry_type = entry_type;
01131 
01132   create_sheet_entry(sheet);
01133 
01134   if(state == GTK_SHEET_NORMAL)
01135     {
01136       gtk_sheet_show_active_cell(sheet); 
01137       gtk_signal_connect(GTK_OBJECT(gtk_sheet_get_entry(sheet)),
01138                          "changed",
01139                          (GtkSignalFunc)gtk_sheet_entry_changed,
01140                          GTK_OBJECT(GTK_WIDGET(sheet)));
01141     }
01142  
01143 }
01144 
01145 void
01146 gtk_sheet_show_grid(GtkSheet *sheet, gboolean show)
01147 {
01148   g_return_if_fail (sheet != NULL);
01149   g_return_if_fail (GTK_IS_SHEET (sheet));
01150 
01151   if(show == sheet->show_grid) return;
01152  
01153   sheet->show_grid = show;
01154 
01155   if(!GTK_SHEET_IS_FROZEN(sheet)) 
01156     gtk_sheet_range_draw(sheet, NULL);
01157 }
01158 
01159 gboolean
01160 gtk_sheet_grid_visible(GtkSheet *sheet)
01161 {
01162   g_return_val_if_fail (sheet != NULL, 0);
01163   g_return_val_if_fail (GTK_IS_SHEET (sheet), 0);
01164 
01165   return sheet->show_grid;
01166 }
01167 
01168 void
01169 gtk_sheet_set_background(GtkSheet *sheet, GdkColor *color)
01170 {
01171   g_return_if_fail (sheet != NULL);
01172   g_return_if_fail (GTK_IS_SHEET (sheet));
01173 
01174   if(!color)
01175     gdk_color_white(gdk_colormap_get_system(), &sheet->bg_color);
01176   else
01177     sheet->bg_color = *color;
01178 
01179   if(!GTK_SHEET_IS_FROZEN(sheet)) 
01180     gtk_sheet_range_draw(sheet, NULL);
01181 }
01182 
01183 void
01184 gtk_sheet_set_grid(GtkSheet *sheet, GdkColor *color)
01185 {
01186   g_return_if_fail (sheet != NULL);
01187   g_return_if_fail (GTK_IS_SHEET (sheet));
01188 
01189   if(!color)
01190     gdk_color_black(gdk_colormap_get_system(), &sheet->grid_color);
01191   else
01192     sheet->grid_color = *color;
01193 
01194   if(!GTK_SHEET_IS_FROZEN(sheet)) 
01195     gtk_sheet_range_draw(sheet, NULL);
01196 }
01197 
01198 guint
01199 gtk_sheet_get_columns_count(GtkSheet *sheet)
01200 {
01201   g_return_val_if_fail (sheet != NULL, 0);
01202   g_return_val_if_fail (GTK_IS_SHEET (sheet), 0);
01203 
01204   return sheet->maxcol + 1;
01205 }
01206 
01207 guint
01208 gtk_sheet_get_rows_count(GtkSheet *sheet)
01209 {
01210   g_return_val_if_fail (sheet != NULL, 0);
01211   g_return_val_if_fail (GTK_IS_SHEET (sheet), 0);
01212 
01213   return sheet->maxrow + 1;
01214 }
01215 
01216 gint
01217 gtk_sheet_get_state(GtkSheet *sheet)
01218 {
01219   g_return_val_if_fail (sheet != NULL, 0);
01220   g_return_val_if_fail (GTK_IS_SHEET (sheet), 0);
01221 
01222   return (sheet->state);
01223 }
01224 
01225 void
01226 gtk_sheet_set_selection_mode(GtkSheet *sheet, gint mode)
01227 {
01228   g_return_if_fail (sheet != NULL);
01229   g_return_if_fail (GTK_IS_SHEET (sheet));
01230 
01231   if(GTK_WIDGET_REALIZED(sheet))
01232    gtk_sheet_real_unselect_range(sheet, NULL);
01233 
01234   sheet->selection_mode = mode;
01235 }
01236 
01237 void
01238 gtk_sheet_set_autoresize                (GtkSheet *sheet, gboolean autoresize)
01239 {
01240   g_return_if_fail (sheet != NULL);
01241   g_return_if_fail (GTK_IS_SHEET (sheet));
01242 
01243   sheet->autoresize = autoresize;
01244 }
01245 
01246 gboolean
01247 gtk_sheet_autoresize                    (GtkSheet *sheet)
01248 {
01249   g_return_val_if_fail (sheet != NULL, FALSE);
01250   g_return_val_if_fail (GTK_IS_SHEET (sheet), FALSE);
01251 
01252   return sheet->autoresize;
01253 }
01254 
01255 void
01256 gtk_sheet_set_autoscroll                (GtkSheet *sheet, gboolean autoscroll)
01257 {
01258   g_return_if_fail (sheet != NULL);
01259   g_return_if_fail (GTK_IS_SHEET (sheet));
01260 
01261   sheet->autoscroll = autoscroll;
01262 }
01263 
01264 gboolean
01265 gtk_sheet_autoscroll                    (GtkSheet *sheet)
01266 {
01267   g_return_val_if_fail (sheet != NULL, FALSE);
01268   g_return_val_if_fail (GTK_IS_SHEET (sheet), FALSE);
01269 
01270   return sheet->autoscroll;
01271 }
01272 
01273 void
01274 gtk_sheet_set_clip_text                (GtkSheet *sheet, gboolean clip_text)
01275 {
01276   g_return_if_fail (sheet != NULL);
01277   g_return_if_fail (GTK_IS_SHEET (sheet));
01278 
01279   sheet->clip_text = clip_text;
01280 }
01281 
01282 gboolean
01283 gtk_sheet_clip_text                    (GtkSheet *sheet)
01284 {
01285   g_return_val_if_fail (sheet != NULL, FALSE);
01286   g_return_val_if_fail (GTK_IS_SHEET (sheet), FALSE);
01287 
01288   return sheet->clip_text;
01289 }
01290 
01291 void
01292 gtk_sheet_set_justify_entry             (GtkSheet *sheet, gboolean justify)
01293 {
01294   g_return_if_fail (sheet != NULL);
01295   g_return_if_fail (GTK_IS_SHEET (sheet));
01296 
01297   sheet->justify_entry = justify;
01298 }
01299 
01300 gboolean
01301 gtk_sheet_justify_entry                    (GtkSheet *sheet)
01302 {
01303   g_return_val_if_fail (sheet != NULL, FALSE);
01304   g_return_val_if_fail (GTK_IS_SHEET (sheet), FALSE);
01305 
01306   return sheet->justify_entry;
01307 }
01308 
01309 void
01310 gtk_sheet_set_locked             (GtkSheet *sheet, gboolean locked)
01311 {
01312   g_return_if_fail (sheet != NULL);
01313   g_return_if_fail (GTK_IS_SHEET (sheet));
01314 
01315   sheet->locked = locked;
01316 }
01317 
01318 gboolean
01319 gtk_sheet_locked                    (GtkSheet *sheet)
01320 {
01321   g_return_val_if_fail (sheet != NULL, FALSE);
01322   g_return_val_if_fail (GTK_IS_SHEET (sheet), FALSE);
01323 
01324   return sheet->locked;
01325 }
01326 
01327 /* This routine has problems with gtk+-1.2 related with the
01328  * label/button drawing - I think it's a bug in gtk+-1.2 */
01329 
01330 void
01331 gtk_sheet_set_title(GtkSheet *sheet, const gchar *title)
01332 {
01333 /*  GtkWidget *old_widget;
01334 */  GtkWidget *label;
01335 
01336   g_return_if_fail (sheet != NULL);
01337   g_return_if_fail (title != NULL);
01338   g_return_if_fail (GTK_IS_SHEET (sheet));
01339 
01340   if (sheet->name)
01341     g_free (sheet->name);
01342 
01343   sheet->name = g_strdup (title);
01344 
01345   if(!GTK_WIDGET_REALIZED(GTK_WIDGET(sheet)) || !title) return;
01346 
01347   if(GTK_BIN(sheet->button)->child)
01348            label = GTK_BIN(sheet->button)->child;
01349 /*
01350   gtk_label_set_text(GTK_LABEL(label), title);
01351 */
01352   size_allocate_global_button(sheet);
01353 
01354   /* remove and destroy the old widget */
01355 /*
01356   old_widget = GTK_BIN (sheet->button)->child;
01357   if (old_widget)
01358     {
01359       gtk_container_remove (GTK_CONTAINER (sheet->button), old_widget);
01360     }
01361 
01362   label = gtk_label_new (title);
01363   gtk_misc_set_alignment(GTK_MISC(label), 0.5 , 0.5 );
01364 
01365   gtk_container_add (GTK_CONTAINER (sheet->button), label);
01366   gtk_widget_show (label);
01367 
01368   size_allocate_global_button(sheet);
01369 
01370   gtk_signal_emit(GTK_OBJECT(sheet),sheet_signals[CHANGED], -1, -1);
01371 
01372   if(old_widget)
01373       gtk_widget_destroy (old_widget);
01374 */
01375 }
01376 
01377 void
01378 gtk_sheet_freeze (GtkSheet *sheet)
01379 {
01380   g_return_if_fail (sheet != NULL);
01381   g_return_if_fail (GTK_IS_SHEET (sheet));
01382 
01383   sheet->freeze_count++;
01384   GTK_SHEET_SET_FLAGS(sheet, GTK_SHEET_IS_FROZEN);
01385 }
01386 
01387 void
01388 gtk_sheet_thaw(GtkSheet *sheet)
01389 {
01390   g_return_if_fail (sheet != NULL);
01391   g_return_if_fail (GTK_IS_SHEET (sheet));
01392 
01393   if(sheet->freeze_count == 0) return;
01394 
01395   sheet->freeze_count--;
01396   if(sheet->freeze_count > 0) return;
01397 
01398   adjust_scrollbars(sheet);
01399 
01400   GTK_SHEET_UNSET_FLAGS(sheet, GTK_SHEET_IS_FROZEN);
01401 
01402   sheet->old_vadjustment = -1.;
01403   sheet->old_hadjustment = -1.;
01404 
01405   if(sheet->hadjustment)
01406       gtk_signal_emit_by_name (GTK_OBJECT (sheet->hadjustment), 
01407                   "value_changed");
01408   if(sheet->vadjustment)
01409       gtk_signal_emit_by_name (GTK_OBJECT (sheet->vadjustment), 
01410                   "value_changed");
01411 
01412   if(sheet->state == GTK_STATE_NORMAL)
01413      if(sheet->sheet_entry && GTK_WIDGET_MAPPED(sheet->sheet_entry)){
01414         gtk_sheet_activate_cell(sheet, sheet->active_cell.row, sheet->active_cell.col);
01415 /*
01416         gtk_signal_connect(GTK_OBJECT(gtk_sheet_get_entry(sheet)),
01417                        "changed",
01418                            (GtkSignalFunc)gtk_sheet_entry_changed,
01419                            GTK_OBJECT(GTK_WIDGET(sheet)));
01420         gtk_sheet_show_active_cell(sheet);
01421 */
01422      }
01423 
01424 }
01425 
01426 void
01427 gtk_sheet_set_row_titles_width(GtkSheet *sheet, guint width)
01428 {
01429  if(width < COLUMN_MIN_WIDTH) return;
01430 
01431  sheet->row_title_area.width = width;
01432  sheet->view.col0=COLUMN_FROM_XPIXEL(sheet, sheet->row_title_area.width+1);
01433  sheet->view.coli=COLUMN_FROM_XPIXEL(sheet, sheet->sheet_window_width);
01434  gtk_sheet_recalc_top_ypixels(sheet, 0);
01435  gtk_sheet_recalc_left_xpixels(sheet, 0);
01436  adjust_scrollbars(sheet);
01437 
01438  sheet->old_hadjustment = -1.;
01439  if(sheet->hadjustment)
01440      gtk_signal_emit_by_name (GTK_OBJECT (sheet->hadjustment), 
01441                   "value_changed");
01442  size_allocate_global_button(sheet);
01443 }
01444 
01445 void
01446 gtk_sheet_set_column_titles_height(GtkSheet *sheet, guint height)
01447 {
01448  if(height < DEFAULT_ROW_HEIGHT(GTK_WIDGET(sheet))) return;
01449 
01450  sheet->column_title_area.height = height;
01451  sheet->view.row0=ROW_FROM_YPIXEL(sheet, sheet->column_title_area.height+1);
01452  sheet->view.rowi=ROW_FROM_YPIXEL(sheet, sheet->sheet_window_height-1);
01453  gtk_sheet_recalc_top_ypixels(sheet, 0);
01454  gtk_sheet_recalc_left_xpixels(sheet, 0);
01455  adjust_scrollbars(sheet);
01456 
01457  sheet->old_vadjustment = -1.;
01458  if(sheet->vadjustment)
01459      gtk_signal_emit_by_name (GTK_OBJECT (sheet->vadjustment), 
01460                   "value_changed");
01461  size_allocate_global_button(sheet);
01462 }
01463 
01464 void
01465 gtk_sheet_show_column_titles(GtkSheet *sheet)
01466 {
01467  gint col;
01468 
01469  if(sheet->column_titles_visible) return;
01470 
01471  sheet->column_titles_visible = TRUE;
01472  gtk_sheet_recalc_top_ypixels(sheet, 0);
01473  gtk_sheet_recalc_left_xpixels(sheet, 0);
01474  if(GTK_WIDGET_REALIZED(GTK_WIDGET(sheet))){
01475   gdk_window_show(sheet->column_title_window);
01476   gdk_window_move_resize (sheet->column_title_window,
01477                           sheet->column_title_area.x,
01478                           sheet->column_title_area.y,
01479                           sheet->column_title_area.width,
01480                           sheet->column_title_area.height);
01481 
01482   for(col = MIN_VISIBLE_COLUMN(sheet); col <= MAX_VISIBLE_COLUMN(sheet); col++){
01483     GtkSheetChild *child;
01484     child = sheet->column[col].button.child;
01485     if(child){
01486         gtk_sheet_child_show(child);
01487     }
01488   }
01489   adjust_scrollbars(sheet);
01490  } 
01491 
01492  sheet->old_vadjustment = -1.;
01493  if(sheet->vadjustment)
01494      gtk_signal_emit_by_name (GTK_OBJECT (sheet->vadjustment), 
01495                   "value_changed");
01496  size_allocate_global_button(sheet);
01497 }
01498 
01499 void
01500 gtk_sheet_show_row_titles(GtkSheet *sheet)
01501 {
01502  gint row;
01503 
01504  if(sheet->row_titles_visible) return;
01505 
01506  sheet->row_titles_visible = TRUE;
01507  gtk_sheet_recalc_top_ypixels(sheet, 0);
01508  gtk_sheet_recalc_left_xpixels(sheet, 0);
01509  if(GTK_WIDGET_REALIZED(GTK_WIDGET(sheet))){
01510   gdk_window_show(sheet->row_title_window);
01511   gdk_window_move_resize (sheet->row_title_window,
01512                           sheet->row_title_area.x,
01513                           sheet->row_title_area.y,
01514                           sheet->row_title_area.width,
01515                           sheet->row_title_area.height);
01516 
01517   for(row = MIN_VISIBLE_ROW(sheet); row <= MAX_VISIBLE_ROW(sheet); row++){
01518     GtkSheetChild *child;
01519     child = sheet->row[row].button.child;
01520     if(child){
01521         gtk_sheet_child_show(child);
01522     }
01523   }
01524   adjust_scrollbars(sheet);
01525  }
01526 
01527  sheet->old_hadjustment = -1.;
01528  if(sheet->hadjustment)
01529      gtk_signal_emit_by_name (GTK_OBJECT (sheet->hadjustment), 
01530                   "value_changed");
01531  size_allocate_global_button(sheet);
01532 }
01533 
01534 void
01535 gtk_sheet_hide_column_titles(GtkSheet *sheet)
01536 {
01537  gint col;
01538 
01539  if(!sheet->column_titles_visible) return;
01540 
01541  sheet->column_titles_visible = FALSE;
01542  gtk_sheet_recalc_top_ypixels(sheet, 0);
01543  gtk_sheet_recalc_left_xpixels(sheet, 0);
01544  if(GTK_WIDGET_REALIZED(GTK_WIDGET(sheet))){
01545   if(sheet->column_title_window) 
01546     gdk_window_hide(sheet->column_title_window);
01547   if(GTK_WIDGET_VISIBLE(sheet->button)) 
01548     gtk_widget_hide(sheet->button);
01549 
01550   for(col = MIN_VISIBLE_COLUMN(sheet); col <= MAX_VISIBLE_COLUMN(sheet); col++){
01551     GtkSheetChild *child;
01552     child = sheet->column[col].button.child;
01553     if(child){
01554         gtk_sheet_child_hide(child);
01555     }
01556   }
01557   adjust_scrollbars(sheet);
01558  }
01559  
01560  sheet->old_vadjustment = -1.;
01561  if(sheet->vadjustment)
01562      gtk_signal_emit_by_name (GTK_OBJECT (sheet->vadjustment), 
01563                   "value_changed");
01564 }
01565 
01566 void
01567 gtk_sheet_hide_row_titles(GtkSheet *sheet)
01568 {
01569  gint row;
01570 
01571  if(!sheet->row_titles_visible) return;
01572 
01573  sheet->row_titles_visible = FALSE;
01574  gtk_sheet_recalc_top_ypixels(sheet, 0);
01575  gtk_sheet_recalc_left_xpixels(sheet, 0);
01576  if(GTK_WIDGET_REALIZED(GTK_WIDGET(sheet))){
01577   if(sheet->row_title_window) 
01578     gdk_window_hide(sheet->row_title_window);
01579   if(GTK_WIDGET_VISIBLE(sheet->button)) 
01580     gtk_widget_hide(sheet->button);
01581   for(row = MIN_VISIBLE_ROW(sheet); row <= MAX_VISIBLE_ROW(sheet); row++){
01582     GtkSheetChild *child;
01583     child = sheet->row[row].button.child;
01584     if(child){
01585         gtk_sheet_child_hide(child);
01586     }
01587   }
01588   adjust_scrollbars(sheet);
01589  }
01590 
01591  sheet->old_hadjustment = -1.;
01592  if(sheet->hadjustment)
01593      gtk_signal_emit_by_name (GTK_OBJECT (sheet->hadjustment), 
01594                   "value_changed");
01595 }
01596 
01597 gboolean
01598 gtk_sheet_column_titles_visible(GtkSheet *sheet)
01599 {
01600   g_return_val_if_fail (sheet != NULL, FALSE);
01601   g_return_val_if_fail (GTK_IS_SHEET (sheet), FALSE);
01602   return sheet->column_titles_visible;
01603 }
01604 
01605 gboolean
01606 gtk_sheet_row_titles_visible(GtkSheet *sheet)
01607 {
01608   g_return_val_if_fail (sheet != NULL, FALSE);
01609   g_return_val_if_fail (GTK_IS_SHEET (sheet), FALSE);
01610   return sheet->row_titles_visible;
01611 }
01612 
01613 void
01614 gtk_sheet_set_column_title (GtkSheet * sheet,
01615                 gint column,
01616                 const gchar * title)
01617 {
01618   g_return_if_fail (sheet != NULL);
01619   g_return_if_fail (GTK_IS_SHEET (sheet));
01620 
01621   if (sheet->column[column].name)
01622     g_free (sheet->column[column].name);
01623 
01624   sheet->column[column].name = g_strdup(title);
01625 }
01626 
01627 void
01628 gtk_sheet_set_row_title (GtkSheet * sheet,
01629              gint row,
01630              const gchar * title)
01631 {
01632   g_return_if_fail (sheet != NULL);
01633   g_return_if_fail (GTK_IS_SHEET (sheet));
01634 
01635   if (sheet->row[row].name)
01636     g_free (sheet->row[row].name);
01637 
01638   sheet->row[row].name = g_strdup (title);
01639 }
01640 
01641 const gchar *
01642 gtk_sheet_get_row_title (GtkSheet * sheet,
01643              gint row)
01644 {
01645   g_return_val_if_fail (sheet != NULL, NULL);
01646   g_return_val_if_fail (GTK_IS_SHEET (sheet), NULL);
01647 
01648   return(sheet->row[row].name);
01649 }
01650 
01651 const gchar *
01652 gtk_sheet_get_column_title (GtkSheet * sheet,
01653                 gint column)
01654 {
01655   g_return_val_if_fail (sheet != NULL, NULL);
01656   g_return_val_if_fail (GTK_IS_SHEET (sheet), NULL);
01657 
01658   return(sheet->column[column].name);
01659 }
01660 
01661 void
01662 gtk_sheet_row_button_add_label(GtkSheet *sheet, gint row, const gchar *label)
01663 {
01664   GtkSheetButton *button;
01665   GtkRequisition req;
01666   gboolean aux;
01667 
01668   g_return_if_fail (sheet != NULL);
01669   g_return_if_fail (GTK_IS_SHEET (sheet));
01670 
01671   if(row < 0 || row > sheet->maxrow) return;
01672 
01673   button = &sheet->row[row].button;
01674   if (button->label) g_free (button->label);
01675   button->label = g_strdup (label);
01676 
01677   aux = gtk_sheet_autoresize(sheet);
01678   gtk_sheet_set_autoresize(sheet, TRUE);
01679   gtk_sheet_button_size_request(sheet, button, &req);
01680   gtk_sheet_set_autoresize(sheet, aux);
01681 
01682   if(req.height > sheet->row[row].height)
01683      gtk_sheet_set_row_height(sheet, row, req.height);
01684 
01685   if(req.width > sheet->row_title_area.width){
01686      gtk_sheet_set_row_titles_width(sheet, req.width);
01687   }
01688 
01689   if(!GTK_SHEET_IS_FROZEN(sheet)){
01690     gtk_sheet_button_draw(sheet, row, -1);
01691     gtk_signal_emit(GTK_OBJECT(sheet),sheet_signals[CHANGED], row, -1);
01692   }
01693 }  
01694 
01695 const gchar *
01696 gtk_sheet_row_button_get_label(GtkSheet *sheet, gint row)
01697 {
01698   g_return_val_if_fail (sheet != NULL, NULL);
01699   g_return_val_if_fail (GTK_IS_SHEET (sheet), NULL);
01700 
01701   if(row < 0 || row > sheet->maxrow) return NULL;
01702 
01703   return (sheet->row[row].button.label);
01704 }
01705 
01706 void
01707 gtk_sheet_row_label_set_visibility(GtkSheet *sheet, gint row, gboolean visible)
01708 {
01709   g_return_if_fail (sheet != NULL);
01710   g_return_if_fail (GTK_IS_SHEET (sheet));
01711 
01712   if(row < 0 || row > sheet->maxrow) return;
01713 
01714   sheet->row[row].button.label_visible = visible;
01715 
01716   if(!GTK_SHEET_IS_FROZEN(sheet)){  
01717     gtk_sheet_button_draw(sheet, row, -1);
01718     gtk_signal_emit(GTK_OBJECT(sheet),sheet_signals[CHANGED], row, -1);
01719   }
01720 }
01721 
01722 void
01723 gtk_sheet_rows_labels_set_visibility(GtkSheet *sheet, gboolean visible)
01724 {
01725   gint i;
01726 
01727   g_return_if_fail (sheet != NULL);
01728   g_return_if_fail (GTK_IS_SHEET (sheet));
01729 
01730   for(i = 0; i <= sheet->maxrow; i++)
01731     gtk_sheet_row_label_set_visibility(sheet, i, visible);
01732 }
01733 
01734 
01735 void
01736 gtk_sheet_column_button_add_label(GtkSheet *sheet, gint column, const gchar *label)
01737 {
01738   GtkSheetButton *button;
01739   GtkRequisition req;
01740   gboolean aux;
01741 
01742   g_return_if_fail (sheet != NULL);
01743   g_return_if_fail (GTK_IS_SHEET (sheet));
01744 
01745   if(column < 0 || column >sheet->maxcol) return;
01746 
01747   button = &sheet->column[column].button;
01748   if (button->label) g_free (button->label);
01749   button->label = g_strdup (label);
01750 
01751   aux = gtk_sheet_autoresize(sheet);
01752   gtk_sheet_set_autoresize(sheet, TRUE);
01753   gtk_sheet_button_size_request(sheet, button, &req);
01754   gtk_sheet_set_autoresize(sheet, aux);
01755 
01756   if(req.width > sheet->column[column].width)
01757      gtk_sheet_set_column_width(sheet, column, req.width);
01758 
01759   if(req.height > sheet->column_title_area.height)
01760      gtk_sheet_set_column_titles_height(sheet, req.height);
01761 
01762   if(!GTK_SHEET_IS_FROZEN(sheet)){
01763     gtk_sheet_button_draw(sheet, -1, column);
01764     gtk_signal_emit(GTK_OBJECT(sheet),sheet_signals[CHANGED], -1, column);
01765   }
01766 }  
01767 
01768 const gchar *
01769 gtk_sheet_column_button_get_label(GtkSheet *sheet, gint column)
01770 {
01771   g_return_val_if_fail (sheet != NULL, NULL);
01772   g_return_val_if_fail (GTK_IS_SHEET (sheet), NULL);
01773 
01774   if(column < 0 || column >sheet->maxcol) return NULL;
01775 
01776   return(sheet->column[column].button.label);
01777 }
01778 
01779 void
01780 gtk_sheet_column_label_set_visibility(GtkSheet *sheet, gint col, gboolean visible)
01781 {
01782   g_return_if_fail (sheet != NULL);
01783   g_return_if_fail (GTK_IS_SHEET (sheet));
01784 
01785   if(col < 0 || col > sheet->maxcol) return;
01786 
01787   sheet->column[col].button.label_visible = visible;
01788 
01789   if(!GTK_SHEET_IS_FROZEN(sheet)){  
01790     gtk_sheet_button_draw(sheet, -1, col);
01791     gtk_signal_emit(GTK_OBJECT(sheet),sheet_signals[CHANGED], -1, col);
01792   }
01793 }
01794 
01795 void
01796 gtk_sheet_columns_labels_set_visibility(GtkSheet *sheet, gboolean visible)
01797 {
01798   gint i;
01799 
01800   g_return_if_fail (sheet != NULL);
01801   g_return_if_fail (GTK_IS_SHEET (sheet));
01802 
01803   for(i = 0; i <= sheet->maxcol; i++)
01804     gtk_sheet_column_label_set_visibility(sheet, i, visible);
01805 }
01806 
01807 void
01808 gtk_sheet_row_button_justify(GtkSheet *sheet, gint row, 
01809                              GtkJustification justification)
01810 {
01811   GtkSheetButton *button;
01812 
01813   g_return_if_fail (sheet != NULL);
01814   g_return_if_fail (GTK_IS_SHEET (sheet));
01815 
01816   if(row < 0 || row > sheet->maxrow) return;
01817 
01818   button = &sheet->row[row].button;
01819   button->justification = justification;
01820 
01821   if(!GTK_SHEET_IS_FROZEN(sheet)){  
01822     gtk_sheet_button_draw(sheet, row, -1);
01823     gtk_signal_emit(GTK_OBJECT(sheet),sheet_signals[CHANGED], row, -1);
01824   }
01825 }  
01826 
01827 void
01828 gtk_sheet_column_button_justify(GtkSheet *sheet, gint column, 
01829                                 GtkJustification justification)
01830 {
01831   GtkSheetButton *button;
01832 
01833   g_return_if_fail (sheet != NULL);
01834   g_return_if_fail (GTK_IS_SHEET (sheet));
01835 
01836   if(column < 0 || column > sheet->maxcol) return;
01837 
01838   button = &sheet->column[column].button;
01839   button->justification = justification;
01840 
01841   if(!GTK_SHEET_IS_FROZEN(sheet)){  
01842     gtk_sheet_button_draw(sheet, -1, column);
01843     gtk_signal_emit(GTK_OBJECT(sheet),sheet_signals[CHANGED], -1, column);
01844   }
01845 }  
01846 
01847 
01848 void
01849 gtk_sheet_moveto (GtkSheet * sheet,
01850           gint row,
01851           gint column,
01852               gfloat row_align,
01853                   gfloat col_align)
01854 {
01855   gint x, y;
01856   guint width, height;
01857   gint adjust;
01858   gint min_row, min_col;
01859 
01860   g_return_if_fail (sheet != NULL);
01861   g_return_if_fail (GTK_IS_SHEET (sheet));
01862   g_return_if_fail (sheet->hadjustment != NULL);
01863   g_return_if_fail (sheet->vadjustment != NULL);
01864 
01865   if (row < 0 || row > sheet->maxrow)
01866     return;
01867   if (column < 0 || column > sheet->maxcol)
01868     return;
01869 
01870   height = sheet->sheet_window_height;
01871   width = sheet->sheet_window_width;
01872 
01873   /* adjust vertical scrollbar */
01874 
01875   if (row >= 0 && row_align >=0.)
01876     {
01877       y = ROW_TOP_YPIXEL(sheet, row) - sheet->voffset -
01878           row_align*height-
01879           (1.-row_align)*sheet->row[row].height;
01880 
01881       /* This forces the sheet to scroll when you don't see the entire cell */
01882       min_row = row;
01883       adjust = 0;
01884       if(row_align == 1.){
01885         while(min_row >= 0 && min_row > MIN_VISIBLE_ROW(sheet)){
01886          if(sheet->row[min_row].is_visible) 
01887                 adjust += sheet->row[min_row].height;
01888          if(adjust >= height){
01889            break;
01890          }
01891          min_row--;
01892         }
01893         min_row = MAX(min_row, 0);
01894         y = ROW_TOP_YPIXEL(sheet, min_row) - sheet->voffset +
01895             sheet->row[min_row].height - 1;
01896       }
01897 
01898       if (y < 0)
01899     sheet->vadjustment->value = 0.0;
01900       else
01901     sheet->vadjustment->value = y;
01902 
01903       sheet->old_vadjustment = -1.;
01904       gtk_signal_emit_by_name (GTK_OBJECT (sheet->vadjustment), 
01905                    "value_changed");
01906 
01907     } 
01908      
01909   /* adjust horizontal scrollbar */
01910   if (column >= 0 && col_align >= 0.)
01911     {
01912       x = COLUMN_LEFT_XPIXEL (sheet, column) - sheet->hoffset -
01913           col_align*width -
01914           (1.-col_align)*sheet->column[column].width;
01915 
01916       /* This forces the sheet to scroll when you don't see the entire cell */
01917       min_col = column;
01918       adjust = 0;
01919       if(col_align == 1.){
01920         while(min_col >= 0 && min_col > MIN_VISIBLE_COLUMN(sheet)){
01921          if(sheet->column[min_col].is_visible) 
01922                 adjust += sheet->column[min_col].width;
01923          if(adjust >= width){
01924            break;
01925          }
01926          min_col--;
01927         }
01928         min_col = MAX(min_col, 0);
01929         x = COLUMN_LEFT_XPIXEL(sheet, min_col) - sheet->hoffset +
01930             sheet->column[min_col].width - 1;
01931       }
01932 
01933       if (x < 0)
01934     sheet->hadjustment->value = 0.0;
01935       else
01936     sheet->hadjustment->value = x;
01937 
01938       sheet->old_vadjustment = -1.;
01939       gtk_signal_emit_by_name (GTK_OBJECT (sheet->hadjustment), 
01940                    "value_changed");
01941 
01942     }
01943 }
01944 
01945 void 
01946 gtk_sheet_column_set_sensitivity(GtkSheet *sheet, gint column, gboolean sensitive)
01947 {
01948   g_return_if_fail (sheet != NULL);
01949   g_return_if_fail (GTK_IS_SHEET (sheet));
01950 
01951   if(column < 0 || column > sheet->maxcol) return;
01952 
01953   sheet->column[column].is_sensitive=sensitive;
01954   if(!sensitive)
01955      sheet->column[column].button.state=GTK_STATE_INSENSITIVE;
01956   else
01957      sheet->column[column].button.state=GTK_STATE_NORMAL;
01958 
01959   if(GTK_WIDGET_REALIZED(sheet) && !GTK_SHEET_IS_FROZEN(sheet))
01960       gtk_sheet_button_draw(sheet, -1, column);
01961 }
01962 
01963 
01964 void
01965 gtk_sheet_columns_set_sensitivity(GtkSheet *sheet, gboolean sensitive)
01966 {
01967   gint i;
01968 
01969   g_return_if_fail (sheet != NULL);
01970   g_return_if_fail (GTK_IS_SHEET (sheet));
01971 
01972   for(i=0; i<=sheet->maxcol; i++)
01973      gtk_sheet_column_set_sensitivity(sheet, i, sensitive);
01974 }
01975 
01976 void
01977 gtk_sheet_columns_set_resizable (GtkSheet *sheet, gboolean resizable)
01978 {
01979   g_return_if_fail (sheet != NULL);
01980   g_return_if_fail (GTK_IS_SHEET (sheet));
01981 
01982   sheet->columns_resizable = resizable;
01983 }
01984 
01985 gboolean
01986 gtk_sheet_columns_resizable (GtkSheet *sheet)
01987 {
01988   g_return_val_if_fail (sheet != NULL, FALSE);
01989   g_return_val_if_fail (GTK_IS_SHEET (sheet), FALSE);
01990 
01991   return sheet->columns_resizable;
01992 }
01993 
01994 void 
01995 gtk_sheet_row_set_sensitivity(GtkSheet *sheet, gint row,  gboolean sensitive)
01996 {
01997 
01998   g_return_if_fail (sheet != NULL);
01999   g_return_if_fail (GTK_IS_SHEET (sheet));
02000 
02001   if(row < 0 || row > sheet->maxrow) return;
02002 
02003   sheet->row[row].is_sensitive=sensitive;
02004   if(!sensitive)
02005      sheet->row[row].button.state=GTK_STATE_INSENSITIVE;
02006   else
02007      sheet->row[row].button.state=GTK_STATE_NORMAL;
02008 
02009   if(GTK_WIDGET_REALIZED(sheet) && !GTK_SHEET_IS_FROZEN(sheet))
02010       gtk_sheet_button_draw(sheet, row, -1);
02011 }
02012 
02013 void
02014 gtk_sheet_rows_set_sensitivity(GtkSheet *sheet, gboolean sensitive)
02015 {
02016   gint i;
02017 
02018   g_return_if_fail (sheet != NULL);
02019   g_return_if_fail (GTK_IS_SHEET (sheet));
02020 
02021   for(i=0; i<=sheet->maxrow; i++)
02022      gtk_sheet_row_set_sensitivity(sheet, i, sensitive);
02023 }
02024 
02025 
02026 void
02027 gtk_sheet_rows_set_resizable (GtkSheet *sheet, gboolean resizable)
02028 {
02029   g_return_if_fail (sheet != NULL);
02030   g_return_if_fail (GTK_IS_SHEET (sheet));
02031 
02032   sheet->rows_resizable = resizable;
02033 }
02034 
02035 gboolean
02036 gtk_sheet_rows_resizable (GtkSheet *sheet)
02037 {
02038   g_return_val_if_fail (sheet != NULL, FALSE);
02039   g_return_val_if_fail (GTK_IS_SHEET (sheet), FALSE);
02040 
02041   return sheet->rows_resizable;
02042 }
02043 
02044 void
02045 gtk_sheet_column_set_visibility(GtkSheet *sheet, gint column, gboolean visible)
02046 {
02047   g_return_if_fail (sheet != NULL);
02048   g_return_if_fail (GTK_IS_SHEET (sheet));
02049 
02050   if(column < 0 || column > sheet->maxcol) return;
02051   if(sheet->column[column].is_visible == visible) return;
02052 
02053   sheet->column[column].is_visible = visible;
02054 
02055   gtk_sheet_recalc_left_xpixels(sheet, column);
02056 
02057   if(!GTK_SHEET_IS_FROZEN(sheet) && 
02058     gtk_sheet_cell_isvisible(sheet, MIN_VISIBLE_ROW(sheet), column)){
02059       gtk_sheet_range_draw(sheet, NULL);
02060       size_allocate_column_title_buttons(sheet);
02061   }
02062 }
02063 
02064 void
02065 gtk_sheet_row_set_visibility(GtkSheet *sheet, gint row, gboolean visible)
02066 {
02067   g_return_if_fail (sheet != NULL);
02068   g_return_if_fail (GTK_IS_SHEET (sheet));
02069 
02070   if(row < 0 || row > sheet->maxrow) return;
02071   if(sheet->row[row].is_visible == visible) return;
02072 
02073   sheet->row[row].is_visible = visible;
02074 
02075   gtk_sheet_recalc_top_ypixels(sheet, row);
02076 
02077   if(!GTK_SHEET_IS_FROZEN(sheet) && 
02078     gtk_sheet_cell_isvisible(sheet, row, MIN_VISIBLE_COLUMN(sheet))){
02079       gtk_sheet_range_draw(sheet, NULL);
02080       size_allocate_row_title_buttons(sheet);
02081   }
02082 }
02083 
02084 void
02085 gtk_sheet_select_row (GtkSheet * sheet,
02086               gint row)
02087 {
02088   g_return_if_fail (sheet != NULL);
02089   g_return_if_fail (GTK_IS_SHEET (sheet));
02090 
02091   if (row < 0 || row > sheet->maxrow)
02092     return;
02093 
02094   if(sheet->state != GTK_SHEET_NORMAL) 
02095      gtk_sheet_real_unselect_range(sheet, NULL);
02096   else
02097   {
02098      gboolean veto = TRUE;
02099      veto = gtk_sheet_deactivate_cell(sheet);
02100      if(!veto) return;
02101   }
02102 
02103   sheet->state=GTK_SHEET_ROW_SELECTED;                     
02104   sheet->range.row0=row;
02105   sheet->range.col0=0;
02106   sheet->range.rowi=row;
02107   sheet->range.coli=sheet->maxcol;
02108   sheet->active_cell.row=row;
02109   sheet->active_cell.col=0;
02110 
02111   gtk_signal_emit (GTK_OBJECT (sheet), sheet_signals[SELECT_ROW], row);
02112   gtk_sheet_real_select_range(sheet, NULL);
02113 
02114 }
02115 
02116 
02117 void
02118 gtk_sheet_select_column (GtkSheet * sheet,
02119                  gint column)
02120 {
02121   
02122   g_return_if_fail (sheet != NULL);
02123   g_return_if_fail (GTK_IS_SHEET (sheet));
02124 
02125   if (column < 0 || column > sheet->maxcol)
02126     return;
02127 
02128   if(sheet->state != GTK_SHEET_NORMAL) 
02129      gtk_sheet_real_unselect_range(sheet, NULL);
02130   else
02131   {
02132      gboolean veto = TRUE;
02133      veto = gtk_sheet_deactivate_cell(sheet);
02134      if(!veto) return;
02135   }
02136 
02137   sheet->state=GTK_SHEET_COLUMN_SELECTED;                     
02138   sheet->range.row0=0;
02139   sheet->range.col0=column;
02140   sheet->range.rowi=sheet->maxrow;
02141   sheet->range.coli=column;
02142   sheet->active_cell.row=0;
02143   sheet->active_cell.col=column;
02144 
02145   gtk_signal_emit (GTK_OBJECT (sheet), sheet_signals[SELECT_COLUMN], column);
02146   gtk_sheet_real_select_range(sheet, NULL);
02147 
02148 }
02149 
02150 void
02151 gtk_sheet_clip_range (GtkSheet *sheet, const GtkSheetRange *range)
02152 {
02153 
02154   g_return_if_fail (sheet != NULL);
02155   g_return_if_fail (GTK_IS_SHEET (sheet));
02156 
02157   if(GTK_SHEET_IN_CLIP(sheet)) return;
02158 
02159   GTK_SHEET_SET_FLAGS(sheet, GTK_SHEET_IN_CLIP);
02160 
02161   if(range == NULL)
02162     sheet->clip_range = sheet->range;
02163   else
02164     sheet->clip_range=*range;
02165 
02166   sheet->interval=0;
02167   sheet->clip_timer=gtk_timeout_add(TIMEOUT_FLASH, gtk_sheet_flash, sheet); 
02168 
02169   gtk_signal_emit(GTK_OBJECT(sheet), sheet_signals[CLIP_RANGE],
02170                                      &sheet->clip_range);
02171 
02172 }
02173 
02174 void
02175 gtk_sheet_unclip_range(GtkSheet *sheet)
02176 {
02177 
02178   g_return_if_fail (sheet != NULL);
02179   g_return_if_fail (GTK_IS_SHEET (sheet));
02180 
02181   if(!GTK_SHEET_IN_CLIP(sheet)) return;
02182 
02183   GTK_SHEET_UNSET_FLAGS(sheet, GTK_SHEET_IN_CLIP);
02184   gtk_timeout_remove(sheet->clip_timer);
02185   gtk_sheet_range_draw(sheet, &sheet->clip_range);
02186 
02187   if(gtk_sheet_range_isvisible(sheet, sheet->range))
02188     gtk_sheet_range_draw(sheet, &sheet->range);
02189 }
02190 
02191 gboolean
02192 gtk_sheet_in_clip (GtkSheet *sheet)
02193 {
02194   g_return_val_if_fail (sheet != NULL, FALSE);
02195   g_return_val_if_fail (GTK_IS_SHEET (sheet), FALSE);
02196 
02197   return GTK_SHEET_IN_CLIP(sheet);
02198 }
02199 
02200 static gint
02201 gtk_sheet_flash(gpointer data)
02202 {
02203   GtkSheet *sheet;
02204   gint x,y,width,height;
02205   GdkRectangle clip_area;
02206 
02207   sheet=GTK_SHEET(data);
02208 
02209   if(!GTK_WIDGET_REALIZED(GTK_WIDGET(sheet))) return TRUE;
02210   if(!GTK_WIDGET_DRAWABLE(GTK_WIDGET(sheet))) return TRUE;
02211   if(!gtk_sheet_range_isvisible(sheet, sheet->clip_range)) return TRUE;
02212   if(GTK_SHEET_IN_XDRAG(sheet)) return TRUE; 
02213   if(GTK_SHEET_IN_YDRAG(sheet)) return TRUE; 
02214 
02215   GDK_THREADS_ENTER();
02216  
02217   x=COLUMN_LEFT_XPIXEL(sheet,sheet->clip_range.col0)+1;
02218   y=ROW_TOP_YPIXEL(sheet,sheet->clip_range.row0)+1;
02219   width=COLUMN_LEFT_XPIXEL(sheet,sheet->clip_range.coli)-x+ 
02220              sheet->column[sheet->clip_range.coli].width-1;
02221   height=ROW_TOP_YPIXEL(sheet,sheet->clip_range.rowi)-y+
02222              sheet->row[sheet->clip_range.rowi].height-1;
02223 
02224   clip_area.x=COLUMN_LEFT_XPIXEL(sheet, MIN_VISIBLE_COLUMN(sheet));
02225   clip_area.y=ROW_TOP_YPIXEL(sheet, MIN_VISIBLE_ROW(sheet));
02226   clip_area.width=sheet->sheet_window_width;
02227   clip_area.height=sheet->sheet_window_height;
02228 
02229   if(x<0) {
02230      width=width+x+1;
02231      x=-1;
02232   }
02233   if(width>clip_area.width) width=clip_area.width+10;
02234   if(y<0) {
02235      height=height+y+1;
02236      y=-1;
02237   }
02238   if(height>clip_area.height) height=clip_area.height+10;
02239 
02240   gdk_draw_pixmap(sheet->sheet_window,
02241                   GTK_WIDGET(sheet)->style->fg_gc[GTK_STATE_NORMAL],
02242                   sheet->pixmap,
02243                   x, y,
02244                   x, y,
02245                   1, height);
02246 
02247   gdk_draw_pixmap(sheet->sheet_window,
02248                   GTK_WIDGET(sheet)->style->fg_gc[GTK_STATE_NORMAL],
02249                   sheet->pixmap,
02250                   x, y,
02251                   x, y,
02252                   width, 1);
02253 
02254   gdk_draw_pixmap(sheet->sheet_window,
02255                   GTK_WIDGET(sheet)->style->fg_gc[GTK_STATE_NORMAL],
02256                   sheet->pixmap,
02257                   x, y+height,
02258                   x, y+height,
02259                   width, 1);
02260 
02261   gdk_draw_pixmap(sheet->sheet_window,
02262                   GTK_WIDGET(sheet)->style->fg_gc[GTK_STATE_NORMAL],
02263                   sheet->pixmap,
02264                   x+width, y,
02265                   x+width, y,
02266                   1, height);
02267 
02268 
02269   sheet->interval=sheet->interval+1;
02270   if(sheet->interval==TIME_INTERVAL) sheet->interval=0;
02271 
02272   gdk_gc_set_dashes(sheet->xor_gc, sheet->interval, (gint8*)"\4\4", 2);
02273   gtk_sheet_draw_flashing_range(sheet,sheet->clip_range);
02274   gdk_gc_set_dashes(sheet->xor_gc, 0, (gint8*)"\4\4", 2);
02275 
02276   GDK_THREADS_LEAVE();
02277 
02278   return TRUE;
02279 
02280 }
02281 
02282 static void
02283 gtk_sheet_draw_flashing_range(GtkSheet *sheet, GtkSheetRange range)
02284 {
02285   GdkRectangle clip_area;
02286   gint x,y,width,height;
02287 
02288   if(!gtk_sheet_range_isvisible(sheet, sheet->clip_range)) return;
02289   
02290   clip_area.x=COLUMN_LEFT_XPIXEL(sheet, MIN_VISIBLE_COLUMN(sheet));
02291   clip_area.y=ROW_TOP_YPIXEL(sheet, MIN_VISIBLE_ROW(sheet));
02292   clip_area.width=sheet->sheet_window_width;
02293   clip_area.height=sheet->sheet_window_height;
02294 
02295   gdk_gc_set_clip_rectangle(sheet->xor_gc, &clip_area);  
02296 
02297   x=COLUMN_LEFT_XPIXEL(sheet,sheet->clip_range.col0)+1;
02298   y=ROW_TOP_YPIXEL(sheet,sheet->clip_range.row0)+1;
02299   width=COLUMN_LEFT_XPIXEL(sheet,sheet->clip_range.coli)-x+ 
02300              sheet->column[sheet->clip_range.coli].width-1;
02301   height=ROW_TOP_YPIXEL(sheet,sheet->clip_range.rowi)-y+
02302              sheet->row[sheet->clip_range.rowi].height-1;
02303 
02304   if(x<0) {
02305      width=width+x+1;
02306      x=-1;
02307   }
02308   if(width>clip_area.width) width=clip_area.width+10;
02309   if(y<0) {
02310      height=height+y+1;
02311      y=-1;
02312   }
02313   if(height>clip_area.height) height=clip_area.height+10;
02314 
02315   gdk_gc_set_line_attributes(sheet->xor_gc, 1, 1, 0 ,0 );
02316 
02317   gdk_draw_rectangle(sheet->sheet_window, sheet->xor_gc, FALSE, 
02318                      x, y,
02319                      width, height);
02320 
02321   gdk_gc_set_line_attributes (sheet->xor_gc, 1, 0, 0, 0);
02322 
02323   gdk_gc_set_clip_rectangle(sheet->xor_gc, NULL);
02324 
02325 }
02326 
02327 static gint
02328 gtk_sheet_range_isvisible (GtkSheet * sheet,
02329              GtkSheetRange range)
02330 {
02331   g_return_val_if_fail (sheet != NULL, FALSE);
02332 
02333   if (range.row0 < 0 || range.row0 > sheet->maxrow)
02334     return FALSE;
02335 
02336   if (range.rowi < 0 || range.rowi > sheet->maxrow)
02337     return FALSE;
02338 
02339   if (range.col0 < 0 || range.col0 > sheet->maxcol)
02340     return FALSE;
02341 
02342   if (range.coli < 0 || range.coli > sheet->maxcol)
02343     return FALSE;
02344 
02345   if (range.rowi < MIN_VISIBLE_ROW (sheet))
02346     return FALSE;
02347 
02348   if (range.row0 > MAX_VISIBLE_ROW (sheet))
02349     return FALSE;
02350 
02351   if (range.coli < MIN_VISIBLE_COLUMN (sheet))
02352     return FALSE;
02353 
02354   if (range.col0 > MAX_VISIBLE_COLUMN (sheet))
02355     return FALSE;
02356 
02357   return TRUE;
02358 }
02359 
02360 static gint
02361 gtk_sheet_cell_isvisible (GtkSheet * sheet,
02362               gint row, gint column)
02363 {
02364   GtkSheetRange range;
02365 
02366   range.row0 = row;
02367   range.col0 = column;
02368   range.rowi = row;
02369   range.coli = column;
02370 
02371   return gtk_sheet_range_isvisible(sheet, range);
02372 }
02373 
02374 void 
02375 gtk_sheet_get_visible_range(GtkSheet *sheet, GtkSheetRange *range)
02376 {
02377 
02378   g_return_if_fail (sheet != NULL);
02379   g_return_if_fail (GTK_IS_SHEET (sheet)) ;
02380   g_return_if_fail (range != NULL);
02381 
02382   range->row0 = MIN_VISIBLE_ROW(sheet);
02383   range->col0 = MIN_VISIBLE_COLUMN(sheet);
02384   range->rowi = MAX_VISIBLE_ROW(sheet);
02385   range->coli = MAX_VISIBLE_COLUMN(sheet);
02386 
02387 }
02388 
02389 GtkAdjustment *
02390 gtk_sheet_get_vadjustment (GtkSheet * sheet)
02391 {
02392   g_return_val_if_fail (sheet != NULL, NULL);
02393   g_return_val_if_fail (GTK_IS_SHEET (sheet), NULL);
02394 
02395   return sheet->vadjustment;
02396 }
02397 
02398 GtkAdjustment *
02399 gtk_sheet_get_hadjustment (GtkSheet * sheet)
02400 {
02401   g_return_val_if_fail (sheet != NULL, NULL);
02402   g_return_val_if_fail (GTK_IS_SHEET (sheet), NULL);
02403 
02404   return sheet->hadjustment;
02405 }
02406 
02407 void
02408 gtk_sheet_set_vadjustment (GtkSheet      *sheet,
02409                GtkAdjustment *adjustment)
02410 {
02411   GtkAdjustment *old_adjustment;
02412 
02413   g_return_if_fail (sheet != NULL);
02414   g_return_if_fail (GTK_IS_SHEET (sheet));
02415   if (adjustment)
02416     g_return_if_fail (GTK_IS_ADJUSTMENT (adjustment));
02417   
02418   if (sheet->vadjustment == adjustment)
02419     return;
02420   
02421   old_adjustment = sheet->vadjustment;
02422 
02423   if (sheet->vadjustment)
02424     {
02425       gtk_signal_disconnect_by_data (GTK_OBJECT (sheet->vadjustment), sheet);
02426       gtk_object_unref (GTK_OBJECT (sheet->vadjustment));
02427     }
02428 
02429   sheet->vadjustment = adjustment;
02430 
02431   if (sheet->vadjustment)
02432     {
02433       gtk_object_ref (GTK_OBJECT (sheet->vadjustment));
02434       gtk_object_sink (GTK_OBJECT (sheet->vadjustment));
02435 
02436       gtk_signal_connect (GTK_OBJECT (sheet->vadjustment), "changed",
02437               (GtkSignalFunc) vadjustment_changed,
02438               (gpointer) sheet);
02439       gtk_signal_connect (GTK_OBJECT (sheet->vadjustment), "value_changed",
02440               (GtkSignalFunc) vadjustment_value_changed,
02441               (gpointer) sheet);
02442     }
02443 
02444   if (!sheet->vadjustment || !old_adjustment)
02445      {
02446        gtk_widget_queue_resize (GTK_WIDGET (sheet));
02447        return;
02448      }
02449 
02450   sheet->old_vadjustment = sheet->vadjustment->value;
02451 }
02452 
02453 void
02454 gtk_sheet_set_hadjustment (GtkSheet      *sheet,
02455                GtkAdjustment *adjustment)
02456 {
02457   GtkAdjustment *old_adjustment;
02458 
02459   g_return_if_fail (sheet != NULL);
02460   g_return_if_fail (GTK_IS_SHEET (sheet));
02461   if (adjustment)
02462     g_return_if_fail (GTK_IS_ADJUSTMENT (adjustment));
02463   
02464   if (sheet->hadjustment == adjustment)
02465     return;
02466   
02467   old_adjustment = sheet->hadjustment;
02468 
02469   if (sheet->hadjustment)
02470     {
02471       gtk_signal_disconnect_by_data (GTK_OBJECT (sheet->hadjustment), sheet);
02472       gtk_object_unref (GTK_OBJECT (sheet->hadjustment));
02473     }
02474 
02475   sheet->hadjustment = adjustment;
02476 
02477   if (sheet->hadjustment)
02478     {
02479       gtk_object_ref (GTK_OBJECT (sheet->hadjustment));
02480       gtk_object_sink (GTK_OBJECT (sheet->hadjustment));
02481 
02482       gtk_signal_connect (GTK_OBJECT (sheet->hadjustment), "changed",
02483               (GtkSignalFunc) hadjustment_changed,
02484               (gpointer) sheet);
02485       gtk_signal_connect (GTK_OBJECT (sheet->hadjustment), "value_changed",
02486               (GtkSignalFunc) hadjustment_value_changed,
02487               (gpointer) sheet);
02488     }
02489 
02490   if (!sheet->hadjustment || !old_adjustment)
02491      {
02492        gtk_widget_queue_resize (GTK_WIDGET (sheet));
02493        return;
02494      }
02495 
02496   sheet->old_hadjustment = sheet->hadjustment->value;
02497 }
02498 
02499 static void
02500 gtk_sheet_set_scroll_adjustments (GtkSheet *sheet,
02501                   GtkAdjustment *hadjustment,
02502                   GtkAdjustment *vadjustment)
02503 {
02504    if(sheet->hadjustment != hadjustment)
02505          gtk_sheet_set_hadjustment (sheet, hadjustment);
02506    if(sheet->vadjustment != vadjustment)
02507          gtk_sheet_set_vadjustment (sheet, vadjustment);
02508 }
02509 
02510 static void
02511 gtk_sheet_finalize (GObject * object)
02512 {
02513   GtkSheet *sheet;
02514 
02515   g_return_if_fail (object != NULL);
02516   g_return_if_fail (GTK_IS_SHEET (object));
02517 
02518   sheet = GTK_SHEET (object);
02519 
02520   /* get rid of all the cells */
02521   gtk_sheet_range_clear (sheet, NULL);
02522   gtk_sheet_range_delete(sheet, NULL);
02523 
02524   gtk_sheet_delete_rows (sheet, 0, sheet->maxrow + 1);
02525   gtk_sheet_delete_columns (sheet, 0, sheet->maxcol + 1);
02526 
02527   DeleteRow (sheet, 0, sheet->maxrow + 1);
02528   DeleteColumn (sheet, 0, sheet->maxcol + 1);
02529 
02530   g_free(sheet->row);
02531   sheet->row = NULL;
02532   g_free(sheet->column);
02533   sheet->column = NULL;
02534   g_free(sheet->data);
02535   sheet->data = NULL;
02536 
02537   if(sheet->name){
02538       g_free(sheet->name);
02539       sheet->name = NULL;
02540   }
02541 
02542   if (G_OBJECT_CLASS (parent_class)->finalize)
02543     (*G_OBJECT_CLASS (parent_class)->finalize) (object);
02544 }
02545 
02546 static void
02547 gtk_sheet_destroy (GtkObject * object)
02548 {
02549   GtkSheet *sheet;
02550   GList *children;
02551 
02552   g_return_if_fail (object != NULL);
02553   g_return_if_fail (GTK_IS_SHEET (object));
02554 
02555   sheet = GTK_SHEET (object);
02556 
02557   /* destroy the entry */
02558   if(sheet->sheet_entry && GTK_IS_WIDGET(sheet->sheet_entry)){
02559     gtk_widget_destroy (sheet->sheet_entry);
02560     sheet->sheet_entry = NULL;
02561   }
02562 
02563   /* destroy the global selection button */
02564   if(sheet->button && GTK_IS_WIDGET(sheet->button)){
02565     gtk_widget_destroy (sheet->button);
02566     sheet->button = NULL;
02567   }
02568 
02569   if(sheet->timer){
02570      gtk_timeout_remove(sheet->timer);
02571      sheet->timer = 0;
02572   }
02573 
02574   if(sheet->clip_timer){
02575      gtk_timeout_remove(sheet->clip_timer);
02576      sheet->clip_timer = 0;
02577   }
02578 
02579   /* unref adjustments */
02580   if (sheet->hadjustment)
02581     {
02582       gtk_signal_disconnect_by_data (GTK_OBJECT (sheet->hadjustment), sheet);
02583       gtk_object_unref (GTK_OBJECT (sheet->hadjustment));
02584       sheet->hadjustment = NULL;
02585     }
02586   if (sheet->vadjustment)
02587     {
02588       gtk_signal_disconnect_by_data (GTK_OBJECT (sheet->vadjustment), sheet);
02589       gtk_object_unref (GTK_OBJECT (sheet->vadjustment));
02590       sheet->vadjustment = NULL;
02591     }
02592 
02593   children = sheet->children;
02594   while(children){
02595     GtkSheetChild *child = (GtkSheetChild *)children->data;
02596     if(child && child->widget) 
02597       gtk_sheet_remove(GTK_CONTAINER(sheet), child->widget);
02598     children = sheet->children;
02599   }  
02600   sheet->children = NULL;
02601 
02602   if (GTK_OBJECT_CLASS (parent_class)->destroy)
02603     (*GTK_OBJECT_CLASS (parent_class)->destroy) (object);
02604 }
02605 
02606 static void
02607 gtk_sheet_style_set (GtkWidget *widget,
02608              GtkStyle  *previous_style)
02609 {
02610   GtkSheet *sheet;
02611 
02612   g_return_if_fail (widget != NULL);
02613   g_return_if_fail (GTK_IS_SHEET (widget));
02614 
02615   if (GTK_WIDGET_CLASS (parent_class)->style_set)
02616     (*GTK_WIDGET_CLASS (parent_class)->style_set) (widget, previous_style);
02617 
02618   sheet = GTK_SHEET (widget);
02619 
02620   if(GTK_WIDGET_REALIZED(widget))
02621      {
02622        gtk_style_set_background (widget->style, widget->window, widget->state);
02623      }
02624 
02625 }
02626 
02627 static void
02628 gtk_sheet_realize (GtkWidget * widget)
02629 {
02630   GtkSheet *sheet;
02631   GdkWindowAttr attributes;
02632   gint attributes_mask;
02633   GdkGCValues values, auxvalues;
02634   GdkColormap *colormap;
02635   gchar *name;
02636   GtkSheetChild *child;
02637   GList *children;
02638 
02639   g_return_if_fail (widget != NULL);
02640   g_return_if_fail (GTK_IS_SHEET (widget));
02641 
02642   sheet = GTK_SHEET (widget);
02643 
02644   GTK_WIDGET_SET_FLAGS (widget, GTK_REALIZED);
02645 
02646   attributes.window_type = GDK_WINDOW_CHILD;
02647   attributes.x = widget->allocation.x;
02648   attributes.y = widget->allocation.y;
02649   attributes.width = widget->allocation.width;
02650   attributes.height = widget->allocation.height;
02651   attributes.wclass = GDK_INPUT_OUTPUT;
02652 
02653   attributes.visual = gtk_widget_get_visual (widget);
02654   attributes.colormap = gtk_widget_get_colormap (widget);
02655 
02656   attributes.event_mask = gtk_widget_get_events (widget);
02657   attributes.event_mask |= (GDK_EXPOSURE_MASK |
02658                 GDK_BUTTON_PRESS_MASK |
02659                 GDK_BUTTON_RELEASE_MASK |
02660                 GDK_KEY_PRESS_MASK |
02661                 GDK_POINTER_MOTION_MASK |
02662                 GDK_POINTER_MOTION_HINT_MASK);
02663   attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL | GDK_WA_COLORMAP |
02664                     GDK_WA_CURSOR;
02665 
02666   attributes.cursor = gdk_cursor_new(GDK_TOP_LEFT_ARROW);
02667 
02668   /* main window */
02669   widget->window = gdk_window_new (gtk_widget_get_parent_window (widget), &attributes, attributes_mask);
02670 
02671   gdk_window_set_user_data (widget->window, sheet);
02672 
02673   widget->style = gtk_style_attach (widget->style, widget->window);
02674 
02675   gtk_style_set_background (widget->style, widget->window, GTK_STATE_NORMAL);
02676 
02677   attributes.x = 0;
02678   if(sheet->row_titles_visible)
02679        attributes.x = sheet->row_title_area.width;
02680   attributes.y = 0;
02681   attributes.width = sheet->column_title_area.width;
02682   attributes.height = sheet->column_title_area.height;
02683 
02684   /* column-title window */
02685   sheet->column_title_window = gdk_window_new (widget->window, &attributes, attributes_mask);
02686   gdk_window_set_user_data (sheet->column_title_window, sheet);
02687   gtk_style_set_background (widget->style, sheet->column_title_window, GTK_STATE_NORMAL);
02688 
02689   attributes.x = 0;
02690   attributes.y = 0;
02691   if(sheet->column_titles_visible)
02692        attributes.y = sheet->column_title_area.height;
02693   attributes.width = sheet->row_title_area.width;
02694   attributes.height = sheet->row_title_area.height;
02695 
02696   /* row-title window */
02697   sheet->row_title_window = gdk_window_new (widget->window, &attributes, attributes_mask);
02698   gdk_window_set_user_data (sheet->row_title_window, sheet);
02699   gtk_style_set_background (widget->style, sheet->row_title_window, GTK_STATE_NORMAL);
02700 
02701   /* sheet-window */
02702   attributes.cursor = gdk_cursor_new(GDK_PLUS);
02703 
02704   attributes.x = 0;
02705   attributes.y = 0;
02706   attributes.width = sheet->sheet_window_width, 
02707   attributes.height = sheet->sheet_window_height;
02708 
02709   sheet->sheet_window = gdk_window_new (widget->window, &attributes, attributes_mask);
02710   gdk_window_set_user_data (sheet->sheet_window, sheet);
02711 
02712   gdk_window_set_background (sheet->sheet_window, &widget->style->white);
02713   gdk_window_show (sheet->sheet_window);
02714 
02715   /* backing_pixmap */
02716   gtk_sheet_make_backing_pixmap(sheet, 0, 0);  
02717 
02718   /* GCs */
02719   if(sheet->fg_gc) 
02720       gdk_gc_unref(sheet->fg_gc);
02721   if(sheet->bg_gc) 
02722       gdk_gc_unref(sheet->bg_gc);
02723   sheet->fg_gc = gdk_gc_new (widget->window);
02724   sheet->bg_gc = gdk_gc_new (widget->window);
02725 
02726   colormap = gtk_widget_get_colormap(widget);
02727 
02728   gdk_color_white(colormap, &widget->style->white);
02729   gdk_color_black(colormap, &widget->style->black);
02730 
02731   gdk_gc_get_values(sheet->fg_gc, &auxvalues);
02732 
02733   values.foreground = widget->style->white;
02734   values.function = GDK_INVERT;
02735   values.subwindow_mode = GDK_INCLUDE_INFERIORS;
02736   if(sheet->xor_gc)
02737     gdk_gc_unref(sheet->xor_gc);
02738   sheet->xor_gc = gdk_gc_new_with_values (widget->window,
02739                       &values,
02740                       GDK_GC_FOREGROUND |
02741                       GDK_GC_FUNCTION |
02742                       GDK_GC_SUBWINDOW);
02743 
02744   if(sheet->sheet_entry->parent){
02745           gtk_widget_ref(sheet->sheet_entry);
02746           gtk_widget_unparent(sheet->sheet_entry);
02747   }
02748   gtk_widget_set_parent_window (sheet->sheet_entry, sheet->sheet_window);
02749   gtk_widget_set_parent(sheet->sheet_entry, GTK_WIDGET(sheet));
02750 
02751   if(sheet->button && sheet->button->parent){
02752           gtk_widget_ref(sheet->button);
02753           gtk_widget_unparent(sheet->button);
02754   }
02755   gtk_widget_set_parent_window(sheet->button, sheet->sheet_window);
02756   gtk_widget_set_parent(sheet->button, GTK_WIDGET(sheet));
02757 
02758 /*
02759   gtk_sheet_activate_cell(sheet, sheet->active_cell.row, sheet->active_cell.col);
02760 */
02761   if(!sheet->cursor_drag)
02762        sheet->cursor_drag = gdk_cursor_new(GDK_PLUS);
02763  
02764   if(sheet->column_titles_visible)
02765      gdk_window_show(sheet->column_title_window);
02766   if(sheet->row_titles_visible)
02767      gdk_window_show(sheet->row_title_window);
02768 
02769   size_allocate_row_title_buttons(sheet);
02770   size_allocate_column_title_buttons(sheet);
02771 
02772   name = g_strdup(sheet->name);
02773   gtk_sheet_set_title(sheet, name);
02774 
02775   g_free(name);
02776 
02777   children = sheet->children;
02778   while(children)
02779     {
02780       child = children->data;
02781       children = g_list_next(children);
02782  
02783       gtk_sheet_realize_child(sheet, child);
02784     }
02785 }
02786 
02787 static void
02788 create_global_button(GtkSheet *sheet)
02789 {
02790    sheet->button = gtk_button_new_with_label(" ");
02791 
02792    gtk_signal_connect (GTK_OBJECT (sheet->button),
02793               "pressed",
02794               (GtkSignalFunc) global_button_clicked,
02795               (gpointer) sheet);
02796 }
02797 
02798 static void
02799 size_allocate_global_button(GtkSheet *sheet)
02800 {
02801   GtkAllocation allocation;
02802 
02803   if(!sheet->column_titles_visible) return;
02804   if(!sheet->row_titles_visible) return;
02805 
02806   gtk_widget_size_request(sheet->button, NULL);
02807 
02808   allocation.x=0;
02809   allocation.y=0;
02810   allocation.width=sheet->row_title_area.width;
02811   allocation.height=sheet->column_title_area.height;
02812 
02813   gtk_widget_size_allocate(sheet->button, &allocation);
02814   gtk_widget_show(sheet->button);
02815 }
02816 
02817 static void
02818 global_button_clicked(GtkWidget *widget, gpointer data)
02819 {
02820   gboolean veto;
02821 
02822   gtk_sheet_click_cell(GTK_SHEET(data), -1, -1, &veto);
02823   gtk_widget_grab_focus(GTK_WIDGET(data));
02824 }
02825 
02826 
02827 static void
02828 gtk_sheet_unrealize (GtkWidget * widget)
02829 {
02830   GtkSheet *sheet;
02831 
02832   g_return_if_fail (widget != NULL);
02833   g_return_if_fail (GTK_IS_SHEET (widget));
02834 
02835   sheet = GTK_SHEET (widget);
02836 
02837   gdk_cursor_destroy (sheet->cursor_drag);
02838 
02839   gdk_gc_destroy (sheet->xor_gc);
02840   gdk_gc_destroy (sheet->fg_gc);
02841   gdk_gc_destroy (sheet->bg_gc);
02842 
02843   gdk_window_destroy (sheet->sheet_window);
02844   gdk_window_destroy (sheet->column_title_window);
02845   gdk_window_destroy (sheet->row_title_window);
02846 
02847   if (sheet->pixmap){
02848     g_object_unref (sheet->pixmap);
02849     sheet->pixmap = NULL;
02850   }
02851 
02852   sheet->column_title_window=NULL;
02853   sheet->sheet_window = NULL;
02854   sheet->cursor_drag = NULL;
02855   sheet->xor_gc = NULL;
02856   sheet->fg_gc = NULL;
02857   sheet->bg_gc = NULL;
02858 
02859   if (GTK_WIDGET_CLASS (parent_class)->unrealize)
02860     (* GTK_WIDGET_CLASS (parent_class)->unrealize) (widget);
02861 }
02862 
02863 static void
02864 gtk_sheet_map (GtkWidget * widget)
02865 {
02866   GtkSheet *sheet;
02867   GtkSheetChild *child;
02868   GList *children;
02869 
02870   g_return_if_fail (widget != NULL);
02871   g_return_if_fail (GTK_IS_SHEET (widget));
02872 
02873   sheet = GTK_SHEET (widget);
02874 
02875   if (!GTK_WIDGET_MAPPED (widget))
02876     {
02877       GTK_WIDGET_SET_FLAGS (widget, GTK_MAPPED);
02878 
02879       if(!sheet->cursor_drag) sheet->cursor_drag=gdk_cursor_new(GDK_PLUS);
02880 
02881       gdk_window_show (widget->window);
02882 
02883       gdk_window_show (sheet->sheet_window);
02884 
02885       if(sheet->column_titles_visible){
02886            gdk_window_show (sheet->column_title_window);
02887       }
02888       if(sheet->row_titles_visible){
02889            gdk_window_show (sheet->row_title_window);
02890       }
02891 
02892       if(!GTK_WIDGET_MAPPED (sheet->sheet_entry)){
02893                   gtk_widget_show (sheet->sheet_entry);
02894               gtk_widget_map (sheet->sheet_entry);
02895       }
02896 
02897       if (GTK_WIDGET_VISIBLE (sheet->button) &&
02898       !GTK_WIDGET_MAPPED (sheet->button)){
02899                   gtk_widget_show(sheet->button);
02900               gtk_widget_map (sheet->button);
02901       }
02902 
02903       if(GTK_BIN(sheet->button)->child)
02904         if (GTK_WIDGET_VISIBLE (GTK_BIN(sheet->button)->child) &&
02905        !GTK_WIDGET_MAPPED (GTK_BIN(sheet->button)->child))
02906               gtk_widget_map (GTK_BIN(sheet->button)->child);
02907 
02908       gtk_sheet_range_draw(sheet, NULL);
02909       gtk_sheet_activate_cell(sheet, 
02910                               sheet->active_cell.row, 
02911                               sheet->active_cell.col);
02912 
02913       children = sheet->children;
02914       while (children)
02915       {
02916         child = children->data;
02917         children = g_list_next(children);
02918 
02919         if (GTK_WIDGET_VISIBLE (child->widget) &&
02920             !GTK_WIDGET_MAPPED (child->widget)){
02921       gtk_widget_map (child->widget);
02922           gtk_sheet_position_child(sheet, child);
02923         }
02924       }
02925 
02926     }
02927 }
02928 
02929 static void
02930 gtk_sheet_unmap (GtkWidget * widget)
02931 {
02932   GtkSheet *sheet;
02933   GtkSheetChild *child;
02934   GList *children;
02935 
02936   g_return_if_fail (widget != NULL);
02937   g_return_if_fail (GTK_IS_SHEET (widget));
02938 
02939   sheet = GTK_SHEET (widget);
02940 
02941   if (GTK_WIDGET_MAPPED (widget))
02942     {
02943       GTK_WIDGET_UNSET_FLAGS (widget, GTK_MAPPED);
02944 
02945       gdk_window_hide (sheet->sheet_window);
02946       if(sheet->column_titles_visible)
02947           gdk_window_hide (sheet->column_title_window);
02948       if(sheet->row_titles_visible)
02949           gdk_window_hide (sheet->row_title_window);
02950       gdk_window_hide (widget->window);
02951 
02952       if (GTK_WIDGET_MAPPED (sheet->sheet_entry))
02953     gtk_widget_unmap (sheet->sheet_entry);
02954 
02955       if (GTK_WIDGET_MAPPED (sheet->button))
02956     gtk_widget_unmap (sheet->button);
02957 
02958       children = sheet->children;
02959       while (children)
02960         {
02961           child = children->data;
02962           children = g_list_next(children);
02963 
02964           if (GTK_WIDGET_VISIBLE (child->widget) &&
02965           GTK_WIDGET_MAPPED (child->widget))
02966                 {
02967                  gtk_widget_unmap (child->widget);
02968                 }
02969         }
02970 
02971     }
02972 }
02973 
02974 
02975 static void
02976 gtk_sheet_cell_draw_default (GtkSheet *sheet, gint row, gint col)
02977 {
02978   GtkWidget *widget;
02979   GdkGC *fg_gc, *bg_gc;
02980   GtkSheetCellAttr attributes;
02981   GdkRectangle area;
02982 
02983   g_return_if_fail (sheet != NULL);
02984 
02985   /* bail now if we arn't drawable yet */
02986   if (!GTK_WIDGET_DRAWABLE (sheet)) return;
02987 
02988   if (row < 0 || row > sheet->maxrow) return;
02989   if (col < 0 || col > sheet->maxcol) return;
02990   if (!sheet->column[col].is_visible) return;
02991   if (!sheet->row[row].is_visible) return;
02992 
02993   widget = GTK_WIDGET (sheet);
02994 
02995   gtk_sheet_get_attributes(sheet, row, col, &attributes);
02996  
02997   /* select GC for background rectangle */
02998   gdk_gc_set_foreground (sheet->fg_gc, &attributes.foreground);
02999   gdk_gc_set_foreground (sheet->bg_gc, &attributes.background);
03000 
03001   fg_gc = sheet->fg_gc;
03002   bg_gc = sheet->bg_gc;
03003 
03004   area.x=COLUMN_LEFT_XPIXEL(sheet,col);
03005   area.y=ROW_TOP_YPIXEL(sheet,row);
03006   area.width=sheet->column[col].width;
03007   area.height=sheet->row[row].height;
03008 
03009   gdk_draw_rectangle (sheet->pixmap,
03010                   bg_gc,
03011                   TRUE,
03012                   area.x,
03013                       area.y,
03014                   area.width,
03015                       area.height);
03016 
03017   gdk_gc_set_line_attributes (sheet->fg_gc, 1, 0, 0, 0);
03018 
03019   if(sheet->show_grid){
03020     gdk_gc_set_foreground (sheet->bg_gc, &sheet->grid_color);
03021 
03022     gdk_draw_rectangle (sheet->pixmap,
03023                         sheet->bg_gc,
03024                         FALSE,
03025                     area.x, area.y,
03026                     area.width, area.height);
03027   }
03028 }
03029 
03030 static void
03031 gtk_sheet_cell_draw_border (GtkSheet *sheet, gint row, gint col, gint mask)
03032 {
03033   GtkWidget *widget;
03034   GdkGC *fg_gc, *bg_gc;
03035   GtkSheetCellAttr attributes;
03036   GdkRectangle area;
03037   guint width;
03038 
03039   g_return_if_fail (sheet != NULL);
03040 
03041   /* bail now if we arn't drawable yet */
03042   if (!GTK_WIDGET_DRAWABLE (sheet)) return;
03043 
03044   if (row < 0 || row > sheet->maxrow) return;
03045   if (col < 0 || col > sheet->maxcol) return;
03046   if (!sheet->column[col].is_visible) return;
03047   if (!sheet->row[row].is_visible) return;
03048 
03049   widget = GTK_WIDGET (sheet);
03050 
03051   gtk_sheet_get_attributes(sheet, row, col, &attributes);
03052 
03053   /* select GC for background rectangle */
03054   gdk_gc_set_foreground (sheet->fg_gc, &attributes.border.color);
03055   gdk_gc_set_foreground (sheet->bg_gc, &attributes.background);
03056 
03057   fg_gc = sheet->fg_gc;
03058   bg_gc = sheet->bg_gc;
03059 
03060   area.x=COLUMN_LEFT_XPIXEL(sheet,col);
03061   area.y=ROW_TOP_YPIXEL(sheet,row);
03062   area.width=sheet->column[col].width;
03063   area.height=sheet->row[row].height;
03064 
03065   width = attributes.border.width;
03066   gdk_gc_set_line_attributes(sheet->fg_gc, attributes.border.width,
03067                                            attributes.border.line_style,
03068                                            attributes.border.cap_style,
03069                                            attributes.border.join_style);
03070   if(width>0){
03071 
03072    if(attributes.border.mask & GTK_SHEET_LEFT_BORDER & mask)
03073       gdk_draw_line(sheet->pixmap, sheet->fg_gc,
03074                     area.x, area.y-width/2,
03075                     area.x, area.y+area.height+width/2+1);
03076 
03077    if(attributes.border.mask & GTK_SHEET_RIGHT_BORDER & mask)
03078       gdk_draw_line(sheet->pixmap, sheet->fg_gc,
03079                     area.x+area.width, area.y-width/2,
03080                     area.x+area.width, 
03081                     area.y+area.height+width/2+1);
03082 
03083    if(attributes.border.mask & GTK_SHEET_TOP_BORDER & mask)
03084       gdk_draw_line(sheet->pixmap, sheet->fg_gc,
03085                     area.x-width/2,area.y,
03086                     area.x+area.width+width/2+1, 
03087                     area.y);
03088 
03089    if(attributes.border.mask & GTK_SHEET_BOTTOM_BORDER & mask)
03090       gdk_draw_line(sheet->pixmap, sheet->fg_gc,
03091                     area.x-width/2, area.y+area.height,
03092                     area.x+area.width+width/2+1, 
03093                     area.y+area.height);
03094   }
03095 
03096 }
03097 
03098 
03099 static void
03100 gtk_sheet_cell_draw_label (GtkSheet *sheet, gint row, gint col)
03101 {
03102   GtkWidget *widget;
03103   GdkRectangle area, clip_area;
03104   gint i;
03105   gint text_width, text_height, y;
03106   gint xoffset=0;  
03107   gint size, sizel, sizer;
03108   GdkGC *fg_gc, *bg_gc;
03109   GtkSheetCellAttr attributes;
03110   PangoLayout *layout;
03111   PangoRectangle rect;
03112   PangoRectangle logical_rect;
03113   PangoLayoutLine *line;
03114   PangoFontMetrics *metrics;
03115   PangoContext *context = gtk_widget_get_pango_context(GTK_WIDGET(sheet)); 
03116   gint ascent, descent, y_pos;
03117 
03118   char *label;
03119 
03120   g_return_if_fail (sheet != NULL);
03121 
03122    /* bail now if we aren't drawable yet */
03123    if (!GTK_WIDGET_DRAWABLE (sheet))
03124     return;
03125 
03126   if (row > sheet->maxallocrow) return;
03127   if (col > sheet->maxalloccol) return;
03128   if (!sheet->data[row]) return;
03129   if (!sheet->data[row][col]) return;
03130   if (!sheet->data[row][col]->text || strlen(sheet->data[row][col]->text)==0)
03131       return;
03132 
03133   if (row < 0 || row > sheet->maxrow) return;
03134   if (col < 0 || col > sheet->maxcol) return;
03135   if (!sheet->column[col].is_visible) return;
03136   if (!sheet->row[row].is_visible) return;
03137 
03138 
03139   widget = GTK_WIDGET(sheet);
03140 
03141   label = sheet->data[row][col]->text;
03142 
03143   gtk_sheet_get_attributes(sheet, row, col, &attributes);
03144 
03145   /* select GC for background rectangle */
03146   gdk_gc_set_foreground (sheet->fg_gc, &attributes.foreground);
03147   gdk_gc_set_foreground (sheet->bg_gc, &attributes.background);
03148 
03149   fg_gc = sheet->fg_gc;
03150   bg_gc = sheet->bg_gc;
03151 
03152   area.x=COLUMN_LEFT_XPIXEL(sheet,col);
03153   area.y=ROW_TOP_YPIXEL(sheet,row);
03154   area.width=sheet->column[col].width;
03155   area.height=sheet->row[row].height;
03156 
03157   clip_area = area;
03158 
03159   layout = gtk_widget_create_pango_layout (GTK_WIDGET(sheet), label);
03160   pango_layout_set_font_description (layout, attributes.font_desc);
03161 
03162   pango_layout_get_pixel_extents (layout, NULL, &rect);
03163 
03164   line = pango_layout_get_lines (layout)->data;
03165   pango_layout_line_get_extents (line, NULL, &logical_rect);
03166 
03167   metrics = pango_context_get_metrics(context,
03168                                   attributes.font_desc,
03169                                   pango_context_get_language(context)); 
03170 
03171   ascent = pango_font_metrics_get_ascent(metrics) / PANGO_SCALE;
03172   descent = pango_font_metrics_get_descent(metrics) / PANGO_SCALE;
03173 
03174   pango_font_metrics_unref(metrics);
03175 
03176   /* Align primarily for locale's ascent/descent */
03177 
03178   logical_rect.height /= PANGO_SCALE;
03179   logical_rect.y /= PANGO_SCALE;
03180   y_pos =  area.height - logical_rect.height;
03181 
03182   if (logical_rect.height > area.height)
03183     y_pos = (logical_rect.height - area.height - 2*CELLOFFSET) / 2;
03184   else if (y_pos < 0)
03185     y_pos = 0;
03186   else if (y_pos + logical_rect.height > area.height)
03187     y_pos = area.height - logical_rect.height;
03188 
03189   text_width = rect.width;
03190   text_height = rect.height;
03191   y = area.y + y_pos - CELLOFFSET;
03192 
03193   switch(attributes.justification){
03194     case GTK_JUSTIFY_RIGHT:
03195           size=area.width;
03196           area.x+=area.width;
03197           if(!gtk_sheet_clip_text(sheet)){          
03198            for(i=col-1; i>=MIN_VISIBLE_COLUMN(sheet); i--){
03199              if(gtk_sheet_cell_get_text(sheet, row, i)) break;
03200              if(size>=text_width+CELLOFFSET) break;
03201              size+=sheet->column[i].width;
03202              sheet->column[i].right_text_column = MAX(col, sheet->column[i].right_text_column);
03203            }
03204            area.width=size;
03205           }
03206           area.x-=size;
03207           xoffset+=area.width-text_width - 2 * CELLOFFSET -
03208                    attributes.border.width/2;
03209           break;
03210      case GTK_JUSTIFY_CENTER:
03211           sizel=area.width/2;
03212           sizer=area.width/2;
03213       area.x+=area.width/2;
03214           if(!gtk_sheet_clip_text(sheet)){          
03215            for(i=col+1; i<=MAX_VISIBLE_COLUMN(sheet); i++){
03216              if(gtk_sheet_cell_get_text(sheet, row, i)) break;
03217              if(sizer>=text_width/2) break;
03218              sizer+=sheet->column[i].width;
03219              sheet->column[i].left_text_column = MIN(col, sheet->column[i].left_text_column);
03220            }
03221            for(i=col-1; i>=MIN_VISIBLE_COLUMN(sheet); i--){
03222              if(gtk_sheet_cell_get_text(sheet, row, i)) break;
03223              if(sizel>=text_width/2) break;
03224              sizel+=sheet->column[i].width;
03225              sheet->column[i].right_text_column = MAX(col, sheet->column[i].right_text_column);
03226            }
03227            size=MIN(sizel, sizer);
03228           }
03229       area.x-=sizel;
03230           xoffset+= sizel - text_width/2 - CELLOFFSET;
03231       area.width=sizel+sizer;
03232           break;
03233       case GTK_JUSTIFY_LEFT:
03234       default:
03235           size=area.width;
03236           if(!gtk_sheet_clip_text(sheet)){          
03237            for(i=col+1; i<=MAX_VISIBLE_COLUMN(sheet); i++){
03238              if(gtk_sheet_cell_get_text(sheet, row, i)) break;
03239              if(size>=text_width+CELLOFFSET) break;
03240              size+=sheet->column[i].width;
03241              sheet->column[i].left_text_column = MIN(col, sheet->column[i].left_text_column);
03242            }
03243            area.width=size;
03244           }
03245           xoffset += attributes.border.width/2;
03246           break;
03247    }
03248 
03249   if(!gtk_sheet_clip_text(sheet)) clip_area = area;
03250   gdk_gc_set_clip_rectangle(fg_gc, &clip_area);
03251 
03252 
03253   gdk_draw_layout (sheet->pixmap, fg_gc,
03254                    area.x + xoffset + CELLOFFSET,
03255            y,
03256                    layout);
03257 
03258   gdk_gc_set_clip_rectangle(fg_gc, NULL);
03259   g_object_unref(G_OBJECT(layout));
03260 
03261   gdk_draw_pixmap(sheet->sheet_window,
03262                   GTK_WIDGET(sheet)->style->fg_gc[GTK_STATE_NORMAL],
03263                   sheet->pixmap,
03264                   area.x,
03265                   area.y,
03266                   area.x,
03267                   area.y,
03268                   area.width,
03269                   area.height);      
03270 
03271 }
03272 
03273 
03274 
03275 static void
03276 gtk_sheet_range_draw(GtkSheet *sheet, const GtkSheetRange *range)
03277 {
03278  gint i,j;
03279  GtkSheetRange drawing_range;
03280  GdkRectangle area;
03281 
03282  g_return_if_fail(sheet != NULL);
03283  g_return_if_fail(GTK_SHEET(sheet));
03284  
03285  if(!GTK_WIDGET_DRAWABLE(GTK_WIDGET(sheet))) return;
03286  if(!GTK_WIDGET_REALIZED(GTK_WIDGET(sheet))) return;
03287  if(!GTK_WIDGET_MAPPED(GTK_WIDGET(sheet))) return;
03288 
03289  if(range == NULL)
03290  {
03291    drawing_range.row0=MIN_VISIBLE_ROW(sheet);
03292    drawing_range.col0=MIN_VISIBLE_COLUMN(sheet);
03293    drawing_range.rowi=MAX_VISIBLE_ROW(sheet);
03294    drawing_range.coli=MAX_VISIBLE_COLUMN(sheet);
03295 /*
03296    gdk_draw_rectangle (sheet->pixmap,
03297                    GTK_WIDGET(sheet)->style->white_gc,
03298                    TRUE,
03299                    0,0,
03300                    sheet->sheet_window_width,sheet->sheet_window_height);
03301 */
03302  }
03303  else
03304  {
03305    drawing_range.row0=MAX(range->row0, MIN_VISIBLE_ROW(sheet));
03306    drawing_range.col0=MAX(range->col0, MIN_VISIBLE_COLUMN(sheet));
03307    drawing_range.rowi=MIN(range->rowi, MAX_VISIBLE_ROW(sheet));
03308    drawing_range.coli=MIN(range->coli, MAX_VISIBLE_COLUMN(sheet));
03309  }
03310 
03311  if(drawing_range.coli == sheet->maxcol){
03312   area.x=COLUMN_LEFT_XPIXEL(sheet,sheet->maxcol)+
03313          sheet->column[sheet->maxcol].width+1;
03314   area.y=0;
03315 
03316   gdk_gc_set_foreground(sheet->fg_gc, &sheet->bg_color);
03317 
03318   gdk_draw_rectangle (sheet->pixmap,
03319                   sheet->fg_gc,
03320                   TRUE,
03321                   area.x,area.y,
03322                   sheet->sheet_window_width - area.x, 
03323                       sheet->sheet_window_height);
03324 
03325   gdk_draw_pixmap(sheet->sheet_window,
03326                   GTK_WIDGET(sheet)->style->fg_gc[GTK_STATE_NORMAL],
03327                   sheet->pixmap,
03328                   area.x,
03329                   area.y,
03330                   area.x,
03331                   area.y,
03332               sheet->sheet_window_width - area.x, 
03333                   sheet->sheet_window_height);                  
03334  }
03335  if(drawing_range.rowi == sheet->maxrow){
03336   area.x=0;
03337   area.y=ROW_TOP_YPIXEL(sheet,sheet->maxrow)+sheet->row[sheet->maxrow].height+1;
03338 
03339   gdk_gc_set_foreground(sheet->fg_gc, &sheet->bg_color);
03340 
03341   gdk_draw_rectangle (sheet->pixmap,
03342                   sheet->fg_gc,
03343                   TRUE,
03344                   area.x,area.y,
03345                   sheet->sheet_window_width,
03346                       sheet->sheet_window_height - area.y);
03347 
03348   gdk_draw_pixmap(sheet->sheet_window,
03349                   GTK_WIDGET(sheet)->style->fg_gc[GTK_STATE_NORMAL],
03350                   sheet->pixmap,
03351                   area.x,
03352                   area.y,
03353                   area.x,
03354                   area.y,
03355                   sheet->sheet_window_width,
03356                   sheet->sheet_window_height - area.y);
03357  }
03358 
03359  for(i=drawing_range.row0; i<=drawing_range.rowi; i++)
03360   for(j=drawing_range.col0; j<=drawing_range.coli; j++){
03361      gtk_sheet_cell_draw_default(sheet, i, j);
03362   }
03363 
03364  for(i=drawing_range.row0; i<=drawing_range.rowi; i++)
03365   for(j=drawing_range.col0; j<=drawing_range.coli; j++){
03366      gtk_sheet_cell_draw_border(sheet, i-1, j, GTK_SHEET_BOTTOM_BORDER);
03367      gtk_sheet_cell_draw_border(sheet, i+1, j, GTK_SHEET_TOP_BORDER);
03368      gtk_sheet_cell_draw_border(sheet, i, j-1, GTK_SHEET_RIGHT_BORDER);
03369      gtk_sheet_cell_draw_border(sheet, i, j+1, GTK_SHEET_LEFT_BORDER);
03370      gtk_sheet_cell_draw_border(sheet, i, j, 15);
03371   }
03372 
03373  for(i=drawing_range.row0; i<=drawing_range.rowi; i++)
03374   for(j=drawing_range.col0; j<=drawing_range.coli; j++)
03375      if(i<=sheet->maxallocrow && j<=sheet->maxalloccol &&
03376         sheet->data[i] && sheet->data[i][j])
03377                   gtk_sheet_cell_draw_label (sheet, i, j);
03378      
03379  for(i=drawing_range.row0; i<=drawing_range.rowi; i++)
03380   for(j=sheet->column[drawing_range.col0].left_text_column; j<drawing_range.col0; j++)
03381      if(i<=sheet->maxallocrow && j<=sheet->maxalloccol && 
03382         sheet->data[i] && sheet->data[i][j])
03383                   gtk_sheet_cell_draw_label (sheet, i, j);
03384     
03385  for(i=drawing_range.row0; i<=drawing_range.rowi; i++)
03386   for(j=drawing_range.coli+1; j<=sheet->column[drawing_range.coli].right_text_column; j++)
03387      if(i<=sheet->maxallocrow && j<=sheet->maxalloccol && 
03388         sheet->data[i] && sheet->data[i][j])
03389                   gtk_sheet_cell_draw_label (sheet, i, j); 
03390 
03391   gtk_sheet_draw_backing_pixmap(sheet, drawing_range);
03392 
03393   if(sheet->state != GTK_SHEET_NORMAL && gtk_sheet_range_isvisible(sheet, sheet->range))
03394        gtk_sheet_range_draw_selection(sheet, drawing_range);
03395   
03396   if(sheet->state == GTK_STATE_NORMAL && 
03397      sheet->active_cell.row >= drawing_range.row0 &&
03398      sheet->active_cell.row <= drawing_range.rowi &&
03399      sheet->active_cell.col >= drawing_range.col0 &&
03400      sheet->active_cell.col <= drawing_range.coli)    
03401                             gtk_sheet_show_active_cell(sheet);
03402 
03403 }
03404 
03405 static void
03406 gtk_sheet_range_draw_selection(GtkSheet *sheet, GtkSheetRange range)
03407 {
03408   GdkRectangle area;
03409   gint i,j;
03410   GtkSheetRange aux;
03411 
03412   if(range.col0 > sheet->range.coli || range.coli < sheet->range.col0 ||
03413      range.row0 > sheet->range.rowi || range.rowi < sheet->range.row0)
03414      return;
03415 
03416   if(!gtk_sheet_range_isvisible(sheet, range)) return;
03417   if(!GTK_WIDGET_REALIZED(GTK_WIDGET(sheet))) return;
03418 
03419   aux=range;
03420 
03421   range.col0=MAX(sheet->range.col0, range.col0);
03422   range.coli=MIN(sheet->range.coli, range.coli);
03423   range.row0=MAX(sheet->range.row0, range.row0);
03424   range.rowi=MIN(sheet->range.rowi, range.rowi);
03425 
03426   range.col0=MAX(range.col0, MIN_VISIBLE_COLUMN(sheet));
03427   range.coli=MIN(range.coli, MAX_VISIBLE_COLUMN(sheet));
03428   range.row0=MAX(range.row0, MIN_VISIBLE_ROW(sheet));
03429   range.rowi=MIN(range.rowi, MAX_VISIBLE_ROW(sheet));
03430 
03431   for(i=range.row0; i<=range.rowi; i++){
03432    for(j=range.col0; j<=range.coli; j++){
03433 
03434     if(gtk_sheet_cell_get_state(sheet, i, j)==GTK_STATE_SELECTED && 
03435        sheet->column[j].is_visible && sheet->row[i].is_visible){
03436 
03437       row_button_set(sheet, i);
03438       column_button_set(sheet, j);
03439 
03440       area.x=COLUMN_LEFT_XPIXEL(sheet,j);
03441       area.y=ROW_TOP_YPIXEL(sheet,i);
03442       area.width=sheet->column[j].width;
03443       area.height=sheet->row[i].height;
03444 
03445       if(i==sheet->range.row0){
03446             area.y=area.y+2;
03447             area.height=area.height-2;
03448       }
03449       if(i==sheet->range.rowi) area.height=area.height-3;
03450       if(j==sheet->range.col0){
03451             area.x=area.x+2;
03452             area.width=area.width-2;
03453       }
03454       if(j==sheet->range.coli) area.width=area.width-3;
03455 
03456       if(i!=sheet->active_cell.row || j!=sheet->active_cell.col){
03457        gdk_draw_rectangle (sheet->sheet_window,
03458                        sheet->xor_gc,
03459                    TRUE,
03460                        area.x+1,area.y+1,
03461                        area.width,area.height);
03462       }
03463     }
03464 
03465    }
03466   }
03467 
03468   gtk_sheet_draw_border(sheet, sheet->range);
03469 
03470 }
03471 
03472 static void
03473 gtk_sheet_draw_backing_pixmap(GtkSheet *sheet, GtkSheetRange range)
03474 {
03475   gint x,y,width,height;
03476 
03477   if(!GTK_WIDGET_REALIZED(GTK_WIDGET(sheet))) return;
03478  
03479   x=COLUMN_LEFT_XPIXEL(sheet,range.col0);
03480   y=ROW_TOP_YPIXEL(sheet, range.row0);  
03481   width=COLUMN_LEFT_XPIXEL(sheet, range.coli)-x+sheet->column[range.coli].width;
03482   height=ROW_TOP_YPIXEL(sheet, range.rowi)-y+sheet->row[range.rowi].height;
03483 
03484   if(range.row0==sheet->range.row0){
03485           y=y-5;
03486           height=height+5;
03487   }
03488   if(range.rowi==sheet->range.rowi) height=height+5;
03489   if(range.col0==sheet->range.col0){
03490             x=x-5;
03491             width=width+5;
03492   }
03493   if(range.coli==sheet->range.coli) width=width+5;
03494 
03495   
03496   width=MIN(width, sheet->sheet_window_width-x);
03497   height=MIN(height, sheet->sheet_window_height-y);
03498 
03499   x--; 
03500   y--;
03501   width+=2;
03502   height+=2;
03503 
03504   x = (sheet->row_titles_visible)
03505        ? MAX(x, sheet->row_title_area.width) : MAX(x, 0);
03506   y = (sheet->column_titles_visible)
03507        ? MAX(y, sheet->column_title_area.height) : MAX(y, 0);
03508 
03509   if(range.coli==sheet->maxcol) width=sheet->sheet_window_width-x;
03510   if(range.rowi==sheet->maxrow) height=sheet->sheet_window_height-y;
03511 
03512   gdk_draw_pixmap(sheet->sheet_window,
03513                   GTK_WIDGET(sheet)->style->fg_gc[GTK_STATE_NORMAL],
03514                   sheet->pixmap,
03515                   x,
03516                   y,
03517                   x,
03518                   y,
03519                   width+1,
03520                   height+1);                  
03521 }
03522 
03523 static GtkSheetCell *
03524 gtk_sheet_cell_new()
03525 {
03526  GtkSheetCell *cell;
03527  cell = g_new(GtkSheetCell, 1);
03528  cell->text = NULL;
03529  cell->link = NULL;
03530  cell->attributes = NULL;
03531  return cell;
03532 }
03533 
03534 void 
03535 gtk_sheet_set_cell_text(GtkSheet *sheet, gint row, gint col, const gchar *text)
03536 {
03537  GtkSheetCellAttr attributes;
03538 
03539  g_return_if_fail (sheet != NULL);
03540  g_return_if_fail (GTK_IS_SHEET (sheet));
03541  if (col > sheet->maxcol || row > sheet->maxrow) return;
03542  if (col < 0 || row < 0) return;
03543 
03544  gtk_sheet_get_attributes(sheet, row, col, &attributes);
03545  gtk_sheet_set_cell(sheet, row, col, attributes.justification, text);
03546 }
03547 
03548 void 
03549 gtk_sheet_set_cell(GtkSheet *sheet, gint row, gint col, 
03550                    GtkJustification justification,
03551                    const gchar *text)
03552 {
03553  GtkSheetCell **cell;
03554  GtkSheetRange range;
03555  gint text_width;
03556  GtkSheetCellAttr attributes;
03557 
03558  g_return_if_fail (sheet != NULL);
03559  g_return_if_fail (GTK_IS_SHEET (sheet));
03560  if (col > sheet->maxcol || row > sheet->maxrow) return;
03561  if (col < 0 || row < 0) return;
03562 
03563  CheckBounds(sheet, row, col);
03564 
03565  cell=&sheet->data[row][col];
03566 
03567  if(*cell==NULL)
03568   (*cell) = gtk_sheet_cell_new();
03569 
03570  gtk_sheet_get_attributes(sheet, row, col, &attributes);
03571 
03572  (*cell)->row = row;
03573  (*cell)->col = col;
03574 
03575  attributes.justification = justification;
03576  gtk_sheet_set_cell_attributes(sheet, row, col, attributes);
03577 
03578  if((*cell)->text){
03579     g_free((*cell)->text);
03580     (*cell)->text = NULL;
03581  }
03582 
03583  if(text) 
03584       (*cell)->text=g_strdup(text);
03585 
03586  if(attributes.is_visible){
03587 
03588    text_width = 0;
03589    if((*cell)->text && strlen((*cell)->text) > 0) {
03590      text_width = STRING_WIDTH(GTK_WIDGET(sheet), attributes.font_desc, (*cell)->text);
03591    }
03592 
03593    range.row0 = row;
03594    range.rowi = row;
03595    range.col0 = sheet->view.col0;
03596    range.coli = sheet->view.coli;
03597 
03598    if(gtk_sheet_autoresize(sheet) &&
03599       text_width > sheet->column[col].width-2*CELLOFFSET-attributes.border.width){
03600       gtk_sheet_set_column_width(sheet, col, text_width+2*CELLOFFSET+attributes.border.width);
03601       GTK_SHEET_SET_FLAGS(sheet, GTK_SHEET_REDRAW_PENDING);
03602    }
03603    else
03604      if(!GTK_SHEET_IS_FROZEN(sheet))
03605        gtk_sheet_range_draw(sheet, &range);
03606  }
03607  gtk_signal_emit(GTK_OBJECT(sheet),sheet_signals[CHANGED], row, col);
03608 
03609 
03610 }
03611 
03612 void
03613 gtk_sheet_cell_clear (GtkSheet *sheet, gint row, gint column)
03614 {
03615   GtkSheetRange range;
03616 
03617   g_return_if_fail (sheet != NULL);
03618   g_return_if_fail (GTK_IS_SHEET (sheet));
03619   if (column > sheet->maxcol || row > sheet->maxrow) return;
03620   if (column > sheet->maxalloccol || row > sheet->maxallocrow) return;
03621   if (column < 0 || row < 0) return;
03622 
03623   range.row0 = row;
03624   range.rowi = row;
03625   range.col0 = sheet->view.col0;
03626   range.coli = sheet->view.coli;
03627 
03628   gtk_sheet_real_cell_clear(sheet, row, column, FALSE);
03629 
03630   if(!GTK_SHEET_IS_FROZEN(sheet)){
03631      gtk_sheet_range_draw(sheet, &range);
03632   }
03633 }
03634 
03635 void
03636 gtk_sheet_cell_delete (GtkSheet *sheet, gint row, gint column)
03637 {
03638   GtkSheetRange range;
03639 
03640   g_return_if_fail (sheet != NULL);
03641   g_return_if_fail (GTK_IS_SHEET (sheet));
03642   if (column > sheet->maxcol || row > sheet->maxrow) return;
03643   if (column > sheet->maxalloccol || row > sheet->maxallocrow) return;
03644   if (column < 0 || row < 0) return;
03645 
03646   range.row0 = row;
03647   range.rowi = row;
03648   range.col0 = sheet->view.col0;
03649   range.coli = sheet->view.coli;
03650 
03651   gtk_sheet_real_cell_clear(sheet, row, column, TRUE);
03652 
03653   if(!GTK_SHEET_IS_FROZEN(sheet)){
03654      gtk_sheet_range_draw(sheet, &range);
03655   }
03656 }
03657 
03658 static void
03659 gtk_sheet_real_cell_clear (GtkSheet *sheet, gint row, gint column, gboolean delete)
03660 {
03661   gchar *text;
03662   gpointer link;
03663 
03664   if(row > sheet->maxallocrow || column > sheet->maxalloccol) return;
03665   if(!sheet->data[row]) return;
03666   if(!sheet->data[row][column]) return;
03667 
03668   text = gtk_sheet_cell_get_text(sheet, row, column); 
03669   link = gtk_sheet_get_link(sheet, row, column); 
03670 
03671   if(text){ 
03672     g_free(sheet->data[row][column]->text);
03673     sheet->data[row][column]->text = NULL;
03674 
03675     if(GTK_IS_OBJECT(sheet) && G_OBJECT(sheet)->ref_count > 0)
03676       gtk_signal_emit(GTK_OBJECT(sheet),sheet_signals[CLEAR_CELL], row, column);
03677 
03678     sheet_head->CHANGED = 1;
03679   }  
03680 
03681   if(delete){ 
03682      if(sheet->data[row][column]->attributes){
03683          g_free(sheet->data[row][column]->attributes);
03684          sheet->data[row][column]->attributes = NULL;
03685      }
03686      sheet->data[row][column]->link = NULL;
03687 
03688      if(sheet->data[row][column]) g_free(sheet->data[row][column]);
03689 
03690      sheet->data[row][column] = NULL;
03691   }
03692 
03693 }
03694     
03695 void
03696 gtk_sheet_range_clear (GtkSheet *sheet, const GtkSheetRange *range)
03697 {
03698   g_return_if_fail (sheet != NULL);
03699   g_return_if_fail (GTK_IS_SHEET (sheet));
03700 
03701   gtk_sheet_real_range_clear(sheet, range, FALSE);
03702 }
03703 
03704 void
03705 gtk_sheet_range_delete (GtkSheet *sheet, const GtkSheetRange *range)
03706 {
03707   g_return_if_fail (sheet != NULL);
03708   g_return_if_fail (GTK_IS_SHEET (sheet));
03709 
03710   gtk_sheet_real_range_clear(sheet, range, TRUE);
03711 }
03712  
03713 static void
03714 gtk_sheet_real_range_clear (GtkSheet *sheet, const GtkSheetRange *range, 
03715                             gboolean delete)
03716 {
03717   gint i, j;
03718   GtkSheetRange clear;
03719 
03720   if(!range){
03721     clear.row0=0;
03722     clear.rowi=sheet->maxallocrow;
03723     clear.col0=0;
03724     clear.coli=sheet->maxalloccol;
03725   }else
03726     clear=*range;  
03727 
03728   clear.row0=MAX(clear.row0, 0);
03729   clear.col0=MAX(clear.col0, 0);
03730   clear.rowi=MIN(clear.rowi, sheet->maxallocrow);
03731   clear.coli=MIN(clear.coli, sheet->maxalloccol);
03732 
03733   for(i=clear.row0; i<=clear.rowi; i++)
03734     for(j=clear.col0; j<=clear.coli; j++){
03735         gtk_sheet_real_cell_clear(sheet, i, j, delete);
03736     }
03737 
03738   gtk_sheet_range_draw(sheet, NULL);
03739 }
03740 
03741 
03742 gchar *     
03743 gtk_sheet_cell_get_text (GtkSheet *sheet, gint row, gint col)
03744 {
03745   g_return_val_if_fail (sheet != NULL, NULL);
03746   g_return_val_if_fail (GTK_IS_SHEET (sheet), NULL);
03747 
03748   if(col > sheet->maxcol || row > sheet->maxrow) return NULL;
03749   if(col < 0 || row < 0) return NULL;
03750   if(row > sheet->maxallocrow || col > sheet->maxalloccol) return NULL;
03751   if(!sheet->data[row]) return NULL;
03752   if(!sheet->data[row][col]) return NULL;
03753   if(!sheet->data[row][col]->text) return NULL;
03754   if(strlen(sheet->data[row][col]->text) == 0) return NULL;
03755 
03756   return (sheet->data[row][col]->text);
03757 }
03758 
03759 void 
03760 gtk_sheet_link_cell(GtkSheet *sheet, gint row, gint col, gpointer link)
03761 {
03762  g_return_if_fail (sheet != NULL);
03763  g_return_if_fail (GTK_IS_SHEET (sheet));
03764  if(col > sheet->maxcol || row > sheet->maxrow) return;
03765  if(col < 0 || row < 0) return;
03766 
03767  if(row > sheet->maxallocrow || col > sheet->maxalloccol ||
03768     !sheet->data[row] || !sheet->data[row][col])
03769        gtk_sheet_set_cell_text(sheet, row, col, "");
03770 
03771  sheet->data[row][col]->link = link;
03772 }
03773 
03774 gpointer 
03775 gtk_sheet_get_link(GtkSheet *sheet, gint row, gint col)
03776 {
03777  g_return_val_if_fail (sheet != NULL, NULL);
03778  g_return_val_if_fail (GTK_IS_SHEET (sheet), NULL);
03779  if(col > sheet->maxcol || row > sheet->maxrow) return NULL;
03780  if(col < 0 || row < 0) return NULL;
03781 
03782  if (row > sheet->maxallocrow || col > sheet->maxalloccol) return NULL; 
03783  if (!sheet->data[row]) return NULL; /* Added by Chris Howell */ 
03784  if (!sheet->data[row][col]) return NULL; /* Added by Bob Lissner */ 
03785 
03786  return(sheet->data[row][col]->link);
03787 }
03788 
03789 void
03790 gtk_sheet_remove_link(GtkSheet *sheet, gint row, gint col)
03791 {
03792  g_return_if_fail (sheet != NULL);
03793  g_return_if_fail (GTK_IS_SHEET (sheet));
03794  if(col > sheet->maxcol || row > sheet->maxrow) return;
03795  if(col < 0 || row < 0) return;
03796  
03797  /* Fixed by Andreas Voegele */
03798  if(row < sheet->maxallocrow && col < sheet->maxalloccol &&
03799     sheet->data[row] && sheet->data[row][col] &&
03800     sheet->data[row][col]->link)
03801                             sheet->data[row][col]->link = NULL;
03802 }
03803 
03804 
03805 GtkStateType
03806 gtk_sheet_cell_get_state (GtkSheet *sheet, gint row, gint col)
03807 {
03808  gint state;
03809  GtkSheetRange *range;
03810 
03811  g_return_val_if_fail (sheet != NULL, 0);
03812  g_return_val_if_fail (GTK_IS_SHEET (sheet), 0);
03813  if(col > sheet->maxcol || row > sheet->maxrow) return 0;
03814  if(col < 0 || row < 0) return 0;
03815 
03816  state = sheet->state;
03817  range = &sheet->range;
03818 
03819  switch (state){
03820                 case GTK_SHEET_NORMAL:
03821                      return GTK_STATE_NORMAL;
03822              break;
03823         case GTK_SHEET_ROW_SELECTED:
03824                      if(row>=range->row0 && row<=range->rowi) 
03825                                         return GTK_STATE_SELECTED;
03826              break;
03827                 case GTK_SHEET_COLUMN_SELECTED:
03828                      if(col>=range->col0 && col<=range->coli) 
03829                                         return GTK_STATE_SELECTED;
03830              break;
03831         case GTK_SHEET_RANGE_SELECTED:
03832                      if(row >= range->row0 && row <= range->rowi && \
03833                         col >= range->col0 && col <= range->coli)
03834                                         return GTK_STATE_SELECTED;
03835              break;
03836  }
03837  return GTK_STATE_NORMAL;
03838 }
03839 
03840 gboolean
03841 gtk_sheet_get_pixel_info (GtkSheet * sheet,
03842               gint x,
03843               gint y,
03844               gint * row,
03845               gint * column)
03846 {
03847   gint trow, tcol;
03848 
03849   g_return_val_if_fail (sheet != NULL, 0);
03850   g_return_val_if_fail (GTK_IS_SHEET (sheet), 0);
03851 
03852   /* bounds checking, return false if the user clicked 
03853    * on a blank area */
03854   trow = ROW_FROM_YPIXEL (sheet, y);
03855   if (trow > sheet->maxrow)
03856     return FALSE;
03857 
03858   *row = trow;
03859 
03860   tcol = COLUMN_FROM_XPIXEL (sheet, x);
03861   if (tcol > sheet->maxcol)
03862     return FALSE;
03863 
03864  *column = tcol;
03865 
03866   return TRUE;
03867 }
03868 
03869 gboolean
03870 gtk_sheet_get_cell_area  (GtkSheet * sheet,
03871               gint row,
03872                           gint column,
03873               GdkRectangle *area)
03874 {
03875   g_return_val_if_fail (sheet != NULL, 0);
03876   g_return_val_if_fail (GTK_IS_SHEET (sheet), 0);
03877 
03878   if(row > sheet->maxrow || column > sheet->maxcol) return FALSE;
03879 
03880   area->x = (column == -1) ? 0 : (COLUMN_LEFT_XPIXEL(sheet, column) -
03881                                  (sheet->row_titles_visible
03882                                    ? sheet->row_title_area.width
03883                                    : 0));
03884   area->y = (row == -1) ? 0 : (ROW_TOP_YPIXEL(sheet, row) -
03885                               (sheet->column_titles_visible
03886                                ? sheet->column_title_area.height
03887                                : 0));
03888   area->width= (column == -1) ? sheet->row_title_area.width
03889                               : sheet->column[column].width;
03890   area->height= (row == -1) ? sheet->column_title_area.height
03891                             : sheet->row[row].height;
03892 
03893 /*
03894   if(row < 0 || column < 0) return FALSE;
03895 
03896   area->x = COLUMN_LEFT_XPIXEL(sheet, column);
03897   area->y = ROW_TOP_YPIXEL(sheet, row);
03898   if(sheet->row_titles_visible)
03899            area->x -= sheet->row_title_area.width;
03900   if(sheet->column_titles_visible)
03901            area->y -= sheet->column_title_area.height;
03902 
03903   area->width=sheet->column[column].width;
03904   area->height=sheet->row[row].height;  
03905 */
03906   return TRUE;
03907 }
03908 
03909 gboolean 
03910 gtk_sheet_set_active_cell (GtkSheet *sheet, gint row, gint column)
03911 {
03912  g_return_val_if_fail (sheet != NULL, 0);
03913  g_return_val_if_fail (GTK_IS_SHEET (sheet), 0);
03914 
03915  if(row < 0 || column < 0) return FALSE;
03916  if(row > sheet->maxrow || column > sheet->maxcol) return FALSE;
03917 
03918  if(GTK_WIDGET_REALIZED(GTK_WIDGET(sheet)))
03919    {
03920        if(!gtk_sheet_deactivate_cell(sheet)) return FALSE;
03921    }
03922 
03923  sheet->active_cell.row=row;
03924  sheet->active_cell.col=column;
03925  
03926  if(!gtk_sheet_activate_cell(sheet, row, column)) return FALSE;
03927  
03928  return TRUE;
03929 }
03930 
03931 void
03932 gtk_sheet_get_active_cell (GtkSheet *sheet, gint *row, gint *column)
03933 {
03934   g_return_if_fail (sheet != NULL);
03935   g_return_if_fail (GTK_IS_SHEET (sheet));
03936 
03937   *row = sheet->active_cell.row;
03938   *column = sheet->active_cell.col;
03939 }
03940 
03941 static void
03942 gtk_sheet_entry_changed(GtkWidget *widget, gpointer data)
03943 {
03944  GtkSheet *sheet;
03945  gint row,col;
03946  const char *text;
03947  GtkJustification justification;
03948  GtkSheetCellAttr attributes;
03949 
03950  g_return_if_fail (data != NULL);
03951  g_return_if_fail (GTK_IS_SHEET (data));
03952 
03953  sheet=GTK_SHEET(data);
03954 
03955  if(!GTK_WIDGET_VISIBLE(widget)) return;
03956  if(sheet->state != GTK_STATE_NORMAL) return;
03957 
03958  row=sheet->active_cell.row;
03959  col=sheet->active_cell.col;
03960 
03961  if(row<0 || col<0) return;
03962 
03963  sheet->active_cell.row=-1;
03964  sheet->active_cell.col=-1;
03965 
03966  text=gtk_entry_get_text(GTK_ENTRY(gtk_sheet_get_entry(sheet)));
03967 
03968  GTK_SHEET_SET_FLAGS(sheet, GTK_SHEET_IS_FROZEN);
03969 
03970  if(text && strlen(text)!=0){
03971       gtk_sheet_get_attributes(sheet, row, col, &attributes); 
03972       justification=attributes.justification;
03973       gtk_sheet_set_cell(sheet, row, col, justification, text);
03974  }
03975  else
03976  {
03977  /* Added by Matias Mutchinick */
03978       gtk_sheet_cell_clear(sheet, row, col);
03979  }
03980 
03981  sheet_head->CHANGED = 1;
03982 
03983  if(sheet->freeze_count == 0)
03984         GTK_SHEET_UNSET_FLAGS(sheet, GTK_SHEET_IS_FROZEN);
03985  
03986  sheet->active_cell.row=row;;
03987  sheet->active_cell.col=col;
03988 
03989 }
03990 
03991 
03992 static gboolean 
03993 gtk_sheet_deactivate_cell(GtkSheet *sheet)
03994 {
03995  gboolean veto = TRUE;
03996 
03997  g_return_val_if_fail (sheet != NULL, FALSE);
03998  g_return_val_if_fail (GTK_IS_SHEET (sheet), FALSE);
03999 
04000  if(!GTK_WIDGET_REALIZED(GTK_WIDGET(sheet))) return FALSE;
04001  if(sheet->state != GTK_SHEET_NORMAL) return FALSE;
04002 
04003  _gtkextra_signal_emit(GTK_OBJECT(sheet),sheet_signals[DEACTIVATE], 
04004                                    sheet->active_cell.row,
04005                                    sheet->active_cell.col, &veto);
04006 
04007  if(!veto) return FALSE;
04008 
04009  gtk_signal_disconnect_by_func(GTK_OBJECT(gtk_sheet_get_entry(sheet)),
04010                            (GtkSignalFunc) gtk_sheet_entry_changed,
04011                            GTK_OBJECT(GTK_WIDGET(sheet)));
04012 
04013  gtk_sheet_hide_active_cell(sheet);
04014  sheet->active_cell.row=-1;
04015  sheet->active_cell.col=-1;
04016  
04017  if(GTK_SHEET_REDRAW_PENDING(sheet)){
04018    GTK_SHEET_UNSET_FLAGS(sheet, GTK_SHEET_REDRAW_PENDING);
04019    gtk_sheet_range_draw(sheet, NULL);
04020  }
04021 
04022  return TRUE;
04023 }   
04024 
04025 static void
04026 gtk_sheet_hide_active_cell(GtkSheet *sheet)
04027 {
04028  const char *text;
04029  gint row,col;
04030  GtkJustification justification;
04031  GtkSheetCellAttr attributes;
04032 
04033  if(!GTK_WIDGET_REALIZED(GTK_WIDGET(sheet))) return;
04034 
04035  row=sheet->active_cell.row;
04036  col=sheet->active_cell.col;
04037 
04038  if(row < 0 || col < 0) return;
04039 
04040  if(sheet->freeze_count == 0)
04041      GTK_SHEET_UNSET_FLAGS(sheet, GTK_SHEET_IS_FROZEN);
04042 
04043  text=gtk_entry_get_text(GTK_ENTRY(gtk_sheet_get_entry(sheet)));
04044 
04045  gtk_sheet_get_attributes(sheet, row, col, &attributes); 
04046  justification=attributes.justification;
04047 
04048  if(text && strlen(text)!=0){
04049       gtk_sheet_set_cell(sheet, row, col, justification, text);
04050       gtk_signal_emit(GTK_OBJECT(sheet),sheet_signals[SET_CELL], row, col);
04051  }
04052  else
04053  {
04054       gtk_sheet_cell_clear(sheet, row, col);
04055  }
04056 
04057  row=sheet->active_cell.row;
04058  col=sheet->active_cell.col;
04059 
04060  column_button_release(sheet, col);
04061  row_button_release(sheet, row);
04062 
04063  gtk_widget_unmap(sheet->sheet_entry);
04064 
04065  if(row != -1 && col != -1)
04066    gdk_draw_pixmap(sheet->sheet_window,
04067                    GTK_WIDGET(sheet)->style->fg_gc[GTK_STATE_NORMAL],
04068                    sheet->pixmap,
04069                    COLUMN_LEFT_XPIXEL(sheet,col)-1,
04070                    ROW_TOP_YPIXEL(sheet,row)-1,
04071                    COLUMN_LEFT_XPIXEL(sheet,col)-1,
04072                    ROW_TOP_YPIXEL(sheet,row)-1,
04073                    sheet->column[col].width+4,
04074                    sheet->row[row].height+4);   
04075 
04076  GTK_WIDGET_UNSET_FLAGS(sheet->sheet_entry, GTK_HAS_FOCUS);
04077  GTK_WIDGET_SET_FLAGS(GTK_WIDGET(sheet), GTK_HAS_FOCUS);
04078  gtk_widget_grab_focus(GTK_WIDGET(sheet));
04079 
04080  GTK_WIDGET_UNSET_FLAGS(GTK_WIDGET(sheet->sheet_entry), GTK_VISIBLE);
04081 
04082 }
04083 
04084 static gboolean
04085 gtk_sheet_activate_cell(GtkSheet *sheet, gint row, gint col)
04086 {
04087  gboolean veto = TRUE;
04088 
04089  g_return_val_if_fail (sheet != NULL, FALSE);
04090  g_return_val_if_fail (GTK_IS_SHEET (sheet), FALSE);
04091 
04092  if(row < 0 || col < 0) return FALSE;
04093  if(row > sheet->maxrow || col > sheet->maxcol) return FALSE;
04094 
04095 /* _gtkextra_signal_emit(GTK_OBJECT(sheet),sheet_signals[ACTIVATE], row, col, &veto);
04096  if(!GTK_WIDGET_REALIZED(GTK_WIDGET(sheet))) return veto;
04097 */
04098 
04099  if(!veto) return FALSE;
04100  if(sheet->state != GTK_SHEET_NORMAL){
04101         sheet->state=GTK_SHEET_NORMAL;
04102         gtk_sheet_real_unselect_range(sheet, NULL);
04103  }
04104 
04105  sheet->range.row0=row;
04106  sheet->range.col0=col;
04107  sheet->range.rowi=row;
04108  sheet->range.coli=col;
04109  sheet->active_cell.row=row;
04110  sheet->active_cell.col=col;
04111  sheet->selection_cell.row=row;
04112  sheet->selection_cell.col=col;
04113  row_button_set(sheet, row);
04114  column_button_set(sheet, col); 
04115 
04116  GTK_SHEET_UNSET_FLAGS(sheet, GTK_SHEET_IN_SELECTION);
04117  gtk_sheet_show_active_cell(sheet);
04118 
04119  gtk_signal_connect(GTK_OBJECT(gtk_sheet_get_entry(sheet)),
04120                 "changed",
04121                     (GtkSignalFunc)gtk_sheet_entry_changed,
04122                     GTK_OBJECT(GTK_WIDGET(sheet)));
04123 
04124  _gtkextra_signal_emit(GTK_OBJECT(sheet),sheet_signals[ACTIVATE], row, col, &veto);
04125 
04126  return TRUE;
04127 }
04128 
04129 static void
04130 gtk_sheet_show_active_cell(GtkSheet *sheet)
04131 {
04132  GtkSheetCell *cell;
04133  GtkEntry *sheet_entry;
04134  GtkSheetCellAttr attributes;
04135  gchar *text = NULL;
04136  GtkJustification justification;
04137  gint row, col;
04138 
04139  g_return_if_fail (sheet != NULL);
04140  g_return_if_fail (GTK_IS_SHEET (sheet));
04141 
04142  row = sheet->active_cell.row;
04143  col = sheet->active_cell.col;
04144 
04145  /* Don't show the active cell, if there is no active cell: */
04146  if(!(row >= 0 && col >= 0)) /* e.g row or coll == -1. */
04147    return;
04148   
04149  if(!GTK_WIDGET_REALIZED(GTK_WIDGET(sheet))) return;
04150  if(sheet->state != GTK_SHEET_NORMAL) return;
04151  if(GTK_SHEET_IN_SELECTION(sheet)) return;
04152 
04153  GTK_WIDGET_SET_FLAGS(GTK_WIDGET(sheet->sheet_entry), GTK_VISIBLE);
04154 
04155  sheet_entry = GTK_ENTRY(gtk_sheet_get_entry(sheet));
04156 
04157  gtk_sheet_get_attributes(sheet, row, col, &attributes); 
04158 
04159  justification = GTK_JUSTIFY_LEFT;
04160 
04161  if(gtk_sheet_justify_entry(sheet))
04162       justification = attributes.justification;
04163 
04164  if(row <= sheet->maxallocrow && col <= sheet->maxalloccol) {
04165    if(sheet->data[row]) {
04166        if(sheet->data[row][col]) {
04167          cell = sheet->data[row][col];
04168          if(cell->text)
04169            text = g_strdup(cell->text);
04170        }
04171      }
04172  }
04173 
04174  if(!text) text = g_strdup("");
04175 
04176  gtk_entry_set_visibility(GTK_ENTRY(sheet_entry), attributes.is_visible);
04177 
04178  if(gtk_sheet_locked(sheet) || !attributes.is_editable){ 
04179             gtk_entry_set_editable(GTK_ENTRY(sheet_entry), FALSE);
04180  }else{
04181             gtk_entry_set_editable(GTK_ENTRY(sheet_entry), TRUE);
04182  }
04183 
04184 
04185  gtk_entry_set_text(GTK_ENTRY(sheet_entry), text);
04186 
04187 
04188  gtk_sheet_size_allocate_entry(sheet);
04189 
04190  gtk_widget_map(sheet->sheet_entry);
04191  gtk_sheet_draw_active_cell(sheet);
04192 
04193  gtk_widget_grab_focus(GTK_WIDGET(sheet_entry));
04194  GTK_WIDGET_SET_FLAGS(GTK_WIDGET(sheet_entry), GTK_HAS_FOCUS);
04195  GTK_WIDGET_UNSET_FLAGS(GTK_WIDGET(sheet), GTK_HAS_FOCUS);
04196 
04197  g_free(text);
04198 }
04199 
04200 static void
04201 gtk_sheet_draw_active_cell(GtkSheet *sheet)
04202 {
04203     gint row, col;
04204 
04205     if(!GTK_WIDGET_DRAWABLE(GTK_WIDGET(sheet))) return;
04206     if(!GTK_WIDGET_REALIZED(GTK_WIDGET(sheet))) return;
04207 
04208     row = sheet->active_cell.row;
04209     col = sheet->active_cell.col;
04210  
04211     if(row<0 || col<0) return;
04212 
04213     if(!gtk_sheet_cell_isvisible(sheet, row, col)) return;
04214  
04215     row_button_set(sheet, row);
04216     column_button_set(sheet, col);
04217 
04218     gtk_sheet_draw_backing_pixmap(sheet, sheet->range);
04219     gtk_sheet_draw_border(sheet, sheet->range);
04220 
04221 }
04222 
04223 
04224 static void
04225 gtk_sheet_make_backing_pixmap (GtkSheet *sheet, guint width, guint height)
04226 {
04227   gint pixmap_width, pixmap_height;
04228 
04229   if(!GTK_WIDGET_REALIZED(GTK_WIDGET(sheet))) return;
04230 
04231   if(width == 0 && height == 0){
04232      width=sheet->sheet_window_width+80;
04233      height=sheet->sheet_window_height+80;
04234   }
04235 
04236   if (!sheet->pixmap)
04237     {
04238       /* allocate */
04239       sheet->pixmap = gdk_pixmap_new (sheet->sheet_window,
04240                           width, height,
04241                       -1);
04242       if(!GTK_SHEET_IS_FROZEN(sheet)) gtk_sheet_range_draw(sheet, NULL);
04243     }
04244   else
04245     {
04246       /* reallocate if sizes don't match */
04247       gdk_window_get_size (sheet->pixmap,
04248                &pixmap_width, &pixmap_height);
04249       if ((pixmap_width != width) || (pixmap_height != height))
04250     {
04251           gdk_pixmap_unref(sheet->pixmap); /* replaced by SDB on 7.31.2006 */
04252           /* g_free(sheet->pixmap); */
04253       sheet->pixmap = gdk_pixmap_new (sheet->sheet_window,
04254                            width, height,
04255                            -1);
04256           if(!GTK_SHEET_IS_FROZEN(sheet)) gtk_sheet_range_draw(sheet, NULL);
04257     }
04258     }
04259 }
04260 
04261 static void
04262 gtk_sheet_new_selection(GtkSheet *sheet, GtkSheetRange *range)
04263 {
04264   gint i,j, mask1, mask2;
04265   gint state, selected;
04266   gint x,y,width,height;
04267   GtkSheetRange new_range, aux_range;
04268 
04269   g_return_if_fail (sheet != NULL);
04270 
04271   if(range==NULL) range=&sheet->range;
04272 
04273   new_range=*range;
04274 
04275   range->row0=MIN(range->row0, sheet->range.row0);
04276   range->rowi=MAX(range->rowi, sheet->range.rowi);
04277   range->col0=MIN(range->col0, sheet->range.col0);
04278   range->coli=MAX(range->coli, sheet->range.coli);
04279 
04280   range->row0=MAX(range->row0, MIN_VISIBLE_ROW(sheet));
04281   range->rowi=MIN(range->rowi, MAX_VISIBLE_ROW(sheet));
04282   range->col0=MAX(range->col0, MIN_VISIBLE_COLUMN(sheet));
04283   range->coli=MIN(range->coli, MAX_VISIBLE_COLUMN(sheet));
04284 
04285   aux_range.row0=MAX(new_range.row0, MIN_VISIBLE_ROW(sheet));
04286   aux_range.rowi=MIN(new_range.rowi, MAX_VISIBLE_ROW(sheet));
04287   aux_range.col0=MAX(new_range.col0, MIN_VISIBLE_COLUMN(sheet));
04288   aux_range.coli=MIN(new_range.coli, MAX_VISIBLE_COLUMN(sheet));
04289 
04290   for(i=range->row0; i<=range->rowi; i++){
04291    for(j=range->col0; j<=range->coli; j++){     
04292 
04293     state=gtk_sheet_cell_get_state(sheet, i, j);
04294     selected=(i<=new_range.rowi && i>=new_range.row0 && 
04295         j<=new_range.coli && j>=new_range.col0) ? TRUE : FALSE;
04296 
04297     if(state==GTK_STATE_SELECTED && selected &&
04298        sheet->column[j].is_visible && sheet->row[i].is_visible &&
04299        (i==sheet->range.row0 || i==sheet->range.rowi ||
04300         j==sheet->range.col0 || j==sheet->range.coli ||
04301         i==new_range.row0 || i==new_range.rowi ||
04302         j==new_range.col0 || j==new_range.coli)){
04303 
04304        mask1 = i==sheet->range.row0 ? 1 : 0;
04305        mask1 = i==sheet->range.rowi ? mask1+2 : mask1;
04306        mask1 = j==sheet->range.col0 ? mask1+4 : mask1;
04307        mask1 = j==sheet->range.coli ? mask1+8 : mask1;
04308 
04309        mask2 = i==new_range.row0 ? 1 : 0;
04310        mask2 = i==new_range.rowi ? mask2+2 : mask2;
04311        mask2 = j==new_range.col0 ? mask2+4 : mask2;
04312        mask2 = j==new_range.coli ? mask2+8 : mask2;     
04313 
04314        if(mask1 != mask2){
04315          x=COLUMN_LEFT_XPIXEL(sheet,j);
04316          y=ROW_TOP_YPIXEL(sheet, i);  
04317          width=COLUMN_LEFT_XPIXEL(sheet, j)-x+sheet->column[j].width;
04318          height=ROW_TOP_YPIXEL(sheet, i)-y+sheet->row[i].height;
04319 
04320          if(i==sheet->range.row0){
04321             y=y-3;
04322             height=height+3;
04323          }
04324          if(i==sheet->range.rowi) height=height+3;
04325          if(j==sheet->range.col0){
04326             x=x-3;
04327             width=width+3;
04328          }
04329          if(j==sheet->range.coli) width=width+3;
04330 
04331          gdk_draw_pixmap(sheet->sheet_window,
04332                   GTK_WIDGET(sheet)->style->fg_gc[GTK_STATE_NORMAL],
04333                   sheet->pixmap,
04334                   x+1,
04335                   y+1,
04336                   x+1,
04337                   y+1,
04338                   width,
04339                   height);           
04340 
04341          if(i != sheet->active_cell.row || j != sheet->active_cell.col){
04342            x=COLUMN_LEFT_XPIXEL(sheet,j);
04343            y=ROW_TOP_YPIXEL(sheet, i);  
04344            width=COLUMN_LEFT_XPIXEL(sheet, j)-x+sheet->column[j].width;
04345            height=ROW_TOP_YPIXEL(sheet, i)-y+sheet->row[i].height;
04346 
04347            if(i==new_range.row0){
04348                y=y+2;
04349                height=height-2;
04350             }
04351             if(i==new_range.rowi) height=height-3;
04352             if(j==new_range.col0){
04353                x=x+2;
04354                width=width-2;
04355             }
04356             if(j==new_range.coli) width=width-3;
04357 
04358             gdk_draw_rectangle (sheet->sheet_window,
04359                        sheet->xor_gc,
04360                    TRUE,
04361                        x+1,y+1,
04362                        width,height);
04363           }
04364        }
04365     }
04366    }
04367   }
04368 
04369   for(i=range->row0; i<=range->rowi; i++){
04370    for(j=range->col0; j<=range->coli; j++){     
04371 
04372     state=gtk_sheet_cell_get_state(sheet, i, j);
04373     selected=(i<=new_range.rowi && i>=new_range.row0 && 
04374         j<=new_range.coli && j>=new_range.col0) ? TRUE : FALSE;
04375 
04376     if(state==GTK_STATE_SELECTED && !selected &&   
04377        sheet->column[j].is_visible && sheet->row[i].is_visible){
04378 
04379       x=COLUMN_LEFT_XPIXEL(sheet,j);
04380       y=ROW_TOP_YPIXEL(sheet, i);  
04381       width=COLUMN_LEFT_XPIXEL(sheet, j)-x+sheet->column[j].width;
04382       height=ROW_TOP_YPIXEL(sheet, i)-y+sheet->row[i].height;
04383 
04384       if(i==sheet->range.row0){
04385             y=y-3;
04386             height=height+3;
04387       }
04388       if(i==sheet->range.rowi) height=height+3;
04389       if(j==sheet->range.col0){
04390             x=x-3;
04391             width=width+3;
04392       }
04393       if(j==sheet->range.coli) width=width+3;
04394 
04395       gdk_draw_pixmap(sheet->sheet_window,
04396                   GTK_WIDGET(sheet)->style->fg_gc[GTK_STATE_NORMAL],
04397                   sheet->pixmap,
04398                   x+1,
04399                   y+1,
04400                   x+1,
04401                   y+1,
04402                   width,
04403                   height);           
04404     }
04405    }
04406   }
04407 
04408   for(i=range->row0; i<=range->rowi; i++){
04409    for(j=range->col0; j<=range->coli; j++){     
04410 
04411     state=gtk_sheet_cell_get_state(sheet, i, j);
04412     selected=(i<=new_range.rowi && i>=new_range.row0 && 
04413         j<=new_range.coli && j>=new_range.col0) ? TRUE : FALSE;
04414 
04415     if(state!=GTK_STATE_SELECTED && selected &&
04416        sheet->column[j].is_visible && sheet->row[i].is_visible &&
04417        (i != sheet->active_cell.row || j != sheet->active_cell.col)){
04418 
04419       x=COLUMN_LEFT_XPIXEL(sheet,j);
04420       y=ROW_TOP_YPIXEL(sheet, i);  
04421       width=COLUMN_LEFT_XPIXEL(sheet, j)-x+sheet->column[j].width;
04422       height=ROW_TOP_YPIXEL(sheet, i)-y+sheet->row[i].height;
04423 
04424       if(i==new_range.row0){
04425             y=y+2;
04426             height=height-2;
04427        }
04428        if(i==new_range.rowi) height=height-3;
04429        if(j==new_range.col0){
04430             x=x+2;
04431             width=width-2;
04432        }
04433        if(j==new_range.coli) width=width-3;
04434 
04435        gdk_draw_rectangle (sheet->sheet_window,
04436                        sheet->xor_gc,
04437                    TRUE,
04438                        x+1,y+1,
04439                        width,height);
04440 
04441     }   
04442 
04443    }
04444   }
04445 
04446   for(i=aux_range.row0; i<=aux_range.rowi; i++){
04447    for(j=aux_range.col0; j<=aux_range.coli; j++){     
04448 
04449     if(sheet->column[j].is_visible && sheet->row[i].is_visible){
04450 
04451        state=gtk_sheet_cell_get_state(sheet, i, j);
04452 
04453        mask1 = i==sheet->range.row0 ? 1 : 0;
04454        mask1 = i==sheet->range.rowi ? mask1+2 : mask1;
04455        mask1 = j==sheet->range.col0 ? mask1+4 : mask1;
04456        mask1 = j==sheet->range.coli ? mask1+8 : mask1;
04457 
04458        mask2 = i==new_range.row0 ? 1 : 0;
04459        mask2 = i==new_range.rowi ? mask2+2 : mask2;
04460        mask2 = j==new_range.col0 ? mask2+4 : mask2;
04461        mask2 = j==new_range.coli ? mask2+8 : mask2;    
04462        if(mask2!=mask1 || (mask2==mask1 && state!=GTK_STATE_SELECTED)){
04463          x=COLUMN_LEFT_XPIXEL(sheet,j);
04464          y=ROW_TOP_YPIXEL(sheet, i);  
04465          width=sheet->column[j].width;
04466          height=sheet->row[i].height;
04467          if(mask2 & 1)
04468                gdk_draw_rectangle (sheet->sheet_window,
04469                                sheet->xor_gc,
04470                            TRUE,
04471                                x+1,y-1,
04472                                width,3);
04473 
04474            
04475          if(mask2 & 2)
04476                gdk_draw_rectangle (sheet->sheet_window,
04477                                sheet->xor_gc,
04478                            TRUE,
04479                                x+1,y+height-1,
04480                                width,3);
04481 
04482          if(mask2 & 4)
04483                gdk_draw_rectangle (sheet->sheet_window,
04484                                sheet->xor_gc,
04485                            TRUE,
04486                                x-1,y+1,
04487                                3,height);
04488 
04489 
04490          if(mask2 & 8)
04491                gdk_draw_rectangle (sheet->sheet_window,
04492                                sheet->xor_gc,
04493                            TRUE,
04494                                x+width-1,y+1,
04495                                3,height);
04496 
04497        
04498 
04499        }         
04500 
04501     } 
04502 
04503    }
04504   } 
04505 
04506 
04507   *range=new_range;
04508   gtk_sheet_draw_corners(sheet, new_range);
04509 
04510 }
04511 
04512 static void
04513 gtk_sheet_draw_border (GtkSheet *sheet, GtkSheetRange new_range)
04514 {
04515   GtkWidget *widget;
04516   GdkRectangle area;
04517   gint i;
04518   gint x,y,width,height;
04519 
04520   widget = GTK_WIDGET(sheet);
04521 
04522   x=COLUMN_LEFT_XPIXEL(sheet,new_range.col0);
04523   y=ROW_TOP_YPIXEL(sheet,new_range.row0);
04524   width=COLUMN_LEFT_XPIXEL(sheet,new_range.coli)-x+ 
04525              sheet->column[new_range.coli].width;
04526   height=ROW_TOP_YPIXEL(sheet,new_range.rowi)-y+
04527              sheet->row[new_range.rowi].height;
04528 
04529   area.x=COLUMN_LEFT_XPIXEL(sheet, MIN_VISIBLE_COLUMN(sheet));
04530   area.y=ROW_TOP_YPIXEL(sheet, MIN_VISIBLE_ROW(sheet));
04531   area.width=sheet->sheet_window_width;
04532   area.height=sheet->sheet_window_height;
04533 
04534   if(x<0) {
04535       width=width+x;
04536       x=0;
04537   }
04538   if(width>area.width) width=area.width+10;
04539   if(y<0) {
04540       height=height+y;
04541       y=0;
04542   }
04543   if(height>area.height) height=area.height+10;
04544 
04545   gdk_gc_set_clip_rectangle(sheet->xor_gc, &area);
04546 
04547   for(i=-1; i<=1; ++i)
04548      gdk_draw_rectangle (sheet->sheet_window,
04549                      sheet->xor_gc,
04550                          FALSE,
04551                      x+i,y+i,
04552                      width-2*i,height-2*i);
04553 
04554   gdk_gc_set_clip_rectangle(sheet->xor_gc, NULL);
04555   
04556   gtk_sheet_draw_corners(sheet, new_range);
04557 
04558 }
04559 
04560 static void
04561 gtk_sheet_draw_corners(GtkSheet *sheet, GtkSheetRange range)
04562 {
04563   gint x,y;
04564   guint width = 1;
04565 
04566   if(gtk_sheet_cell_isvisible(sheet, range.row0, range.col0)){
04567        x=COLUMN_LEFT_XPIXEL(sheet,range.col0);
04568        y=ROW_TOP_YPIXEL(sheet,range.row0);
04569        gdk_draw_pixmap(sheet->sheet_window,
04570                        GTK_WIDGET(sheet)->style->fg_gc[GTK_STATE_NORMAL],
04571                        sheet->pixmap,
04572                        x-1,
04573                        y-1,
04574                        x-1,
04575                        y-1,
04576                        3,
04577                        3);         
04578        gdk_draw_rectangle (sheet->sheet_window,
04579                        sheet->xor_gc,
04580                            TRUE,
04581                        x-1,y-1,
04582                        3,3);
04583   }
04584 
04585   if(gtk_sheet_cell_isvisible(sheet, range.row0, range.coli) ||
04586      sheet->state == GTK_SHEET_COLUMN_SELECTED){
04587        x=COLUMN_LEFT_XPIXEL(sheet,range.coli)+
04588          sheet->column[range.coli].width;
04589        y=ROW_TOP_YPIXEL(sheet,range.row0);
04590        width = 1;
04591        if(sheet->state == GTK_SHEET_COLUMN_SELECTED)
04592          {
04593              y = ROW_TOP_YPIXEL(sheet, sheet->view.row0)+3;
04594              width = 3;
04595          }
04596        gdk_draw_pixmap(sheet->sheet_window,
04597                        GTK_WIDGET(sheet)->style->fg_gc[GTK_STATE_NORMAL],
04598                        sheet->pixmap,
04599                        x-width,
04600                        y-width,
04601                        x-width,
04602                        y-width,
04603                        2*width+1,
04604                        2*width+1);         
04605        gdk_draw_rectangle (sheet->sheet_window,
04606                        sheet->xor_gc,
04607                            TRUE,
04608                        x-width+width/2,y-width+width/2,
04609                        2+width,2+width);
04610   }
04611 
04612   if(gtk_sheet_cell_isvisible(sheet, range.rowi, range.col0) ||
04613      sheet->state == GTK_SHEET_ROW_SELECTED){
04614        x=COLUMN_LEFT_XPIXEL(sheet,range.col0);
04615        y=ROW_TOP_YPIXEL(sheet,range.rowi)+
04616          sheet->row[range.rowi].height;
04617        width = 1;
04618        if(sheet->state == GTK_SHEET_ROW_SELECTED) 
04619          {
04620              x = COLUMN_LEFT_XPIXEL(sheet, sheet->view.col0)+3;
04621              width = 3;
04622          }
04623        gdk_draw_pixmap(sheet->sheet_window,
04624                        GTK_WIDGET(sheet)->style->fg_gc[GTK_STATE_NORMAL],
04625                        sheet->pixmap,
04626                        x-width,
04627                        y-width,
04628                        x-width,
04629                        y-width,
04630                        2*width+1,
04631                        2*width+1);         
04632        gdk_draw_rectangle (sheet->sheet_window,
04633                        sheet->xor_gc,
04634                            TRUE,
04635                        x-width+width/2,y-width+width/2,
04636                        2+width,2+width);
04637   }
04638 
04639   if(gtk_sheet_cell_isvisible(sheet, range.rowi, range.coli)){
04640        x=COLUMN_LEFT_XPIXEL(sheet,range.coli)+
04641          sheet->column[range.coli].width;
04642        y=ROW_TOP_YPIXEL(sheet,range.rowi)+
04643          sheet->row[range.rowi].height;
04644        width = 1;
04645        if(sheet->state == GTK_SHEET_RANGE_SELECTED) width = 3;
04646        if(sheet->state == GTK_SHEET_NORMAL) width = 3;
04647        gdk_draw_pixmap(sheet->sheet_window,
04648                        GTK_WIDGET(sheet)->style->fg_gc[GTK_STATE_NORMAL],
04649                        sheet->pixmap,
04650                        x-width,
04651                        y-width,
04652                        x-width,
04653                        y-width,
04654                        2*width+1,
04655                        2*width+1);         
04656        gdk_draw_rectangle (sheet->sheet_window,
04657                        sheet->xor_gc,
04658                            TRUE,
04659                        x-width+width/2,y-width+width/2,
04660                        2+width,2+width);
04661 
04662   }
04663 
04664 }
04665 
04666 
04667 static void
04668 gtk_sheet_real_select_range (GtkSheet * sheet,
04669                  GtkSheetRange * range)
04670 {
04671   gint i;
04672   gint state;
04673 
04674   g_return_if_fail (sheet != NULL);
04675 
04676   if(range==NULL) range=&sheet->range;
04677 
04678   if(range->row0 < 0 || range->rowi < 0) return;
04679   if(range->col0 < 0 || range->coli < 0) return;
04680 
04681   state=sheet->state;
04682 
04683   if(state==GTK_SHEET_COLUMN_SELECTED || state==GTK_SHEET_RANGE_SELECTED){
04684    for(i=sheet->range.col0; i< range->col0; i++)
04685     column_button_release(sheet, i);
04686    for(i=range->coli+1; i<= sheet->range.coli; i++)
04687     column_button_release(sheet, i);
04688    for(i=range->col0; i<=range->coli; i++){
04689     column_button_set(sheet, i);
04690    }
04691   }
04692  
04693   if(state==GTK_SHEET_ROW_SELECTED || state==GTK_SHEET_RANGE_SELECTED){
04694    for(i=sheet->range.row0; i< range->row0; i++)
04695     row_button_release(sheet, i);
04696    for(i=range->rowi+1; i<= sheet->range.rowi; i++)
04697     row_button_release(sheet, i);
04698    for(i=range->row0; i<=range->rowi; i++){
04699     row_button_set(sheet, i);
04700    }
04701   }
04702 
04703   if(range->coli != sheet->range.coli || range->col0 != sheet->range.col0 ||
04704      range->rowi != sheet->range.rowi || range->row0 != sheet->range.row0)
04705          {
04706 
04707            gtk_sheet_new_selection(sheet, range);
04708 
04709        sheet->range.col0=range->col0;
04710        sheet->range.coli=range->coli;
04711        sheet->range.row0=range->row0;
04712        sheet->range.rowi=range->rowi;
04713 
04714      }
04715   else
04716          {
04717        gtk_sheet_draw_backing_pixmap(sheet, sheet->range);
04718            gtk_sheet_range_draw_selection(sheet, sheet->range);
04719          }
04720 
04721   gtk_signal_emit(GTK_OBJECT(sheet), sheet_signals[SELECT_RANGE], range);
04722 }
04723 
04724 void
04725 gtk_sheet_select_range(GtkSheet * sheet, const GtkSheetRange *range)
04726 {
04727   g_return_if_fail (sheet != NULL);
04728 
04729   if(range==NULL) range=&sheet->range;
04730 
04731   if(range->row0 < 0 || range->rowi < 0) return;
04732   if(range->col0 < 0 || range->coli < 0) return;
04733 
04734   if(sheet->state != GTK_SHEET_NORMAL) 
04735        gtk_sheet_real_unselect_range(sheet, NULL);
04736   else
04737   {
04738      gboolean veto = TRUE;
04739      veto = gtk_sheet_deactivate_cell(sheet);
04740      if(!veto) return;
04741   }
04742 
04743   sheet->range.row0=range->row0;
04744   sheet->range.rowi=range->rowi;
04745   sheet->range.col0=range->col0;
04746   sheet->range.coli=range->coli;
04747   sheet->active_cell.row=range->row0;
04748   sheet->active_cell.col=range->col0;
04749   sheet->selection_cell.row=range->rowi;
04750   sheet->selection_cell.col=range->coli;
04751 
04752   sheet->state = GTK_SHEET_RANGE_SELECTED;
04753   gtk_sheet_real_select_range(sheet, NULL);
04754 
04755 }
04756 
04757 void
04758 gtk_sheet_unselect_range (GtkSheet * sheet)
04759 {
04760   gtk_sheet_real_unselect_range(sheet, NULL);
04761   sheet->state = GTK_STATE_NORMAL;
04762   gtk_sheet_activate_cell(sheet, sheet->active_cell.row, sheet->active_cell.col);
04763 }
04764 
04765 
04766 static void
04767 gtk_sheet_real_unselect_range (GtkSheet * sheet,
04768                    const GtkSheetRange *range)
04769 {
04770   gint i;
04771  
04772   g_return_if_fail (sheet != NULL);
04773   g_return_if_fail (GTK_WIDGET_REALIZED(GTK_WIDGET(sheet)));
04774 
04775   if(range==NULL){
04776      range=&sheet->range;
04777   }
04778 
04779   if(range->row0 < 0 || range->rowi < 0) return;
04780   if(range->col0 < 0 || range->coli < 0) return;
04781 
04782   if (gtk_sheet_range_isvisible (sheet, *range)){
04783     gtk_sheet_draw_backing_pixmap(sheet, *range);
04784   }
04785 
04786   for(i=range->col0; i<=range->coli; i++){
04787      column_button_release(sheet, i);
04788   }
04789 
04790   for(i=range->row0; i<=range->rowi; i++){
04791      row_button_release(sheet, i);
04792   }
04793 
04794 }
04795 
04796 
04797 static gint
04798 gtk_sheet_expose (GtkWidget * widget,
04799           GdkEventExpose * event)
04800 {
04801   GtkSheet *sheet;
04802   GtkSheetRange range;
04803 
04804 #ifdef DEBUG
04805   printf("---> Entered gtk_sheet_expose ... must have received expose_event\n");
04806 #endif 
04807 
04808   g_return_val_if_fail (widget != NULL, FALSE);
04809   g_return_val_if_fail (GTK_IS_SHEET (widget), FALSE);
04810   g_return_val_if_fail (event != NULL, FALSE);
04811 
04812   sheet = GTK_SHEET (widget);
04813 
04814   if (GTK_WIDGET_DRAWABLE (widget))
04815   {
04816       range.row0=ROW_FROM_YPIXEL(sheet,event->area.y);
04817       range.col0=COLUMN_FROM_XPIXEL(sheet,event->area.x);
04818       range.rowi=ROW_FROM_YPIXEL(sheet,event->area.y+event->area.height);
04819       range.coli=COLUMN_FROM_XPIXEL(sheet,event->area.x+event->area.width);
04820 
04821       /* exposure events on the sheet */
04822  
04823       if( (event->window == sheet->row_title_window) && sheet->row_titles_visible){
04824                      size_allocate_row_title_buttons(sheet);
04825       }
04826 
04827       if( (event->window == sheet->column_title_window) && sheet->column_titles_visible){
04828                      size_allocate_column_title_buttons(sheet);
04829       }
04830 
04831       if (event->window == sheet->sheet_window){
04832         gtk_sheet_draw_backing_pixmap(sheet, range);
04833               
04834         if(sheet->state != GTK_SHEET_NORMAL){
04835                 if(gtk_sheet_range_isvisible(sheet, sheet->range))          
04836                    gtk_sheet_draw_backing_pixmap(sheet, sheet->range);
04837                 if(GTK_SHEET_IN_RESIZE(sheet) || GTK_SHEET_IN_DRAG(sheet))
04838                    gtk_sheet_draw_backing_pixmap(sheet, sheet->drag_range);
04839 
04840                 if(gtk_sheet_range_isvisible(sheet, sheet->range))          
04841                    gtk_sheet_range_draw_selection(sheet, sheet->range);
04842                 if(GTK_SHEET_IN_RESIZE(sheet) || GTK_SHEET_IN_DRAG(sheet))
04843                    draw_xor_rectangle(sheet, sheet->drag_range);
04844         }
04845 
04846         if((!GTK_SHEET_IN_XDRAG(sheet)) && (!GTK_SHEET_IN_YDRAG(sheet))){
04847              if(sheet->state == GTK_SHEET_NORMAL){ 
04848                  gtk_sheet_draw_active_cell(sheet);
04849                  if(!GTK_SHEET_IN_SELECTION(sheet))
04850                          gtk_widget_queue_draw(sheet->sheet_entry);
04851              }
04852         }
04853 
04854 
04855       }
04856 
04857   }
04858 
04859   if(sheet->state != GTK_SHEET_NORMAL && GTK_SHEET_IN_SELECTION(sheet))
04860      gtk_widget_grab_focus(GTK_WIDGET(sheet));
04861 
04862   (* GTK_WIDGET_CLASS (parent_class)->expose_event) (widget, event);
04863 
04864 #ifdef DEBUG
04865   printf("<--- Leaving gtk_sheet_expose\n");
04866 #endif 
04867 
04868   return FALSE;
04869 }
04870 
04871 
04872 static gint
04873 gtk_sheet_button_press (GtkWidget * widget,
04874             GdkEventButton * event)
04875 {
04876   GtkSheet *sheet;
04877   GdkModifierType mods;
04878   gint x, y, row, column;
04879   gboolean veto;
04880 
04881   g_return_val_if_fail (widget != NULL, FALSE);
04882   g_return_val_if_fail (GTK_IS_SHEET (widget), FALSE);
04883   g_return_val_if_fail (event != NULL, FALSE);
04884 
04885   if(event->type != GDK_BUTTON_PRESS) return TRUE;
04886   gdk_window_get_pointer(widget->window, NULL, NULL, &mods);
04887   if(!(mods & GDK_BUTTON1_MASK)) return TRUE;
04888 
04889   sheet = GTK_SHEET (widget);
04890 
04891   /* press on resize windows */
04892   if (event->window == sheet->column_title_window &&
04893       gtk_sheet_columns_resizable(sheet))
04894       {
04895     gtk_widget_get_pointer (widget, &sheet->x_drag, NULL);
04896         if(POSSIBLE_XDRAG(sheet, sheet->x_drag, &sheet->drag_cell.col)){
04897           guint req;
04898           gtk_sheet_column_size_request(sheet, sheet->drag_cell.col, &req);
04899       GTK_SHEET_SET_FLAGS (sheet, GTK_SHEET_IN_XDRAG);
04900       gdk_pointer_grab (sheet->column_title_window, FALSE,
04901                 GDK_POINTER_MOTION_HINT_MASK |
04902                 GDK_BUTTON1_MOTION_MASK |
04903                 GDK_BUTTON_RELEASE_MASK,
04904                 NULL, NULL, event->time);
04905 
04906       draw_xor_vline (sheet);
04907       return TRUE;
04908         }
04909       }
04910 
04911   if (event->window == sheet->row_title_window && gtk_sheet_rows_resizable(sheet))
04912       {
04913     gtk_widget_get_pointer (widget, NULL, &sheet->y_drag);
04914 
04915         if(POSSIBLE_YDRAG(sheet, sheet->y_drag, &sheet->drag_cell.row)){
04916           guint req;
04917           gtk_sheet_row_size_request(sheet, sheet->drag_cell.row, &req);
04918       GTK_SHEET_SET_FLAGS (sheet, GTK_SHEET_IN_YDRAG);
04919       gdk_pointer_grab (sheet->row_title_window, FALSE,
04920                 GDK_POINTER_MOTION_HINT_MASK |
04921                 GDK_BUTTON1_MOTION_MASK |
04922                 GDK_BUTTON_RELEASE_MASK,
04923                 NULL, NULL, event->time);
04924 
04925       draw_xor_hline (sheet);
04926       return TRUE;
04927         }
04928       }
04929 
04930   /* selections on the sheet */
04931     if(event->window == sheet->sheet_window){
04932      gtk_widget_get_pointer (widget, &x, &y);
04933      gtk_sheet_get_pixel_info (sheet, x, y, &row, &column);
04934      gdk_pointer_grab (sheet->sheet_window, FALSE,
04935                GDK_POINTER_MOTION_HINT_MASK |
04936                GDK_BUTTON1_MOTION_MASK |
04937                GDK_BUTTON_RELEASE_MASK,
04938                NULL, NULL, event->time);
04939      gtk_grab_add(GTK_WIDGET(sheet));
04940      sheet->timer=gtk_timeout_add(TIMEOUT_SCROLL, gtk_sheet_scroll, sheet); 
04941      GTK_WIDGET_UNSET_FLAGS(sheet->sheet_entry, GTK_HAS_FOCUS);
04942      GTK_WIDGET_SET_FLAGS(GTK_SHEET(sheet), GTK_HAS_FOCUS);
04943      gtk_widget_grab_focus(GTK_WIDGET(sheet));
04944 
04945      if(sheet->selection_mode != GTK_SELECTION_SINGLE &&
04946         sheet->cursor_drag->type==GDK_SIZING &&
04947         !GTK_SHEET_IN_SELECTION(sheet) && !GTK_SHEET_IN_RESIZE(sheet)){
04948         if(sheet->state==GTK_STATE_NORMAL) {
04949           row=sheet->active_cell.row;
04950           column=sheet->active_cell.col;
04951           if(!gtk_sheet_deactivate_cell(sheet)) return FALSE;
04952           sheet->active_cell.row=row;
04953           sheet->active_cell.col=column;
04954           sheet->drag_range=sheet->range;
04955           sheet->state=GTK_SHEET_RANGE_SELECTED;
04956           gtk_sheet_select_range(sheet, &sheet->drag_range);
04957         }
04958         sheet->x_drag=x;
04959         sheet->y_drag=y;
04960         if(row > sheet->range.rowi) row--;
04961         if(column > sheet->range.coli) column--;
04962         sheet->drag_cell.row = row;
04963         sheet->drag_cell.col = column;
04964         sheet->drag_range=sheet->range;
04965         draw_xor_rectangle(sheet, sheet->drag_range);
04966         GTK_SHEET_SET_FLAGS(sheet, GTK_SHEET_IN_RESIZE);
04967      }
04968      else if(sheet->cursor_drag->type==GDK_TOP_LEFT_ARROW &&
04969             !GTK_SHEET_IN_SELECTION(sheet) && !GTK_SHEET_IN_DRAG(sheet)) {
04970             if(sheet->state==GTK_STATE_NORMAL) {
04971               row=sheet->active_cell.row;
04972               column=sheet->active_cell.col;
04973               if(!gtk_sheet_deactivate_cell(sheet)) return FALSE;
04974               sheet->active_cell.row=row;
04975               sheet->active_cell.col=column;
04976               sheet->drag_range=sheet->range;
04977               sheet->state=GTK_SHEET_RANGE_SELECTED;
04978               gtk_sheet_select_range(sheet, &sheet->drag_range);
04979             }
04980             sheet->x_drag=x;
04981             sheet->y_drag=y;
04982             if(row < sheet->range.row0) row++;
04983             if(row > sheet->range.rowi) row--;
04984             if(column < sheet->range.col0) column++;
04985             if(column > sheet->range.coli) column--;
04986             sheet->drag_cell.row=row;
04987             sheet->drag_cell.col=column;
04988             sheet->drag_range=sheet->range;
04989             draw_xor_rectangle(sheet, sheet->drag_range);
04990             GTK_SHEET_SET_FLAGS(sheet, GTK_SHEET_IN_DRAG);
04991           }
04992           else 
04993           {
04994            gtk_sheet_click_cell(sheet, row, column, &veto);
04995            if(veto) GTK_SHEET_SET_FLAGS(sheet, GTK_SHEET_IN_SELECTION);
04996           }
04997 
04998     }
04999 
05000     if(event->window == sheet->column_title_window){
05001      gtk_widget_get_pointer (widget, &x, &y);
05002      column = COLUMN_FROM_XPIXEL(sheet, x);
05003      if(sheet->column[column].is_sensitive){;
05004        gtk_sheet_click_cell(sheet, -1, column, &veto);
05005        gtk_grab_add(GTK_WIDGET(sheet));
05006        sheet->timer=gtk_timeout_add(TIMEOUT_SCROLL, gtk_sheet_scroll, sheet); 
05007        GTK_WIDGET_UNSET_FLAGS(sheet->sheet_entry, GTK_HAS_FOCUS);
05008        GTK_WIDGET_SET_FLAGS(GTK_SHEET(sheet), GTK_HAS_FOCUS);
05009        gtk_widget_grab_focus(GTK_WIDGET(sheet));
05010        GTK_SHEET_SET_FLAGS(sheet, GTK_SHEET_IN_SELECTION);
05011      }
05012     }
05013 
05014     if(event->window == sheet->row_title_window){
05015      gtk_widget_get_pointer (widget, &x, &y);
05016      row = ROW_FROM_YPIXEL(sheet, y);
05017      if(sheet->row[row].is_sensitive){
05018        gtk_sheet_click_cell(sheet, row, -1, &veto);
05019        gtk_grab_add(GTK_WIDGET(sheet));
05020        sheet->timer=gtk_timeout_add(TIMEOUT_SCROLL, gtk_sheet_scroll, sheet); 
05021        GTK_WIDGET_UNSET_FLAGS(sheet->sheet_entry, GTK_HAS_FOCUS);
05022        GTK_WIDGET_SET_FLAGS(GTK_SHEET(sheet), GTK_HAS_FOCUS);
05023        gtk_widget_grab_focus(GTK_WIDGET(sheet));
05024        GTK_SHEET_SET_FLAGS(sheet, GTK_SHEET_IN_SELECTION);
05025      }
05026     }
05027 
05028     return TRUE;
05029 }
05030 
05031 static gint
05032 gtk_sheet_scroll(gpointer data)
05033 {
05034  GtkSheet *sheet;
05035  gint x,y,row,column;
05036  gint move;
05037   
05038  sheet=GTK_SHEET(data);
05039 
05040  GDK_THREADS_ENTER();
05041 
05042  gtk_widget_get_pointer (GTK_WIDGET(sheet), &x, &y);
05043  gtk_sheet_get_pixel_info (sheet, x, y, &row, &column);
05044 
05045  move=TRUE;
05046 
05047  if(GTK_SHEET_IN_SELECTION(sheet))
05048       gtk_sheet_extend_selection(sheet, row, column);
05049 
05050  if(GTK_SHEET_IN_DRAG(sheet) || GTK_SHEET_IN_RESIZE(sheet)){
05051        move=gtk_sheet_move_query(sheet, row, column);
05052        if(move) draw_xor_rectangle(sheet, sheet->drag_range);      
05053  }       
05054 
05055  GDK_THREADS_LEAVE();
05056 
05057  return TRUE;
05058       
05059 }
05060 
05061 static void
05062 gtk_sheet_click_cell(GtkSheet *sheet, gint row, gint column, gboolean *veto)
05063 {
05064       *veto = TRUE;
05065 
05066       if(row > sheet->maxrow || column > sheet->maxcol){
05067           *veto = FALSE;
05068           return;
05069       }
05070 
05071       if(column >= 0 && row >= 0)
05072        if(!sheet->column[column].is_visible || !sheet->row[row].is_visible) 
05073          {
05074            *veto = FALSE;
05075            return;
05076          }
05077 
05078       _gtkextra_signal_emit(GTK_OBJECT(sheet), sheet_signals[TRAVERSE],
05079                             sheet->active_cell.row, sheet->active_cell.col, 
05080                             &row, &column, veto);
05081 
05082       if(!*veto){
05083            if(sheet->state == GTK_STATE_NORMAL) return;
05084 
05085            row = sheet->active_cell.row;
05086            column = sheet->active_cell.col;
05087            gtk_sheet_activate_cell(sheet, row, column);
05088            return;
05089       }
05090 
05091       if(row == -1 && column >= 0){
05092           if(gtk_sheet_autoscroll(sheet))
05093             gtk_sheet_move_query(sheet, row, column);
05094       gtk_sheet_select_column(sheet, column);
05095           return;
05096       }
05097       if(column == -1 && row >= 0){
05098           if(gtk_sheet_autoscroll(sheet))
05099             gtk_sheet_move_query(sheet, row, column);
05100       gtk_sheet_select_row(sheet, row);
05101           return;
05102       }
05103 
05104       if(row==-1 && column ==-1){
05105           sheet->range.row0=0;
05106           sheet->range.col0=0;
05107           sheet->range.rowi=sheet->maxrow;
05108           sheet->range.coli=sheet->maxcol;
05109       sheet->active_cell.row=0;
05110       sheet->active_cell.col=0;
05111       gtk_sheet_select_range(sheet, NULL);
05112       return;
05113       }
05114 
05115       if(row!=-1 && column !=-1){
05116           if(sheet->state != GTK_SHEET_NORMAL){
05117             sheet->state = GTK_SHEET_NORMAL;
05118             gtk_sheet_real_unselect_range(sheet, NULL);
05119           }
05120           else
05121           {
05122             if(!gtk_sheet_deactivate_cell(sheet)){
05123               *veto = FALSE;
05124               return;
05125             }
05126           }
05127 
05128           if(gtk_sheet_autoscroll(sheet))
05129             gtk_sheet_move_query(sheet, row, column);
05130           sheet->active_cell.row=row;
05131           sheet->active_cell.col=column;
05132       sheet->selection_cell.row=row;
05133           sheet->selection_cell.col=column;
05134           sheet->range.row0=row;
05135           sheet->range.col0=column;
05136           sheet->range.rowi=row;
05137           sheet->range.coli=column;
05138       sheet->state=GTK_SHEET_NORMAL;
05139           GTK_SHEET_SET_FLAGS(sheet, GTK_SHEET_IN_SELECTION);
05140       gtk_sheet_draw_active_cell(sheet);
05141       return;
05142       }
05143 
05144       gtk_sheet_activate_cell(sheet, sheet->active_cell.row,
05145                                      sheet->active_cell.col);
05146 }
05147 
05148 static gint
05149 gtk_sheet_button_release (GtkWidget * widget,
05150             GdkEventButton * event)
05151 {
05152   GtkSheet *sheet;
05153   gint x,y;
05154  
05155   sheet=GTK_SHEET(widget);
05156 
05157   /* release on resize windows */
05158   if (GTK_SHEET_IN_XDRAG (sheet)){
05159       GTK_SHEET_UNSET_FLAGS (sheet, GTK_SHEET_IN_XDRAG);
05160           GTK_SHEET_UNSET_FLAGS (sheet, GTK_SHEET_IN_SELECTION);
05161       gtk_widget_get_pointer (widget, &x, NULL);
05162       gdk_pointer_ungrab (event->time);
05163       draw_xor_vline (sheet);
05164       
05165       gtk_sheet_set_column_width (sheet, sheet->drag_cell.col, new_column_width (sheet, sheet->drag_cell.col, &x));
05166           sheet->old_hadjustment = -1.;
05167           gtk_signal_emit_by_name (GTK_OBJECT (sheet->hadjustment), "value_changed");
05168       return TRUE;
05169   }
05170 
05171   if (GTK_SHEET_IN_YDRAG (sheet)){
05172       GTK_SHEET_UNSET_FLAGS (sheet, GTK_SHEET_IN_YDRAG);
05173           GTK_SHEET_UNSET_FLAGS (sheet, GTK_SHEET_IN_SELECTION);
05174       gtk_widget_get_pointer (widget, NULL, &y);
05175       gdk_pointer_ungrab (event->time);
05176       draw_xor_hline (sheet);
05177       
05178       gtk_sheet_set_row_height (sheet, sheet->drag_cell.row, new_row_height (sheet, sheet->drag_cell.row, &y));
05179           sheet->old_vadjustment = -1.;
05180           gtk_signal_emit_by_name (GTK_OBJECT (sheet->vadjustment), "value_changed");
05181       return TRUE;
05182   }
05183 
05184   
05185   if (GTK_SHEET_IN_DRAG(sheet)){
05186       GtkSheetRange old_range;
05187       draw_xor_rectangle(sheet, sheet->drag_range);
05188       GTK_SHEET_UNSET_FLAGS(sheet, GTK_SHEET_IN_DRAG);
05189       gdk_pointer_ungrab (event->time);
05190 
05191       gtk_sheet_real_unselect_range(sheet, NULL);
05192       
05193       sheet->active_cell.row = sheet->active_cell.row +
05194                                (sheet->drag_range.row0 - sheet->range.row0);
05195       sheet->active_cell.col = sheet->active_cell.col +
05196                                (sheet->drag_range.col0 - sheet->range.col0);
05197       sheet->selection_cell.row = sheet->selection_cell.row +
05198                                   (sheet->drag_range.row0 - sheet->range.row0);
05199       sheet->selection_cell.col = sheet->selection_cell.col +
05200                                   (sheet->drag_range.col0 - sheet->range.col0);
05201       old_range=sheet->range;
05202       sheet->range=sheet->drag_range;
05203       sheet->drag_range=old_range;
05204       gtk_signal_emit(GTK_OBJECT(sheet),sheet_signals[MOVE_RANGE],
05205                       &sheet->drag_range, &sheet->range);
05206       gtk_sheet_select_range(sheet, &sheet->range);
05207   }
05208 
05209   if (GTK_SHEET_IN_RESIZE(sheet)){
05210       GtkSheetRange old_range;
05211       draw_xor_rectangle(sheet, sheet->drag_range);
05212       GTK_SHEET_UNSET_FLAGS(sheet, GTK_SHEET_IN_RESIZE);
05213       gdk_pointer_ungrab (event->time);
05214 
05215       gtk_sheet_real_unselect_range(sheet, NULL);
05216       
05217       sheet->active_cell.row = sheet->active_cell.row +
05218                                (sheet->drag_range.row0 - sheet->range.row0);
05219       sheet->active_cell.col = sheet->active_cell.col +
05220                                (sheet->drag_range.col0 - sheet->range.col0);
05221       if(sheet->drag_range.row0 < sheet->range.row0)
05222                      sheet->selection_cell.row = sheet->drag_range.row0;
05223       if(sheet->drag_range.rowi >= sheet->range.rowi)
05224                      sheet->selection_cell.row = sheet->drag_range.rowi;
05225       if(sheet->drag_range.col0 < sheet->range.col0)
05226                      sheet->selection_cell.col = sheet->drag_range.col0;
05227       if(sheet->drag_range.coli >= sheet->range.coli)
05228                      sheet->selection_cell.col = sheet->drag_range.coli;
05229       old_range = sheet->range;
05230       sheet->range = sheet->drag_range;
05231       sheet->drag_range = old_range;
05232 
05233       if(sheet->state==GTK_STATE_NORMAL) sheet->state=GTK_SHEET_RANGE_SELECTED;
05234       gtk_signal_emit(GTK_OBJECT(sheet),sheet_signals[RESIZE_RANGE],
05235                       &sheet->drag_range, &sheet->range);
05236       gtk_sheet_select_range(sheet, &sheet->range);
05237   }
05238 
05239   if(sheet->state == GTK_SHEET_NORMAL && GTK_SHEET_IN_SELECTION(sheet)){
05240       GTK_SHEET_UNSET_FLAGS(sheet, GTK_SHEET_IN_SELECTION);
05241       gdk_pointer_ungrab (event->time);
05242       gtk_sheet_activate_cell(sheet, sheet->active_cell.row, 
05243                                      sheet->active_cell.col);
05244   }
05245 
05246   if(GTK_SHEET_IN_SELECTION)
05247          gdk_pointer_ungrab (event->time);
05248   if(sheet->timer)
05249          gtk_timeout_remove(sheet->timer);
05250   gtk_grab_remove(GTK_WIDGET(sheet));
05251 
05252   GTK_SHEET_UNSET_FLAGS(sheet, GTK_SHEET_IN_SELECTION);
05253 
05254   return TRUE;
05255 }
05256 
05257 static gint
05258 gtk_sheet_motion (GtkWidget * widget,
05259           GdkEventMotion * event)
05260 {
05261   GtkSheet *sheet;
05262   GdkModifierType mods;
05263   GdkCursorType new_cursor;
05264   gint x, y, row, column;
05265 
05266   g_return_val_if_fail (widget != NULL, FALSE);
05267   g_return_val_if_fail (GTK_IS_SHEET (widget), FALSE);
05268   g_return_val_if_fail (event != NULL, FALSE);
05269 
05270 
05271   sheet = GTK_SHEET (widget);
05272 
05273 
05274   /* selections on the sheet */
05275   x = event->x;
05276   y = event->y;
05277 
05278   if(event->window == sheet->column_title_window && gtk_sheet_columns_resizable(sheet)){
05279     gtk_widget_get_pointer(widget, &x, &y);
05280     if(!GTK_SHEET_IN_SELECTION(sheet) && POSSIBLE_XDRAG(sheet, x, &column)){
05281       new_cursor=GDK_SB_H_DOUBLE_ARROW;
05282       if(new_cursor != sheet->cursor_drag->type){
05283         gdk_cursor_destroy(sheet->cursor_drag);
05284         sheet->cursor_drag=gdk_cursor_new(GDK_SB_H_DOUBLE_ARROW);
05285         gdk_window_set_cursor(sheet->column_title_window,sheet->cursor_drag);
05286       }
05287     }else{
05288       new_cursor=GDK_TOP_LEFT_ARROW;
05289       if(!GTK_SHEET_IN_XDRAG(sheet) && new_cursor != sheet->cursor_drag->type){
05290         gdk_cursor_destroy(sheet->cursor_drag);
05291         sheet->cursor_drag=gdk_cursor_new(GDK_TOP_LEFT_ARROW);
05292         gdk_window_set_cursor(sheet->column_title_window,sheet->cursor_drag);
05293       }
05294     }
05295   }      
05296 
05297   if(event->window == sheet->row_title_window && gtk_sheet_rows_resizable(sheet)){
05298     gtk_widget_get_pointer(widget, &x, &y);
05299     if(!GTK_SHEET_IN_SELECTION(sheet) && POSSIBLE_YDRAG(sheet,y, &column)){
05300       new_cursor=GDK_SB_V_DOUBLE_ARROW;
05301       if(new_cursor != sheet->cursor_drag->type){
05302         gdk_cursor_destroy(sheet->cursor_drag);
05303         sheet->cursor_drag=gdk_cursor_new(GDK_SB_V_DOUBLE_ARROW);
05304         gdk_window_set_cursor(sheet->row_title_window,sheet->cursor_drag);
05305       }
05306     }else{
05307       new_cursor=GDK_TOP_LEFT_ARROW;
05308       if(!GTK_SHEET_IN_YDRAG(sheet) && new_cursor != sheet->cursor_drag->type){
05309         gdk_cursor_destroy(sheet->cursor_drag);
05310         sheet->cursor_drag=gdk_cursor_new(GDK_TOP_LEFT_ARROW);
05311         gdk_window_set_cursor(sheet->row_title_window,sheet->cursor_drag);
05312       }
05313     }
05314   }      
05315 
05316   new_cursor=GDK_PLUS;
05317   if(!POSSIBLE_DRAG(sheet,x,y,&row,&column) && !GTK_SHEET_IN_DRAG(sheet) &&
05318      !POSSIBLE_RESIZE(sheet,x,y,&row,&column) && !GTK_SHEET_IN_RESIZE(sheet) &&
05319      event->window == sheet->sheet_window && 
05320      new_cursor != sheet->cursor_drag->type){
05321          gdk_cursor_destroy(sheet->cursor_drag);
05322          sheet->cursor_drag=gdk_cursor_new(GDK_PLUS);
05323          gdk_window_set_cursor(sheet->sheet_window,sheet->cursor_drag);
05324   }
05325 
05326   new_cursor=GDK_TOP_LEFT_ARROW;
05327   if(!(POSSIBLE_RESIZE(sheet,x,y,&row,&column) || GTK_SHEET_IN_RESIZE(sheet)) &&
05328      (POSSIBLE_DRAG(sheet, x,y,&row,&column) || GTK_SHEET_IN_DRAG(sheet)) && 
05329      event->window == sheet->sheet_window && 
05330      new_cursor != sheet->cursor_drag->type){
05331          gdk_cursor_destroy(sheet->cursor_drag);
05332          sheet->cursor_drag=gdk_cursor_new(GDK_TOP_LEFT_ARROW);
05333          gdk_window_set_cursor(sheet->sheet_window,sheet->cursor_drag);
05334   }
05335 
05336   new_cursor=GDK_SIZING;
05337   if(!GTK_SHEET_IN_DRAG(sheet) &&
05338      (POSSIBLE_RESIZE(sheet,x,y,&row,&column) || GTK_SHEET_IN_RESIZE(sheet)) &&
05339      event->window == sheet->sheet_window && 
05340      new_cursor != sheet->cursor_drag->type){
05341          gdk_cursor_destroy(sheet->cursor_drag);
05342          sheet->cursor_drag=gdk_cursor_new(GDK_SIZING);
05343          gdk_window_set_cursor(sheet->sheet_window,sheet->cursor_drag);
05344   }
05345 
05346   gdk_window_get_pointer (widget->window, &x, &y, &mods);
05347   if(!(mods & GDK_BUTTON1_MASK)) return FALSE;
05348 
05349   if (GTK_SHEET_IN_XDRAG (sheet)){
05350     if (event->is_hint || event->window != widget->window)
05351         gtk_widget_get_pointer (widget, &x, NULL);
05352       else
05353         x = event->x;
05354 
05355       new_column_width (sheet, sheet->drag_cell.col, &x);
05356       if (x != sheet->x_drag)
05357         {
05358           draw_xor_vline (sheet);
05359           sheet->x_drag = x;
05360           draw_xor_vline (sheet);
05361         }
05362           return TRUE;
05363   }
05364 
05365   if (GTK_SHEET_IN_YDRAG (sheet)){
05366       if (event->is_hint || event->window != widget->window)
05367         gtk_widget_get_pointer (widget, NULL, &y);
05368       else
05369         y = event->y;
05370 
05371       new_row_height (sheet, sheet->drag_cell.row, &y);
05372       if (y != sheet->y_drag)
05373         {
05374           draw_xor_hline (sheet);
05375           sheet->y_drag = y;
05376           draw_xor_hline (sheet);
05377         }
05378           return TRUE;
05379   }
05380 
05381   if (GTK_SHEET_IN_DRAG(sheet)){
05382        GtkSheetRange aux;
05383        column=COLUMN_FROM_XPIXEL(sheet,x)-sheet->drag_cell.col;
05384        row=ROW_FROM_YPIXEL(sheet,y)-sheet->drag_cell.row;
05385        if(sheet->state==GTK_SHEET_COLUMN_SELECTED) row=0;
05386        if(sheet->state==GTK_SHEET_ROW_SELECTED) column=0;
05387        sheet->x_drag=x;
05388        sheet->y_drag=y;
05389        aux=sheet->range;
05390        if(aux.row0+row >= 0 && aux.rowi+row <= sheet->maxrow &&
05391           aux.col0+column >= 0 && aux.coli+column <= sheet->maxcol){
05392              aux=sheet->drag_range;
05393              sheet->drag_range.row0=sheet->range.row0+row;
05394              sheet->drag_range.col0=sheet->range.col0+column;
05395              sheet->drag_range.rowi=sheet->range.rowi+row;
05396              sheet->drag_range.coli=sheet->range.coli+column;
05397              if(aux.row0 != sheet->drag_range.row0 ||
05398                 aux.col0 != sheet->drag_range.col0){
05399                 draw_xor_rectangle (sheet, aux);
05400                 draw_xor_rectangle (sheet, sheet->drag_range);
05401              }
05402        }
05403        return TRUE;
05404   }
05405 
05406   if (GTK_SHEET_IN_RESIZE(sheet)){
05407        GtkSheetRange aux;
05408        gint v_h;
05409        v_h=1;
05410        if(abs(x-COLUMN_LEFT_XPIXEL(sheet,sheet->drag_cell.col)) >
05411           abs(y-ROW_TOP_YPIXEL(sheet,sheet->drag_cell.row))) v_h=2;
05412 
05413        column=COLUMN_FROM_XPIXEL(sheet,x)-sheet->drag_cell.col;
05414        row=ROW_FROM_YPIXEL(sheet,y)-sheet->drag_cell.row;
05415        if(sheet->state==GTK_SHEET_COLUMN_SELECTED) row=0;
05416        if(sheet->state==GTK_SHEET_ROW_SELECTED) column=0;
05417        sheet->x_drag=x;
05418        sheet->y_drag=y;
05419        aux=sheet->range;
05420 
05421        if(row < sheet->range.row0 - sheet->range.rowi - 1) 
05422           row=row+(sheet->range.rowi-sheet->range.row0 + 1);
05423        else if(row<0) row=0;
05424 
05425        if(column < sheet->range.col0 - sheet->range.coli - 1)
05426           column=column+(sheet->range.coli-sheet->range.col0 + 1);
05427        else if(column<0) column=0;
05428 
05429        if(v_h==1) 
05430            column=0;
05431        else
05432            row=0;
05433 
05434        if(aux.row0+row >= 0 && aux.rowi+row <= sheet->maxrow &&
05435           aux.col0+column >= 0 && aux.coli+column <= sheet->maxcol){
05436 
05437              aux=sheet->drag_range;
05438              sheet->drag_range=sheet->range;
05439 
05440              if(row<0) sheet->drag_range.row0=sheet->range.row0+row;
05441              if(row>0) sheet->drag_range.rowi=sheet->range.rowi+row;
05442              if(column<0) sheet->drag_range.col0=sheet->range.col0+column;
05443              if(column>0) sheet->drag_range.coli=sheet->range.coli+column;
05444              
05445              if(aux.row0 != sheet->drag_range.row0 ||
05446                 aux.rowi != sheet->drag_range.rowi ||
05447                 aux.col0 != sheet->drag_range.col0 ||
05448                 aux.coli != sheet->drag_range.coli){
05449                      draw_xor_rectangle (sheet, aux);
05450                      draw_xor_rectangle (sheet, sheet->drag_range);
05451              }
05452        }
05453        return TRUE;
05454   }
05455 
05456   
05457 
05458   gtk_sheet_get_pixel_info (sheet, x, y, &row, &column);
05459 
05460   if(sheet->state==GTK_SHEET_NORMAL && row==sheet->active_cell.row &&
05461      column==sheet->active_cell.col) return TRUE;
05462 
05463   if(GTK_SHEET_IN_SELECTION(sheet) && mods&GDK_BUTTON1_MASK)
05464                           gtk_sheet_extend_selection(sheet, row, column);
05465 
05466   return TRUE;
05467 }
05468 
05469 static gint
05470 gtk_sheet_move_query(GtkSheet *sheet, gint row, gint column)
05471 {
05472   gint row_move, column_move;
05473   gfloat row_align, col_align;
05474   guint height, width;
05475   gint new_row = row;
05476   gint new_col = column;
05477 
05478   row_move=FALSE;
05479   column_move=FALSE;
05480   row_align=-1.;
05481   col_align=-1.;
05482 
05483   height = sheet->sheet_window_height;
05484   width = sheet->sheet_window_width;
05485 
05486   if(row>=MAX_VISIBLE_ROW(sheet) && sheet->state!=GTK_SHEET_COLUMN_SELECTED) {
05487           row_align = 1.;
05488       new_row = MIN(sheet->maxrow, row + 1);
05489           row_move = TRUE;
05490           if(MAX_VISIBLE_ROW(sheet) == sheet->maxrow &&
05491              ROW_TOP_YPIXEL(sheet, sheet->maxrow) + 
05492              sheet->row[sheet->maxrow].height < height){
05493                  row_move = FALSE;
05494          row_align = -1.;
05495           }
05496   }
05497   if(row<MIN_VISIBLE_ROW(sheet) && sheet->state!=GTK_SHEET_COLUMN_SELECTED) {
05498           row_align= 0.;
05499           row_move = TRUE;
05500   }
05501   if(column>=MAX_VISIBLE_COLUMN(sheet) && sheet->state!=GTK_SHEET_ROW_SELECTED) {
05502           col_align = 1.;
05503           new_col = MIN(sheet->maxcol, column + 1);
05504           column_move = TRUE;
05505           if(MAX_VISIBLE_COLUMN(sheet) == sheet->maxcol &&
05506              COLUMN_LEFT_XPIXEL(sheet, sheet->maxcol) + 
05507              sheet->column[sheet->maxcol].width < width){
05508                  column_move = FALSE;
05509          col_align = -1.;
05510           }
05511   } 
05512   if(column<MIN_VISIBLE_COLUMN(sheet) && sheet->state!=GTK_SHEET_ROW_SELECTED) {
05513       col_align = 0.;
05514           column_move = TRUE;
05515   }
05516 
05517   if(row_move || column_move){
05518         gtk_sheet_moveto(sheet, new_row, new_col, row_align, col_align);
05519   }
05520 
05521   return(row_move || column_move);
05522 }
05523 
05524 static void
05525 gtk_sheet_extend_selection(GtkSheet *sheet, gint row, gint column)
05526 {
05527    GtkSheetRange range;
05528    gint state;
05529    gint r,c;
05530 
05531    if(row == sheet->selection_cell.row && column == sheet->selection_cell.col)
05532         return;
05533 
05534    if(sheet->selection_mode == GTK_SELECTION_SINGLE) return;
05535 
05536    gtk_sheet_move_query(sheet, row, column);
05537    gtk_widget_grab_focus(GTK_WIDGET(sheet));
05538 
05539    if(GTK_SHEET_IN_DRAG(sheet)) return;
05540 
05541    state=sheet->state;
05542 
05543    switch(sheet->state){
05544     case GTK_SHEET_ROW_SELECTED:
05545      column = sheet->maxcol;
05546          break;
05547     case GTK_SHEET_COLUMN_SELECTED:
05548      row = sheet->maxrow;
05549          break; 
05550     case GTK_SHEET_NORMAL:
05551      sheet->state=GTK_SHEET_RANGE_SELECTED;
05552          r=sheet->active_cell.row;
05553          c=sheet->active_cell.col;
05554          sheet->range.col0=c;
05555          sheet->range.row0=r;
05556          sheet->range.coli=c;
05557          sheet->range.rowi=r;
05558          gdk_draw_pixmap(sheet->sheet_window,
05559                    GTK_WIDGET(sheet)->style->fg_gc[GTK_STATE_NORMAL],
05560                    sheet->pixmap,
05561                    COLUMN_LEFT_XPIXEL(sheet,c)-1,
05562                    ROW_TOP_YPIXEL(sheet,r)-1,
05563                    COLUMN_LEFT_XPIXEL(sheet,c)-1,
05564                    ROW_TOP_YPIXEL(sheet,r)-1,
05565                    sheet->column[c].width+4,
05566                    sheet->row[r].height+4);   
05567          gtk_sheet_range_draw_selection(sheet, sheet->range);
05568     case GTK_SHEET_RANGE_SELECTED:
05569          sheet->state=GTK_SHEET_RANGE_SELECTED;
05570    }
05571 
05572    sheet->selection_cell.row = row;
05573    sheet->selection_cell.col = column;
05574 
05575    range.col0=MIN(column,sheet->active_cell.col);
05576    range.coli=MAX(column,sheet->active_cell.col);
05577    range.row0=MIN(row,sheet->active_cell.row);
05578    range.rowi=MAX(row,sheet->active_cell.row);
05579 
05580    if(range.row0 != sheet->range.row0 || range.rowi != sheet->range.rowi ||
05581       range.col0 != sheet->range.col0 || range.coli != sheet->range.coli ||
05582       state==GTK_SHEET_NORMAL)
05583                gtk_sheet_real_select_range(sheet, &range);
05584 
05585 }
05586 
05587 /* Removed by SDB while cleaning up key press behavior */
05588 #if 0
05589 static gint
05590 gtk_sheet_entry_key_press(GtkWidget *widget,
05591                   GdkEventKey *key)
05592 {
05593   gboolean focus;
05594 #ifdef DEBUG
05595   printf("Entered gtk_sheet_entry_key_press. . . . . \n");
05596 #endif
05597 
05598   gtk_signal_emit_by_name(GTK_OBJECT(widget), "key_press_event", key, &focus);
05599   return focus;
05600 }
05601 #endif
05602 
05603 static gint
05604 gtk_sheet_key_press(GtkWidget *widget,
05605             GdkEventKey *key)
05606 {
05607   GtkSheet *sheet;
05608   gint row, col;
05609   gint state;
05610   gboolean extend_selection = FALSE;
05611 #if 0
05612   gboolean force_move = FALSE;
05613 #endif
05614   gboolean in_selection = FALSE;
05615   gboolean veto = TRUE;
05616   gint scroll = 1;
05617 
05618   sheet = GTK_SHEET(widget);
05619 
05620 #ifdef DEBUG
05621     printf("\n\nJust entered gtk_sheet_key_press. . . . \n");
05622 #endif
05623 
05624 
05625   if(key->state & GDK_CONTROL_MASK || key->keyval==GDK_Control_L ||
05626      key->keyval==GDK_Control_R) return FALSE;
05627 
05628 /*
05629   {
05630     if(key->keyval=='c' || key->keyval == 'C' && sheet->state != GTK_STATE_NORMAL)
05631             gtk_sheet_clip_range(sheet, sheet->range);
05632     if(key->keyval=='x' || key->keyval == 'X')
05633             gtk_sheet_unclip_range(sheet);    
05634     return FALSE;
05635   }
05636 */
05637 
05638   /* extend_selection is set when shift, ctrl, etc is pressed & held down */
05639   extend_selection = (key->state & GDK_SHIFT_MASK) || key->keyval==GDK_Shift_L 
05640 || key->keyval==GDK_Shift_R;
05641 
05642 #ifdef DEBUG
05643     printf(". . . .  extend_selection = %d\n", extend_selection);
05644 #endif
05645 
05646   state=sheet->state;
05647   in_selection = GTK_SHEET_IN_SELECTION(sheet);
05648   GTK_SHEET_UNSET_FLAGS(sheet, GTK_SHEET_IN_SELECTION);
05649 
05650 #ifdef DEBUG
05651     printf("We are about to enter the switch statement. . .\n");
05652 #endif
05653 
05654   switch(key->keyval){
05655     case GDK_Return: case GDK_KP_Enter:
05656       if(sheet->state == GTK_SHEET_NORMAL && 
05657          !GTK_SHEET_IN_SELECTION(sheet))
05658          gtk_signal_emit_stop_by_name(GTK_OBJECT(gtk_sheet_get_entry(sheet)), 
05659                                      "key_press_event");
05660       row = sheet->active_cell.row;
05661       col = sheet->active_cell.col;
05662       if(sheet->state == GTK_SHEET_COLUMN_SELECTED)
05663            row = MIN_VISIBLE_ROW(sheet)-1;
05664       if(sheet->state == GTK_SHEET_ROW_SELECTED)
05665            col = MIN_VISIBLE_COLUMN(sheet);
05666       if(row < sheet->maxrow){
05667            row = row + scroll;
05668            while(!sheet->row[row].is_visible && row<sheet->maxrow) row++;
05669       }
05670       gtk_sheet_click_cell(sheet, row, col, &veto);
05671       extend_selection = FALSE;
05672       break;
05673 
05674     case GDK_ISO_Left_Tab:
05675     case GDK_Left:   /* Left arrow  */
05676 #ifdef DEBUG
05677       printf("In gtk_sheet_key_press, received GDK_Left.\n");
05678 #endif
05679       row = sheet->active_cell.row;
05680       col = sheet->active_cell.col;
05681       if(sheet->state == GTK_SHEET_ROW_SELECTED) 
05682     col = MIN_VISIBLE_COLUMN(sheet)-1;
05683       if(sheet->state == GTK_SHEET_COLUMN_SELECTED) 
05684     row = MIN_VISIBLE_ROW(sheet);
05685       if(col > 0){
05686     col = col - scroll; 
05687     while(!sheet->column[col].is_visible && col>0) col--;
05688     col=MAX(0, col);
05689       }       
05690       gtk_sheet_click_cell(sheet, row, col, &veto);
05691       extend_selection = FALSE;
05692       break;
05693 
05694     case GDK_Tab:
05695     case GDK_Right: /* Right arrow  */
05696 #ifdef DEBUG
05697       printf("In gtk_sheet_key_press, received GDK_Right.\n");
05698 #endif
05699       row = sheet->active_cell.row;
05700       col = sheet->active_cell.col;
05701       if(sheet->state == GTK_SHEET_ROW_SELECTED) 
05702            col = MIN_VISIBLE_COLUMN(sheet)-1;
05703       if(sheet->state == GTK_SHEET_COLUMN_SELECTED) 
05704            row = MIN_VISIBLE_ROW(sheet);
05705       if(col < sheet->maxcol){
05706            col = col + scroll; 
05707            while(!sheet->column[col].is_visible && col<sheet->maxcol) col++;
05708       }       
05709       gtk_sheet_click_cell(sheet, row, col, &veto);
05710       extend_selection = FALSE;
05711       break;
05712 
05713 /*    case GDK_BackSpace:
05714       if(sheet->active_cell.row >= 0 && sheet->active_cell.col >= 0){
05715        if(sheet->active_cell.col > 0){
05716             col = sheet->active_cell.col - scroll; 
05717         row = sheet->active_cell.row;
05718             while(!sheet->column[col].is_visible && col > 0) col--;
05719        }       
05720       }
05721       gtk_sheet_click_cell(sheet, row, col, &veto);
05722       extend_selection = FALSE;
05723       break;
05724 */
05725 
05726     case GDK_Page_Up:
05727       scroll=MAX_VISIBLE_ROW(sheet)-MIN_VISIBLE_ROW(sheet)+1;
05728     case GDK_Up:       /* arrow key up */
05729       if(extend_selection){
05730         if(state==GTK_STATE_NORMAL){
05731            row=sheet->active_cell.row;
05732            col=sheet->active_cell.col;
05733            gtk_sheet_click_cell(sheet, row, col, &veto);
05734            if(!veto) break;
05735         }
05736         if(sheet->selection_cell.row > 0){
05737           row = sheet->selection_cell.row - scroll;
05738           while(!sheet->row[row].is_visible && row > 0) row--;
05739           row = MAX(0, row);
05740           gtk_sheet_extend_selection(sheet, row, sheet->selection_cell.col);
05741         }
05742         return TRUE;
05743       }
05744       col = sheet->active_cell.col;
05745       row = sheet->active_cell.row;
05746       if(state==GTK_SHEET_COLUMN_SELECTED) 
05747              row = MIN_VISIBLE_ROW(sheet);
05748       if(state==GTK_SHEET_ROW_SELECTED) 
05749              col = MIN_VISIBLE_COLUMN(sheet);
05750       row = row - scroll;
05751       while(!sheet->row[row].is_visible && row > 0) row--;
05752       row = MAX(0,row);
05753       gtk_sheet_click_cell(sheet, row, col, &veto);
05754       extend_selection = FALSE;
05755       break;
05756 
05757     case GDK_Page_Down:
05758       scroll=MAX_VISIBLE_ROW(sheet)-MIN_VISIBLE_ROW(sheet)+1;
05759     case GDK_Down:       /* arrow key down */
05760       if(extend_selection){
05761         if(state==GTK_STATE_NORMAL){
05762            row=sheet->active_cell.row;
05763            col=sheet->active_cell.col;
05764            gtk_sheet_click_cell(sheet, row, col, &veto);
05765            if(!veto) break;
05766         }
05767         if(sheet->selection_cell.row < sheet->maxrow){
05768           row = sheet->selection_cell.row + scroll;
05769           while(!sheet->row[row].is_visible && row < sheet->maxrow) row++;
05770           row = MIN(sheet->maxrow, row);
05771           gtk_sheet_extend_selection(sheet, row, sheet->selection_cell.col);
05772         }
05773         return TRUE;
05774       }
05775       col = sheet->active_cell.col;
05776       row = sheet->active_cell.row;
05777       if(sheet->active_cell.row < sheet->maxrow){
05778        if(state==GTK_SHEET_COLUMN_SELECTED) 
05779                 row = MIN_VISIBLE_ROW(sheet)-1;
05780        if(state==GTK_SHEET_ROW_SELECTED) 
05781                 col = MIN_VISIBLE_COLUMN(sheet);
05782        row = row + scroll;
05783            while(!sheet->row[row].is_visible && row < sheet->maxrow) row++;
05784            row = MIN(sheet->maxrow, row);
05785       }
05786       gtk_sheet_click_cell(sheet, row, col, &veto);
05787       extend_selection = FALSE;
05788       break;
05789 
05790 #if 0
05791   case GDK_Right:
05792     if(extend_selection){
05793       if(state==GTK_STATE_NORMAL){
05794     row=sheet->active_cell.row;
05795     col=sheet->active_cell.col;
05796     gtk_sheet_click_cell(sheet, row, col, &veto);
05797     if(!veto) break;
05798       }
05799       if(sheet->selection_cell.col < sheet->maxcol){
05800     col = sheet->selection_cell.col + 1;
05801     while(!sheet->column[col].is_visible && col < sheet->maxcol) col++;
05802     gtk_sheet_extend_selection(sheet, sheet->selection_cell.row, col);
05803       }
05804       return TRUE;
05805     }
05806     col = sheet->active_cell.col;
05807     row = sheet->active_cell.row;
05808     if(sheet->active_cell.col < sheet->maxcol){
05809       col ++;
05810       if(state==GTK_SHEET_ROW_SELECTED) 
05811     col = MIN_VISIBLE_COLUMN(sheet)-1;
05812       if(state==GTK_SHEET_COLUMN_SELECTED) 
05813     row = MIN_VISIBLE_ROW(sheet);
05814       while(!sheet->column[col].is_visible && col < sheet->maxcol) col++;
05815       if(strlen(gtk_entry_get_text(GTK_ENTRY(gtk_sheet_get_entry(sheet)))) == 0 
05816      || force_move) {
05817         gtk_sheet_click_cell(sheet, row, col, &veto);
05818       }
05819       else
05820     return FALSE;
05821     }
05822     extend_selection = FALSE;
05823     break;
05824     
05825     
05826   case GDK_Left: 
05827     if(extend_selection){
05828       if(state==GTK_STATE_NORMAL){
05829     row=sheet->active_cell.row;
05830         col=sheet->active_cell.col;
05831     gtk_sheet_click_cell(sheet, row, col, &veto);
05832     if(!veto) break;
05833       }
05834       if(sheet->selection_cell.col > 0){
05835     col = sheet->selection_cell.col - 1;
05836         while(!sheet->column[col].is_visible && col > 0) col--;          
05837     gtk_sheet_extend_selection(sheet, sheet->selection_cell.row, col);
05838       }
05839       return TRUE;
05840     }
05841     col = sheet->active_cell.col - 1;
05842     row = sheet->active_cell.row;
05843     if(state==GTK_SHEET_ROW_SELECTED) 
05844       col = MIN_VISIBLE_COLUMN(sheet)-1;
05845     if(state==GTK_SHEET_COLUMN_SELECTED) 
05846       row = MIN_VISIBLE_ROW(sheet);
05847     while(!sheet->column[col].is_visible && col > 0) col--;
05848     col = MAX(0, col);
05849     
05850     if(strlen(gtk_entry_get_text(GTK_ENTRY(gtk_sheet_get_entry(sheet)))) == 0
05851        || force_move){
05852       gtk_sheet_click_cell(sheet, row, col, &veto);
05853     }
05854     else
05855       return FALSE;
05856     extend_selection = FALSE;
05857     break;
05858 #endif
05859 
05860 
05861     case GDK_Home:
05862       row=0;
05863       while(!sheet->row[row].is_visible && row < sheet->maxrow) row++;
05864       gtk_sheet_click_cell(sheet, row, sheet->active_cell.col, &veto);
05865       extend_selection = FALSE;
05866       break;
05867 
05868     case GDK_End:
05869       row=sheet->maxrow;
05870       while(!sheet->row[row].is_visible && row > 0) row--;
05871       gtk_sheet_click_cell(sheet, row, sheet->active_cell.col, &veto);
05872       extend_selection = FALSE;
05873       break;
05874 
05875     default:
05876 #ifdef DEBUG
05877       printf("In gtk_sheet_key_press, after switch, found default case.\n");
05878       printf("  User probably typed letter key or DEL.\n");
05879 #endif
05880       if(in_selection) {
05881     GTK_SHEET_SET_FLAGS(sheet, GTK_SHEET_IN_SELECTION);
05882     if(extend_selection) return TRUE; 
05883       }
05884       if(state == GTK_SHEET_ROW_SELECTED) 
05885       sheet->active_cell.col=MIN_VISIBLE_COLUMN(sheet);
05886       if(state == GTK_SHEET_COLUMN_SELECTED)
05887         sheet->active_cell.row=MIN_VISIBLE_ROW(sheet);
05888       return FALSE;
05889   }  /*  switch  */
05890 
05891   if(extend_selection) return TRUE;
05892 
05893   gtk_sheet_activate_cell(sheet, sheet->active_cell.row,
05894                                  sheet->active_cell.col);
05895 
05896   return TRUE;
05897 } 
05898 
05899 static void
05900 gtk_sheet_size_request (GtkWidget * widget,
05901             GtkRequisition * requisition)
05902 {
05903   GtkSheet *sheet;
05904   GList *children;
05905   GtkSheetChild *child;
05906   GtkRequisition child_requisition;
05907 
05908   g_return_if_fail (widget != NULL);
05909   g_return_if_fail (GTK_IS_SHEET (widget));
05910   g_return_if_fail (requisition != NULL);
05911 
05912   sheet = GTK_SHEET (widget);
05913 
05914   requisition->width = 3*DEFAULT_COLUMN_WIDTH;
05915   requisition->height = 3*DEFAULT_ROW_HEIGHT(widget);
05916 
05917   /* compute the size of the column title area */
05918   if(sheet->column_titles_visible) 
05919      requisition->height += sheet->column_title_area.height;
05920 
05921   /* compute the size of the row title area */
05922   if(sheet->row_titles_visible) 
05923      requisition->width += sheet->row_title_area.width;
05924 
05925   sheet->view.row0=ROW_FROM_YPIXEL(sheet, sheet->column_title_area.height+1);
05926   sheet->view.rowi=ROW_FROM_YPIXEL(sheet, sheet->sheet_window_height-1);
05927   sheet->view.col0=COLUMN_FROM_XPIXEL(sheet, sheet->row_title_area.width+1);
05928   sheet->view.coli=COLUMN_FROM_XPIXEL(sheet, sheet->sheet_window_width);
05929 
05930   if(!sheet->column_titles_visible) 
05931      sheet->view.row0=ROW_FROM_YPIXEL(sheet, 1);
05932 
05933   if(!sheet->row_titles_visible) 
05934      sheet->view.col0=COLUMN_FROM_XPIXEL(sheet, 1);
05935 
05936   children = sheet->children;
05937   while (children)
05938   {
05939     child = children->data;
05940     children = g_list_next(children);
05941 
05942     gtk_widget_size_request(child->widget, &child_requisition);
05943   }
05944 }
05945 
05946  
05947 static void
05948 gtk_sheet_size_allocate (GtkWidget * widget,
05949              GtkAllocation * allocation)
05950 {
05951   GtkSheet *sheet;
05952   GtkAllocation sheet_allocation;
05953   gint border_width;
05954 
05955   g_return_if_fail (widget != NULL);
05956   g_return_if_fail (GTK_IS_SHEET (widget));
05957   g_return_if_fail (allocation != NULL);
05958 
05959   sheet = GTK_SHEET (widget);
05960   widget->allocation = *allocation;
05961   border_width = GTK_CONTAINER(widget)->border_width;
05962 
05963   if (GTK_WIDGET_REALIZED (widget))
05964     gdk_window_move_resize (widget->window,
05965                     allocation->x + border_width,
05966                         allocation->y + border_width,
05967                             allocation->width - 2*border_width,
05968                         allocation->height - 2*border_width);
05969 
05970   /* use internal allocation structure for all the math
05971    * because it's easier than always subtracting the container
05972    * border width */
05973   sheet->internal_allocation.x = 0;
05974   sheet->internal_allocation.y = 0;
05975   sheet->internal_allocation.width = allocation->width - 2*border_width;
05976   sheet->internal_allocation.height = allocation->height - 2*border_width;
05977     
05978   sheet_allocation.x = 0;
05979   sheet_allocation.y = 0;
05980   sheet_allocation.width = allocation->width - 2*border_width;
05981   sheet_allocation.height = allocation->height - 2*border_width;
05982 
05983   sheet->sheet_window_width = sheet_allocation.width;
05984   sheet->sheet_window_height = sheet_allocation.height;
05985 
05986   if (GTK_WIDGET_REALIZED (widget))
05987     gdk_window_move_resize (sheet->sheet_window,
05988                 sheet_allocation.x,
05989                 sheet_allocation.y,
05990                 sheet_allocation.width,
05991                 sheet_allocation.height);
05992 
05993     /* position the window which holds the column title buttons */
05994   sheet->column_title_area.x = 0;
05995   sheet->column_title_area.y = 0;
05996   if(sheet->row_titles_visible)
05997        sheet->column_title_area.x = sheet->row_title_area.width;
05998   sheet->column_title_area.width = sheet_allocation.width - 
05999                                      sheet->column_title_area.x;
06000   if(GTK_WIDGET_REALIZED(widget) && sheet->column_titles_visible)
06001       gdk_window_move_resize (sheet->column_title_window,
06002                   sheet->column_title_area.x,
06003                   sheet->column_title_area.y,
06004                   sheet->column_title_area.width,
06005                   sheet->column_title_area.height);
06006 
06007   sheet->sheet_window_width = sheet_allocation.width;
06008   sheet->sheet_window_height = sheet_allocation.height;
06009 
06010   /* column button allocation */
06011   size_allocate_column_title_buttons (sheet);
06012 
06013   /* position the window which holds the row title buttons */
06014   sheet->row_title_area.x = 0;
06015   sheet->row_title_area.y = 0;
06016   if(sheet->column_titles_visible)
06017        sheet->row_title_area.y = sheet->column_title_area.height;
06018   sheet->row_title_area.height = sheet_allocation.height -
06019                                    sheet->row_title_area.y;
06020 
06021   if(GTK_WIDGET_REALIZED(widget) && sheet->row_titles_visible)
06022       gdk_window_move_resize (sheet->row_title_window,
06023                   sheet->row_title_area.x,
06024                   sheet->row_title_area.y,
06025                   sheet->row_title_area.width,
06026                   sheet->row_title_area.height);
06027 
06028 
06029   /* row button allocation */
06030   size_allocate_row_title_buttons (sheet);
06031 
06032   sheet->view.row0=ROW_FROM_YPIXEL(sheet, sheet->column_title_area.height+1);
06033   sheet->view.rowi=ROW_FROM_YPIXEL(sheet, sheet->sheet_window_height-1);
06034   sheet->view.col0=COLUMN_FROM_XPIXEL(sheet, sheet->row_title_area.width+1);
06035   sheet->view.coli=COLUMN_FROM_XPIXEL(sheet, sheet->sheet_window_width);
06036 
06037   if(!sheet->column_titles_visible)
06038        sheet->view.row0=ROW_FROM_YPIXEL(sheet, 1);
06039       
06040   if(!sheet->row_titles_visible)
06041        sheet->view.col0=COLUMN_FROM_XPIXEL(sheet, 1);
06042 
06043   size_allocate_column_title_buttons(sheet);
06044   size_allocate_row_title_buttons(sheet);
06045 
06046   /* re-scale backing pixmap */
06047   gtk_sheet_make_backing_pixmap(sheet, 0, 0); 
06048   gtk_sheet_position_children(sheet);
06049 
06050   /* set the scrollbars adjustments */
06051   adjust_scrollbars (sheet);
06052 }
06053 
06054 static void
06055 size_allocate_column_title_buttons (GtkSheet * sheet)
06056 {
06057   gint i;
06058   gint x,width;
06059 
06060   if (!sheet->column_titles_visible) return;
06061   if (!GTK_WIDGET_REALIZED (sheet))
06062     return;
06063 
06064   width = sheet->sheet_window_width;
06065   x = 0;
06066 
06067   if(sheet->row_titles_visible)
06068     {
06069       width -= sheet->row_title_area.width;
06070       x = sheet->row_title_area.width;
06071     }
06072 
06073   if(sheet->column_title_area.width != width || sheet->column_title_area.x != x)
06074   {
06075      sheet->column_title_area.width = width;
06076      sheet->column_title_area.x = x;
06077      gdk_window_move_resize (sheet->column_title_window,
06078                  sheet->column_title_area.x,
06079                  sheet->column_title_area.y,
06080                  sheet->column_title_area.width,
06081                  sheet->column_title_area.height);
06082   }
06083 
06084 
06085   if(MAX_VISIBLE_COLUMN(sheet) == sheet->maxcol)
06086      gdk_window_clear_area (sheet->column_title_window,
06087                 0,0,
06088                 sheet->column_title_area.width, 
06089                             sheet->column_title_area.height);
06090 
06091   if(!GTK_WIDGET_DRAWABLE(sheet)) return;
06092 
06093   for (i = MIN_VISIBLE_COLUMN(sheet); i <= MAX_VISIBLE_COLUMN(sheet); i++)
06094       gtk_sheet_button_draw(sheet,-1,i);
06095 }
06096     
06097 static void
06098 size_allocate_row_title_buttons (GtkSheet * sheet)
06099 {
06100   gint i;
06101   gint y, height;
06102 
06103   if (!sheet->row_titles_visible) return;
06104   if (!GTK_WIDGET_REALIZED (sheet))
06105     return;
06106 
06107   height = sheet->sheet_window_height;
06108   y = 0;
06109 
06110   if(sheet->column_titles_visible)
06111     {
06112       height -= sheet->column_title_area.height;
06113       y = sheet->column_title_area.height;
06114     }
06115     
06116   if(sheet->row_title_area.height != height || sheet->row_title_area.y != y){
06117      sheet->row_title_area.y = y;
06118      sheet->row_title_area.height = height;
06119      gdk_window_move_resize (sheet->row_title_window,
06120                  sheet->row_title_area.x,
06121                  sheet->row_title_area.y,
06122                  sheet->row_title_area.width,
06123                  sheet->row_title_area.height);
06124   }
06125   if(MAX_VISIBLE_ROW(sheet) == sheet->maxrow)
06126     gdk_window_clear_area (sheet->row_title_window,
06127                0,0,
06128                sheet->row_title_area.width, 
06129                            sheet->row_title_area.height);
06130 
06131   if(!GTK_WIDGET_DRAWABLE(sheet)) return;
06132 
06133   for(i = MIN_VISIBLE_ROW(sheet); i <= MAX_VISIBLE_ROW(sheet); i++)
06134       gtk_sheet_button_draw(sheet,i,-1);
06135 }
06136       
06137 static void
06138 gtk_sheet_recalc_top_ypixels(GtkSheet *sheet, gint row)
06139 {
06140   gint i, cy;
06141 
06142   cy = sheet->column_title_area.height;
06143   if(!sheet->column_titles_visible) cy = 0;
06144   for(i=0; i<=sheet->maxrow; i++){
06145       sheet->row[i].top_ypixel=cy;
06146       if(sheet->row[i].is_visible) cy+=sheet->row[i].height;
06147   }
06148 }
06149 
06150 static void
06151 gtk_sheet_recalc_left_xpixels(GtkSheet *sheet, gint column)
06152 {
06153   gint i, cx;
06154 
06155   cx = sheet->row_title_area.width;
06156   if(!sheet->row_titles_visible) cx = 0;
06157   for(i=0; i<=sheet->maxcol; i++){
06158       sheet->column[i].left_xpixel=cx;
06159       if(sheet->column[i].is_visible) cx+=sheet->column[i].width;
06160   }
06161 
06162 }
06163 
06164 
06165 
06166 static void
06167 gtk_sheet_size_allocate_entry(GtkSheet *sheet)
06168 {
06169  GtkAllocation shentry_allocation;
06170  GtkSheetCellAttr attributes;
06171  GtkEntry *sheet_entry;
06172  GtkStyle *style = NULL, *previous_style = NULL;
06173  gint row, col;
06174  gint size, max_size, text_size, column_width;
06175  const gchar *text;
06176 
06177  if(!GTK_WIDGET_REALIZED(GTK_WIDGET(sheet))) return;
06178  if(!GTK_WIDGET_MAPPED(GTK_WIDGET(sheet))) return;
06179 
06180  sheet_entry = GTK_ENTRY(gtk_sheet_get_entry(sheet));
06181 
06182  gtk_sheet_get_attributes(sheet, sheet->active_cell.row, sheet->active_cell.col, &attributes); 
06183 
06184  if(GTK_WIDGET_REALIZED(sheet->sheet_entry)){
06185 
06186   if(!GTK_WIDGET(sheet_entry)->style) 
06187         gtk_widget_ensure_style(GTK_WIDGET(sheet_entry));
06188 
06189   previous_style = GTK_WIDGET(sheet_entry)->style;
06190 
06191   style = gtk_style_copy(previous_style);
06192   style->bg[GTK_STATE_NORMAL] = attributes.background;
06193   style->fg[GTK_STATE_NORMAL] = attributes.foreground;
06194   style->text[GTK_STATE_NORMAL] = attributes.foreground;
06195   style->bg[GTK_STATE_ACTIVE] = attributes.background;
06196   style->fg[GTK_STATE_ACTIVE] = attributes.foreground;
06197   style->text[GTK_STATE_ACTIVE] = attributes.foreground;
06198 
06199   pango_font_description_free(style->font_desc);
06200   style->font_desc = pango_font_description_copy(attributes.font_desc);
06201 
06202   GTK_WIDGET(sheet_entry)->style = style;
06203   gtk_widget_size_request(sheet->sheet_entry, NULL);
06204   GTK_WIDGET(sheet_entry)->style = previous_style;
06205 
06206   if(style != previous_style){
06207     style->bg[GTK_STATE_NORMAL] = previous_style->bg[GTK_STATE_NORMAL];
06208     style->fg[GTK_STATE_NORMAL] = previous_style->fg[GTK_STATE_NORMAL];
06209     style->bg[GTK_STATE_ACTIVE] = previous_style->bg[GTK_STATE_ACTIVE];
06210     style->fg[GTK_STATE_ACTIVE] = previous_style->fg[GTK_STATE_ACTIVE];
06211     gtk_widget_set_style(GTK_WIDGET(sheet_entry), style);
06212   }
06213  }
06214 
06215  max_size = 0;
06216 
06217  text_size = 0;
06218  text = gtk_entry_get_text(GTK_ENTRY(sheet_entry));
06219  if(text && strlen(text) > 0){ 
06220      text_size = STRING_WIDTH(GTK_WIDGET(sheet), attributes.font_desc, text);
06221  }
06222 
06223  column_width=sheet->column[sheet->active_cell.col].width;
06224 
06225  size=MIN(text_size, max_size);
06226  size=MAX(size,column_width-2*CELLOFFSET);
06227 
06228  row=sheet->active_cell.row;
06229  col=sheet->active_cell.col;
06230 
06231  shentry_allocation.x = COLUMN_LEFT_XPIXEL(sheet,sheet->active_cell.col);
06232  shentry_allocation.y = ROW_TOP_YPIXEL(sheet,sheet->active_cell.row);
06233  shentry_allocation.width = column_width;
06234  shentry_allocation.height = sheet->row[sheet->active_cell.row].height;
06235 
06236  shentry_allocation.x += 2;
06237  shentry_allocation.y += 2;
06238  shentry_allocation.width -= MIN(shentry_allocation.width, 3);
06239  shentry_allocation.height -= MIN(shentry_allocation.height, 3);
06240 
06241  gtk_widget_size_allocate(sheet->sheet_entry, &shentry_allocation);
06242 
06243  if(previous_style == style) gtk_style_unref(previous_style);
06244 }
06245 
06246 
06247 static void
06248 create_sheet_entry(GtkSheet *sheet)
06249 {
06250  GtkWidget *widget;
06251  GtkWidget *parent;
06252  GtkWidget *entry;
06253  GtkStyle *style;
06254  gint found_entry = FALSE;
06255 
06256  widget = GTK_WIDGET(sheet);
06257 
06258  style = gtk_style_copy(GTK_WIDGET(sheet)->style); 
06259 
06260  if(sheet->sheet_entry){
06261     /* avoids warnings */
06262     gtk_widget_ref(sheet->sheet_entry);
06263     gtk_widget_unparent(sheet->sheet_entry);
06264     gtk_widget_destroy(sheet->sheet_entry);
06265  }
06266 
06267  if(sheet->entry_type){
06268 
06269    if(!gtk_type_is_a (sheet->entry_type, GTK_TYPE_ENTRY)){
06270 
06271      parent = GTK_WIDGET(gtk_type_new(sheet->entry_type));
06272 
06273      sheet->sheet_entry = parent;
06274 
06275      entry = gtk_sheet_get_entry (sheet);
06276      if(GTK_IS_ENTRY(entry)) found_entry = TRUE;
06277 
06278    } else {
06279 
06280      parent = GTK_WIDGET(gtk_type_new(sheet->entry_type));
06281      entry = parent;
06282      found_entry = TRUE;
06283 
06284    }
06285 
06286    if(!found_entry){
06287 
06288      g_warning ("Entry type must be GtkEntry subclass, using default");
06289      entry = gtk_entry_new ();
06290      sheet->sheet_entry = entry;
06291 
06292    } else {
06293 
06294      sheet->sheet_entry = parent;
06295 
06296    }
06297 
06298 
06299  } else {
06300 
06301      entry = gtk_entry_new ();
06302      sheet->sheet_entry = entry;
06303 
06304  }
06305  
06306  gtk_widget_size_request(sheet->sheet_entry, NULL);
06307  
06308  if(GTK_WIDGET_REALIZED(sheet))
06309    {
06310       gtk_widget_set_parent_window (sheet->sheet_entry, sheet->sheet_window);
06311       gtk_widget_set_parent(sheet->sheet_entry, GTK_WIDGET(sheet));
06312       gtk_widget_realize(sheet->sheet_entry);
06313    }
06314 
06315  /* #if 0 */
06316  /*  SDB says:  I need to work out the event passing system */
06317  gtk_signal_connect_object(GTK_OBJECT(entry),"key_press_event",
06318                            (GtkSignalFunc) gtk_sheet_key_press,
06319                            GTK_OBJECT(sheet)); 
06320  /*  gtk_signal_connect_object(GTK_OBJECT(entry),"key_press_event",
06321                            (GtkSignalFunc) gtk_sheet_entry_key_press,
06322                            GTK_OBJECT(sheet)); 
06323  */
06324  /* #endif */
06325 
06326  gtk_widget_show (sheet->sheet_entry); 
06327 }
06328 
06329 
06330 GtkWidget * 
06331 gtk_sheet_get_entry(GtkSheet *sheet)
06332 {
06333  GtkWidget *parent;
06334  GtkWidget *entry = NULL;
06335  GtkTableChild *table_child;
06336  GtkBoxChild *box_child;
06337  GList *children = NULL;
06338 
06339  g_return_val_if_fail (sheet != NULL, NULL);
06340  g_return_val_if_fail (GTK_IS_SHEET (sheet), NULL);
06341  g_return_val_if_fail (sheet->sheet_entry != NULL, NULL);
06342 
06343  if(GTK_IS_ENTRY(sheet->sheet_entry)) return (sheet->sheet_entry);
06344 
06345  parent = GTK_WIDGET(sheet->sheet_entry);
06346 
06347  if(GTK_IS_TABLE(parent)) children = GTK_TABLE(parent)->children;
06348  if(GTK_IS_BOX(parent)) children = GTK_BOX(parent)->children;
06349 
06350  if(!children) return NULL;
06351 
06352  while(children){
06353       if(GTK_IS_TABLE(parent)) {
06354                  table_child = children->data;
06355                  entry = table_child->widget;
06356       }
06357       if(GTK_IS_BOX(parent)){
06358                  box_child = children->data; 
06359                  entry = box_child->widget;
06360       }
06361 
06362       if(GTK_IS_ENTRY(entry))  
06363                                 break;
06364       children = g_list_next(children);
06365  } 
06366 
06367 
06368  if(!GTK_IS_ENTRY(entry))   return NULL;
06369 
06370  return (entry);
06371 
06372 }
06373 
06374 GtkWidget * 
06375 gtk_sheet_get_entry_widget(GtkSheet *sheet)
06376 {
06377  g_return_val_if_fail (sheet != NULL, NULL);
06378  g_return_val_if_fail (GTK_IS_SHEET (sheet), NULL);
06379  g_return_val_if_fail (sheet->sheet_entry != NULL, NULL);
06380 
06381  return (sheet->sheet_entry);
06382 }
06383 
06384 /* BUTTONS */
06385 static void
06386 row_button_set (GtkSheet *sheet, gint row)
06387 {
06388   if(sheet->row[row].button.state == GTK_STATE_ACTIVE) return;
06389 
06390   sheet->row[row].button.state = GTK_STATE_ACTIVE;
06391   gtk_sheet_button_draw(sheet, row, -1);
06392  
06393 }
06394 
06395 static void
06396 column_button_set (GtkSheet *sheet, gint column)
06397 {
06398   if(sheet->column[column].button.state == GTK_STATE_ACTIVE) return;
06399 
06400   sheet->column[column].button.state = GTK_STATE_ACTIVE;
06401   gtk_sheet_button_draw(sheet, -1, column);
06402  
06403 }
06404 
06405 static void
06406 row_button_release (GtkSheet *sheet, gint row)
06407 {
06408   if(sheet->row[row].button.state == GTK_STATE_NORMAL) return;
06409 
06410   sheet->row[row].button.state = GTK_STATE_NORMAL;
06411   gtk_sheet_button_draw(sheet, row, -1);
06412 }
06413 
06414 static void
06415 column_button_release (GtkSheet *sheet, gint column)
06416 {
06417   if(sheet->column[column].button.state == GTK_STATE_NORMAL) return;
06418 
06419   sheet->column[column].button.state = GTK_STATE_NORMAL;
06420   gtk_sheet_button_draw(sheet, -1, column);
06421 }
06422 
06423 static void
06424 gtk_sheet_button_draw (GtkSheet *sheet, gint row, gint column)
06425 {
06426   GdkWindow *window = NULL;
06427   GtkShadowType shadow_type;
06428   guint width = 0, height = 0;
06429   gint x = 0, y = 0;
06430   gint index = 0;
06431   gint text_width = 0, text_height = 0;
06432   GtkSheetButton *button = NULL;
06433   GtkSheetChild *child = NULL;
06434   GdkRectangle allocation;
06435   gboolean is_sensitive = FALSE;
06436   gint state = 0;
06437   gint len = 0;
06438   gchar *line = 0;
06439   gchar *words = 0;
06440   gchar label[10];
06441 
06442   if(!GTK_WIDGET_REALIZED(GTK_WIDGET(sheet))) return;
06443 
06444   if(row >= 0 && !sheet->row[row].is_visible) return;
06445   if(column >= 0 && !sheet->column[column].is_visible) return;
06446   if(row >= 0 && !sheet->row_titles_visible) return;
06447   if(column >= 0 && !sheet->column_titles_visible) return;
06448   if(column>=0 && column <MIN_VISIBLE_COLUMN(sheet)) return;
06449   if(column>=0 && column >MAX_VISIBLE_COLUMN(sheet)) return;
06450   if(row>=0 && row <MIN_VISIBLE_ROW(sheet)) return;
06451   if(row>=0 && row >MAX_VISIBLE_ROW(sheet)) return;
06452   if( (row == -1) && (column == -1) ) return; 
06453 
06454   if(row==-1){
06455      window=sheet->column_title_window;
06456      button=&sheet->column[column].button;
06457      index=column;
06458      x = COLUMN_LEFT_XPIXEL(sheet, column)+CELL_SPACING;
06459      if(sheet->row_titles_visible) x -= sheet->row_title_area.width;
06460      y = 0;
06461      width = sheet->column[column].width;
06462      height = sheet->column_title_area.height;
06463      is_sensitive=sheet->column[column].is_sensitive;
06464   }
06465   else if(column==-1){
06466      window=sheet->row_title_window;
06467      button=&sheet->row[row].button;
06468      index=row;
06469      x = 0;
06470      y = ROW_TOP_YPIXEL(sheet, row)+CELL_SPACING;
06471      if(sheet->column_titles_visible) y-=sheet->column_title_area.height;
06472      width = sheet->row_title_area.width;
06473      height = sheet->row[row].height;
06474      is_sensitive=sheet->row[row].is_sensitive;
06475   }
06476 
06477   allocation.x = x;
06478   allocation.y = y;
06479   allocation.width = width;
06480   allocation.height = height;
06481  
06482   gdk_window_clear_area (window,
06483                          x, y,
06484                      width, height);
06485 
06486   gtk_paint_box (sheet->button->style, window,
06487                  GTK_STATE_NORMAL, GTK_SHADOW_OUT, 
06488                  &allocation, GTK_WIDGET(sheet),
06489                  "buttondefault", x, y, width, height);
06490 
06491   state = button->state;
06492   if(!is_sensitive) state=GTK_STATE_INSENSITIVE;
06493 
06494   if (state == GTK_STATE_ACTIVE)
06495      shadow_type = GTK_SHADOW_IN;
06496   else
06497      shadow_type = GTK_SHADOW_OUT;
06498 
06499   if(state != GTK_STATE_NORMAL && state != GTK_STATE_INSENSITIVE)
06500   gtk_paint_box (sheet->button->style, window,
06501                  button->state, shadow_type, 
06502                  &allocation, GTK_WIDGET(sheet),
06503                  "button", x, y, width, height);
06504 
06505   if(button->label_visible){
06506 
06507     text_height=DEFAULT_ROW_HEIGHT(GTK_WIDGET(sheet))-2*CELLOFFSET;
06508 
06509     gdk_gc_set_clip_rectangle(GTK_WIDGET(sheet)->style->fg_gc[button->state], 
06510                               &allocation);
06511     gdk_gc_set_clip_rectangle(GTK_WIDGET(sheet)->style->white_gc, &allocation);
06512 
06513     y += DEFAULT_ROW_HEIGHT(GTK_WIDGET(sheet))/2 + sheet->button->style->ythickness + DEFAULT_FONT_DESCENT(GTK_WIDGET(sheet));
06514 
06515     if(button->label && strlen(button->label)>0){
06516 
06517            words=button->label;
06518            line = g_new(gchar, 1);
06519            line[0]='\0';
06520 
06521            while(words && *words != '\0'){
06522              if(*words != '\n'){
06523                 len=strlen(line);
06524                 line=g_realloc(line, len+2);
06525                 line[len]=*words;
06526                 line[len+1]='\0';
06527              }
06528              if(*words == '\n' || *(words+1) == '\0'){
06529                text_width = STRING_WIDTH(GTK_WIDGET(sheet), GTK_WIDGET(sheet)->style->font_desc, line);
06530 
06531                switch(button->justification){
06532                  case GTK_JUSTIFY_LEFT:
06533                    gtk_paint_string (GTK_WIDGET(sheet)->style, window, state,
06534                                      &allocation, GTK_WIDGET(sheet), "label",
06535                                      x + CELLOFFSET, y,
06536                                      line);
06537                    break;
06538                  case GTK_JUSTIFY_RIGHT:
06539                    gtk_paint_string (GTK_WIDGET(sheet)->style, window, state,
06540                                      &allocation, GTK_WIDGET(sheet), "label",
06541                                      x + width - text_width - CELLOFFSET, y,
06542                                      line);
06543                    break;
06544                  case GTK_JUSTIFY_CENTER:
06545                  default:
06546                    gtk_paint_string (GTK_WIDGET(sheet)->style, window, state,
06547                                      &allocation, GTK_WIDGET(sheet), "label",
06548                                      x + (width - text_width) /2, y,
06549                                      line);
06550                }
06551 
06552                y += text_height + 2;
06553 
06554                g_free(line);
06555                line = g_new(gchar, 1);
06556                line[0]='\0';
06557              }
06558              words++;
06559            }
06560            g_free(line);
06561     }else{
06562            sprintf(label,"%d",index);
06563            text_width = STRING_WIDTH(GTK_WIDGET(sheet), GTK_WIDGET(sheet)->style->font_desc, label);
06564 
06565            switch(button->justification){
06566              case GTK_JUSTIFY_LEFT:
06567                gtk_paint_string (GTK_WIDGET(sheet)->style, window, state,
06568                                  &allocation, GTK_WIDGET(sheet), "label",
06569                                  x + CELLOFFSET, y,
06570                                  label);
06571                break;
06572              case GTK_JUSTIFY_RIGHT:
06573                gtk_paint_string (GTK_WIDGET(sheet)->style, window, state,
06574                                  &allocation, GTK_WIDGET(sheet), "label",
06575                                  x + width - text_width - CELLOFFSET, y,
06576                                  label);
06577                break;
06578              case GTK_JUSTIFY_CENTER:
06579              default:
06580                gtk_paint_string (GTK_WIDGET(sheet)->style, window, state,
06581                                  &allocation, GTK_WIDGET(sheet), "label",
06582                                  x + (width - text_width) /2, y,
06583                                  label);
06584            }
06585 
06586     }
06587 
06588     gdk_gc_set_clip_rectangle(GTK_WIDGET(sheet)->style->fg_gc[button->state],
06589                             NULL);
06590     gdk_gc_set_clip_rectangle(GTK_WIDGET(sheet)->style->white_gc, NULL);
06591 
06592   }
06593 
06594   if((child = button->child) && (child->widget)){
06595       child->x = allocation.x;
06596       child->y = allocation.y;
06597 
06598       child->x += (width - child->widget->requisition.width) / 2; 
06599       child->y += (height - child->widget->requisition.height) / 2;
06600       allocation.x = child->x;
06601       allocation.y = child->y;
06602       allocation.width = child->widget->requisition.width;
06603       allocation.height = child->widget->requisition.height;
06604 
06605       x = child->x;
06606       y = child->y;
06607 
06608       gtk_widget_set_state(child->widget, button->state);
06609 
06610       if(GTK_WIDGET_REALIZED(GTK_WIDGET(sheet)) &&
06611          GTK_WIDGET_MAPPED(child->widget))
06612             {
06613               gtk_widget_size_allocate(child->widget, 
06614                                        &allocation);
06615               gtk_widget_queue_draw(child->widget);
06616             }
06617   }
06618    
06619 }
06620 
06621 
06622 /* SCROLLBARS
06623  *
06624  * functions:
06625  *   adjust_scrollbars
06626  *   vadjustment_changed
06627  *   hadjustment_changed
06628  *   vadjustment_value_changed
06629  *   hadjustment_value_changed */
06630 
06631 static void
06632 adjust_scrollbars (GtkSheet * sheet)
06633 {
06634 
06635  if(sheet->vadjustment){ 
06636   sheet->vadjustment->page_size = sheet->sheet_window_height;
06637   sheet->vadjustment->page_increment = sheet->sheet_window_height / 2;
06638   sheet->vadjustment->step_increment = DEFAULT_ROW_HEIGHT(GTK_WIDGET(sheet));
06639   sheet->vadjustment->lower = 0;
06640   sheet->vadjustment->upper = SHEET_HEIGHT (sheet) + 80;
06641 /*
06642   if (sheet->sheet_window_height - sheet->voffset > SHEET_HEIGHT (sheet))
06643     {
06644       sheet->vadjustment->value = MAX(0, SHEET_HEIGHT (sheet) - 
06645     sheet->sheet_window_height);
06646       gtk_signal_emit_by_name (GTK_OBJECT (sheet->vadjustment), 
06647                    "value_changed");
06648     }
06649 */
06650     gtk_signal_emit_by_name (GTK_OBJECT(sheet->vadjustment), "changed");
06651 
06652  }
06653 
06654  if(sheet->hadjustment){
06655   sheet->hadjustment->page_size = sheet->sheet_window_width;
06656   sheet->hadjustment->page_increment = sheet->sheet_window_width / 2;
06657   sheet->hadjustment->step_increment = DEFAULT_COLUMN_WIDTH;
06658   sheet->hadjustment->lower = 0;
06659   sheet->hadjustment->upper = SHEET_WIDTH (sheet)+ 80;
06660 /*
06661   if (sheet->sheet_window_width - sheet->hoffset > SHEET_WIDTH (sheet))
06662     {
06663       sheet->hadjustment->value = MAX(0, SHEET_WIDTH (sheet) - 
06664     sheet->sheet_window_width);
06665       gtk_signal_emit_by_name (GTK_OBJECT(sheet->hadjustment), 
06666                    "value_changed");
06667     }
06668 */
06669     gtk_signal_emit_by_name (GTK_OBJECT(sheet->hadjustment), "changed");
06670 
06671  }
06672 /*
06673  if(GTK_WIDGET_REALIZED(sheet)) 
06674    {
06675      if(sheet->row_titles_visible){
06676                  size_allocate_row_title_buttons(sheet);
06677                  gdk_window_show(sheet->row_title_window);
06678      }
06679 
06680      if(sheet->column_titles_visible){
06681                  size_allocate_column_title_buttons(sheet);
06682                  gdk_window_show(sheet->column_title_window);
06683      }
06684 
06685      gtk_sheet_range_draw(sheet, NULL);
06686    }
06687 */
06688 }
06689 
06690 
06691 static void
06692 vadjustment_changed (GtkAdjustment * adjustment,
06693                    gpointer data)
06694 {
06695   GtkSheet *sheet;
06696 
06697   g_return_if_fail (adjustment != NULL);
06698   g_return_if_fail (data != NULL);
06699 
06700   sheet = GTK_SHEET (data);
06701 
06702 }
06703 
06704 static void
06705 hadjustment_changed (GtkAdjustment * adjustment,
06706                    gpointer data)
06707 {
06708   GtkSheet *sheet;
06709 
06710   g_return_if_fail (adjustment != NULL);
06711   g_return_if_fail (data != NULL);
06712 
06713   sheet = GTK_SHEET (data);
06714 
06715 }
06716 
06717 
06718 static void
06719 vadjustment_value_changed (GtkAdjustment * adjustment,
06720                      gpointer data)
06721 {
06722   GtkSheet *sheet;
06723   gint diff, value, old_value;
06724   gint i;
06725   gint row, new_row;
06726   gint y=0;
06727 
06728   g_return_if_fail (adjustment != NULL);
06729   g_return_if_fail (data != NULL);
06730   g_return_if_fail (GTK_IS_SHEET (data));
06731 
06732   sheet = GTK_SHEET (data);
06733 
06734   if(GTK_SHEET_IS_FROZEN(sheet)) return;
06735 
06736   row=ROW_FROM_YPIXEL(sheet,sheet->column_title_area.height + CELL_SPACING);
06737   if(!sheet->column_titles_visible)
06738      row=ROW_FROM_YPIXEL(sheet,CELL_SPACING);
06739     
06740   old_value = -sheet->voffset;
06741 
06742   for(i=0; i<= sheet->maxrow; i++){
06743    if(sheet->row[i].is_visible) y+=sheet->row[i].height;
06744    if(y > adjustment->value) break;
06745   }
06746   y-=sheet->row[i].height;
06747   new_row=i;
06748 
06749   if (adjustment->value > sheet->old_vadjustment && sheet->old_vadjustment > 0. &&
06750       sheet->row[i].height > sheet->vadjustment->step_increment){
06751 /* This avoids embarrassing twitching */
06752           if(row == new_row && row != sheet->maxrow &&
06753              adjustment->value - sheet->old_vadjustment >= 
06754                           sheet->vadjustment->step_increment &&
06755              new_row + 1 != MIN_VISIBLE_ROW(sheet)){
06756                 new_row+=1;
06757                 y=y+sheet->row[row].height;
06758           }
06759   }
06760 
06761 /* Negative old_adjustment enforces the redraw, otherwise avoid spureous redraw */
06762   if(sheet->old_vadjustment >= 0. && row == new_row){
06763       sheet->old_vadjustment = sheet->vadjustment->value;
06764       return;
06765   }
06766 
06767   sheet->old_vadjustment = sheet->vadjustment->value;
06768   adjustment->value=y;
06769 
06770  
06771   if(new_row == 0){
06772    sheet->vadjustment->step_increment=
06773    sheet->row[0].height;
06774   }else{
06775    sheet->vadjustment->step_increment=
06776    MIN(sheet->row[new_row].height, sheet->row[new_row-1].height);
06777   }
06778 
06779   sheet->vadjustment->value=adjustment->value;
06780 
06781   value = adjustment->value;
06782 
06783   if (value >= -sheet->voffset)
06784     {
06785       /* scroll down */
06786       diff = value + sheet->voffset;
06787     }
06788   else
06789     {
06790       /* scroll up */
06791       diff = -sheet->voffset - value;
06792     }
06793 
06794       sheet->voffset = -value;
06795  
06796   sheet->view.row0=ROW_FROM_YPIXEL(sheet, sheet->column_title_area.height+1);
06797   sheet->view.rowi=ROW_FROM_YPIXEL(sheet, sheet->sheet_window_height-1);
06798   if(!sheet->column_titles_visible)
06799      sheet->view.row0=ROW_FROM_YPIXEL(sheet, 1);
06800 
06801   if(GTK_WIDGET_REALIZED(sheet->sheet_entry) &&
06802      sheet->state == GTK_SHEET_NORMAL && 
06803      sheet->active_cell.row >= 0 && sheet->active_cell.col >= 0 &&
06804      !gtk_sheet_cell_isvisible(sheet, sheet->active_cell.row,
06805                                       sheet->active_cell.col))
06806     {
06807       const gchar *text;
06808 
06809       text = gtk_entry_get_text(GTK_ENTRY(gtk_sheet_get_entry(sheet)));
06810 
06811       if(!text || strlen(text)==0) 
06812              gtk_sheet_cell_clear(sheet,
06813                                   sheet->active_cell.row,
06814                                   sheet->active_cell.col);
06815        gtk_widget_unmap(sheet->sheet_entry);
06816     }
06817 
06818   gtk_sheet_position_children(sheet);
06819 
06820   gtk_sheet_range_draw(sheet, NULL);
06821   size_allocate_row_title_buttons(sheet);
06822   size_allocate_global_button(sheet);
06823 }
06824 
06825 static void
06826 hadjustment_value_changed (GtkAdjustment * adjustment,
06827                gpointer data)
06828 {
06829   GtkSheet *sheet;
06830   gint i, diff, value, old_value;
06831   gint column, new_column;
06832   gint x=0;
06833 
06834   g_return_if_fail (adjustment != NULL);
06835   g_return_if_fail (data != NULL);
06836   g_return_if_fail (GTK_IS_SHEET (data));
06837 
06838   sheet = GTK_SHEET (data);
06839 
06840   if(GTK_SHEET_IS_FROZEN(sheet)) return;
06841 
06842   column=COLUMN_FROM_XPIXEL(sheet,sheet->row_title_area.width + CELL_SPACING);
06843   if(!sheet->row_titles_visible)
06844      column=COLUMN_FROM_XPIXEL(sheet, CELL_SPACING);
06845 
06846   old_value = -sheet->hoffset;
06847 
06848   for(i=0; i<= sheet->maxcol; i++){
06849    if(sheet->column[i].is_visible) x+=sheet->column[i].width;
06850    if(x > adjustment->value) break;
06851   }
06852   x-=sheet->column[i].width;
06853   new_column=i;
06854 
06855   if (adjustment->value > sheet->old_hadjustment && sheet->old_hadjustment > 0 &&
06856       sheet->column[i].width > sheet->hadjustment->step_increment){
06857 /* This avoids embarrassing twitching */
06858           if(column == new_column && column != sheet->maxcol &&
06859              adjustment->value - sheet->old_hadjustment >= 
06860                           sheet->hadjustment->step_increment &&
06861              new_column + 1 != MIN_VISIBLE_COLUMN(sheet)){
06862              new_column+=1;
06863              x=x+sheet->column[column].width;
06864           }
06865   }
06866 
06867 /* Negative old_adjustment enforces the redraw, otherwise avoid spureous redraw */
06868   if(sheet->old_hadjustment >= 0. && new_column == column){
06869      sheet->old_hadjustment = sheet->hadjustment->value;
06870      return;
06871   }
06872 
06873   sheet->old_hadjustment = sheet->hadjustment->value;
06874   adjustment->value=x;
06875 
06876   if(new_column == 0){
06877    sheet->hadjustment->step_increment=
06878    sheet->column[0].width;
06879   }else{
06880    sheet->hadjustment->step_increment=
06881    MIN(sheet->column[new_column].width, sheet->column[new_column-1].width);
06882   }
06883 
06884 
06885   sheet->hadjustment->value=adjustment->value;
06886 
06887   value = adjustment->value;
06888 
06889   if (value >= -sheet->hoffset)
06890         {
06891       /* scroll right */
06892       diff = value + sheet->hoffset;
06893     }
06894   else
06895     {
06896       /* scroll left */
06897       diff = -sheet->hoffset - value;
06898     }
06899 
06900   sheet->hoffset = -value;
06901 
06902   sheet->view.col0=COLUMN_FROM_XPIXEL(sheet, sheet->row_title_area.width+1);
06903   sheet->view.coli=COLUMN_FROM_XPIXEL(sheet, sheet->sheet_window_width);
06904   if(!sheet->row_titles_visible)
06905     sheet->view.col0=COLUMN_FROM_XPIXEL(sheet, 1);
06906 
06907   if(GTK_WIDGET_REALIZED(sheet->sheet_entry) &&
06908      sheet->state == GTK_SHEET_NORMAL && 
06909      sheet->active_cell.row >= 0 && sheet->active_cell.col >= 0 &&
06910      !gtk_sheet_cell_isvisible(sheet, sheet->active_cell.row,
06911                                       sheet->active_cell.col))
06912     {
06913       const gchar *text;
06914 
06915       text = gtk_entry_get_text(GTK_ENTRY(gtk_sheet_get_entry(sheet)));
06916       if(!text || strlen(text)==0) 
06917              gtk_sheet_cell_clear(sheet,
06918                                   sheet->active_cell.row,
06919                                   sheet->active_cell.col);
06920 
06921       gtk_widget_unmap(sheet->sheet_entry);
06922     }
06923 
06924   gtk_sheet_position_children(sheet);
06925 
06926   gtk_sheet_range_draw(sheet, NULL);
06927   size_allocate_column_title_buttons(sheet);
06928 }
06929     
06930 
06931 /* COLUMN RESIZING */
06932 static void                          
06933 draw_xor_vline (GtkSheet * sheet)
06934 {
06935   GtkWidget *widget;
06936   
06937   g_return_if_fail (sheet != NULL);
06938   
06939   widget = GTK_WIDGET (sheet);
06940 
06941   gdk_draw_line (widget->window, sheet->xor_gc,  
06942                  sheet->x_drag,                                       
06943                  sheet->column_title_area.height,                               
06944                  sheet->x_drag,                                             
06945                  sheet->sheet_window_height + 1);
06946 }
06947 
06948 /* ROW RESIZING */
06949 static void                          
06950 draw_xor_hline (GtkSheet * sheet)
06951 {
06952   GtkWidget *widget;
06953   
06954   g_return_if_fail (sheet != NULL);
06955   
06956   widget = GTK_WIDGET (sheet);
06957 
06958   gdk_draw_line (widget->window, sheet->xor_gc,  
06959          sheet->row_title_area.width,
06960                  sheet->y_drag,                                       
06961                         
06962              sheet->sheet_window_width + 1,                      
06963                  sheet->y_drag);                                             
06964 }
06965 
06966 /* SELECTED RANGE */
06967 static void
06968 draw_xor_rectangle(GtkSheet *sheet, GtkSheetRange range)
06969 {
06970    gint i;
06971    GdkRectangle clip_area, area;
06972    GdkGCValues values;
06973 
06974    area.x=COLUMN_LEFT_XPIXEL(sheet, range.col0);
06975    area.y=ROW_TOP_YPIXEL(sheet, range.row0);
06976    area.width=COLUMN_LEFT_XPIXEL(sheet, range.coli)-area.x+
06977                                         sheet->column[range.coli].width;
06978    area.height=ROW_TOP_YPIXEL(sheet, range.rowi)-area.y+
06979                                         sheet->row[range.rowi].height;
06980 
06981    clip_area.x=sheet->row_title_area.width;
06982    clip_area.y=sheet->column_title_area.height;
06983    clip_area.width=sheet->sheet_window_width;
06984    clip_area.height=sheet->sheet_window_height;
06985 
06986    if(!sheet->row_titles_visible) clip_area.x = 0;
06987    if(!sheet->column_titles_visible) clip_area.y = 0;
06988 
06989    if(area.x<0) {
06990       area.width=area.width+area.x;
06991       area.x=0;
06992    }
06993    if(area.width>clip_area.width) area.width=clip_area.width+10;
06994    if(area.y<0) {
06995       area.height=area.height+area.y;
06996       area.y=0;
06997    }
06998    if(area.height>clip_area.height) area.height=clip_area.height+10;
06999 
07000    clip_area.x--;
07001    clip_area.y--;
07002    clip_area.width+=3;
07003    clip_area.height+=3;
07004 
07005    gdk_gc_get_values(sheet->xor_gc, &values);
07006 
07007    gdk_gc_set_clip_rectangle(sheet->xor_gc, &clip_area);
07008 
07009    for(i=-1;i<=1;i++)
07010      gdk_draw_rectangle(sheet->sheet_window,
07011                         sheet->xor_gc,
07012                 FALSE,
07013                 area.x+i, area.y+i,
07014                         area.width-2*i, area.height-2*i);
07015 
07016 
07017    gdk_gc_set_clip_rectangle(sheet->xor_gc, NULL);
07018 
07019    gdk_gc_set_foreground(sheet->xor_gc, &values.foreground);
07020 
07021 }                      
07022 
07023   
07024 /* this function returns the new width of the column being resized given
07025  * the column and x position of the cursor; the x cursor position is passed
07026  * in as a pointer and automaticaly corrected if it's beyond min/max limits */
07027 static guint
07028 new_column_width (GtkSheet * sheet,
07029           gint column,
07030           gint * x)
07031 {
07032   gint cx, width;
07033   GtkRequisition requisition;
07034 
07035   cx = *x;
07036 
07037   requisition.width = sheet->column[column].requisition;
07038 
07039   /* you can't shrink a column to less than its minimum width */
07040   if (cx < COLUMN_LEFT_XPIXEL (sheet, column) + requisition.width)
07041     {
07042       *x = cx = COLUMN_LEFT_XPIXEL (sheet, column) + requisition.width;
07043     }
07044 
07045   /* don't grow past the end of the window */
07046   /*
07047   if (cx > sheet->sheet_window_width)
07048     {
07049       *x = cx = sheet->sheet_window_width;
07050     }
07051     */
07052   /* calculate new column width making sure it doesn't end up
07053    * less than the minimum width */
07054   width = cx - COLUMN_LEFT_XPIXEL (sheet, column);
07055   if (width < requisition.width)
07056     width = requisition.width;
07057 
07058   sheet->column[column].width = width;
07059   gtk_sheet_recalc_left_xpixels(sheet, column+1);
07060   sheet->view.coli=COLUMN_FROM_XPIXEL(sheet, sheet->sheet_window_width);
07061   size_allocate_column_title_buttons (sheet);
07062   
07063   return width;
07064 }
07065 
07066 /* this function returns the new height of the row being resized given
07067  * the row and y position of the cursor; the y cursor position is passed
07068  * in as a pointer and automaticaly corrected if it's beyond min/max limits */
07069 static guint
07070 new_row_height (GtkSheet * sheet,
07071         gint row,
07072         gint * y)
07073 {
07074   GtkRequisition requisition;
07075   gint cy, height;
07076 
07077   cy = *y;
07078 
07079   requisition.height = sheet->row[row].requisition;
07080 
07081   /* you can't shrink a row to less than its minimum height */
07082   if (cy < ROW_TOP_YPIXEL (sheet, row) + requisition.height)
07083 
07084     {
07085       *y = cy = ROW_TOP_YPIXEL (sheet, row) + requisition.height;
07086     }
07087 
07088   /* don't grow past the end of the window */
07089   /*
07090   if (cy > sheet->sheet_window_height)
07091     {
07092       *y = cy = sheet->sheet_window_height;
07093     }
07094     */
07095   /* calculate new row height making sure it doesn't end up
07096    * less than the minimum height */
07097   height = (cy - ROW_TOP_YPIXEL (sheet, row));
07098   if (height < requisition.height)
07099     height = requisition.height;
07100 
07101   sheet->row[row].height = height;
07102   gtk_sheet_recalc_top_ypixels(sheet, row);
07103   sheet->view.rowi=ROW_FROM_YPIXEL(sheet, sheet->sheet_window_height-1);
07104   size_allocate_row_title_buttons (sheet);
07105 
07106   return height;
07107 }
07108 
07109 void
07110 gtk_sheet_set_column_width (GtkSheet * sheet,
07111                 gint column,
07112                 guint width)
07113 {
07114   guint min_width;
07115 
07116   g_return_if_fail (sheet != NULL);
07117   g_return_if_fail (GTK_IS_SHEET (sheet));
07118 
07119   if (column < 0 || column > sheet->maxcol)
07120     return;
07121 
07122   gtk_sheet_column_size_request(sheet, column, &min_width);
07123   if(width < min_width) return;
07124 
07125   sheet->column[column].width = width;
07126 
07127   gtk_sheet_recalc_left_xpixels(sheet, column+1);
07128 
07129   if(GTK_WIDGET_REALIZED(GTK_WIDGET(sheet)) && !GTK_SHEET_IS_FROZEN(sheet)){
07130     size_allocate_column_title_buttons (sheet);
07131     adjust_scrollbars (sheet);
07132     gtk_sheet_size_allocate_entry(sheet);
07133     gtk_sheet_range_draw (sheet, NULL);
07134   } else
07135 
07136   gtk_signal_emit(GTK_OBJECT(sheet), sheet_signals[CHANGED], -1, column);
07137   gtk_signal_emit(GTK_OBJECT(sheet), sheet_signals[NEW_COL_WIDTH], column, width);
07138 
07139 }
07140 
07141 void
07142 gtk_sheet_set_row_height (GtkSheet * sheet,
07143                 gint row,
07144                 guint height)
07145 {
07146   guint min_height;
07147 
07148   g_return_if_fail (sheet != NULL);
07149   g_return_if_fail (GTK_IS_SHEET (sheet));
07150 
07151   if (row < 0 || row > sheet->maxrow)
07152     return;
07153 
07154   gtk_sheet_row_size_request(sheet, row, &min_height);
07155   if(height < min_height) return;
07156 
07157   sheet->row[row].height = height;
07158 
07159   gtk_sheet_recalc_top_ypixels(sheet, row+1);
07160 
07161   if(GTK_WIDGET_REALIZED(GTK_WIDGET(sheet)) && !GTK_SHEET_IS_FROZEN(sheet)){
07162     size_allocate_row_title_buttons (sheet);
07163     adjust_scrollbars (sheet);
07164     gtk_sheet_size_allocate_entry(sheet);
07165     gtk_sheet_range_draw (sheet, NULL);
07166   }
07167 
07168   gtk_signal_emit(GTK_OBJECT(sheet), sheet_signals[CHANGED], row, -1);
07169   gtk_signal_emit(GTK_OBJECT(sheet), sheet_signals[NEW_ROW_HEIGHT], row, height);
07170 
07171 }
07172 
07173 
07174 void
07175 gtk_sheet_add_column(GtkSheet *sheet, guint ncols)
07176 {
07177 
07178  g_return_if_fail (sheet != NULL);
07179  g_return_if_fail (GTK_IS_SHEET (sheet));
07180 
07181  AddColumn(sheet, ncols);
07182 
07183  if(!GTK_WIDGET_REALIZED(sheet)) return;
07184 
07185  adjust_scrollbars(sheet);
07186 
07187  if(sheet->state==GTK_SHEET_ROW_SELECTED) sheet->range.coli+=ncols;
07188 
07189  sheet->old_hadjustment = -1.;
07190  if(!GTK_SHEET_IS_FROZEN(sheet) && sheet->hadjustment)
07191       gtk_signal_emit_by_name (GTK_OBJECT (sheet->hadjustment), 
07192                    "value_changed");
07193 }
07194 
07195 void
07196 gtk_sheet_add_row(GtkSheet *sheet, guint nrows)
07197 {
07198 
07199  g_return_if_fail (sheet != NULL);
07200  g_return_if_fail (GTK_IS_SHEET (sheet));
07201 
07202  AddRow(sheet, nrows);
07203 
07204  if(!GTK_WIDGET_REALIZED(sheet)) return;
07205 
07206  if(sheet->state==GTK_SHEET_COLUMN_SELECTED) sheet->range.rowi+=nrows;
07207 
07208  adjust_scrollbars(sheet);
07209 
07210  sheet->old_vadjustment = -1.;
07211  if(!GTK_SHEET_IS_FROZEN(sheet) && sheet->vadjustment)
07212       gtk_signal_emit_by_name (GTK_OBJECT (sheet->vadjustment), 
07213                    "value_changed");
07214 }
07215 
07216 void
07217 gtk_sheet_insert_rows(GtkSheet *sheet, guint row, guint nrows)
07218 {
07219  GList *children;
07220  GtkSheetChild *child;
07221 
07222  g_return_if_fail (sheet != NULL);
07223  g_return_if_fail (GTK_IS_SHEET (sheet));
07224 
07225  if(GTK_WIDGET_REALIZED(sheet))
07226    gtk_sheet_real_unselect_range(sheet, NULL);
07227 
07228  InsertRow(sheet, row, nrows);
07229 
07230  children = sheet->children;
07231  while(children)
07232    {
07233      child = (GtkSheetChild *)children->data;
07234 
07235      if(child->attached_to_cell)
07236         if(child->row >= row) child->row += nrows; 
07237 
07238      children = g_list_next(children);
07239    }
07240 
07241  if(!GTK_WIDGET_REALIZED(sheet)) return;
07242 
07243  if(sheet->state==GTK_SHEET_COLUMN_SELECTED) sheet->range.rowi+=nrows;
07244  adjust_scrollbars(sheet);
07245  
07246  sheet->old_vadjustment = -1.;
07247  if(!GTK_SHEET_IS_FROZEN(sheet) && sheet->vadjustment)
07248       gtk_signal_emit_by_name (GTK_OBJECT (sheet->vadjustment), 
07249                    "value_changed");
07250 
07251 }
07252 
07253 void
07254 gtk_sheet_insert_columns(GtkSheet *sheet, guint col, guint ncols)
07255 {
07256  GList *children;
07257  GtkSheetChild *child;
07258 
07259  g_return_if_fail (sheet != NULL);
07260  g_return_if_fail (GTK_IS_SHEET (sheet));
07261 
07262  if(GTK_WIDGET_REALIZED(sheet))
07263    gtk_sheet_real_unselect_range(sheet, NULL);
07264 
07265  InsertColumn(sheet, col, ncols);
07266 
07267  children = sheet->children;
07268  while(children)
07269    {
07270      child = (GtkSheetChild *)children->data;
07271 
07272      if(child->attached_to_cell)
07273         if(child->col >= col) child->col += ncols; 
07274 
07275      children = g_list_next(children);
07276    }
07277 
07278  if(!GTK_WIDGET_REALIZED(sheet)) return;
07279 
07280  if(sheet->state==GTK_SHEET_ROW_SELECTED) sheet->range.coli+=ncols;
07281  adjust_scrollbars(sheet);
07282 
07283  sheet->old_hadjustment = -1.;
07284  if(!GTK_SHEET_IS_FROZEN(sheet) && sheet->hadjustment)
07285       gtk_signal_emit_by_name (GTK_OBJECT (sheet->hadjustment), 
07286                    "value_changed");
07287 
07288 }
07289 
07290 void
07291 gtk_sheet_delete_rows(GtkSheet *sheet, guint row, guint nrows)
07292 {
07293  GList *children;
07294  GtkSheetChild *child;
07295  gint irow, icol;
07296  gboolean veto;
07297 
07298  g_return_if_fail (sheet != NULL);
07299  g_return_if_fail (GTK_IS_SHEET (sheet));
07300 
07301  nrows = MIN(nrows, sheet->maxrow-row+1);
07302 
07303  if(GTK_WIDGET_REALIZED(sheet))
07304    gtk_sheet_real_unselect_range(sheet, NULL);
07305 
07306  DeleteRow(sheet, row, nrows);
07307 
07308  children = sheet->children;
07309  while(children)
07310    {
07311      child = (GtkSheetChild *)children->data;
07312 
07313      if(child->attached_to_cell &&
07314         child->row >= row && child->row < row+nrows){  
07315               gtk_container_remove(GTK_CONTAINER(sheet), child->widget);
07316               children = sheet->children;
07317      } else
07318         children = g_list_next(children);
07319    }
07320 
07321  children = sheet->children;
07322  while(children)
07323    {
07324      child = (GtkSheetChild *)children->data;
07325 
07326      if(child->attached_to_cell && child->row > row) child->row -= nrows; 
07327      children = g_list_next(children);
07328    }
07329 
07330  if(!GTK_WIDGET_REALIZED(sheet)) return;
07331 
07332  irow = sheet->active_cell.row;
07333  icol = sheet->active_cell.col;
07334 
07335  sheet->active_cell.row = -1;
07336  sheet->active_cell.col = -1;
07337 
07338 /* if(sheet->state == GTK_SHEET_ROW_SELECTED)
07339 */
07340 
07341  irow = MIN(irow, sheet->maxrow);
07342  irow = MAX(irow, 0);
07343  gtk_sheet_click_cell(sheet, irow, icol, &veto);
07344 
07345  gtk_sheet_activate_cell(sheet, sheet->active_cell.row,
07346                                        sheet->active_cell.col);
07347 
07348  adjust_scrollbars(sheet);
07349 
07350  sheet->old_vadjustment = -1.;
07351  if(!GTK_SHEET_IS_FROZEN(sheet) && sheet->vadjustment)
07352       gtk_signal_emit_by_name (GTK_OBJECT (sheet->vadjustment), 
07353                    "value_changed");
07354 
07355 }
07356 
07357 void
07358 gtk_sheet_delete_columns(GtkSheet *sheet, guint col, guint ncols)
07359 {
07360  GList *children;
07361  GtkSheetChild *child;
07362  gint irow, icol;
07363  gboolean veto;
07364 
07365  g_return_if_fail (sheet != NULL);
07366  g_return_if_fail (GTK_IS_SHEET (sheet));
07367 
07368  ncols = MIN(ncols, sheet->maxcol-col+1);
07369 
07370  if(GTK_WIDGET_REALIZED(sheet))
07371    gtk_sheet_real_unselect_range(sheet, NULL);
07372 
07373  DeleteColumn(sheet, col, ncols);
07374 
07375  children = sheet->children;
07376  while(children)
07377    {
07378      child = (GtkSheetChild *)children->data;
07379 
07380      if(child->attached_to_cell &&
07381         child->col >= col && child->col < col+ncols){  
07382               gtk_container_remove(GTK_CONTAINER(sheet), child->widget);
07383               children = sheet->children;
07384      } else
07385         children = g_list_next(children);
07386    }
07387 
07388  children = sheet->children;
07389  while(children)
07390    {
07391      child = (GtkSheetChild *)children->data;
07392 
07393      if(child->attached_to_cell && child->col > col) child->col -= ncols; 
07394      children = g_list_next(children);
07395    }
07396 
07397  if(!GTK_WIDGET_REALIZED(sheet)) return;
07398 
07399  irow = sheet->active_cell.row;
07400  icol = sheet->active_cell.col;
07401 
07402  sheet->active_cell.row = -1;
07403  sheet->active_cell.col = -1;
07404 
07405 /* if(sheet->state == GTK_SHEET_COLUMN_SELECTED)
07406 */
07407 
07408  icol = MIN(icol, sheet->maxcol);
07409  icol = MAX(icol, 0);
07410  gtk_sheet_click_cell(sheet, irow, icol, &veto);
07411 
07412  gtk_sheet_activate_cell(sheet, sheet->active_cell.row,
07413                                        sheet->active_cell.col);
07414 
07415  adjust_scrollbars(sheet);
07416 
07417  sheet->old_hadjustment = -1.;
07418  if(!GTK_SHEET_IS_FROZEN(sheet) && sheet->hadjustment)
07419       gtk_signal_emit_by_name (GTK_OBJECT (sheet->hadjustment), 
07420                    "value_changed");
07421 
07422 }
07423 
07424 void
07425 gtk_sheet_range_set_background(GtkSheet *sheet, const GtkSheetRange *urange, const GdkColor *color)
07426 {
07427   gint i, j;
07428   GtkSheetCellAttr attributes;
07429   GtkSheetRange range;
07430 
07431   g_return_if_fail (sheet != NULL);
07432   g_return_if_fail (GTK_IS_SHEET (sheet));
07433 
07434   if(!urange) 
07435      range = sheet->range;
07436   else
07437      range = *urange;
07438 
07439   for (i=range.row0; i<=range.rowi; i++)
07440     for (j=range.col0; j<=range.coli; j++){
07441       gtk_sheet_get_attributes(sheet, i, j, &attributes);
07442       if(color != NULL)
07443         attributes.background = *color;
07444       else
07445         attributes.background = sheet->bg_color;
07446  
07447       gtk_sheet_set_cell_attributes(sheet, i, j, attributes); 
07448     }
07449 
07450   range.row0--;
07451   range.col0--;
07452   range.rowi++;
07453   range.coli++;
07454 
07455   if(!GTK_SHEET_IS_FROZEN(sheet))
07456       gtk_sheet_range_draw(sheet, &range);
07457 
07458 }
07459 
07460 void
07461 gtk_sheet_range_set_foreground(GtkSheet *sheet, const GtkSheetRange *urange, const GdkColor *color)
07462 {
07463   gint i, j;
07464   GtkSheetCellAttr attributes;
07465   GtkSheetRange range;
07466 
07467   g_return_if_fail (sheet != NULL);
07468   g_return_if_fail (GTK_IS_SHEET (sheet));
07469 
07470   if(!urange) 
07471      range = sheet->range;
07472   else
07473      range = *urange;
07474 
07475   for (i=range.row0; i<=range.rowi; i++)
07476     for (j=range.col0; j<=range.coli; j++){
07477       gtk_sheet_get_attributes(sheet, i, j, &attributes);
07478 
07479       if(color != NULL)
07480         attributes.foreground = *color;
07481       else
07482         gdk_color_black(gdk_colormap_get_system(), &attributes.foreground);
07483  
07484       gtk_sheet_set_cell_attributes(sheet, i, j, attributes); 
07485     }
07486 
07487   if(!GTK_SHEET_IS_FROZEN(sheet))
07488       gtk_sheet_range_draw(sheet, &range);
07489 
07490 }
07491 
07492 void
07493 gtk_sheet_range_set_justification(GtkSheet *sheet, const GtkSheetRange *urange, 
07494                                   GtkJustification just)
07495 {
07496   gint i, j;
07497   GtkSheetCellAttr attributes;
07498   GtkSheetRange range;
07499 
07500   g_return_if_fail (sheet != NULL);
07501   g_return_if_fail (GTK_IS_SHEET (sheet));
07502 
07503   if(!urange) 
07504      range = sheet->range;
07505   else
07506      range = *urange;
07507 
07508   for (i=range.row0; i<=range.rowi; i++)
07509     for (j=range.col0; j<=range.coli; j++){
07510       gtk_sheet_get_attributes(sheet, i, j, &attributes);
07511       attributes.justification = just;
07512       gtk_sheet_set_cell_attributes(sheet, i, j, attributes); 
07513     }
07514 
07515   range.col0 = sheet->view.col0;    
07516   range.coli = sheet->view.coli;    
07517 
07518   if(!GTK_SHEET_IS_FROZEN(sheet))
07519       gtk_sheet_range_draw(sheet, &range);
07520 
07521 }
07522 
07523 void
07524 gtk_sheet_column_set_justification(GtkSheet *sheet, gint col, 
07525                                    GtkJustification justification)
07526 {
07527   g_return_if_fail (sheet != NULL);
07528   g_return_if_fail (GTK_IS_SHEET (sheet));
07529 
07530   if(col > sheet->maxcol) return;
07531 
07532   sheet->column[col].justification = justification;
07533   
07534   if(GTK_WIDGET_REALIZED(sheet) && !GTK_SHEET_IS_FROZEN(sheet) &&
07535      col >= MIN_VISIBLE_COLUMN(sheet) && col <= MAX_VISIBLE_COLUMN(sheet))
07536           gtk_sheet_range_draw(sheet, NULL);
07537 
07538 }
07539 
07540 void
07541 gtk_sheet_range_set_editable(GtkSheet *sheet, const GtkSheetRange *urange, gboolean editable)
07542 {
07543   gint i, j;
07544   GtkSheetCellAttr attributes;
07545   GtkSheetRange range;
07546  
07547   g_return_if_fail (sheet != NULL);
07548   g_return_if_fail (GTK_IS_SHEET (sheet));
07549 
07550   if(!urange) 
07551      range = sheet->range;
07552   else
07553      range = *urange;
07554 
07555   for (i=range.row0; i<=range.rowi; i++)
07556     for (j=range.col0; j<=range.coli; j++){
07557       gtk_sheet_get_attributes(sheet, i, j, &attributes);
07558       attributes.is_editable = editable;
07559       gtk_sheet_set_cell_attributes(sheet, i, j, attributes); 
07560     }
07561  
07562   if(!GTK_SHEET_IS_FROZEN(sheet))
07563       gtk_sheet_range_draw(sheet, &range);
07564 
07565 }
07566 
07567 void
07568 gtk_sheet_range_set_visible(GtkSheet *sheet, const GtkSheetRange *urange, gboolean visible)
07569 {
07570   gint i, j;
07571   GtkSheetCellAttr attributes;
07572   GtkSheetRange range;
07573 
07574   g_return_if_fail (sheet != NULL);
07575   g_return_if_fail (GTK_IS_SHEET (sheet));
07576 
07577   if(!urange) 
07578      range = sheet->range;
07579   else
07580      range = *urange;
07581 
07582   for (i=range.row0; i<=range.rowi; i++)
07583     for (j=range.col0; j<=range.coli; j++){
07584       gtk_sheet_get_attributes(sheet, i, j, &attributes);
07585       attributes.is_visible=visible;
07586       gtk_sheet_set_cell_attributes(sheet, i, j, attributes); 
07587     }
07588  
07589   if(!GTK_SHEET_IS_FROZEN(sheet))
07590       gtk_sheet_range_draw(sheet, &range);
07591 
07592 }
07593 
07594 void
07595 gtk_sheet_range_set_border(GtkSheet *sheet, const GtkSheetRange *urange, gint mask, 
07596 guint width, gint line_style)
07597 {
07598   gint i, j;
07599   GtkSheetCellAttr attributes;
07600   GtkSheetRange range;
07601 
07602   g_return_if_fail (sheet != NULL);
07603   g_return_if_fail (GTK_IS_SHEET (sheet));
07604 
07605   if(!urange) 
07606      range = sheet->range;
07607   else
07608      range = *urange;
07609 
07610   for (i=range.row0; i<=range.rowi; i++)
07611     for (j=range.col0; j<=range.coli; j++){
07612       gtk_sheet_get_attributes(sheet, i, j, &attributes);
07613       attributes.border.mask = mask;
07614       attributes.border.width = width;
07615       attributes.border.line_style=line_style;
07616       attributes.border.cap_style=GDK_CAP_NOT_LAST;
07617       attributes.border.join_style=GDK_JOIN_MITER;
07618       gtk_sheet_set_cell_attributes(sheet, i, j, attributes);      
07619     }
07620 
07621   range.row0--; 
07622   range.col0--; 
07623   range.rowi++; 
07624   range.coli++; 
07625 
07626   if(!GTK_SHEET_IS_FROZEN(sheet))
07627       gtk_sheet_range_draw(sheet, &range);
07628 
07629 }
07630 
07631 void
07632 gtk_sheet_range_set_border_color(GtkSheet *sheet, const GtkSheetRange *urange, const GdkColor *color)
07633 {
07634   gint i, j;
07635   GtkSheetCellAttr attributes;
07636   GtkSheetRange range;
07637 
07638   g_return_if_fail (sheet != NULL);
07639   g_return_if_fail (GTK_IS_SHEET (sheet));
07640 
07641   if(!urange) 
07642      range = sheet->range;
07643   else
07644      range = *urange;
07645 
07646   for (i=range.row0; i<=range.rowi; i++)
07647     for (j=range.col0; j<=range.coli; j++){
07648       gtk_sheet_get_attributes(sheet, i, j, &attributes);
07649       attributes.border.color = *color;
07650       gtk_sheet_set_cell_attributes(sheet, i, j, attributes); 
07651     }
07652  
07653   if(!GTK_SHEET_IS_FROZEN(sheet))
07654       gtk_sheet_range_draw(sheet, &range);
07655 
07656 }
07657 
07658 void
07659 gtk_sheet_range_set_font(GtkSheet *sheet, const GtkSheetRange *urange, PangoFontDescription *font)
07660 {
07661   gint i, j;
07662   gint font_height;
07663   GtkSheetCellAttr attributes;
07664   GtkSheetRange range;
07665   PangoContext *context;
07666   PangoFontMetrics *metrics;
07667 
07668   g_return_if_fail (sheet != NULL);
07669   g_return_if_fail (GTK_IS_SHEET (sheet));
07670 
07671   if(!urange) 
07672      range = sheet->range;
07673   else
07674      range = *urange;
07675 
07676   gtk_sheet_freeze(sheet);
07677 
07678   context = gtk_widget_get_pango_context(GTK_WIDGET(sheet)); 
07679   metrics = pango_context_get_metrics(context,
07680                                 font,
07681                                 pango_context_get_language(context)); 
07682   font_height = pango_font_metrics_get_descent(metrics) + 
07683                 pango_font_metrics_get_ascent(metrics);
07684   font_height = PANGO_PIXELS(font_height) + 2*CELLOFFSET;
07685 
07686   for (i=range.row0; i<=range.rowi; i++)
07687     for (j=range.col0; j<=range.coli; j++){
07688       gtk_sheet_get_attributes(sheet, i, j, &attributes);
07689       attributes.font_desc = font; 
07690       if(font_height > sheet->row[i].height){
07691           sheet->row[i].height = font_height;
07692           gtk_sheet_recalc_top_ypixels(sheet, i);
07693       }
07694 
07695       gtk_sheet_set_cell_attributes(sheet, i, j, attributes);  
07696     }
07697 
07698   gtk_sheet_thaw(sheet);
07699   pango_font_metrics_unref(metrics);
07700 }
07701 
07702 static void
07703 gtk_sheet_set_cell_attributes(GtkSheet *sheet, gint row, gint col, GtkSheetCellAttr attributes)
07704 {
07705   GtkSheetCell **cell;
07706 
07707   if(row > sheet->maxrow || col >sheet->maxcol) return;
07708 
07709   CheckBounds(sheet, row, col);
07710 
07711   cell = &sheet->data[row][col];
07712 
07713   if(*cell==NULL){
07714    (*cell) = gtk_sheet_cell_new();
07715    (*cell)->row = row;
07716    (*cell)->col = col;
07717   }
07718 
07719   if((*cell)->attributes == NULL) 
07720       (*cell)->attributes = g_new(GtkSheetCellAttr, 1);
07721 
07722   *((*cell)->attributes) = attributes;
07723 }
07724 
07725 gboolean
07726 gtk_sheet_get_attributes(GtkSheet *sheet, gint row, gint col, GtkSheetCellAttr *attributes)
07727 {
07728  GtkSheetCell **cell = NULL;
07729 
07730  g_return_val_if_fail (sheet != NULL, FALSE);
07731  g_return_val_if_fail (GTK_IS_SHEET (sheet), FALSE);
07732 
07733  if(row < 0 || col < 0) return FALSE;
07734 
07735  if(row > sheet->maxallocrow || col > sheet->maxalloccol){
07736     init_attributes(sheet, col, attributes);
07737     return FALSE;
07738  }
07739 
07740  if(row <= sheet->maxallocrow && col <= sheet->maxalloccol){
07741     if(sheet->data[row] && sheet->data[row][col])
07742                                     cell = &sheet->data[row][col];
07743     if(cell == NULL || *cell == NULL){
07744       init_attributes(sheet, col, attributes);
07745       return FALSE;
07746     } else
07747       if((*cell)->attributes == NULL){
07748          init_attributes(sheet, col, attributes);
07749          return FALSE;
07750       }else{
07751          *attributes = *(sheet->data[row][col]->attributes);
07752          if(sheet->column[col].justification != GTK_JUSTIFY_FILL)
07753               attributes->justification = sheet->column[col].justification;
07754       }
07755  }   
07756  
07757  return TRUE;
07758 }
07759 
07760 static void
07761 init_attributes(GtkSheet *sheet, gint col, GtkSheetCellAttr *attributes)
07762 {
07763  /* DEFAULT VALUES */    
07764  attributes->foreground = GTK_WIDGET(sheet)->style->black;
07765  attributes->background = sheet->bg_color;
07766  if(!GTK_WIDGET_REALIZED(GTK_WIDGET(sheet))){
07767    GdkColormap *colormap;
07768    colormap=gdk_colormap_get_system();
07769    gdk_color_black(colormap, &attributes->foreground);
07770    attributes->background = sheet->bg_color;
07771  }
07772  attributes->justification = sheet->column[col].justification;
07773  attributes->border.width = 0;
07774  attributes->border.line_style = GDK_LINE_SOLID;
07775  attributes->border.cap_style = GDK_CAP_NOT_LAST;
07776  attributes->border.join_style = GDK_JOIN_MITER;
07777  attributes->border.mask = 0;
07778  attributes->border.color = GTK_WIDGET(sheet)->style->black;
07779  attributes->is_editable = TRUE;
07780  attributes->is_visible = TRUE;
07781  attributes->font = GTK_WIDGET(sheet)->style->private_font;
07782  attributes->font_desc = GTK_WIDGET(sheet)->style->font_desc;
07783 
07784 }       
07785  
07786 /**********************************************************************
07787  * Memory allocation routines: 
07788  * AddRow & AddColumn allocate memory for GtkSheetColumn & GtkSheetRow structs.
07789  * InsertRow 
07790  * InsertColumn
07791  * DeleteRow
07792  * DeleteColumn
07793  * GrowSheet allocates memory for the sheet cells contents using an array of 
07794  * pointers. Alternative to this could be a linked list or a hash table.
07795  * CheckBounds checks whether the given cell is currently allocated or not. 
07796  * If not, it calls to GrowSheet.
07797  **********************************************************************/
07798 
07799 static gint
07800 AddColumn(GtkSheet *tbl, gint ncols)
07801 {
07802    gint i;
07803 
07804    if(ncols == -1 && tbl->maxcol == 0)
07805      {
07806        ncols = 1;
07807      }
07808    else
07809      {
07810        tbl->maxcol += ncols;
07811        tbl->column = (GtkSheetColumn *)g_realloc(tbl->column,(tbl->maxcol+1)*
07812                                                  sizeof(GtkSheetColumn));
07813      }
07814 
07815    for(i=tbl->maxcol-ncols+1; i<= tbl->maxcol; i++){
07816         tbl->column[i].width=DEFAULT_COLUMN_WIDTH;
07817     tbl->column[i].button.label=NULL;
07818     tbl->column[i].button.child=NULL;
07819         tbl->column[i].button.state=GTK_STATE_NORMAL;
07820         tbl->column[i].button.justification=GTK_JUSTIFY_CENTER;
07821         tbl->column[i].button.label_visible = TRUE;
07822         tbl->column[i].name=NULL;
07823         tbl->column[i].is_visible=TRUE;
07824         tbl->column[i].is_sensitive=TRUE;
07825         tbl->column[i].left_text_column=i;
07826         tbl->column[i].right_text_column=i;
07827         tbl->column[i].justification=GTK_JUSTIFY_FILL;
07828         tbl->column[i].requisition=DEFAULT_COLUMN_WIDTH;
07829         if(i>0)
07830         {
07831            tbl->column[i].left_text_column=tbl->column[i-1].left_text_column;
07832            tbl->column[i].left_xpixel=tbl->column[i-1].left_xpixel +
07833                                      tbl->column[i-1].width;
07834     }
07835         else
07836         {
07837        tbl->column[i].left_xpixel=tbl->row_title_area.width;
07838        if(!tbl->row_titles_visible) 
07839                         tbl->column[i].left_xpixel=0;
07840         }
07841    }
07842    return TRUE;
07843 }
07844 
07845 static gint
07846 AddRow(GtkSheet *tbl, gint nrows)
07847 {
07848    gint i;
07849 
07850    if(nrows == -1 && tbl->maxrow == 0)
07851      {
07852        nrows = 1;
07853      }
07854    else
07855      {
07856        tbl->maxrow += nrows;
07857        tbl->row = (GtkSheetRow *)g_realloc(tbl->row,(tbl->maxrow+1)*
07858                                             sizeof(GtkSheetRow));
07859      }
07860 
07861    for(i=tbl->maxrow-nrows+1; i<= tbl->maxrow; i++){
07862         tbl->row[i].requisition=tbl->row[i].height=DEFAULT_ROW_HEIGHT(GTK_WIDGET(tbl));
07863     tbl->row[i].button.label=NULL;
07864     tbl->row[i].button.child=NULL;
07865         tbl->row[i].button.state=GTK_STATE_NORMAL;
07866         tbl->row[i].button.justification=GTK_JUSTIFY_CENTER;
07867         tbl->row[i].button.label_visible = TRUE;
07868         tbl->row[i].name=NULL;
07869         tbl->row[i].is_visible=TRUE;
07870         tbl->row[i].is_sensitive=TRUE;
07871         if(i>0)
07872            tbl->row[i].top_ypixel=tbl->row[i-1].top_ypixel+tbl->row[i-1].height;
07873     else
07874         {
07875        tbl->row[i].top_ypixel=tbl->column_title_area.height;
07876            if(!tbl->column_titles_visible) 
07877                         tbl->row[i].top_ypixel=0;
07878         } 
07879    }
07880    return TRUE;
07881 }
07882 
07883 static gint
07884 InsertRow(GtkSheet *tbl, gint row, gint nrows)
07885 {
07886   GtkSheetCell **pp;
07887   gint i,j;
07888   GtkSheetCell **auxdata;
07889   GtkSheetRow auxrow;
07890 
07891   AddRow(tbl,nrows);
07892 
07893   for(i=tbl->maxrow; i>=row+nrows; i--){
07894     auxrow = tbl->row[i];  
07895     tbl->row[i]=tbl->row[i-nrows];    
07896     tbl->row[i].is_visible=tbl->row[i-nrows].is_visible;
07897     tbl->row[i].is_sensitive=tbl->row[i-nrows].is_sensitive;
07898     if(auxrow.is_visible) 
07899                tbl->row[i].top_ypixel+=nrows*DEFAULT_ROW_HEIGHT(GTK_WIDGET(tbl));
07900     tbl->row[i-nrows]=auxrow;
07901   }
07902 
07903   if(row <= tbl->maxallocrow){
07904    
07905     GrowSheet(tbl,nrows,0);
07906 
07907     for(i=tbl->maxallocrow; i>=row+nrows; i--){
07908       auxdata = tbl->data[i];
07909       tbl->data[i]=tbl->data[i-nrows];
07910 
07911       pp= tbl->data[i];
07912       for(j=0; j<=tbl->maxalloccol; j++,pp++){
07913         if(*pp!=(GtkSheetCell *)NULL)
07914                                     (*pp)->row=i;
07915       
07916       }
07917       tbl->data[i-nrows]=auxdata;
07918     }
07919   }
07920   gtk_sheet_recalc_top_ypixels(tbl, 0);
07921   return TRUE;
07922 }  
07923 
07924 static gint 
07925 InsertColumn(GtkSheet *tbl, gint col, gint ncols)
07926 {
07927   gint i,j;
07928   GtkSheetColumn auxcol;
07929 
07930   AddColumn(tbl,ncols);
07931 
07932   for(i=tbl->maxcol; i>=col+ncols; i--){
07933     auxcol = tbl->column[i];
07934     tbl->column[i]=tbl->column[i-ncols];
07935     tbl->column[i].is_visible=tbl->column[i-ncols].is_visible;
07936     tbl->column[i].is_sensitive=tbl->column[i-ncols].is_sensitive;
07937     tbl->column[i].left_text_column=tbl->column[i-ncols].left_text_column;
07938     tbl->column[i].right_text_column=tbl->column[i-ncols].right_text_column;
07939     tbl->column[i].justification=tbl->column[i-ncols].justification;
07940     if(auxcol.is_visible) tbl->column[i].left_xpixel+=ncols*DEFAULT_COLUMN_WIDTH;
07941     tbl->column[i-ncols]=auxcol;
07942   }
07943 
07944   if(col <= tbl->maxalloccol){
07945    
07946     GrowSheet(tbl,0,ncols);
07947 
07948     for(i=0; i<=tbl->maxallocrow; i++){
07949       for(j=tbl->maxalloccol; j>=col+ncols; j--){
07950         gtk_sheet_real_cell_clear(tbl, i, j, TRUE);
07951         tbl->data[i][j]=tbl->data[i][j-ncols];
07952         if(tbl->data[i][j]) tbl->data[i][j]->col=j;
07953         tbl->data[i][j-ncols]=NULL;
07954       }
07955     }
07956   }
07957   gtk_sheet_recalc_left_xpixels(tbl, 0);
07958   return TRUE;
07959 }
07960 
07961 static gint
07962 DeleteRow(GtkSheet *tbl, gint row, gint nrows)
07963 {
07964   GtkSheetCell **auxdata = NULL;
07965   gint i,j;
07966 
07967   if(nrows <= 0 || row > tbl->maxrow) return TRUE;
07968 
07969   nrows=MIN(nrows,tbl->maxrow-row+1);
07970 
07971   for(i=row; i<row+nrows; i++){
07972     if(tbl->row[i].name){
07973             g_free(tbl->row[i].name);
07974             tbl->row[i].name = NULL;
07975     }
07976     if(tbl->row[i].button.label){
07977             g_free(tbl->row[i].button.label);
07978             tbl->row[i].button.label = NULL;
07979     }
07980   }           
07981 
07982   for(i=row; i<=tbl->maxrow-nrows; i++){
07983     if(i+nrows <= tbl->maxrow){ 
07984       tbl->row[i]=tbl->row[i+nrows];
07985     }
07986   }
07987 
07988   if(row <= tbl->maxallocrow){
07989 
07990     for(i=row; i<=tbl->maxrow-nrows; i++){
07991       if(i<=tbl->maxallocrow){
07992         auxdata=tbl->data[i];
07993         for(j=0; j<=tbl->maxalloccol; j++){
07994               gtk_sheet_real_cell_clear(tbl, i, j, TRUE);
07995         }
07996       }
07997       if(i+nrows<=tbl->maxallocrow){
07998         tbl->data[i]=tbl->data[i+nrows];
07999         tbl->data[i+nrows]=auxdata;
08000         for(j=0; j<=tbl->maxalloccol; j++){
08001             if(tbl->data[i][j]) tbl->data[i][j]->row=i;
08002         }
08003       }
08004     }
08005 
08006     for(i=tbl->maxrow-nrows+1; i<=tbl->maxallocrow; i++){
08007            if(i > 0 && tbl->data[i]){
08008                 g_free(tbl->data[i]);
08009                 tbl->data[i] = NULL;
08010            }
08011     }
08012 
08013     tbl->maxallocrow-=MIN(nrows,tbl->maxallocrow-row+1);
08014     tbl->maxallocrow = MIN(tbl->maxallocrow, tbl->maxrow);
08015 
08016   }
08017 
08018   tbl->maxrow-=nrows;
08019   gtk_sheet_recalc_top_ypixels(tbl, 0);
08020   return TRUE;
08021 } 
08022 
08023 static gint
08024 DeleteColumn(GtkSheet *tbl, gint column, gint ncols)
08025 {
08026   gint i,j;
08027   GtkSheetColumn auxcol;
08028 
08029   ncols = MIN(ncols,tbl->maxcol-column+1);
08030 
08031   if(ncols <= 0 || column > tbl->maxcol) return TRUE;
08032 
08033   for(i=column; i<column+ncols; i++){
08034     auxcol=tbl->column[i];
08035     if(tbl->column[i].name){
08036              g_free(tbl->column[i].name);
08037              tbl->column[i].name = NULL;
08038     }
08039     if(tbl->column[i].button.label){
08040              g_free(tbl->column[i].button.label);
08041              tbl->column[i].button.label = NULL;
08042     }
08043   }
08044 
08045   for(i=column; i<=tbl->maxcol-ncols; i++){
08046     if(i+ncols <= tbl->maxcol){
08047       tbl->column[i]=tbl->column[i+ncols];    
08048     } 
08049   }
08050 
08051   if(column <= tbl->maxalloccol){
08052 
08053     for(i=column; i<=tbl->maxcol-ncols; i++){
08054       if(i<=tbl->maxalloccol){
08055         for(j=0; j<=tbl->maxallocrow; j++){
08056               gtk_sheet_real_cell_clear(tbl, j, i, TRUE);
08057               if(i+ncols <= tbl->maxalloccol){
08058                   tbl->data[j][i] = tbl->data[j][i+ncols];
08059                   tbl->data[j][i+ncols] = NULL;
08060               if(tbl->data[j][i]) tbl->data[j][i]->col=i;
08061               }
08062         }
08063       }
08064 
08065     }
08066 
08067     tbl->maxalloccol-=MIN(ncols,tbl->maxalloccol-column+1);
08068     tbl->maxalloccol = MIN(tbl->maxalloccol, tbl->maxcol);
08069   }
08070   tbl->maxcol-=ncols;
08071   gtk_sheet_recalc_left_xpixels(tbl, 0);
08072   return TRUE;
08073 }  
08074 
08075 static gint
08076 GrowSheet(GtkSheet *tbl, gint newrows, gint newcols)
08077 {
08078   gint i,j;
08079   gint inirow, inicol;
08080 
08081   inirow = tbl->maxallocrow + 1;  
08082   inicol = tbl->maxalloccol + 1;  
08083 
08084   tbl->maxalloccol = tbl->maxalloccol + newcols;
08085   tbl->maxallocrow = tbl->maxallocrow + newrows;
08086 
08087   if(newrows>0){
08088       tbl->data = (GtkSheetCell***)
08089                  g_realloc(tbl->data,(tbl->maxallocrow+1)*sizeof(GtkSheetCell **)+sizeof(double));
08090 
08091       for(i=inirow; i <= tbl->maxallocrow; i++){
08092         tbl->data[i] = (GtkSheetCell **) \
08093                        g_malloc((tbl->maxcol+1)*sizeof(GtkSheetCell *)+sizeof(double));
08094         for(j=0; j<inicol; j++) {
08095           tbl->data[i][j] = NULL;
08096         }
08097       }
08098           
08099   }
08100 
08101   if(newcols>0){
08102       for(i=0; i <= tbl->maxallocrow; i++) {
08103         tbl->data[i] = (GtkSheetCell **) \
08104                        g_realloc(tbl->data[i],(tbl->maxalloccol+1)*sizeof(GtkSheetCell *)+sizeof(double));
08105         for(j=inicol; j <= tbl->maxalloccol; j++) {
08106           tbl->data[i][j] = NULL;
08107     }
08108       }
08109   }
08110 
08111   return(0);
08112 }      
08113 
08114 static gint
08115 CheckBounds(GtkSheet *tbl, gint row, gint col)
08116 {
08117   gint newrows=0,newcols=0;
08118 
08119   if(col>tbl->maxalloccol) newcols=col-tbl->maxalloccol;
08120   if(row>tbl->maxallocrow) newrows=row-tbl->maxallocrow;
08121   if(newrows>0 || newcols>0) GrowSheet(tbl, newrows, newcols);
08122   return(0);
08123 } 
08124 
08125 /********************************************************************
08126  * Container Functions:
08127  * gtk_sheet_add
08128  * gtk_sheet_put
08129  * gtk_sheet_attach
08130  * gtk_sheet_remove
08131  * gtk_sheet_move_child
08132  * gtk_sheet_position_child
08133  * gtk_sheet_position_children 
08134  * gtk_sheet_realize_child
08135  * gtk_sheet_get_child_at
08136  ********************************************************************/ 
08137 
08138 GtkSheetChild *
08139 gtk_sheet_put(GtkSheet *sheet, GtkWidget *child, gint x, gint y)
08140 {
08141   GtkRequisition child_requisition;
08142   GtkSheetChild *child_info;
08143 
08144   g_return_val_if_fail(sheet != NULL, NULL);
08145   g_return_val_if_fail(GTK_IS_SHEET(sheet), NULL);
08146   g_return_val_if_fail(child != NULL, NULL);
08147   g_return_val_if_fail(child->parent == NULL, NULL);
08148 
08149   child_info = g_new (GtkSheetChild, 1);
08150   child_info->widget = child;
08151   child_info->x = x;  
08152   child_info->y = y;
08153   child_info->attached_to_cell = FALSE;
08154   child_info->floating = TRUE;
08155   child_info->xpadding = child_info->ypadding = 0;
08156   child_info->xexpand = child_info->yexpand = FALSE;
08157   child_info->xshrink = child_info->yshrink = FALSE;
08158   child_info->xfill = child_info->yfill = FALSE;
08159 
08160   sheet->children = g_list_append(sheet->children, child_info);
08161 
08162   gtk_widget_set_parent (child, GTK_WIDGET(sheet));
08163 
08164   gtk_widget_size_request(child, &child_requisition);
08165 
08166   if (GTK_WIDGET_VISIBLE(GTK_WIDGET(sheet)))
08167     {
08168        if(GTK_WIDGET_REALIZED(GTK_WIDGET(sheet)) && 
08169           (!GTK_WIDGET_REALIZED(child) || GTK_WIDGET_NO_WINDOW(child)))
08170         gtk_sheet_realize_child(sheet, child_info);
08171 
08172        if(GTK_WIDGET_MAPPED(GTK_WIDGET(sheet)) && 
08173           !GTK_WIDGET_MAPPED(child))
08174         gtk_widget_map(child);
08175     }
08176 
08177   gtk_sheet_position_child(sheet, child_info);
08178 
08179 /* This will avoid drawing on the titles */
08180 
08181   if(GTK_WIDGET_REALIZED(GTK_WIDGET(sheet)))
08182    {
08183       if(sheet->row_titles_visible)
08184              gdk_window_show(sheet->row_title_window);
08185       if(sheet->column_titles_visible)
08186              gdk_window_show(sheet->column_title_window);
08187    }
08188 
08189   return (child_info);
08190 }
08191 
08192 void
08193 gtk_sheet_attach_floating       (GtkSheet *sheet,
08194                                  GtkWidget *widget,
08195                                  gint row, gint col)
08196 {
08197   GdkRectangle area;
08198   GtkSheetChild *child;
08199 
08200   if(row < 0 || col < 0){
08201     gtk_sheet_button_attach(sheet, widget, row, col);
08202     return;
08203   }
08204 
08205   gtk_sheet_get_cell_area(sheet, row, col, &area);
08206   child = gtk_sheet_put(sheet, widget, area.x, area.y);
08207   child->attached_to_cell = TRUE;
08208   child->row = row;
08209   child->col = col;
08210 }
08211 
08212 void
08213 gtk_sheet_attach_default        (GtkSheet *sheet,
08214                                  GtkWidget *widget,
08215                                  gint row, gint col)
08216 {
08217   if(row < 0 || col < 0){
08218     gtk_sheet_button_attach(sheet, widget, row, col);
08219     return;
08220   }
08221 
08222   gtk_sheet_attach(sheet, widget, row, col, GTK_EXPAND|GTK_FILL, GTK_EXPAND|GTK_FILL, 0, 0);
08223 }
08224 
08225 void
08226 gtk_sheet_attach        (GtkSheet *sheet,
08227                          GtkWidget *widget,
08228                          gint row, gint col,
08229                          gint xoptions,
08230                          gint yoptions,
08231                          gint xpadding,
08232                          gint ypadding)
08233 {
08234   GdkRectangle area;
08235   GtkSheetChild *child = NULL;
08236 
08237   if(row < 0 || col < 0){
08238     gtk_sheet_button_attach(sheet, widget, row, col);
08239     return;
08240   }
08241 
08242   child = g_new0(GtkSheetChild, 1);
08243   child->attached_to_cell = TRUE;
08244   child->floating = FALSE;
08245   child->widget = widget;
08246   child->row = row;
08247   child->col = col;
08248   child->xpadding = xpadding;
08249   child->ypadding = ypadding;
08250   child->xexpand = (xoptions & GTK_EXPAND) != 0;
08251   child->yexpand = (yoptions & GTK_EXPAND) != 0;
08252   child->xshrink = (xoptions & GTK_SHRINK) != 0;
08253   child->yshrink = (yoptions & GTK_SHRINK) != 0;
08254   child->xfill = (xoptions & GTK_FILL) != 0;
08255   child->yfill = (yoptions & GTK_FILL) != 0;
08256 
08257   sheet->children = g_list_append(sheet->children, child);
08258 
08259   gtk_sheet_get_cell_area(sheet, row, col, &area);
08260 
08261   child->x = area.x + child->xpadding;
08262   child->y = area.y + child->ypadding;
08263 
08264   if (GTK_WIDGET_VISIBLE(GTK_WIDGET(sheet)))
08265     {
08266        if(GTK_WIDGET_REALIZED(GTK_WIDGET(sheet)) &&
08267           (!GTK_WIDGET_REALIZED(widget) || GTK_WIDGET_NO_WINDOW(widget)))
08268         gtk_sheet_realize_child(sheet, child);
08269 
08270        if(GTK_WIDGET_MAPPED(GTK_WIDGET(sheet)) &&
08271           !GTK_WIDGET_MAPPED(widget))
08272         gtk_widget_map(widget);
08273     }
08274 
08275   gtk_sheet_position_child(sheet, child);
08276 
08277 /* This will avoid drawing on the titles */
08278 
08279   if(GTK_WIDGET_REALIZED(GTK_WIDGET(sheet)))
08280    {
08281       if(GTK_SHEET_ROW_TITLES_VISIBLE(sheet))
08282              gdk_window_show(sheet->row_title_window);
08283       if(GTK_SHEET_COL_TITLES_VISIBLE(sheet))
08284              gdk_window_show(sheet->column_title_window);
08285    }
08286 
08287 }
08288 
08289 void
08290 gtk_sheet_button_attach     (GtkSheet *sheet, 
08291                  GtkWidget *widget, 
08292                  gint row, gint col)
08293 {
08294   GtkSheetButton *button;
08295   GtkSheetChild *child;
08296   GtkRequisition button_requisition;
08297 
08298   if(row >= 0 && col >= 0) return;
08299   if(row < 0 && col < 0) return;
08300 
08301   child = g_new (GtkSheetChild, 1);
08302   child->widget = widget;
08303   child->x = 0;  
08304   child->y = 0;  
08305   child->attached_to_cell = TRUE;
08306   child->floating = FALSE;
08307   child->row = row;
08308   child->col = col;
08309   child->xpadding = child->ypadding = 0;
08310   child->xshrink = child->yshrink = FALSE;
08311   child->xfill = child->yfill = FALSE;
08312 
08313   if(row == -1){
08314      button = &sheet->column[col].button;
08315      button->child = child;
08316   }
08317   else
08318   {
08319      button = &sheet->row[row].button;
08320      button->child = child;
08321   }
08322 
08323   sheet->children = g_list_append(sheet->children, child);
08324 
08325   gtk_sheet_button_size_request(sheet, button, &button_requisition);
08326 
08327   if(row == -1){
08328        if(button_requisition.height > sheet->column_title_area.height)
08329              sheet->column_title_area.height = button_requisition.height; 
08330        if(button_requisition.width > sheet->column[col].width)
08331              sheet->column[col].width = button_requisition.width; 
08332   }
08333 
08334   if(col == -1){
08335        if(button_requisition.width > sheet->row_title_area.width)
08336              sheet->row_title_area.width = button_requisition.width; 
08337        if(button_requisition.height > sheet->row[row].height)
08338              sheet->row[row].height = button_requisition.height; 
08339   }
08340 
08341   if (GTK_WIDGET_VISIBLE(GTK_WIDGET(sheet)))
08342     {
08343        if(GTK_WIDGET_REALIZED(GTK_WIDGET(sheet)) && 
08344           (!GTK_WIDGET_REALIZED(widget) || GTK_WIDGET_NO_WINDOW(widget)))
08345         gtk_sheet_realize_child(sheet, child);
08346 
08347        if(GTK_WIDGET_MAPPED(GTK_WIDGET(sheet)) && 
08348           !GTK_WIDGET_MAPPED(widget))
08349         gtk_widget_map(widget);
08350     }
08351 
08352   if(row == -1) size_allocate_column_title_buttons(sheet);
08353   if(col == -1) size_allocate_row_title_buttons(sheet);
08354 
08355 }
08356 
08357 static void
08358 label_size_request(GtkSheet *sheet, gchar *label, GtkRequisition *req)
08359 {
08360   gchar *words;
08361   gchar word[1000];
08362   gint n = 0;
08363   gint row_height = DEFAULT_ROW_HEIGHT(GTK_WIDGET(sheet)) - 2*CELLOFFSET + 2;
08364 
08365   req->height = 0;
08366   req->width = 0;
08367   words=label;
08368 
08369   while(words && *words != '\0'){
08370     if(*words == '\n' || *(words+1) == '\0'){
08371       req->height += row_height;
08372 
08373       word[n] = '\0';
08374       req->width = MAX(req->width, STRING_WIDTH(GTK_WIDGET(sheet), GTK_WIDGET(sheet)->style->font_desc, word));
08375       n = 0;
08376     } else {
08377       word[n++] = *words;
08378     }
08379     words++;
08380   }
08381  
08382   if(n > 0) req->height -= 2;
08383 }
08384 
08385 static void
08386 gtk_sheet_button_size_request   (GtkSheet *sheet,
08387                                  GtkSheetButton *button, 
08388                                  GtkRequisition *button_requisition)
08389 {
08390   GtkRequisition requisition;
08391   GtkRequisition label_requisition;
08392 
08393   if(gtk_sheet_autoresize(sheet) && button->label && strlen(button->label) > 0){
08394      label_size_request(sheet, button->label, &label_requisition);
08395      label_requisition.width += 2*CELLOFFSET;
08396      label_requisition.height += 2*CELLOFFSET;
08397   } else {
08398      label_requisition.height = DEFAULT_ROW_HEIGHT(GTK_WIDGET(sheet));
08399      label_requisition.width = COLUMN_MIN_WIDTH;
08400   } 
08401 
08402   if(button->child)
08403   {
08404      gtk_widget_size_request(button->child->widget, &requisition);
08405      requisition.width += 2*button->child->xpadding;
08406      requisition.height += 2*button->child->ypadding;
08407      requisition.width += 2*sheet->button->style->xthickness;
08408      requisition.height += 2*sheet->button->style->ythickness;
08409   }
08410   else
08411   {
08412      requisition.height = DEFAULT_ROW_HEIGHT(GTK_WIDGET(sheet));
08413      requisition.width = COLUMN_MIN_WIDTH;
08414   }
08415 
08416   *button_requisition = requisition;
08417   button_requisition->width = MAX(requisition.width, label_requisition.width);
08418   button_requisition->height = MAX(requisition.height, label_requisition.height);
08419  
08420 }
08421 
08422 static void
08423 gtk_sheet_row_size_request      (GtkSheet *sheet,
08424                                  gint row,
08425                                  guint *requisition)
08426 {
08427   GtkRequisition button_requisition;
08428   GList *children;
08429 
08430   gtk_sheet_button_size_request(sheet, &sheet->row[row].button, &button_requisition);
08431 
08432   *requisition = button_requisition.height;
08433 
08434   children = sheet->children;
08435   while(children){
08436     GtkSheetChild *child = (GtkSheetChild *)children->data;
08437     GtkRequisition child_requisition;
08438 
08439     if(child->attached_to_cell && child->row == row && child->col != -1 && !child->floating && !child->yshrink){
08440       gtk_widget_get_child_requisition(child->widget, &child_requisition);
08441 
08442       if(child_requisition.height + 2 * child->ypadding > *requisition)
08443         *requisition = child_requisition.height + 2 * child->ypadding;
08444     }
08445     children = g_list_next(children);
08446   }
08447 
08448   sheet->row[row].requisition = *requisition;
08449 }
08450 
08451 static void
08452 gtk_sheet_column_size_request   (GtkSheet *sheet,
08453                                  gint col,
08454                                  guint *requisition)
08455 {
08456   GtkRequisition button_requisition;
08457   GList *children;
08458 
08459   gtk_sheet_button_size_request(sheet, &sheet->column[col].button, &button_requisition);
08460 
08461   *requisition = button_requisition.width;
08462 
08463   children = sheet->children;
08464   while(children){
08465     GtkSheetChild *child = (GtkSheetChild *)children->data;
08466     GtkRequisition child_requisition;
08467 
08468     if(child->attached_to_cell && child->col == col && child->row != -1 && !child->floating && !child->xshrink){
08469       gtk_widget_get_child_requisition(child->widget, &child_requisition);
08470 
08471       if(child_requisition.width + 2 * child->xpadding > *requisition)
08472         *requisition = child_requisition.width + 2 * child->xpadding;
08473     }
08474     children = g_list_next(children);
08475   }
08476 
08477   sheet->column[col].requisition = *requisition;
08478 }
08479 
08480 void
08481 gtk_sheet_move_child(GtkSheet *sheet, GtkWidget *widget, gint x, gint y)
08482 {
08483   GtkSheetChild *child;
08484   GList *children;
08485 
08486   g_return_if_fail(sheet != NULL);
08487   g_return_if_fail(GTK_IS_SHEET(sheet));
08488 
08489   children = sheet->children;
08490   while(children)
08491     {
08492        child = children->data;
08493 
08494        if(child->widget == widget){
08495          child->x = x;
08496          child->y = y;
08497          child->row = ROW_FROM_YPIXEL(sheet, y);
08498      child->col = COLUMN_FROM_XPIXEL(sheet, x);
08499          gtk_sheet_position_child(sheet, child);
08500          return;
08501        }
08502 
08503        children = g_list_next(children);
08504     }
08505 
08506   g_warning("Widget must be a GtkSheet child"); 
08507 
08508 }
08509 
08510 static void
08511 gtk_sheet_position_child(GtkSheet *sheet, GtkSheetChild *child)
08512 {
08513    GtkRequisition child_requisition;
08514    GtkAllocation child_allocation;
08515    gint xoffset = 0; 
08516    gint yoffset = 0;
08517    gint x = 0, y = 0;
08518    GdkRectangle area;
08519 
08520    gtk_widget_get_child_requisition(child->widget, &child_requisition);
08521 
08522    if(sheet->column_titles_visible) 
08523              yoffset = sheet->column_title_area.height;
08524 
08525    if(sheet->row_titles_visible)
08526              xoffset = sheet->row_title_area.width;
08527 
08528    if(child->attached_to_cell){
08529 /*
08530       child->x = COLUMN_LEFT_XPIXEL(sheet, child->col);
08531       child->y = ROW_TOP_YPIXEL(sheet, child->row);
08532 
08533       if(sheet->row_titles_visible) 
08534                                     child->x-=sheet->row_title_area.width;
08535       if(sheet->column_titles_visible) 
08536                                     child->y-=sheet->column_title_area.height;
08537 
08538       width = sheet->column[child->col].width;
08539       height = sheet->row[child->row].height;
08540 */
08541       
08542       gtk_sheet_get_cell_area(sheet, child->row, child->col, &area);
08543       child->x = area.x + child->xpadding;
08544       child->y = area.y + child->ypadding;
08545 
08546       if(!child->floating){
08547         if(child_requisition.width + 2*child->xpadding <= sheet->column[child->col].width){
08548           if(child->xfill){
08549             child_requisition.width = child_allocation.width = sheet->column[child->col].width - 2*child->xpadding;
08550           } else {
08551             if(child->xexpand){
08552               child->x = area.x + sheet->column[child->col].width / 2 -
08553                                   child_requisition.width / 2;
08554             }
08555             child_allocation.width = child_requisition.width;
08556           }
08557         } else {
08558           if(!child->xshrink){
08559             gtk_sheet_set_column_width(sheet, child->col, child_requisition.width + 2 * child->xpadding);
08560           }
08561           child_allocation.width = sheet->column[child->col].width - 2*child->xpadding;
08562         }
08563 
08564         if(child_requisition.height + 2*child->ypadding <= sheet->row[child->row].height){
08565           if(child->yfill){
08566             child_requisition.height = child_allocation.height = sheet->row[child->row].height - 2*child->ypadding;
08567           } else {
08568             if(child->yexpand){
08569               child->y = area.y + sheet->row[child->row].height / 2 -
08570                                   child_requisition.height / 2;
08571             }
08572             child_allocation.height = child_requisition.height;
08573           }
08574         } else {
08575           if(!child->yshrink){
08576             gtk_sheet_set_row_height(sheet, child->row, child_requisition.height + 2 * child->ypadding);
08577           }
08578           child_allocation.height = sheet->row[child->row].height - 2*child->ypadding;
08579         }
08580       } else {
08581         child_allocation.width = child_requisition.width;
08582         child_allocation.height = child_requisition.height;
08583       }
08584 
08585       x = child_allocation.x = child->x + xoffset;
08586       y = child_allocation.y = child->y + yoffset;
08587    }
08588    else
08589    {
08590       x = child_allocation.x = child->x + sheet->hoffset + xoffset;   
08591       x = child_allocation.x = child->x + xoffset;   
08592       y = child_allocation.y = child->y + sheet->voffset + yoffset;
08593       y = child_allocation.y = child->y + yoffset;
08594       child_allocation.width = child_requisition.width;
08595       child_allocation.height = child_requisition.height;
08596    }
08597 
08598    gtk_widget_size_allocate(child->widget, &child_allocation);
08599    gtk_widget_queue_draw(child->widget);
08600 }
08601 
08602 static void
08603 gtk_sheet_forall (GtkContainer *container,
08604                   gboolean      include_internals,
08605                   GtkCallback   callback,
08606                   gpointer      callback_data)
08607 {
08608   GtkSheet *sheet;
08609   GtkSheetChild *child;
08610   GList *children;
08611 
08612   g_return_if_fail (GTK_IS_SHEET (container));
08613   g_return_if_fail (callback != NULL);
08614 
08615   sheet = GTK_SHEET (container);
08616 
08617   children = sheet->children;
08618   while (children)
08619     {
08620       child = children->data;
08621       children = g_list_next(children);
08622 
08623       (* callback) (child->widget, callback_data);
08624     }
08625   if(sheet->button)
08626      (* callback) (sheet->button, callback_data);
08627   if(sheet->sheet_entry)
08628      (* callback) (sheet->sheet_entry, callback_data);
08629 }
08630 
08631 
08632 static void
08633 gtk_sheet_position_children(GtkSheet *sheet)
08634 {
08635   GList *children;
08636   GtkSheetChild *child;
08637 
08638   children = sheet->children;
08639 
08640   while(children)
08641    {
08642      child = (GtkSheetChild *)children->data;
08643 
08644      if(child->col !=-1 && child->row != -1)
08645            gtk_sheet_position_child(sheet, child);
08646 
08647      if(child->row == -1){
08648         if(child->col < MIN_VISIBLE_COLUMN(sheet) || 
08649            child->col > MAX_VISIBLE_COLUMN(sheet))
08650               gtk_sheet_child_hide(child);
08651         else
08652               gtk_sheet_child_show(child);
08653      }
08654      if(child->col == -1){
08655         if(child->row < MIN_VISIBLE_ROW(sheet) ||
08656            child->row > MAX_VISIBLE_ROW(sheet))
08657               gtk_sheet_child_hide(child);
08658         else
08659               gtk_sheet_child_show(child);
08660      }
08661  
08662      children = g_list_next(children);
08663    }
08664     
08665 }
08666 
08667 static void
08668 gtk_sheet_remove (GtkContainer *container, GtkWidget *widget)
08669 {
08670   GtkSheet *sheet;
08671   GList *children;
08672   GtkSheetChild *child = 0;
08673 
08674   g_return_if_fail(container != NULL);
08675   g_return_if_fail(GTK_IS_SHEET(container));
08676 
08677   sheet = GTK_SHEET(container);
08678 
08679   children = sheet->children;
08680 
08681   while(children)
08682    {
08683      child = (GtkSheetChild *)children->data;
08684 
08685      if(child->widget == widget) break;
08686 
08687      children = g_list_next(children);
08688    }
08689 
08690   if (children)
08691    {
08692      if(child->row == -1)
08693         sheet->row[child->col].button.child = NULL;
08694 
08695      if(child->col == -1)
08696         sheet->column[child->row].button.child = NULL;
08697 
08698      gtk_widget_unparent (widget);
08699      child->widget = NULL;
08700 
08701      sheet->children = g_list_remove_link (sheet->children, children);
08702      g_list_free_1 (children);
08703      g_free(child);
08704    }
08705 
08706 }
08707 
08708 static void
08709 gtk_sheet_realize_child(GtkSheet *sheet, GtkSheetChild *child)
08710 {
08711   GtkWidget *widget;
08712 
08713   widget = GTK_WIDGET(sheet);
08714 
08715   if(GTK_WIDGET_REALIZED(widget)){
08716     if(child->row == -1)
08717       gtk_widget_set_parent_window(child->widget, sheet->column_title_window);
08718     else if(child->col == -1)
08719       gtk_widget_set_parent_window(child->widget, sheet->row_title_window);
08720     else
08721       gtk_widget_set_parent_window(child->widget, sheet->sheet_window);
08722   }
08723 
08724   gtk_widget_set_parent(child->widget, widget);
08725 }
08726 
08727 
08728    
08729 GtkSheetChild *
08730 gtk_sheet_get_child_at(GtkSheet *sheet, gint row, gint col)
08731 {
08732   GList *children;
08733   GtkSheetChild *child = 0;
08734 
08735   g_return_val_if_fail(sheet != NULL, NULL);
08736   g_return_val_if_fail(GTK_IS_SHEET(sheet), NULL);
08737 
08738   children = sheet->children;
08739 
08740   while(children)
08741    {
08742      child = (GtkSheetChild *)children->data;
08743 
08744      if(child->attached_to_cell)
08745         if(child->row == row && child->col == col) break; 
08746      
08747      children = g_list_next(children);
08748    }
08749 
08750   if(children) return child; 
08751 
08752   return NULL;
08753 }
08754 
08755 static void
08756 gtk_sheet_child_hide(GtkSheetChild *child) 
08757 {
08758   g_return_if_fail(child != NULL);
08759   gtk_widget_hide(child->widget);
08760 }
08761 
08762 static void
08763 gtk_sheet_child_show(GtkSheetChild *child) 
08764 {
08765   g_return_if_fail(child != NULL);
08766 
08767   gtk_widget_show(child->widget);
08768 }
 All Data Structures Files Functions Variables Typedefs Enumerations Enumerator Defines