void row_calc_spans (ColRowInfo *ri, int row, Sheet const *sheet) { int left, right, col; GnmRange const *merged; GnmCell *cell; int const last = sheet->cols.max_used; row_destroy_span (ri); for (col = 0 ; col <= last ; ) { cell = sheet_cell_get (sheet, col, row); if (cell == NULL) { /* skip segments with no cells */ if (col == COLROW_SEGMENT_START (col) && NULL == COLROW_GET_SEGMENT (&(sheet->cols), col)) col = COLROW_SEGMENT_END (col) + 1; else col++; continue; } /* render as necessary */ (void)gnm_cell_fetch_rendered_value (cell, TRUE); if (gnm_cell_is_merged (cell)) { merged = gnm_sheet_merge_is_corner (sheet, &cell->pos); if (NULL != merged) { col = merged->end.col + 1; continue; } } cell_calc_span (cell, &left, &right); if (left != right) { cell_register_span (cell, left, right); col = right + 1; } else col++; } ri->needs_respan = FALSE; }
/* NOTE : Make sure to set up any merged regions in the target range BEFORE * this is called. */ static void paste_link (GnmPasteTarget const *pt, int top, int left, GnmCellRegion const *cr) { GnmCellPos pos; GnmCellRef source_cell_ref; int x, y; /* Not possible to link to arbitrary (non gnumeric) sources yet. */ /* TODO : eventually support interprocess gnumeric links */ if (cr->origin_sheet == NULL) return; /* TODO : support relative links ? */ source_cell_ref.col_relative = 0; source_cell_ref.row_relative = 0; source_cell_ref.sheet = (cr->origin_sheet != pt->sheet) ? cr->origin_sheet : NULL; pos.col = left; for (x = 0 ; x < cr->cols ; x++, pos.col++) { source_cell_ref.col = cr->base.col + x; pos.row = top; for (y = 0 ; y < cr->rows ; y++, pos.row++) { GnmExprTop const *texpr; GnmCell *cell = sheet_cell_fetch (pt->sheet, pos.col, pos.row); /* This could easily be made smarter */ if (!gnm_cell_is_merged (cell) && gnm_sheet_merge_contains_pos (pt->sheet, &pos)) continue; source_cell_ref.row = cr->base.row + y; texpr = gnm_expr_top_new (gnm_expr_new_cellref (&source_cell_ref)); gnm_cell_set_expr (cell, texpr); gnm_expr_top_unref (texpr); } } }
/* * cell_calc_span: * @cell: The cell we will examine * @col1: return value: the first column used by this cell * @col2: return value: the last column used by this cell * * This routine returns the column interval used by a GnmCell. */ void cell_calc_span (GnmCell const *cell, int *col1, int *col2) { Sheet *sheet; int h_align, v_align, left, max_col, min_col; int row, pos; int cell_width_pixel, indented_w; GnmStyle const *style; ColRowInfo const *ci; GnmRange const *merge_left; GnmRange const *merge_right; g_return_if_fail (cell != NULL); sheet = cell->base.sheet; style = gnm_cell_get_style (cell); h_align = gnm_style_default_halign (style, cell); /* * Report only one column is used if * - Cell is in a hidden col * - Cell is a number * - Cell is the top left of a merged cell * - The text fits inside column (for non center across selection) * - The alignment mode are set to "justify" */ if (sheet != NULL && h_align != HALIGN_CENTER_ACROSS_SELECTION && (gnm_cell_is_merged (cell) || (!sheet->display_formulas && gnm_cell_is_number (cell)))) { *col1 = *col2 = cell->pos.col; return; } v_align = gnm_style_get_align_v (style); row = cell->pos.row; indented_w = cell_width_pixel = gnm_cell_rendered_width (cell); if (h_align == HALIGN_LEFT || h_align == HALIGN_RIGHT) { indented_w += gnm_cell_rendered_offset (cell); if (sheet->text_is_rtl) h_align = (h_align == HALIGN_LEFT) ? HALIGN_RIGHT : HALIGN_LEFT; } ci = sheet_col_get_info (sheet, cell->pos.col); if (gnm_cell_is_empty (cell) || !ci->visible || (h_align != HALIGN_CENTER_ACROSS_SELECTION && (gnm_style_get_wrap_text (style) || indented_w <= COL_INTERNAL_WIDTH (ci))) || h_align == HALIGN_JUSTIFY || h_align == HALIGN_FILL || h_align == HALIGN_DISTRIBUTED || v_align == VALIGN_JUSTIFY || v_align == VALIGN_DISTRIBUTED) { *col1 = *col2 = cell->pos.col; return; } gnm_sheet_merge_get_adjacent (sheet, &cell->pos, &merge_left, &merge_right); min_col = (merge_left != NULL) ? merge_left->end.col : -1; max_col = (merge_right != NULL) ? merge_right->start.col : gnm_sheet_get_max_cols (sheet); *col1 = *col2 = cell->pos.col; switch (h_align) { case HALIGN_LEFT: pos = cell->pos.col + 1; left = indented_w - COL_INTERNAL_WIDTH (ci); for (; left > 0 && pos < max_col; pos++){ ColRowInfo const *ci = sheet_col_get_info (sheet, pos); if (ci->visible) { if (!cellspan_is_empty (pos, cell)) return; /* The space consumed is: * - The margin_b from the last column * - The width of the cell */ left -= ci->size_pixels - 1; *col2 = pos; } } return; case HALIGN_RIGHT: pos = cell->pos.col - 1; left = indented_w - COL_INTERNAL_WIDTH (ci); for (; left > 0 && pos > min_col; pos--){ ColRowInfo const *ci = sheet_col_get_info (sheet, pos); if (ci->visible) { if (!cellspan_is_empty (pos, cell)) return; /* The space consumed is: * - The margin_a from the last column * - The width of this cell */ left -= ci->size_pixels - 1; *col1 = pos; } } return; case HALIGN_CENTER: { int remain_left, remain_right; int pos_l, pos_r; pos_l = pos_r = cell->pos.col; left = cell_width_pixel - COL_INTERNAL_WIDTH (ci); remain_left = left / 2 + (left % 2); remain_right = left / 2; for (; remain_left > 0 || remain_right > 0;){ ColRowInfo const *ci; if (--pos_l > min_col){ ci = sheet_col_get_info (sheet, pos_l); if (ci->visible) { if (cellspan_is_empty (pos_l, cell)) { remain_left -= ci->size_pixels - 1; *col1 = pos_l; } else remain_left = 0; } } else remain_left = 0; if (++pos_r < max_col){ ci = sheet_col_get_info (sheet, pos_r); if (ci->visible) { if (cellspan_is_empty (pos_r, cell)) { remain_right -= ci->size_pixels - 1; *col2 = pos_r; } else max_col = remain_right = 0; } } else remain_right = 0; } /* for */ break; } /* case HALIGN_CENTER */ case HALIGN_CENTER_ACROSS_SELECTION: { int const row = cell->pos.row; int pos_l, pos_r; pos_l = pos_r = cell->pos.col; while (--pos_l > min_col) { ColRowInfo const *ci = sheet_col_get_info (sheet, pos_l); if (ci->visible) { if (cellspan_is_empty (pos_l, cell)) { GnmStyle const * const style = sheet_style_get (cell->base.sheet, pos_l, row); if (gnm_style_get_align_h (style) != HALIGN_CENTER_ACROSS_SELECTION) break; *col1 = pos_l; } else break; } } while (++pos_r < max_col) { ColRowInfo const *ci = sheet_col_get_info (sheet, pos_r); if (ci->visible) { if (cellspan_is_empty (pos_r, cell)) { GnmStyle const * const style = sheet_style_get (cell->base.sheet, pos_r, row); if (gnm_style_get_align_h (style) != HALIGN_CENTER_ACROSS_SELECTION) break; *col2 = pos_r; } else break; } } break; } default: g_warning ("Unknown horizontal alignment type %x.", h_align); } /* switch */ }