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