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