2 * position.c: Utility routines for various types of positional
5 * Copyright (C) 2000-2005 Jody Goldberg (jody@gnome.org)
6 * Copyright (C) 2006-2009 Morten Welinder (terra@gnome.org)
8 * This program is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU General Public License as
10 * published by the Free Software Foundation; either version 2 of the
11 * License, or (at your option) any later version.
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software
20 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
23 #include <gnumeric-config.h>
25 #include <libgnumeric.h>
29 #include <sheet-view.h>
36 /* GnmCellPos made a boxed type */
38 gnm_cell_pos_dup (GnmCellPos
*pos
)
40 GnmCellPos
*res
= g_new (GnmCellPos
, 1);
46 gnm_cell_pos_get_type (void)
51 t
= g_boxed_type_register_static ("GnmCellPos",
52 (GBoxedCopyFunc
)gnm_cell_pos_dup
,
53 (GBoxedFreeFunc
)g_free
);
58 /* GnmEvalPos made a boxed type */
60 gnm_eval_pos_dup (GnmEvalPos
*ep
)
62 return g_memdup (ep
, sizeof (*ep
));
66 gnm_eval_pos_get_type (void)
71 t
= g_boxed_type_register_static ("GnmEvalPos",
72 (GBoxedCopyFunc
)gnm_eval_pos_dup
,
73 (GBoxedFreeFunc
)g_free
);
80 * @ep: The position to init.
85 * Returns: (skip) (transfer none): the initialized #GnmEvalPos (@ep).
88 eval_pos_init (GnmEvalPos
*ep
, Sheet
*sheet
, int col
, int row
)
90 g_return_val_if_fail (ep
!= NULL
, NULL
);
91 g_return_val_if_fail (sheet
!= NULL
, NULL
);
97 ep
->array_texpr
= NULL
;
104 * @ep: The position to init.
108 * Returns: (skip) (transfer none): the initialized #GnmEvalPos (@ep).
111 eval_pos_init_pos (GnmEvalPos
*ep
, Sheet
*sheet
, GnmCellPos
const *pos
)
113 g_return_val_if_fail (ep
!= NULL
, NULL
);
114 g_return_val_if_fail (sheet
!= NULL
, NULL
);
115 g_return_val_if_fail (pos
!= NULL
, NULL
);
120 ep
->array_texpr
= NULL
;
127 * @ep: The position to init.
130 * Returns: (skip) (transfer none): the initialized #GnmEvalPos (@ep).
133 eval_pos_init_dep (GnmEvalPos
*ep
, GnmDependent
const *dep
)
135 g_return_val_if_fail (ep
!= NULL
, NULL
);
136 g_return_val_if_fail (dep
!= NULL
, NULL
);
138 ep
->eval
= *dependent_pos (dep
);
139 ep
->sheet
= dep
->sheet
;
140 ep
->dep
= (GnmDependent
*)dep
;
141 ep
->array_texpr
= NULL
;
147 * eval_pos_init_editpos:
148 * @ep: The position to init.
151 * The function initializes an evalpos with the edit position from the
153 * Returns: (skip) (transfer none): the initialized #GnmEvalPos (@ep).
156 eval_pos_init_editpos (GnmEvalPos
*ep
, SheetView
const *sv
)
158 g_return_val_if_fail (ep
!= NULL
, NULL
);
159 g_return_val_if_fail (GNM_IS_SHEET_VIEW (sv
), NULL
);
161 return eval_pos_init (ep
, sv_sheet (sv
),
162 sv
->edit_pos
.col
, sv
->edit_pos
.row
);
166 * eval_pos_init_cell:
167 * @ep: The position to init.
170 * The function initializes an evalpos with the given cell
172 * Returns: (skip) (transfer none): the initialized #GnmEvalPos (@ep).
175 eval_pos_init_cell (GnmEvalPos
*ep
, GnmCell
const *cell
)
177 g_return_val_if_fail (ep
!= NULL
, NULL
);
178 g_return_val_if_fail (cell
!= NULL
, NULL
);
180 ep
->eval
= cell
->pos
;
181 ep
->sheet
= cell
->base
.sheet
;
182 ep
->dep
= (GnmDependent
*)GNM_CELL_TO_DEP (cell
);
183 ep
->array_texpr
= NULL
;
189 * eval_pos_init_sheet:
190 * @ep: The position to init.
193 * The function initializes an evalpos with the given sheet.
195 * Returns: (skip) (transfer none): the initialized #GnmEvalPos (@ep).
198 eval_pos_init_sheet (GnmEvalPos
*ep
, Sheet
const *sheet
)
200 g_return_val_if_fail (ep
!= NULL
, NULL
);
201 g_return_val_if_fail (IS_SHEET (sheet
), NULL
);
203 ep
->eval
.col
= ep
->eval
.row
= 0;
204 ep
->sheet
= (Sheet
*)sheet
;
206 ep
->array_texpr
= NULL
;
212 eval_pos_is_array_context (GnmEvalPos
const *ep
)
214 return ep
->array_texpr
!= NULL
;
219 gnm_parse_pos_dup (GnmParsePos
*pp
)
221 return g_memdup (pp
, sizeof (*pp
));
225 gnm_parse_pos_get_type (void)
230 t
= g_boxed_type_register_static ("GnmParsePos",
231 (GBoxedCopyFunc
)gnm_parse_pos_dup
,
232 (GBoxedFreeFunc
)g_free
);
239 * @pp: The position to init.
240 * @sheet: The sheet being selected
241 * @wb: The workbook being selected.
245 * Use either a sheet (preferred) or a workbook to initialize the supplied
247 * Returns: (skip) (transfer none): the initialized #GnmParsePos (@pp).
250 parse_pos_init (GnmParsePos
*pp
, Workbook
*wb
, Sheet
const *sheet
,
254 if (wb
== NULL
&& sheet
== NULL
)
257 g_return_val_if_fail (pp
!= NULL
, NULL
);
259 pp
->sheet
= (Sheet
*)sheet
;
260 pp
->wb
= sheet
? sheet
->workbook
: wb
;
268 * parse_pos_init_dep:
269 * @pp: The position to init.
270 * @dep: The dependent
272 * Returns: (skip) (transfer none): the initialized #GnmParsePos (@pp).
275 parse_pos_init_dep (GnmParsePos
*pp
, GnmDependent
const *dep
)
277 g_return_val_if_fail (pp
!= NULL
, NULL
);
279 pp
->sheet
= dep
->sheet
;
280 pp
->wb
= dep
->sheet
? dep
->sheet
->workbook
: NULL
;
281 pp
->eval
= *dependent_pos (dep
);
287 * parse_pos_init_cell:
288 * @pp: The position to init.
291 * Returns: (skip) (transfer none): the initialized #GnmParsePos (@pp).
294 parse_pos_init_cell (GnmParsePos
*pp
, GnmCell
const *cell
)
296 g_return_val_if_fail (cell
!= NULL
, NULL
);
297 g_return_val_if_fail (IS_SHEET (cell
->base
.sheet
), NULL
);
298 g_return_val_if_fail (cell
->base
.sheet
->workbook
!= NULL
, NULL
);
300 return parse_pos_init (pp
, NULL
, cell
->base
.sheet
,
301 cell
->pos
.col
, cell
->pos
.row
);
305 * parse_pos_init_evalpos:
306 * @pp: The position to init.
309 * Returns: (skip) (transfer none): the initialized #GnmParsePos (@pp).
312 parse_pos_init_evalpos (GnmParsePos
*pp
, GnmEvalPos
const *ep
)
314 g_return_val_if_fail (ep
!= NULL
, NULL
);
316 return parse_pos_init (pp
, NULL
, ep
->sheet
, ep
->eval
.col
, ep
->eval
.row
);
320 * parse_pos_init_editpos:
321 * @pp: The position to init.
324 * Returns: (skip) (transfer none): the initialized #GnmParsePos (@pp).
327 parse_pos_init_editpos (GnmParsePos
*pp
, SheetView
const *sv
)
329 g_return_val_if_fail (GNM_IS_SHEET_VIEW (sv
), NULL
);
331 return parse_pos_init (pp
, NULL
, sv_sheet (sv
),
332 sv
->edit_pos
.col
, sv
->edit_pos
.row
);
336 * parse_pos_init_sheet:
337 * @pp: The position to init.
340 * Returns: (skip) (transfer none): the initialized #GnmParsePos (@pp).
343 parse_pos_init_sheet (GnmParsePos
*pp
, Sheet
const *sheet
)
345 g_return_val_if_fail (pp
!= NULL
, NULL
);
346 g_return_val_if_fail (IS_SHEET (sheet
), NULL
);
347 return parse_pos_init (pp
, NULL
, sheet
, 0, 0);
350 /********************************************************************************/
354 gnm_cellref_dup (GnmCellRef
*cr
)
356 return g_memdup (cr
, sizeof (*cr
));
360 gnm_cellref_get_type (void)
365 t
= g_boxed_type_register_static ("GnmCellRef",
366 (GBoxedCopyFunc
)gnm_cellref_dup
,
367 (GBoxedFreeFunc
)g_free
);
372 gnm_cellref_init (GnmCellRef
*ref
, Sheet
*sheet
, int col
, int row
, gboolean relative
)
377 ref
->col_relative
= ref
->row_relative
= relative
;
383 gnm_cellref_equal (GnmCellRef
const *a
, GnmCellRef
const *b
)
385 return (a
->col
== b
->col
) &&
386 (a
->col_relative
== b
->col_relative
) &&
387 (a
->row
== b
->row
) &&
388 (a
->row_relative
== b
->row_relative
) &&
389 (a
->sheet
== b
->sheet
);
393 gnm_cellref_hash (GnmCellRef
const *cr
)
396 h
= (h
<< 16) | (h
>> 16);
397 h
^= ((guint
)cr
->col
<< 2);
398 if (cr
->col_relative
) h
^= 1;
399 if (cr
->row_relative
) h
^= 2;
404 gnm_cellref_get_col (GnmCellRef
const *ref
, GnmEvalPos
const *ep
)
406 g_return_val_if_fail (ref
!= NULL
, 0);
407 g_return_val_if_fail (ep
!= NULL
, 0);
409 if (ref
->col_relative
) {
410 Sheet
const *sheet
= eval_sheet (ref
->sheet
, ep
->sheet
);
411 int res
= (ep
->eval
.col
+ ref
->col
) % gnm_sheet_get_max_cols (sheet
);
413 return res
+ gnm_sheet_get_max_cols (sheet
);
420 gnm_cellref_get_row (GnmCellRef
const *ref
, GnmEvalPos
const *ep
)
422 g_return_val_if_fail (ref
!= NULL
, 0);
423 g_return_val_if_fail (ep
!= NULL
, 0);
425 if (ref
->row_relative
) {
426 Sheet
const *sheet
= eval_sheet (ref
->sheet
, ep
->sheet
);
427 int res
= (ep
->eval
.row
+ ref
->row
) % gnm_sheet_get_max_rows (sheet
);
429 return res
+ gnm_sheet_get_max_rows (sheet
);
436 modulo (int i
, int max
)
450 gnm_cellpos_init_cellref_ss (GnmCellPos
*res
, GnmCellRef
const *cell_ref
,
451 GnmCellPos
const *pos
, GnmSheetSize
const *ss
)
453 g_return_if_fail (cell_ref
!= NULL
);
454 g_return_if_fail (res
!= NULL
);
456 if (cell_ref
->col_relative
) {
457 int col
= cell_ref
->col
+ pos
->col
;
458 res
->col
= modulo (col
, ss
->max_cols
);
460 res
->col
= cell_ref
->col
;
462 if (cell_ref
->row_relative
) {
463 int row
= cell_ref
->row
+ pos
->row
;
464 res
->row
= modulo (row
, ss
->max_rows
);
466 res
->row
= cell_ref
->row
;
470 gnm_cellpos_init_cellref (GnmCellPos
*res
, GnmCellRef
const *cell_ref
,
471 GnmCellPos
const *pos
, Sheet
const *base_sheet
)
473 Sheet
const *sheet
= eval_sheet (cell_ref
->sheet
, base_sheet
);
474 gnm_cellpos_init_cellref_ss (res
, cell_ref
, pos
,
475 gnm_sheet_get_size (sheet
));
479 gnm_cellref_make_abs (GnmCellRef
*dest
, GnmCellRef
const *src
, GnmEvalPos
const *ep
)
483 g_return_if_fail (dest
!= NULL
);
484 g_return_if_fail (src
!= NULL
);
485 g_return_if_fail (ep
!= NULL
);
487 gnm_cellpos_init_cellref (&pos
, src
, &ep
->eval
, ep
->sheet
);
489 dest
->sheet
= src
->sheet
;
492 dest
->col_relative
= FALSE
;
493 dest
->row_relative
= FALSE
;
497 gnm_cellref_set_col_ar (GnmCellRef
*cr
, GnmParsePos
const *pp
, gboolean abs_rel
)
499 if (cr
->col_relative
^ abs_rel
) {
500 if (cr
->col_relative
)
501 cr
->col
+= pp
->eval
.col
;
503 cr
->col
-= pp
->eval
.col
;
504 cr
->col_relative
= abs_rel
;
509 gnm_cellref_set_row_ar (GnmCellRef
*cr
, GnmParsePos
const *pp
, gboolean abs_rel
)
511 if (cr
->row_relative
^ abs_rel
) {
512 if (cr
->row_relative
)
513 cr
->row
+= pp
->eval
.row
;
515 cr
->row
-= pp
->eval
.row
;
516 cr
->row_relative
= abs_rel
;
521 gnm_rangeref_equal (GnmRangeRef
const *a
, GnmRangeRef
const *b
)
523 return gnm_cellref_equal (&a
->a
, &b
->a
) &&
524 gnm_cellref_equal (&a
->b
, &b
->b
);
528 gnm_rangeref_hash (GnmRangeRef
const *rr
)
530 guint h
= gnm_cellref_hash (&rr
->a
);
531 h
= (h
<< 16) | (h
>> 16);
532 h
^= gnm_cellref_hash (&rr
->b
);
537 gnm_rangeref_dup (GnmRangeRef
const *rr
)
541 g_return_val_if_fail (rr
!= NULL
, NULL
);
543 res
= g_new (GnmRangeRef
, 1);
549 gnm_rangeref_get_type (void)
554 t
= g_boxed_type_register_static ("GnmRangeRef",
555 (GBoxedCopyFunc
)gnm_rangeref_dup
,
556 (GBoxedFreeFunc
)g_free
);
562 gnm_rangeref_normalize_pp (GnmRangeRef
const *ref
, GnmParsePos
const *pp
,
563 Sheet
**start_sheet
, Sheet
**end_sheet
,
566 GnmSheetSize
const *ss
;
568 g_return_if_fail (ref
!= NULL
);
569 g_return_if_fail (pp
!= NULL
);
571 *start_sheet
= eval_sheet (ref
->a
.sheet
, pp
->sheet
);
572 *end_sheet
= eval_sheet (ref
->b
.sheet
, *start_sheet
);
574 ss
= gnm_sheet_get_size2 (*start_sheet
, pp
->wb
);
575 gnm_cellpos_init_cellref_ss (&dest
->start
, &ref
->a
, &pp
->eval
, ss
);
578 ? gnm_sheet_get_size (*end_sheet
)
580 gnm_cellpos_init_cellref_ss (&dest
->end
, &ref
->b
, &pp
->eval
, ss
);
582 range_normalize (dest
);
586 * gnm_rangeref_normalize:
588 * Take a range_ref and normalize it by converting to absolute coords and
589 * handling inversions.
592 gnm_rangeref_normalize (GnmRangeRef
const *ref
, GnmEvalPos
const *ep
,
593 Sheet
**start_sheet
, Sheet
**end_sheet
, GnmRange
*dest
)
597 parse_pos_init_evalpos (&pp
, ep
);
598 gnm_rangeref_normalize_pp (ref
, &pp
, start_sheet
, end_sheet
, dest
);
602 gnm_cellpos_hash (GnmCellPos
const *key
)
605 h
= (h
<< 16) | (h
>> 16);
611 gnm_cellpos_equal (GnmCellPos
const *a
, GnmCellPos
const *b
)
613 return (a
->row
== b
->row
&& a
->col
== b
->col
);