GnuCash  2.6.99
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
gnucash-cursor.c
1 /********************************************************************\
2  * This program is free software; you can redistribute it and/or *
3  * modify it under the terms of the GNU General Public License as *
4  * published by the Free Software Foundation; either version 2 of *
5  * the License, or (at your option) any later version. *
6  * *
7  * This program is distributed in the hope that it will be useful, *
8  * but WITHOUT ANY WARRANTY; without even the implied warranty of *
9  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
10  * GNU General Public License for more details. *
11  * *
12  * You should have received a copy of the GNU General Public License*
13  * along with this program; if not, contact: *
14  * *
15  * Free Software Foundation Voice: +1-617-542-5942 *
16  * 51 Franklin Street, Fifth Floor Fax: +1-617-542-2652 *
17  * Boston, MA 02110-1301, USA [email protected] *
18  * *
19 \********************************************************************/
20 
21 /*
22  * The Gnucash Cursor Canvas Item
23  *
24  * Based heavily (i.e., cut and pasted from) on the Gnumeric ItemCursor.
25  *
26  * Authors:
27  * Heath Martin <[email protected]>
28  * Dave Peticolas <[email protected]>
29  */
30 
31 #include "config.h"
32 #include <libgnomecanvas/libgnomecanvas.h>
33 
34 #include "gnucash-color.h"
35 #include "gnucash-cursor.h"
36 #include "gnucash-grid.h"
37 #include "gnucash-sheet.h"
38 #include "gnucash-sheetP.h"
39 #include "gnucash-style.h"
40 
41 static GnomeCanvasItem *gnucash_cursor_parent_class;
42 static GnomeCanvasItem *gnucash_item_cursor_parent_class;
43 
44 enum
45 {
46  PROP_0,
47  PROP_SHEET,
48  PROP_GRID,
49 };
50 
51 
52 static void
53 gnucash_cursor_get_pixel_coords (GnucashCursor *cursor,
54  gint *x, gint *y,
55  gint *w, gint *h)
56 {
57  GnucashSheet *sheet = cursor->sheet;
58  GnucashItemCursor *item_cursor;
59  VirtualCellLocation vcell_loc;
60  CellDimensions *cd;
61  VirtualCell *vcell;
62  SheetBlock *block;
63  gint col;
64 
65  item_cursor =
66  GNUCASH_ITEM_CURSOR(cursor->cursor[GNUCASH_CURSOR_BLOCK]);
67 
68  vcell_loc.virt_row = item_cursor->row;
69  vcell_loc.virt_col = item_cursor->col;
70 
71  block = gnucash_sheet_get_block (sheet, vcell_loc);
72  if (!block)
73  return;
74 
75  vcell = gnc_table_get_virtual_cell (sheet->table, vcell_loc);
76  if (!vcell)
77  return;
78 
79  for (col = 0; col < vcell->cellblock->num_cols; col++)
80  {
81  BasicCell *cell;
82 
83  cell = gnc_cellblock_get_cell (vcell->cellblock, 0, col);
84  if (cell && cell->cell_name)
85  break;
86  }
87 
88  *y = block->origin_y;
89 
90  cd = gnucash_style_get_cell_dimensions (block->style, 0, col);
91  if (cd)
92  *x = cd->origin_x;
93  else
94  *x = block->origin_x;
95 
96  for (col = vcell->cellblock->num_cols - 1; col >= 0; col--)
97  {
98  BasicCell *cell;
99 
100  cell = gnc_cellblock_get_cell (vcell->cellblock, 0, col);
101  if (cell && cell->cell_name)
102  break;
103  }
104 
105  *h = block->style->dimensions->height;
106 
107  cd = gnucash_style_get_cell_dimensions (block->style, 0, col);
108  if (cd)
109  *w = cd->origin_x + cd->pixel_width - *x;
110  else
111  *w = block->style->dimensions->width - *x;
112 }
113 
114 
115 static void
116 gnucash_cursor_request_redraw (GnucashCursor *cursor)
117 {
118  GnomeCanvas *canvas = GNOME_CANVAS_ITEM(cursor)->canvas;
119  int x, y, w, h;
120 
121  x = cursor->x;
122  y = cursor->y;
123  w = cursor->w;
124  h = cursor->h;
125 
126  gnome_canvas_request_redraw (canvas, x, y, x + w + 1, y + h + 1);
127 }
128 
129 
130 void
131 gnucash_cursor_set_style (GnucashCursor *cursor, SheetBlockStyle *style)
132 {
133  g_return_if_fail (cursor != NULL);
134  g_return_if_fail (GNUCASH_IS_CURSOR(cursor));
135 
136  cursor->style = style;
137 }
138 
139 
140 void
141 gnucash_cursor_get_virt (GnucashCursor *cursor, VirtualLocation *virt_loc)
142 {
143  g_return_if_fail (cursor != NULL);
144  g_return_if_fail (GNUCASH_IS_CURSOR (cursor));
145 
146  virt_loc->vcell_loc.virt_row =
147  GNUCASH_ITEM_CURSOR(cursor->cursor[GNUCASH_CURSOR_BLOCK])->row;
148  virt_loc->vcell_loc.virt_col =
149  GNUCASH_ITEM_CURSOR(cursor->cursor[GNUCASH_CURSOR_BLOCK])->col;
150 
151  virt_loc->phys_row_offset =
152  GNUCASH_ITEM_CURSOR(cursor->cursor[GNUCASH_CURSOR_CELL])->row;
153  virt_loc->phys_col_offset =
154  GNUCASH_ITEM_CURSOR(cursor->cursor[GNUCASH_CURSOR_CELL])->col;
155 }
156 
157 
158 void
159 gnucash_cursor_configure (GnucashCursor *cursor)
160 {
161  GnomeCanvasItem *item;
162  GnucashItemCursor *block_cursor;
163  GnucashItemCursor *cell_cursor;
164  GnomeCanvas *canvas;
165  gint x, y, w, h;
166  double wx, wy;
167 
168  g_return_if_fail (cursor != NULL);
169  g_return_if_fail (GNUCASH_IS_CURSOR (cursor));
170 
171  canvas = GNOME_CANVAS(GNOME_CANVAS_ITEM(cursor)->canvas);
172 
173  item = GNOME_CANVAS_ITEM (cursor);
174 
175  gnucash_cursor_get_pixel_coords (cursor, &x, &y, &w, &h);
176  gnome_canvas_item_set (GNOME_CANVAS_ITEM(cursor),
177  "GnomeCanvasGroup::x", (double)x,
178  "GnomeCanvasGroup::y", (double)y,
179  NULL);
180 
181  cursor->w = w;
182  cursor->h = h + 1;
183 
184  item->x1 = cursor->x = x;
185  item->y1 = cursor->y = y;
186  item->x2 = x + w;
187  item->y2 = y + h + 1;
188 
189  item = cursor->cursor[GNUCASH_CURSOR_BLOCK];
190  block_cursor = GNUCASH_ITEM_CURSOR (item);
191 
192  wx = 0;
193  wy = 0;
194 
195  gnome_canvas_item_i2w (item, &wx, &wy);
196  gnome_canvas_w2c (canvas, wx, wy, &block_cursor->x, &block_cursor->y);
197  block_cursor->w = w;
198  block_cursor->h = h + 1;
199 
200  item->x1 = block_cursor->x;
201  item->y1 = block_cursor->y;
202  item->x2 = block_cursor->x + w;
203  item->y2 = block_cursor->y + h + 1;
204 
205  item = cursor->cursor[GNUCASH_CURSOR_CELL];
206  cell_cursor = GNUCASH_ITEM_CURSOR(item);
207 
208  gnucash_sheet_style_get_cell_pixel_rel_coords (cursor->style,
209  cell_cursor->row,
210  cell_cursor->col,
211  &x, &y, &w, &h);
212  wx = x - block_cursor->x;
213  wy = y;
214 
215  gnome_canvas_item_i2w (item, &wx, &wy);
216  gnome_canvas_w2c (canvas, wx, wy, &cell_cursor->x, &cell_cursor->y);
217  cell_cursor->w = w;
218  cell_cursor->h = h;
219 
220  item->x1 = cell_cursor->x;
221  item->y1 = cell_cursor->y;
222  item->x2 = cell_cursor->x + w;
223  item->y2 = cell_cursor->y + h;
224 }
225 
226 
227 static void
228 gnucash_item_cursor_draw (GnomeCanvasItem *item, GdkDrawable *drawable,
229  int x, int y, int width, int height)
230 {
231  GnucashItemCursor *item_cursor = GNUCASH_ITEM_CURSOR (item);
232  GnucashCursor *cursor = GNUCASH_CURSOR(item->parent);
233  gint dx, dy, dw, dh;
234 
235  switch (item_cursor->type)
236  {
237  case GNUCASH_CURSOR_BLOCK:
238  dx = item_cursor->x - x;
239  dy = item_cursor->y - y;
240  dw = item_cursor->w;
241  dh = item_cursor->h;
242 
243  /* draw the rectangle around the entire active
244  virtual row */
245  gdk_gc_set_line_attributes (cursor->gc, 1,
246  GDK_LINE_SOLID, GDK_CAP_NOT_LAST, GDK_JOIN_MITER);
247 
248  gdk_gc_set_foreground (cursor->gc, &gn_black);
249 
250  gdk_draw_rectangle (drawable, cursor->gc, FALSE,
251  dx, dy, dw, dh - 1);
252  gdk_draw_line (drawable, cursor->gc,
253  dx, dy + dh, dx + dw, dy + dh);
254 
255  break;
256 
257  case GNUCASH_CURSOR_CELL:
258  dx = item_cursor->x - x;
259  dy = item_cursor->y - y;
260  dw = item_cursor->w;
261  dh = item_cursor->h;
262 
263  gdk_gc_set_line_attributes (cursor->gc, 1,
264  GDK_LINE_SOLID, GDK_CAP_NOT_LAST, GDK_JOIN_MITER);
265 
266  gdk_gc_set_foreground (cursor->gc, &gn_black);
267 
268  gdk_draw_rectangle (drawable, cursor->gc, FALSE,
269  dx, dy, dw, dh);
270  break;
271  }
272 }
273 
274 
275 static void
276 gnucash_cursor_set_block (GnucashCursor *cursor, VirtualCellLocation vcell_loc)
277 {
278  GnucashSheet *sheet;
279  GnucashItemCursor *item_cursor;
280 
281  g_return_if_fail (cursor != NULL);
282  g_return_if_fail (GNUCASH_IS_CURSOR (cursor));
283 
284  sheet = cursor->sheet;
285  item_cursor =
286  GNUCASH_ITEM_CURSOR(cursor->cursor[GNUCASH_CURSOR_BLOCK]);
287 
288  if (vcell_loc.virt_row < 0 ||
289  vcell_loc.virt_row >= sheet->num_virt_rows ||
290  vcell_loc.virt_col < 0 ||
291  vcell_loc.virt_col >= sheet->num_virt_cols)
292  return;
293 
294  cursor->style = gnucash_sheet_get_style (sheet, vcell_loc);
295 
296  item_cursor->row = vcell_loc.virt_row;
297  item_cursor->col = vcell_loc.virt_col;
298 }
299 
300 
301 static void
302 gnucash_cursor_set_cell (GnucashCursor *cursor, gint cell_row, gint cell_col)
303 {
304  GnucashItemCursor *item_cursor;
305  SheetBlockStyle *style;
306 
307  g_return_if_fail (cursor != NULL);
308  g_return_if_fail (GNUCASH_IS_CURSOR (cursor));
309 
310  item_cursor = GNUCASH_ITEM_CURSOR(cursor->cursor[GNUCASH_CURSOR_CELL]);
311  style = cursor->style;
312 
313  if (cell_row < 0 || cell_row >= style->nrows ||
314  cell_col < 0 || cell_col >= style->ncols)
315  return;
316 
317  item_cursor->row = cell_row;
318  item_cursor->col = cell_col;
319 }
320 
321 
322 void
323 gnucash_cursor_set (GnucashCursor *cursor, VirtualLocation virt_loc)
324 {
325  GnucashSheet *sheet;
326 
327  g_return_if_fail (cursor != NULL);
328  g_return_if_fail (GNUCASH_IS_CURSOR (cursor));
329 
330  sheet = cursor->sheet;
331 
332  gnucash_cursor_request_redraw (cursor);
333 
334  gnucash_cursor_set_block (cursor, virt_loc.vcell_loc);
335  gnucash_cursor_set_cell (cursor,
336  virt_loc.phys_row_offset,
337  virt_loc.phys_col_offset);
338 
339  gnucash_cursor_configure (cursor);
340 
341  gnome_canvas_item_set (GNOME_CANVAS_ITEM(sheet->header_item),
342  "cursor_name",
343  cursor->style->cursor->cursor_name,
344  NULL);
345 
346  gnucash_cursor_request_redraw (cursor);
347 }
348 
349 
350 static void
351 gnucash_item_cursor_init (GnucashItemCursor *cursor)
352 {
353  GnomeCanvasItem *item = GNOME_CANVAS_ITEM (cursor);
354 
355  item->x1 = 0;
356  item->y1 = 0;
357  item->x2 = 1;
358  item->y2 = 1;
359 
360  cursor->col = 0;
361  cursor->row = 0;
362 }
363 
364 
365 static void
366 gnucash_cursor_realize (GnomeCanvasItem *item)
367 {
368  GnucashCursor *cursor = GNUCASH_CURSOR (item);
369  GdkWindow *window;
370 
371  if (GNOME_CANVAS_ITEM_CLASS (gnucash_cursor_parent_class)->realize)
372  (*GNOME_CANVAS_ITEM_CLASS
373  (gnucash_cursor_parent_class)->realize)(item);
374 
375  window = GTK_WIDGET (item->canvas)->window;
376 
377  cursor->gc = gdk_gc_new (window);
378 }
379 
380 
381 static void
382 gnucash_cursor_unrealize (GnomeCanvasItem *item)
383 {
384  GnucashCursor *cursor = GNUCASH_CURSOR (item);
385 
386  if (cursor->gc != NULL)
387  {
388  g_object_unref (cursor->gc);
389  cursor->gc = NULL;
390  }
391 
392  if (GNOME_CANVAS_ITEM_CLASS (gnucash_cursor_parent_class)->unrealize)
393  (*GNOME_CANVAS_ITEM_CLASS
394  (gnucash_cursor_parent_class)->unrealize)(item);
395 }
396 
397 
398 static void
399 gnucash_item_cursor_class_init (GnucashItemCursorClass *klass)
400 {
401  GnomeCanvasItemClass *item_class;
402 
403  item_class = GNOME_CANVAS_ITEM_CLASS (klass);
404 
405  gnucash_item_cursor_parent_class = g_type_class_peek_parent (klass);
406 
407  /* GnomeCanvasItem method overrides */
408  item_class->draw = gnucash_item_cursor_draw;
409 }
410 
411 
412 GType
413 gnucash_item_cursor_get_type (void)
414 {
415  static GType gnucash_item_cursor_type = 0;
416 
417  if (!gnucash_item_cursor_type)
418  {
419  static const GTypeInfo gnucash_item_cursor_info =
420  {
421  sizeof (GnucashItemCursorClass),
422  NULL, /* base_init */
423  NULL, /* base_finalize */
424  (GClassInitFunc) gnucash_item_cursor_class_init,
425  NULL, /* class_finalize */
426  NULL, /* class_data */
427  sizeof (GnucashItemCursor),
428  0, /* n_preallocs */
429  (GInstanceInitFunc) gnucash_item_cursor_init
430  };
431 
432  gnucash_item_cursor_type =
433  g_type_register_static (gnome_canvas_item_get_type (),
434  "GnucashItemCursor",
435  &gnucash_item_cursor_info, 0);
436  }
437 
438  return gnucash_item_cursor_type;
439 }
440 
441 
442 static void
443 gnucash_cursor_set_property (GObject *object,
444  guint prop_id,
445  const GValue *value,
446  GParamSpec *pspec)
447 {
448  GnucashCursor *cursor;
449 
450  cursor = GNUCASH_CURSOR (object);
451 
452  switch (prop_id)
453  {
454  case PROP_SHEET:
455  cursor->sheet =
456  GNUCASH_SHEET (g_value_get_object (value));
457  break;
458  case PROP_GRID:
459  cursor->grid =
460  GNUCASH_GRID (g_value_get_object (value));
461  break;
462  default:
463  break;
464  }
465 }
466 
467 
468 /* Note that g_value_set_object() refs the object, as does
469  * g_object_get(). But g_object_get() only unrefs once when it disgorges
470  * the object, leaving an unbalanced ref, which leaks. So instead of
471  * using g_value_set_object(), use g_value_take_object() which doesn't
472  * ref the object when used in get_property().
473  */
474 static void
475 gnucash_cursor_get_property (GObject *object,
476  guint prop_id,
477  GValue *value,
478  GParamSpec *pspec)
479 {
480  GnucashCursor *cursor = GNUCASH_CURSOR (object);
481 
482  switch (prop_id)
483  {
484  case PROP_SHEET:
485  g_value_take_object (value, cursor->sheet);
486  break;
487  case PROP_GRID:
488  g_value_take_object (value, cursor->grid);
489  break;
490  default:
491  break;
492  }
493 }
494 
495 
496 static void
497 gnucash_cursor_init (GnucashCursor *cursor)
498 {
499  GnomeCanvasItem *item = GNOME_CANVAS_ITEM (cursor);
500 
501  item->x1 = 0;
502  item->y1 = 0;
503  item->x2 = 1;
504  item->y2 = 1;
505 }
506 
507 
508 static void
509 gnucash_cursor_class_init (GnucashCursorClass *klass)
510 {
511  GObjectClass *object_class;
512  GnomeCanvasItemClass *item_class;
513 
514  object_class = G_OBJECT_CLASS (klass);
515  item_class = GNOME_CANVAS_ITEM_CLASS (klass);
516 
517  gnucash_cursor_parent_class = g_type_class_peek_parent (klass);
518 
519  /* GObject method overrides */
520  object_class->set_property = gnucash_cursor_set_property;
521  object_class->get_property = gnucash_cursor_get_property;
522 
523  /* GnomeCanvasItem method overrides */
524  item_class->realize = gnucash_cursor_realize;
525  item_class->unrealize = gnucash_cursor_unrealize;
526 
527  /* properties */
528  g_object_class_install_property
529  (object_class,
530  PROP_SHEET,
531  g_param_spec_object ("sheet",
532  "Sheet Value",
533  "Sheet Value",
534  GNUCASH_TYPE_SHEET,
535  G_PARAM_READWRITE));
536  g_object_class_install_property
537  (object_class,
538  PROP_GRID,
539  g_param_spec_object ("grid",
540  "Grid Value",
541  "Grid Value",
542  GNUCASH_TYPE_GRID,
543  G_PARAM_READWRITE));
544 }
545 
546 
547 GType
548 gnucash_cursor_get_type (void)
549 {
550  static GType gnucash_cursor_type = 0;
551 
552  if (!gnucash_cursor_type)
553  {
554  static const GTypeInfo gnucash_cursor_info =
555  {
556  sizeof (GnucashCursorClass),
557  NULL, /* base_init */
558  NULL, /* base_finalize */
559  (GClassInitFunc) gnucash_cursor_class_init,
560  NULL, /* class_finalize */
561  NULL, /* class_data */
562  sizeof (GnucashCursor),
563  0, /* n_preallocs */
564  (GInstanceInitFunc) gnucash_cursor_init
565  };
566 
567  gnucash_cursor_type =
568  g_type_register_static (gnome_canvas_group_get_type (),
569  "GnucashCursor",
570  &gnucash_cursor_info, 0);
571  }
572 
573  return gnucash_cursor_type;
574 }
575 
576 
577 GnomeCanvasItem *
578 gnucash_cursor_new (GnomeCanvasGroup *parent)
579 {
580  GnomeCanvasItem *item;
581  GnomeCanvasItem *cursor_item;
582  GnucashCursor *cursor;
583  GnucashItemCursor *item_cursor;
584 
585  g_return_val_if_fail (parent != NULL, NULL);
586  g_return_val_if_fail (GNOME_IS_CANVAS_GROUP(parent), NULL);
587 
588  item = gnome_canvas_item_new (parent,
589  gnucash_cursor_get_type(),
590  NULL);
591 
592  cursor = GNUCASH_CURSOR(item);
593 
594  cursor_item = gnome_canvas_item_new (GNOME_CANVAS_GROUP(item),
595  gnucash_item_cursor_get_type(),
596  NULL);
597 
598  item_cursor = GNUCASH_ITEM_CURSOR (cursor_item);
599  item_cursor->type = GNUCASH_CURSOR_CELL;
600 
601  cursor->cursor[GNUCASH_CURSOR_CELL] = cursor_item;
602 
603  cursor_item = gnome_canvas_item_new (GNOME_CANVAS_GROUP(item),
604  gnucash_item_cursor_get_type(),
605  NULL);
606 
607  item_cursor = GNUCASH_ITEM_CURSOR (cursor_item);
608  item_cursor->type = GNUCASH_CURSOR_BLOCK;
609 
610  cursor->cursor[GNUCASH_CURSOR_BLOCK] = cursor_item;
611 
612  return item;
613 }
614 
615