From a57d6d8ccf7783813775be632de589942613cc2d Mon Sep 17 00:00:00 2001 From: Jean Brefort Date: Mon, 30 Mar 2015 17:00:54 +0200 Subject: [PATCH] Make graphs (and images) not resize with cells by default. [#684450] --- ChangeLog | 17 +++ NEWS | 2 + plugins/excel/ChangeLog | 15 ++ plugins/excel/ms-chart.c | 2 +- plugins/excel/ms-escher.c | 10 ++ plugins/excel/ms-excel-read.c | 20 ++- plugins/excel/ms-excel-write.c | 12 +- plugins/excel/xlsx-read-drawing.c | 83 +++++++++-- plugins/excel/xlsx-read.c | 1 + plugins/excel/xlsx-write-drawing.c | 40 +++++- plugins/openoffice/ChangeLog | 7 + plugins/openoffice/openoffice-read.c | 118 ++++++++++------ plugins/openoffice/openoffice-write.c | 93 ++++++++---- src/dialogs/ChangeLog | 7 + src/dialogs/dialog-sheetobject-size.c | 57 +++++++- src/graph.h | 1 + src/item-grid.c | 2 +- src/sheet-control-gui.c | 96 +++++++++---- src/sheet-filter.c | 2 +- src/sheet-object-cell-comment.c | 2 +- src/sheet-object-component.c | 21 +-- src/sheet-object-graph.c | 11 +- src/sheet-object-image.c | 1 + src/sheet-object.c | 234 +++++++++++++++++++++++++------ src/sheet-object.h | 13 +- src/tools/ChangeLog | 6 + src/tools/dao.c | 3 +- src/widgets/ChangeLog | 5 + src/widgets/Makefile.am | 2 + src/widgets/gnm-so-anchor-mode-chooser.c | 97 +++++++++++++ src/widgets/gnm-so-anchor-mode-chooser.h | 42 ++++++ src/workbook-view.c | 2 +- src/xml-sax-read.c | 17 ++- src/xml-sax-write.c | 7 +- 34 files changed, 848 insertions(+), 200 deletions(-) create mode 100644 src/widgets/gnm-so-anchor-mode-chooser.c create mode 100644 src/widgets/gnm-so-anchor-mode-chooser.h diff --git a/ChangeLog b/ChangeLog index 9fce848bb..232941d74 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,20 @@ +2015-03-30 Jean Brefort + + * src/graph.h: add support for absolute anchoring of sheet objects. + * src/item-grid.c: ditto. + * src/sheet-control-gui.c: ditto. + * src/sheet-filter.c: ditto. + * src/sheet-object-cell-comment.c: ditto. + * src/sheet-object-component.c: ditto. + * src/sheet-object-graph.c: ditto and make graphs not anymore resize with + cells by default. [#684450] + * src/sheet-object-image.c: make images don't resize with cells by default. + * src/sheet-object.c : add support for absolute anchoring of sheet objects. + * src/sheet-object.h: ditto. + * src/workbook-view.c: ditto. + * src/xml-sax-read.c: ditto. + * src/xml-sax-write.c: ditto. + 2015-03-30 Morten Welinder * src/xml-sax-read.c (grammar): Use new libgsf check for "2nd". diff --git a/NEWS b/NEWS index 95c1ea899..a89be5e91 100644 --- a/NEWS +++ b/NEWS @@ -6,6 +6,8 @@ Andreas: Jean: * Fix signal handling while running Python. [#744638] + * Implement absolute anchoring for sheet objects. + * Make graphs (and images) not resize with cells by default. [#684450] Morten: * xlsx import/export of log axis. diff --git a/plugins/excel/ChangeLog b/plugins/excel/ChangeLog index c9280dac5..37988431c 100644 --- a/plugins/excel/ChangeLog +++ b/plugins/excel/ChangeLog @@ -1,3 +1,18 @@ +2015-03-30 Jean Brefort + + * ms-chart.c (ms_excel_chart_read): support absolute sheet object anchoring. + * ms-escher.c (ms_escher_clientanchor): ditto. + * ms-excel-read.c (ms_sheet_obj_anchor_to_pos), + (ms_sheet_realize_obj): ditto. + * ms-excel-write.c (excel_write_autofilter_objs), + (excel_write_other_v8): ditto. + * xlsx-read-drawing.c (xlsx_draw_anchor_start), + (xlsx_drawing_twoCellAnchor_end), (xlsx_drawing_oneCellAnchor_end), + (xlsx_drawing_absoluteAnchor_end), (xlsx_drawing_anchor_pos), + (xlsx_vml_client_data_end): ditto. + * xlsx-read.c: ditto. + * xlsx-write-drawing.c (xlsx_write_drawing_objects): ditto. + 2015-03-28 Morten Welinder * xlsx-read-drawing.c (xlsx_axis_crossax): Improve parsing. Take diff --git a/plugins/excel/ms-chart.c b/plugins/excel/ms-chart.c index 31dab39bc..e90d9e5c2 100644 --- a/plugins/excel/ms-chart.c +++ b/plugins/excel/ms-chart.c @@ -3825,7 +3825,7 @@ ms_excel_chart_read (BiffQuery *q, MSContainer *container, static GnmRange const fixed_size = { { 1, 1 }, { 12, 32 } }; SheetObjectAnchor anchor; sheet_object_anchor_init (&anchor, &fixed_size, NULL, - GOD_ANCHOR_DIR_DOWN_RIGHT); + GOD_ANCHOR_DIR_DOWN_RIGHT, GNM_SO_ANCHOR_TWO_CELLS); sheet_object_set_anchor (sog, &anchor); sheet_object_set_sheet (sog, full_page); g_object_unref (sog); diff --git a/plugins/excel/ms-escher.c b/plugins/excel/ms-escher.c index 379b092d5..a265dcafd 100644 --- a/plugins/excel/ms-escher.c +++ b/plugins/excel/ms-escher.c @@ -2373,6 +2373,16 @@ ms_escher_clientanchor (GString *buf, SheetObjectAnchor const *anchor) guint8 *p = tmp + 10; GSF_LE_SET_GUINT32 (tmp + 4, sizeof (tmp) - 8); + switch (anchor->mode) { + case GNM_SO_ANCHOR_ONE_CELL: + tmp[8] = 2; + break; + case GNM_SO_ANCHOR_ABSOLUTE: + tmp[8] = 3; + break; + default: + break; + } GSF_LE_SET_GUINT16 (p + 0, anchor->cell_bound.start.col); GSF_LE_SET_GUINT16 (p + 2, (guint16)(anchor->offset[0]*1024. + .5)); GSF_LE_SET_GUINT16 (p + 4, anchor->cell_bound.start.row); diff --git a/plugins/excel/ms-excel-read.c b/plugins/excel/ms-excel-read.c index 4b5432304..b547de2bb 100644 --- a/plugins/excel/ms-excel-read.c +++ b/plugins/excel/ms-excel-read.c @@ -391,7 +391,7 @@ static gboolean ms_sheet_obj_anchor_to_pos (Sheet const * sheet, G_GNUC_UNUSED MsBiffVersion const ver, guint8 const *raw_anchor, - GnmRange *range, double offset[4]) + GnmRange *range, double offset[4], GnmSOAnchorMode *mode) { /* NOTE : * gnm_float const row_denominator = (ver >= MS_BIFF_V8) ? 256. : 1024.; @@ -407,6 +407,17 @@ ms_sheet_obj_anchor_to_pos (Sheet const * sheet, gsf_mem_dump (raw_anchor, 18); }); + switch (raw_anchor[0]) { + case 2: + *mode = GNM_SO_ANCHOR_ONE_CELL; + break; + case 3: + *mode = GNM_SO_ANCHOR_ABSOLUTE; + break; + default: + *mode = GNM_SO_ANCHOR_TWO_CELLS; + break; + } /* Ignore the first 2 bytes. What are they ? */ /* Dec/1/2000 JEG: I have not researched it, but this may have some * flags indicating whether or not the object is anchored to the cell @@ -494,6 +505,7 @@ ms_sheet_realize_obj (MSContainer *container, MSObj *obj) SheetObjectAnchor anchor; SheetObject *so; GOStyle *style; + GnmSOAnchorMode mode = GNM_SO_ANCHOR_TWO_CELLS; if (obj == NULL) return TRUE; @@ -518,7 +530,7 @@ ms_sheet_realize_obj (MSContainer *container, MSObj *obj) } if (ms_sheet_obj_anchor_to_pos (esheet->sheet, container->importer->ver, - attr->v.v_ptr, &range, offsets)) + attr->v.v_ptr, &range, offsets, &mode)) return TRUE; flip_h = ms_obj_attr_bag_lookup (obj->attrs, MS_OBJ_ATTR_FLIP_H); @@ -527,10 +539,12 @@ ms_sheet_realize_obj (MSContainer *container, MSObj *obj) ((flip_h == NULL) ? GOD_ANCHOR_DIR_RIGHT : 0) | ((flip_v == NULL) ? GOD_ANCHOR_DIR_DOWN : 0); - sheet_object_anchor_init (&anchor, &range, offsets, direction); + sheet_object_anchor_init (&anchor, &range, offsets, direction, GNM_SO_ANCHOR_TWO_CELLS); sheet_object_set_anchor (so, &anchor); } sheet_object_set_sheet (so, esheet->sheet); + if (mode != GNM_SO_ANCHOR_TWO_CELLS) + sheet_object_set_anchor_mode (so, &mode); { gpointer label; diff --git a/plugins/excel/ms-excel-write.c b/plugins/excel/ms-excel-write.c index 7daf59b73..cc2ab5ccc 100644 --- a/plugins/excel/ms-excel-write.c +++ b/plugins/excel/ms-excel-write.c @@ -4251,7 +4251,7 @@ excel_write_autofilter_objs (ExcelWriteSheet *esheet) r.end.col = 1 + (r.start.col = filter->r.start.col + i); sheet_object_anchor_init (&anchor, &r, NULL, - GOD_ANCHOR_DIR_DOWN_RIGHT); + GOD_ANCHOR_DIR_DOWN_RIGHT, GNM_SO_ANCHOR_TWO_CELLS); if (bp->version >= MS_BIFF_V8) { guint32 id = excel_write_start_drawing (esheet); memcpy (buf, obj_v8, sizeof obj_v8); @@ -4615,6 +4615,14 @@ excel_write_other_v8 (ExcelWriteSheet *esheet, ? g_hash_table_lookup (esheet->widget_macroname, so) : NULL; + if (anchor.mode != GNM_SO_ANCHOR_TWO_CELLS) { + double pts[4]; + GnmSOAnchorMode mode = anchor.mode; + sheet_object_anchor_to_pts (&anchor, esheet->gnum_sheet, pts); + anchor.mode = GNM_SO_ANCHOR_TWO_CELLS; + sheet_object_pts_to_anchor (&anchor, esheet->gnum_sheet, pts); + anchor.mode = mode; /* this anchor is not valid for gnumeric but is what we need there */ + } if (GNM_IS_CELL_COMMENT (so)) { static double const offset[4] = { .5, .5, .5, .5 }; GnmRange r; @@ -4625,7 +4633,7 @@ excel_write_other_v8 (ExcelWriteSheet *esheet, r.end.col = r.start.col + 2; r.end.row = r.start.row + 4; sheet_object_anchor_init (&anchor, &r, offset, - GOD_ANCHOR_DIR_DOWN_RIGHT); + GOD_ANCHOR_DIR_DOWN_RIGHT, GNM_SO_ANCHOR_TWO_CELLS); type = MSOT_COMMENT; flags = 0x4011; /* not autofilled */ do_textbox = TRUE; diff --git a/plugins/excel/xlsx-read-drawing.c b/plugins/excel/xlsx-read-drawing.c index 887ab8e1b..d557e7e9d 100644 --- a/plugins/excel/xlsx-read-drawing.c +++ b/plugins/excel/xlsx-read-drawing.c @@ -3116,6 +3116,7 @@ xlsx_draw_anchor_start (GsfXMLIn *xin, G_GNUC_UNUSED xmlChar const **attrs) memset ((gpointer)state->drawing_pos, 0, sizeof (state->drawing_pos)); state->drawing_pos_flags = 0; state->so_direction = GOD_ANCHOR_DIR_DOWN_RIGHT; + state->so_anchor_mode = GNM_SO_ANCHOR_TWO_CELLS; } static void @@ -3135,7 +3136,7 @@ xlsx_drawing_twoCellAnchor_end (GsfXMLIn *xin, G_GNUC_UNUSED GsfXMLBlob *blob) GnmRange r; double coords[4]; double size; - int i; + int i, max; range_init (&r, state->drawing_pos[COL | FROM], @@ -3143,19 +3144,34 @@ xlsx_drawing_twoCellAnchor_end (GsfXMLIn *xin, G_GNUC_UNUSED GsfXMLBlob *blob) state->drawing_pos[COL | TO], state->drawing_pos[ROW | TO]); + switch (state->so_anchor_mode) { + default: + case GNM_SO_ANCHOR_TWO_CELLS: + max = 8; + break; + case GNM_SO_ANCHOR_ONE_CELL: + max = 4; + break; + case GNM_SO_ANCHOR_ABSOLUTE: + max = 0; + break; + } for (i = 0; i < 8; i+=2) { ColRowInfo const *cri; - if (i & 2) { - cri = sheet_row_get (state->sheet, state->drawing_pos[i]); - size = cri? cri->size_pts: sheet_row_get_default_size_pts (state->sheet); - } else { - cri = sheet_col_get (state->sheet, state->drawing_pos[i]); - /* FIXME: scaling horizontally just like in xlsx_CT_Col */ - size = (cri? cri->size_pts: sheet_col_get_default_size_pts (state->sheet)) * 1.16191275167785; - } - coords[i / 2] = (double) state->drawing_pos[i + 1] / 12700. / size; + if (i < max) { + if (i & 2) { + cri = sheet_row_get (state->sheet, state->drawing_pos[i]); + size = cri? cri->size_pts: sheet_row_get_default_size_pts (state->sheet); + } else { + cri = sheet_col_get (state->sheet, state->drawing_pos[i]); + /* FIXME: scaling horizontally just like in xlsx_CT_Col */ + size = (cri? cri->size_pts: sheet_col_get_default_size_pts (state->sheet)) * 1.16191275167785; + } + coords[i / 2] = (double) state->drawing_pos[i + 1] / 12700. / size; + } else + coords[i / 2] = (double) state->drawing_pos[i + 1] / 12700.; } - sheet_object_anchor_init (&anchor, &r, coords, state->so_direction); + sheet_object_anchor_init (&anchor, &r, coords, state->so_direction, state->so_anchor_mode); sheet_object_set_anchor (state->so, &anchor); if (state->cur_style && g_object_class_find_property (G_OBJECT_GET_CLASS (state->so), "style")) @@ -3177,13 +3193,36 @@ xlsx_drawing_oneCellAnchor_end (GsfXMLIn *xin, GsfXMLBlob *blob) { XLSXReadState *state = (XLSXReadState *)xin->user_state; - state->drawing_pos[COL | TO] = state->drawing_pos[COL | FROM] + 5; - state->drawing_pos[ROW | TO] = state->drawing_pos[ROW | FROM] + 5; + state->drawing_pos[COL | TO] = state->drawing_pos[COL | FROM]; + state->drawing_pos[ROW | TO] = state->drawing_pos[ROW | FROM]; state->drawing_pos_flags |= ((1 << (COL | TO)) | (1 << (ROW | TO))); + state->so_anchor_mode = GNM_SO_ANCHOR_ONE_CELL; + xlsx_drawing_twoCellAnchor_end (xin, blob); +} + +static void +xlsx_drawing_absoluteAnchor_end (GsfXMLIn *xin, GsfXMLBlob *blob) +{ + XLSXReadState *state = (XLSXReadState *)xin->user_state; + + state->drawing_pos_flags |= ((1 << (COL | TO)) | (1 << (ROW | TO)) | + (1 << (COL | FROM)) | (1 << (ROW | FROM))); + state->so_anchor_mode = GNM_SO_ANCHOR_ABSOLUTE; xlsx_drawing_twoCellAnchor_end (xin, blob); } static void +xlsx_drawing_anchor_pos (GsfXMLIn *xin, xmlChar const **attrs) +{ + XLSXReadState *state = (XLSXReadState *)xin->user_state; + for (; attrs != NULL && attrs[0] && attrs[1] ; attrs += 2) + if (attr_int64 (xin, attrs, "x", state->drawing_pos + (COL | FROM | OFFSET))) + state->drawing_pos_flags |= (1 << (COL | FROM | OFFSET)); + else if (attr_int64 (xin, attrs, "y", state->drawing_pos + (ROW | FROM | OFFSET))) + state->drawing_pos_flags |= (1 << (ROW | FROM | OFFSET)); +} + +static void xlsx_drawing_ext (GsfXMLIn *xin, xmlChar const **attrs) { XLSXReadState *state = (XLSXReadState *)xin->user_state; @@ -3500,6 +3539,22 @@ GSF_XML_IN_NODE_FULL (START, DRAWING, XL_NS_SS_DRAW, "wsDr", GSF_XML_NO_CONTENT, GSF_XML_IN_NODE (ONE_CELL, ONE_CELL_EXT, XL_NS_SS_DRAW, "ext", GSF_XML_NO_CONTENT, &xlsx_drawing_ext, NULL), GSF_XML_IN_NODE (ONE_CELL, CLIENT_DATA, XL_NS_SS_DRAW, "clientData", GSF_XML_NO_CONTENT, NULL, NULL), /* 2nd Def */ GSF_XML_IN_NODE (ONE_CELL, GRAPHIC_FRAME, XL_NS_SS_DRAW, "graphicFrame", GSF_XML_NO_CONTENT, NULL, NULL), /* 2nd Def */ + GSF_XML_IN_NODE (ONE_CELL, SHAPE, XL_NS_SS_DRAW, "sp", GSF_XML_NO_CONTENT, NULL, NULL), /* 2nd Def */ + GSF_XML_IN_NODE (ONE_CELL, CLIENT_DATA, XL_NS_SS_DRAW, "clientData", GSF_XML_NO_CONTENT, NULL, NULL), /* 2nd Def */ + GSF_XML_IN_NODE (ONE_CELL, CONTENT_PART, XL_NS_SS_DRAW, "contentPart", GSF_XML_NO_CONTENT, NULL, NULL), /* 2nd Def */ + GSF_XML_IN_NODE (ONE_CELL, CXN_SP, XL_NS_SS_DRAW, "cxnSp", GSF_XML_NO_CONTENT, NULL, NULL), /* 2nd Def */ + GSF_XML_IN_NODE (ONE_CELL, PICTURE, XL_NS_SS_DRAW, "pic", GSF_XML_NO_CONTENT, NULL, NULL), /* 2nd Def */ + GSF_XML_IN_NODE (DRAWING, ABSOLUTE, XL_NS_SS_DRAW, "absoluteAnchor", GSF_XML_NO_CONTENT, + &xlsx_draw_anchor_start, &xlsx_drawing_absoluteAnchor_end), + GSF_XML_IN_NODE (ABSOLUTE, ABSOLUTE_POS, XL_NS_SS_DRAW, "pos", GSF_XML_NO_CONTENT, &xlsx_drawing_anchor_pos, NULL), + GSF_XML_IN_NODE (ABSOLUTE, ONE_CELL_EXT, XL_NS_SS_DRAW, "ext", GSF_XML_NO_CONTENT, NULL, NULL), /* 2nd Def */ + GSF_XML_IN_NODE (ABSOLUTE, CLIENT_DATA, XL_NS_SS_DRAW, "clientData", GSF_XML_NO_CONTENT, NULL, NULL), /* 2nd Def */ + GSF_XML_IN_NODE (ABSOLUTE, GRAPHIC_FRAME, XL_NS_SS_DRAW, "graphicFrame", GSF_XML_NO_CONTENT, NULL, NULL), /* 2nd Def */ + GSF_XML_IN_NODE (ABSOLUTE, SHAPE, XL_NS_SS_DRAW, "sp", GSF_XML_NO_CONTENT, NULL, NULL), /* 2nd Def */ + GSF_XML_IN_NODE (ABSOLUTE, CLIENT_DATA, XL_NS_SS_DRAW, "clientData", GSF_XML_NO_CONTENT, NULL, NULL), /* 2nd Def */ + GSF_XML_IN_NODE (ABSOLUTE, CONTENT_PART, XL_NS_SS_DRAW, "contentPart", GSF_XML_NO_CONTENT, NULL, NULL), /* 2nd Def */ + GSF_XML_IN_NODE (ABSOLUTE, CXN_SP, XL_NS_SS_DRAW, "cxnSp", GSF_XML_NO_CONTENT, NULL, NULL), /* 2nd Def */ + GSF_XML_IN_NODE (ABSOLUTE, PICTURE, XL_NS_SS_DRAW, "pic", GSF_XML_NO_CONTENT, NULL, NULL), /* 2nd Def */ GSF_XML_IN_NODE_END }; @@ -3796,7 +3851,7 @@ xlsx_vml_client_data_end (GsfXMLIn *xin, G_GNUC_UNUSED GsfXMLBlob *blob) } r.end.row = pos; coords[3] = (state->chart_pos[3] - sum) / size; - sheet_object_anchor_init (&anchor, &r, coords, state->so_direction); + sheet_object_anchor_init (&anchor, &r, coords, state->so_direction, state->so_anchor_mode); sheet_object_set_anchor (state->so, &anchor); if (GNM_IS_SOW_LIST (state->so) || GNM_IS_SOW_COMBO (state->so)) diff --git a/plugins/excel/xlsx-read.c b/plugins/excel/xlsx-read.c index 33708e406..61ef640c1 100644 --- a/plugins/excel/xlsx-read.c +++ b/plugins/excel/xlsx-read.c @@ -196,6 +196,7 @@ typedef struct { gint64 drawing_pos[8]; int drawing_pos_flags; GODrawingAnchorDir so_direction; + GnmSOAnchorMode so_anchor_mode; GnmExprTop const *link_texpr; /* Legacy drawing state */ diff --git a/plugins/excel/xlsx-write-drawing.c b/plugins/excel/xlsx-write-drawing.c index da6bd6dd5..e64ab84d2 100644 --- a/plugins/excel/xlsx-write-drawing.c +++ b/plugins/excel/xlsx-write-drawing.c @@ -1359,11 +1359,41 @@ xlsx_write_drawing_objects (XLSXWriteState *state, GsfOutput *sheet_part, sheet_object_anchor_to_offset_pts (anchor, state->sheet, res_pts); - gsf_xml_out_start_element (xml, "xdr:twoCellAnchor"); - xlsx_write_object_anchor (xml, &anchor->cell_bound.start, "xdr:from", - res_pts[0], res_pts[1]); - xlsx_write_object_anchor (xml, &anchor->cell_bound.end, "xdr:to", - res_pts[2], res_pts[3]); + switch (anchor->mode) { + case GNM_SO_ANCHOR_TWO_CELLS: + gsf_xml_out_start_element (xml, "xdr:twoCellAnchor"); + xlsx_write_object_anchor (xml, &anchor->cell_bound.start, "xdr:from", + res_pts[0], res_pts[1]); + xlsx_write_object_anchor (xml, &anchor->cell_bound.end, "xdr:to", + res_pts[2], res_pts[3]); + break; + case GNM_SO_ANCHOR_ONE_CELL: + gsf_xml_out_start_element (xml, "xdr:oneCellAnchor"); + xlsx_write_object_anchor (xml, &anchor->cell_bound.start, "xdr:from", + res_pts[0], res_pts[1]); + gsf_xml_out_start_element (xml, "xdr:ext"); + gsf_xml_out_add_int (xml, "cx", + xlsx_pts_to_emu (anchor->offset[2])); + gsf_xml_out_add_int (xml, "cy", + xlsx_pts_to_emu (anchor->offset[3])); + gsf_xml_out_end_element (xml); + break; + case GNM_SO_ANCHOR_ABSOLUTE: + gsf_xml_out_start_element (xml, "xdr:absoluteAnchor"); + gsf_xml_out_start_element (xml, "xdr:pos"); + gsf_xml_out_add_int (xml, "x", + xlsx_pts_to_emu (anchor->offset[0])); + gsf_xml_out_add_int (xml, "y", + xlsx_pts_to_emu (anchor->offset[1])); + gsf_xml_out_end_element (xml); + gsf_xml_out_start_element (xml, "xdr:ext"); + gsf_xml_out_add_int (xml, "cx", + xlsx_pts_to_emu (anchor->offset[2])); + gsf_xml_out_add_int (xml, "cy", + xlsx_pts_to_emu (anchor->offset[3])); + gsf_xml_out_end_element (xml); + break; + } if (GNM_IS_SO_GRAPH (so)) { char *tmp; diff --git a/plugins/openoffice/ChangeLog b/plugins/openoffice/ChangeLog index c3801af2c..fd4d9f114 100644 --- a/plugins/openoffice/ChangeLog +++ b/plugins/openoffice/ChangeLog @@ -1,3 +1,10 @@ +2015-03-30 Jean Brefort + + * openoffice-read.c (odf_shapes), (odf_shapes_end), (oo_table_end), + (od_draw_frame_start), (odf_line): support absolute sheet object anchoring. + * openoffice-write.c (odf_write_frame_size), (odf_write_line), + (odf_sheet_objects_get), (odf_write_content): ditto. + 2015-03-22 Andreas J. Guelzow * openoffice-write.c (-odf_write_circle_axes_styles): deleted diff --git a/plugins/openoffice/openoffice-read.c b/plugins/openoffice/openoffice-read.c index 0712a6267..a36d27bb6 100644 --- a/plugins/openoffice/openoffice-read.c +++ b/plugins/openoffice/openoffice-read.c @@ -2475,6 +2475,20 @@ oo_table_start (GsfXMLIn *xin, xmlChar const **attrs) } static void +odf_shapes (GsfXMLIn *xin, xmlChar const **attrs) +{ + OOParseState *state = (OOParseState *)xin->user_state; + state->pos.eval.col = -1; /* we use that to know that objects have absolute anchors */ +} + +static void +odf_shapes_end (GsfXMLIn *xin, G_GNUC_UNUSED GsfXMLBlob *blob) +{ + OOParseState *state = (OOParseState *)xin->user_state; + state->pos.eval.col = 0; +} + +static void odf_init_pp (GnmParsePos *pp, GsfXMLIn *xin, gchar const *base) { OOParseState *state = (OOParseState *)xin->user_state; @@ -2969,7 +2983,6 @@ odf_validation_help_message_end (GsfXMLIn *xin, G_GNUC_UNUSED GsfXMLBlob *blob) odf_pop_text_p (state); } - static void odf_adjust_offsets_col (OOParseState *state, int *col, double *x, gboolean absolute) { @@ -3185,12 +3198,16 @@ oo_table_end (GsfXMLIn *xin, G_GNUC_UNUSED GsfXMLBlob *blob) SheetObjectAnchor const *old = sheet_object_get_anchor (ob_off->so); GnmRange cell_base = *sheet_object_get_range (ob_off->so); - odf_adjust_offsets (state, &cell_base.start, &ob_off->frame_offset[0], - &ob_off->frame_offset[1], ob_off->absolute_distance); - odf_adjust_offsets (state, &cell_base.end, &ob_off->frame_offset[2], - &ob_off->frame_offset[3], ob_off->absolute_distance); + if (old->mode != GNM_SO_ANCHOR_ABSOLUTE) { + odf_adjust_offsets (state, &cell_base.start, &ob_off->frame_offset[0], + &ob_off->frame_offset[1], ob_off->absolute_distance); + if (old->mode == GNM_SO_ANCHOR_TWO_CELLS) + odf_adjust_offsets (state, &cell_base.end, &ob_off->frame_offset[2], + &ob_off->frame_offset[3], ob_off->absolute_distance); + } sheet_object_anchor_init (&new, &cell_base, ob_off->frame_offset, - old->base.direction); + old->base.direction, + old->mode); sheet_object_set_anchor (ob_off->so, &new); sheet_object_set_sheet (ob_off->so, state->pos.sheet); @@ -7933,9 +7950,9 @@ od_draw_frame_start (GsfXMLIn *xin, xmlChar const **attrs) GnmRange cell_base; double frame_offset[4]; gdouble height = 0., width = 0., x = 0., y = 0., end_x = 0., end_y = 0.; - ColRowInfo const *col, *row; GnmExprTop const *texpr = NULL; int z = -1; + GnmSOAnchorMode mode; height = width = x = y = 0.; for (; attrs != NULL && attrs[0] && attrs[1] ; attrs += 2){ @@ -7964,39 +7981,43 @@ od_draw_frame_start (GsfXMLIn *xin, xmlChar const **attrs) ; } - cell_base.start.col = cell_base.end.col = state->pos.eval.col; - cell_base.start.row = cell_base.end.row = state->pos.eval.row; - - col = sheet_col_get_info (state->pos.sheet, state->pos.eval.col); - row = sheet_row_get_info (state->pos.sheet, state->pos.eval.row); - frame_offset[0] = x; frame_offset[1] = y; + if (state->pos.eval.col >= 0) { + cell_base.start.col = cell_base.end.col = state->pos.eval.col; + cell_base.start.row = cell_base.end.row = state->pos.eval.row; + + if (texpr == NULL || (GNM_EXPR_GET_OPER (texpr->expr) != GNM_EXPR_OP_CELLREF)) { + cell_base.end.col = cell_base.start.col; + cell_base.end.row = cell_base.start.row; + frame_offset[2] = width; + frame_offset[3] = height; + mode = GNM_SO_ANCHOR_ONE_CELL; - if (texpr == NULL || (GNM_EXPR_GET_OPER (texpr->expr) != GNM_EXPR_OP_CELLREF)) { - frame_offset[2] = x+width; - frame_offset[3] = y+height; + } else { + GnmCellRef const *ref = &texpr->expr->cellref.ref; + cell_base.end.col = ref->col; + cell_base.end.row = ref->row; + frame_offset[2] = end_x; + frame_offset[3] = end_y ; + mode = GNM_SO_ANCHOR_TWO_CELLS; + } + if (texpr) + gnm_expr_top_unref (texpr); } else { - GnmCellRef const *ref = &texpr->expr->cellref.ref; - cell_base.end.col = ref->col; - cell_base.end.row = ref->row; - frame_offset[2] = end_x; - frame_offset[3] = end_y ; + cell_base.end.col = cell_base.start.col = + cell_base.end.row = cell_base.start.row = 0; /* actually not needed */ + frame_offset[2] = width; + frame_offset[3] = height; + mode = GNM_SO_ANCHOR_ABSOLUTE; } odf_draw_frame_store_location (state, frame_offset, (height > 0) ? height : go_nan, (width > 0) ? width : go_nan); - frame_offset[0] /= col->size_pts; - frame_offset[1] /= row->size_pts; - frame_offset[2] /= col->size_pts; - frame_offset[3] /= row->size_pts; - - if (texpr) - gnm_expr_top_unref (texpr); sheet_object_anchor_init (&state->chart.anchor, &cell_base, frame_offset, - GOD_ANCHOR_DIR_DOWN_RIGHT); + GOD_ANCHOR_DIR_DOWN_RIGHT, mode); state->chart.so = NULL; state->chart.z_index = z; } @@ -10496,16 +10517,16 @@ odf_line (GsfXMLIn *xin, xmlChar const **attrs) { OOParseState *state = (OOParseState *)xin->user_state; gnm_float x1 = 0., x2 = 0., y1 = 0., y2 = 0.; - ColRowInfo const *col, *row; GODrawingAnchorDir direction; GnmRange cell_base; double frame_offset[4]; char const *style_name = NULL; gdouble height, width; int z = -1; - - cell_base.start.col = cell_base.end.col = state->pos.eval.col; - cell_base.start.row = cell_base.end.row = state->pos.eval.row; + GnmSOAnchorMode mode; + cell_base.start.col = state->pos.eval.col; + cell_base.start.row = state->pos.eval.row; + cell_base.end.col = cell_base.end.row = -1; for (; attrs != NULL && attrs[0] && attrs[1] ; attrs += 2) if (gsf_xml_in_namecmp (xin, CXML2C (attrs[0]), @@ -10567,20 +10588,31 @@ odf_line (GsfXMLIn *xin, xmlChar const **attrs) height = y1 - y2; } + if (state->pos.eval.col >= 0) { + if (cell_base.end.col >= 0) { + mode = GNM_SO_ANCHOR_TWO_CELLS; + } else { + cell_base.end.col = cell_base.start.col; + cell_base.end.row = cell_base.start.row; + frame_offset[2] = width; + frame_offset[3] = height; + mode = GNM_SO_ANCHOR_ONE_CELL; + } + } else { + cell_base.end.col = cell_base.start.col = + cell_base.end.row = cell_base.start.row = 0; /* actually not needed */ + frame_offset[2] = width; + frame_offset[3] = height; + mode = GNM_SO_ANCHOR_ABSOLUTE; + } + odf_draw_frame_store_location (state, frame_offset, height, width); - col = sheet_col_get_info (state->pos.sheet, cell_base.start.col); - row = sheet_row_get_info (state->pos.sheet, cell_base.start.row); - frame_offset[0] /= col->size_pts; - frame_offset[1] /= row->size_pts; - frame_offset[2] /= col->size_pts; - frame_offset[3] /= row->size_pts; - - sheet_object_anchor_init (&state->chart.anchor, &cell_base, frame_offset, - direction); + direction, + mode); state->chart.so = g_object_new (GNM_SO_LINE_TYPE, NULL); if (style_name != NULL) { @@ -11954,7 +11986,7 @@ static GsfXMLInNode const opendoc_content_dtd [] = GSF_XML_IN_NODE (TABLE, SHEET_SELECTIONS, OO_GNUM_NS_EXT, "selections", GSF_XML_NO_CONTENT, &odf_selection, &odf_selection_end), GSF_XML_IN_NODE (SHEET_SELECTIONS, SELECTION, OO_GNUM_NS_EXT, "selection", GSF_XML_NO_CONTENT, &odf_selection_range, NULL), GSF_XML_IN_NODE (TABLE, TABLE_SOURCE, OO_NS_TABLE, "table-source", GSF_XML_NO_CONTENT, NULL, NULL), - GSF_XML_IN_NODE (TABLE, TABLE_SHAPES, OO_NS_TABLE, "shapes", GSF_XML_NO_CONTENT, NULL, NULL), + GSF_XML_IN_NODE (TABLE, TABLE_SHAPES, OO_NS_TABLE, "shapes", GSF_XML_NO_CONTENT, &odf_shapes, &odf_shapes_end), GSF_XML_IN_NODE (TABLE_SHAPES, DRAW_FRAME, OO_NS_DRAW, "frame", GSF_XML_NO_CONTENT, &od_draw_frame_start, &od_draw_frame_end), GSF_XML_IN_NODE (TABLE_SHAPES, DRAW_CAPTION, OO_NS_DRAW, "caption", GSF_XML_NO_CONTENT, &odf_caption, &od_draw_text_frame_end), GSF_XML_IN_NODE (DRAW_CAPTION, TEXT_CONTENT, OO_NS_TEXT, "p", GSF_XML_NO_CONTENT, NULL, NULL), /* 2nd def */ diff --git a/plugins/openoffice/openoffice-write.c b/plugins/openoffice/openoffice-write.c index a1e5c4da0..ad6e316bb 100644 --- a/plugins/openoffice/openoffice-write.c +++ b/plugins/openoffice/openoffice-write.c @@ -2840,25 +2840,40 @@ odf_write_frame_size (GnmOOExport *state, SheetObject *so) sheet_object_anchor_to_offset_pts (anchor, state->sheet, res_pts); - odf_add_pt (state->xml, SVG "x", res_pts[0]); - odf_add_pt (state->xml, SVG "y", res_pts[1]); - odf_add_pt (state->xml, TABLE "end-x", res_pts[2]); - odf_add_pt (state->xml, TABLE "end-y", res_pts[3]); - - /* The next 3 lines should not be needed, but older versions of Gnumeric used the */ - /* width and height. */ - sheet_object_anchor_to_pts (anchor, state->sheet, res_pts); - odf_add_pt (state->xml, SVG "width", res_pts[2] - res_pts[0]); - odf_add_pt (state->xml, SVG "height", res_pts[3] - res_pts[1]); - - gnm_cellref_init (&ref, (Sheet *) state->sheet, r->end.col, r->end.row, TRUE); - texpr = gnm_expr_top_new (gnm_expr_new_cellref (&ref)); - parse_pos_init_sheet (&pp, state->sheet); - formula = gnm_expr_top_as_string (texpr, &pp, state->conv); - gnm_expr_top_unref (texpr); - gsf_xml_out_add_cstr (state->xml, TABLE "end-cell-address", - odf_strip_brackets (formula)); - g_free (formula); + switch (anchor->mode) { + case GNM_SO_ANCHOR_TWO_CELLS: + odf_add_pt (state->xml, SVG "x", res_pts[0]); + odf_add_pt (state->xml, SVG "y", res_pts[1]); + odf_add_pt (state->xml, TABLE "end-x", res_pts[2]); + odf_add_pt (state->xml, TABLE "end-y", res_pts[3]); + /* The next 3 lines should not be needed, but older versions of Gnumeric used the */ + /* width and height. */ + sheet_object_anchor_to_pts (anchor, state->sheet, res_pts); + odf_add_pt (state->xml, SVG "width", res_pts[2] - res_pts[0]); + odf_add_pt (state->xml, SVG "height", res_pts[3] - res_pts[1]); + + gnm_cellref_init (&ref, (Sheet *) state->sheet, r->end.col, r->end.row, TRUE); + texpr = gnm_expr_top_new (gnm_expr_new_cellref (&ref)); + parse_pos_init_sheet (&pp, state->sheet); + formula = gnm_expr_top_as_string (texpr, &pp, state->conv); + gnm_expr_top_unref (texpr); + gsf_xml_out_add_cstr (state->xml, TABLE "end-cell-address", + odf_strip_brackets (formula)); + g_free (formula); + break; + case GNM_SO_ANCHOR_ONE_CELL: + odf_add_pt (state->xml, SVG "x", res_pts[0]); + odf_add_pt (state->xml, SVG "y", res_pts[1]); + odf_add_pt (state->xml, SVG "width", anchor->offset[2]); + odf_add_pt (state->xml, SVG "height", anchor->offset[3]); + break; + case GNM_SO_ANCHOR_ABSOLUTE: + odf_add_pt (state->xml, SVG "x", anchor->offset[0]); + odf_add_pt (state->xml, SVG "y", anchor->offset[1]); + odf_add_pt (state->xml, SVG "width", anchor->offset[2]); + odf_add_pt (state->xml, SVG "height", anchor->offset[3]); + break; + } sheet = sheet_object_get_sheet (so); if (sheet) { @@ -3186,9 +3201,6 @@ odf_write_line (GnmOOExport *state, SheetObject *so) sheet_object_get_stacking (so); gsf_xml_out_add_int (state->xml, DRAW "z-index", z); - sheet_object_anchor_to_offset_pts (anchor, state->sheet, res_pts); - odf_add_pt (state->xml, TABLE "end-x", res_pts[2]); - odf_add_pt (state->xml, TABLE "end-y", res_pts[3]); sheet_object_anchor_to_pts (anchor, state->sheet, res_pts); switch (anchor->base.direction) { @@ -3225,14 +3237,20 @@ odf_write_line (GnmOOExport *state, SheetObject *so) odf_add_pt (state->xml, SVG "x2", x2); odf_add_pt (state->xml, SVG "y2", y2); - gnm_cellref_init (&ref, (Sheet *) state->sheet, r->end.col, r->end.row, TRUE); - texpr = gnm_expr_top_new (gnm_expr_new_cellref (&ref)); - parse_pos_init_sheet (&pp, state->sheet); - formula = gnm_expr_top_as_string (texpr, &pp, state->conv); - gnm_expr_top_unref (texpr); - gsf_xml_out_add_cstr (state->xml, TABLE "end-cell-address", - odf_strip_brackets (formula)); - g_free (formula); + if (anchor->mode == GNM_SO_ANCHOR_TWO_CELLS) { + sheet_object_anchor_to_offset_pts (anchor, state->sheet, res_pts); + odf_add_pt (state->xml, TABLE "end-x", res_pts[2]); + odf_add_pt (state->xml, TABLE "end-y", res_pts[3]); + + gnm_cellref_init (&ref, (Sheet *) state->sheet, r->end.col, r->end.row, TRUE); + texpr = gnm_expr_top_new (gnm_expr_new_cellref (&ref)); + parse_pos_init_sheet (&pp, state->sheet); + formula = gnm_expr_top_as_string (texpr, &pp, state->conv); + gnm_expr_top_unref (texpr); + gsf_xml_out_add_cstr (state->xml, TABLE "end-cell-address", + odf_strip_brackets (formula)); + g_free (formula); + } gsf_xml_out_end_element (state->xml); /* DRAW "line" */ } @@ -3710,7 +3728,10 @@ odf_sheet_objects_get (Sheet const *sheet, GnmCellPos const *pos) for (ptr = sheet->sheet_objects; ptr != NULL ; ptr = ptr->next ) { SheetObject *so = GNM_SO (ptr->data); SheetObjectAnchor const *anchor = sheet_object_get_anchor (so); - if (gnm_cellpos_equal (&anchor->cell_bound.start, pos)) + if (anchor->mode == GNM_SO_ANCHOR_ABSOLUTE) { + if (pos == NULL) + res = g_slist_prepend (res, so); + } else if (pos && gnm_cellpos_equal (&anchor->cell_bound.start, pos)) res = g_slist_prepend (res, so); } return res; @@ -4855,6 +4876,7 @@ odf_write_content (GnmOOExport *state, GsfOutput *child) int graph_n = 1; int image_n = 1; gboolean has_autofilters = FALSE; + GSList *objects; state->xml = create_new_xml_child (state, child); gsf_xml_out_set_doc_type (state->xml, "\n"); @@ -4939,6 +4961,15 @@ odf_write_content (GnmOOExport *state, GsfOutput *child) g_free (formula); } + /* writing shapes with absolute anchors */ + objects = odf_sheet_objects_get (sheet, NULL); + if (objects != NULL) { + gsf_xml_out_start_element (state->xml, TABLE "shapes"); + odf_write_objects (state, objects); + gsf_xml_out_end_element (state->xml); + g_slist_free (objects); + } + odf_write_sheet_controls (state); odf_write_sheet (state); if (state->odf_version > 101 && sheet->names) { diff --git a/src/dialogs/ChangeLog b/src/dialogs/ChangeLog index 35dd15b38..17d1c7ce8 100644 --- a/src/dialogs/ChangeLog +++ b/src/dialogs/ChangeLog @@ -1,3 +1,10 @@ +2015-03-30 Jean Brefort + + * dialog-sheetobject-size.c (dialog_so_size_button_sensitivity), + (set_mode), (cb_dialog_so_size_apply_clicked), + (cb_dialog_so_size_mode_changed), (dialog_so_size): support relative and + absolute anchoring. + 2015-03-04 Morten Welinder * Release 1.12.21 diff --git a/src/dialogs/dialog-sheetobject-size.c b/src/dialogs/dialog-sheetobject-size.c index d083356f7..b7a980c57 100644 --- a/src/dialogs/dialog-sheetobject-size.c +++ b/src/dialogs/dialog-sheetobject-size.c @@ -40,6 +40,7 @@ #include #include #include +#include #include @@ -65,6 +66,7 @@ typedef struct { GtkSpinButton *yspin; GtkEntry *nameentry; GtkWidget *print_check; + GnmSOAnchorModeChooser *modecombo; SheetObject *so; SheetObjectAnchor *old_anchor; @@ -75,6 +77,7 @@ typedef struct { gboolean so_pos_needs_restore; gboolean so_name_changed; gboolean so_print_check_changed; + gboolean so_mode_changed; } SOSizeState; static void @@ -94,7 +97,8 @@ dialog_so_size_button_sensitivity (SOSizeState *state) gboolean sensitive = state->so_size_needs_restore || state->so_pos_needs_restore || state->so_name_changed || - state->so_print_check_changed; + state->so_print_check_changed || + state->so_mode_changed; gtk_widget_set_sensitive (state->ok_button, sensitive); gtk_widget_set_sensitive @@ -206,6 +210,18 @@ set_print_flag (SheetObject *so, gboolean print) g_object_unref, g_free); } +static GOUndo * +set_mode (SheetObject *so, GnmSOAnchorMode mode) +{ + GnmSOAnchorMode *p_mode = g_new (GnmSOAnchorMode, 1); + + *p_mode = mode; + return go_undo_binary_new + (g_object_ref (so), p_mode, + (GOUndoBinaryFunc)sheet_object_set_anchor_mode, + g_object_unref, g_free); +} + static void cb_dialog_so_size_apply_clicked (G_GNUC_UNUSED GtkWidget *button, SOSizeState *state) @@ -252,11 +268,19 @@ cb_dialog_so_size_apply_clicked (G_GNUC_UNUSED GtkWidget *button, undo_name = _("Set Object Print Property"); cnt++; } + if (state->so_mode_changed) { + int new_mode = gnm_so_anchor_mode_chooser_get_mode (state->modecombo); + int old_mode = state->so->anchor.mode; + undo = go_undo_combine (undo, set_mode (state->so, old_mode)); + redo = go_undo_combine (redo, set_mode (state->so, new_mode)); + undo_name = _("Set Object Anchor Mode"); + cnt++; + } if (cnt > 0) { if (cnt > 1) undo_name = _("Set Object Properties"); - state->so_name_changed = state->so_print_check_changed = + state->so_name_changed = state->so_print_check_changed = state->so_mode_changed = cmd_generic (GNM_WBC (state->wbcg), undo_name, undo, redo); } @@ -302,11 +326,26 @@ cb_dialog_so_size_print_check_toggled (GtkToggleButton *togglebutton, return; } +static void +cb_dialog_so_size_mode_changed (GnmSOAnchorModeChooser *chooser, SOSizeState *state) +{ + GnmSOAnchorMode new_mode = gnm_so_anchor_mode_chooser_get_mode (chooser); + GnmSOAnchorMode old_mode = state->so->anchor.mode; + double coords[4]; + + scg_object_anchor_to_coords (state->scg, state->active_anchor, coords); + state->active_anchor->mode = new_mode; + scg_object_coords_to_anchor (state->scg, coords, state->active_anchor); + state->so_mode_changed = new_mode != old_mode; + dialog_so_size_button_sensitivity (state); +} + void dialog_so_size (WBCGtk *wbcg, GObject *so) { GtkBuilder *gui; SOSizeState *state; + GtkGrid *grid; int width, height; g_return_if_fail (wbcg != NULL); @@ -352,6 +391,7 @@ dialog_so_size (WBCGtk *wbcg, GObject *so) state->yspin = GTK_SPIN_BUTTON (go_gtk_builder_get_widget (state->gui, "y-spin")); state->print_check = GTK_WIDGET (go_gtk_builder_get_widget (state->gui, "print-check")); + state->modecombo = GNM_SO_ANCHOR_MODE_CHOOSER (gnm_so_anchor_mode_chooser_new (sheet_object_can_resize (state->so))); dialog_so_size_load (state); state->active_anchor = sheet_object_anchor_dup (sheet_object_get_anchor (state->so)); @@ -364,6 +404,13 @@ dialog_so_size (WBCGtk *wbcg, GObject *so) gtk_spin_button_set_value (state->yspin, 0.); gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (state->print_check), !(state->so->flags & SHEET_OBJECT_PRINT)); + gnm_so_anchor_mode_chooser_set_mode (state->modecombo, + state->so->anchor.mode); + grid = GTK_GRID (gtk_builder_get_object (state->gui, "main-grid")); + gtk_grid_insert_row (grid, 7); + gtk_grid_attach (grid, GTK_WIDGET (state->modecombo), 0, 7, 2, 1); + gtk_widget_set_halign (GTK_WIDGET (state->modecombo), GTK_ALIGN_START); + gtk_widget_show (GTK_WIDGET (state->modecombo)); g_signal_connect (G_OBJECT (state->wspin), "value-changed", G_CALLBACK (cb_dialog_so_size_value_changed_update_points), @@ -404,7 +451,11 @@ dialog_so_size (WBCGtk *wbcg, GObject *so) "value-changed", G_CALLBACK (cb_dialog_so_size_value_changed), state); - state->ok_button = go_gtk_builder_get_widget (state->gui, "ok_button"); + g_signal_connect (G_OBJECT (state->modecombo), + "changed", + G_CALLBACK (cb_dialog_so_size_mode_changed), state); + + state->ok_button = go_gtk_builder_get_widget (state->gui, "ok_button"); g_signal_connect (G_OBJECT (state->ok_button), "clicked", G_CALLBACK (cb_dialog_so_size_ok_clicked), state); diff --git a/src/graph.h b/src/graph.h index 35e47f4c5..0fa2c865f 100644 --- a/src/graph.h +++ b/src/graph.h @@ -45,6 +45,7 @@ typedef struct { gboolean share_x, new_sheet; GObject *obj; GogDataAllocator *dalloc; + GnmSOAnchorMode anchor_mode; } GnmGraphDataClosure; G_END_DECLS diff --git a/src/item-grid.c b/src/item-grid.c index 9afe91f3f..ecf321de3 100644 --- a/src/item-grid.c +++ b/src/item-grid.c @@ -885,7 +885,7 @@ ig_obj_create_begin (GnmItemGrid *ig, int button, gint64 x, gint64 y) coords[0] = coords[2] = x; coords[1] = coords[3] = y; - sheet_object_anchor_init (&anchor, NULL, NULL, GOD_ANCHOR_DIR_DOWN_RIGHT); + sheet_object_anchor_init (&anchor, NULL, NULL, GOD_ANCHOR_DIR_DOWN_RIGHT, so->anchor.mode); scg_object_coords_to_anchor (ig->scg, coords, &anchor); sheet_object_set_anchor (so, &anchor); sheet_object_set_sheet (so, scg_sheet (ig->scg)); diff --git a/src/sheet-control-gui.c b/src/sheet-control-gui.c index 08aa88f1d..1e01bfb9c 100644 --- a/src/sheet-control-gui.c +++ b/src/sheet-control-gui.c @@ -2853,6 +2853,7 @@ cb_collect_objects_to_commit (SheetObject *so, double *coords, CollectObjectsDat SheetObjectAnchor *anchor = sheet_object_anchor_dup ( sheet_object_get_anchor (so)); if (!sheet_object_can_resize (so)) { + /* FIXME: that code should be invalid */ double scale = goc_canvas_get_pixels_per_unit (GOC_CANVAS (data->scg->pane[0])) / 72.; sheet_object_default_size (so, coords + 2, coords + 3); coords[2] *= gnm_app_display_dpi_get (TRUE) * scale; @@ -2960,6 +2961,7 @@ void scg_object_coords_to_anchor (SheetControlGUI const *scg, double const *coords, SheetObjectAnchor *in_out) { + Sheet *sheet = scg_sheet (scg); /* pane 0 always exists and the others are always use the same basis */ GnmPane *pane = scg_pane ((SheetControlGUI *)scg, 0); double tmp[4]; @@ -2984,14 +2986,36 @@ scg_object_coords_to_anchor (SheetControlGUI const *scg, in_out->base.direction |= GOD_ANCHOR_DIR_DOWN; } - in_out->cell_bound.start.col = calc_obj_place (pane, tmp[0], TRUE, - in_out->offset + 0); - in_out->cell_bound.start.row = calc_obj_place (pane, tmp[1], FALSE, - in_out->offset + 1); - in_out->cell_bound.end.col = calc_obj_place (pane, tmp[2], TRUE, - in_out->offset + 2); - in_out->cell_bound.end.row = calc_obj_place (pane, tmp[3], FALSE, - in_out->offset + 3); + switch (in_out->mode) { + case GNM_SO_ANCHOR_TWO_CELLS: + in_out->cell_bound.start.col = calc_obj_place (pane, tmp[0], TRUE, + in_out->offset + 0); + in_out->cell_bound.start.row = calc_obj_place (pane, tmp[1], FALSE, + in_out->offset + 1); + in_out->cell_bound.end.col = calc_obj_place (pane, tmp[2], TRUE, + in_out->offset + 2); + in_out->cell_bound.end.row = calc_obj_place (pane, tmp[3], FALSE, + in_out->offset + 3); + break; + case GNM_SO_ANCHOR_ONE_CELL: + in_out->cell_bound.start.col = calc_obj_place (pane, tmp[0], TRUE, + in_out->offset + 0); + in_out->cell_bound.start.row = calc_obj_place (pane, tmp[1], FALSE, + in_out->offset + 1); + in_out->offset[2] = (tmp[2] - tmp[0]) / colrow_compute_pixel_scale (sheet, TRUE); + in_out->offset[3] = (tmp[3] - tmp[1]) / colrow_compute_pixel_scale (sheet, FALSE); + break; + case GNM_SO_ANCHOR_ABSOLUTE: { + double h, v; + h = colrow_compute_pixel_scale (sheet, TRUE); + v = colrow_compute_pixel_scale (sheet, FALSE); + in_out->offset[0] = tmp[0] / h; + in_out->offset[1] = tmp[1] / v; + in_out->offset[2] = (tmp[2] - tmp[0]) / h; + in_out->offset[3] = (tmp[3] - tmp[1]) / v; + break; + } + } } static double @@ -3016,21 +3040,41 @@ scg_object_anchor_to_coords (SheetControlGUI const *scg, g_return_if_fail (coords != NULL); r = &anchor->cell_bound; - pixels[0] = scg_colrow_distance_get (scg, TRUE, 0, r->start.col); - pixels[2] = pixels[0] + scg_colrow_distance_get (scg, TRUE, - r->start.col, r->end.col); - pixels[1] = scg_colrow_distance_get (scg, FALSE, 0, r->start.row); - pixels[3] = pixels[1] + scg_colrow_distance_get (scg, FALSE, - r->start.row, r->end.row); - /* add .5 to offsets so that the rounding is optimal */ - pixels[0] += cell_offset_calc_pixel (sheet, r->start.col, - TRUE, anchor->offset[0]) + .5; - pixels[1] += cell_offset_calc_pixel (sheet, r->start.row, - FALSE, anchor->offset[1]) + .5; - pixels[2] += cell_offset_calc_pixel (sheet, r->end.col, - TRUE, anchor->offset[2]) + .5; - pixels[3] += cell_offset_calc_pixel (sheet, r->end.row, - FALSE, anchor->offset[3]) + .5; + if (anchor->mode != GNM_SO_ANCHOR_ABSOLUTE) { + pixels[0] = scg_colrow_distance_get (scg, TRUE, 0, r->start.col); + pixels[1] = scg_colrow_distance_get (scg, FALSE, 0, r->start.row); + if (anchor->mode == GNM_SO_ANCHOR_TWO_CELLS) { + pixels[2] = pixels[0] + scg_colrow_distance_get (scg, TRUE, + r->start.col, r->end.col); + pixels[3] = pixels[1] + scg_colrow_distance_get (scg, FALSE, + r->start.row, r->end.row); + /* add .5 to offsets so that the rounding is optimal */ + pixels[0] += cell_offset_calc_pixel (sheet, r->start.col, + TRUE, anchor->offset[0]) + .5; + pixels[1] += cell_offset_calc_pixel (sheet, r->start.row, + FALSE, anchor->offset[1]) + .5; + pixels[2] += cell_offset_calc_pixel (sheet, r->end.col, + TRUE, anchor->offset[2]) + .5; + pixels[3] += cell_offset_calc_pixel (sheet, r->end.row, + FALSE, anchor->offset[3]) + .5; + } else { + /* add .5 to offsets so that the rounding is optimal */ + pixels[0] += cell_offset_calc_pixel (sheet, r->start.col, + TRUE, anchor->offset[0]) + .5; + pixels[1] += cell_offset_calc_pixel (sheet, r->start.row, + FALSE, anchor->offset[1]) + .5; + pixels[2] = pixels[0] + go_fake_floor (anchor->offset[2] * colrow_compute_pixel_scale (sheet, TRUE) + .5); + pixels[3] = pixels[1] + go_fake_floor (anchor->offset[3] * colrow_compute_pixel_scale (sheet, TRUE) + .5); + } + } else { + double h, v; + h = colrow_compute_pixel_scale (sheet, TRUE); + v = colrow_compute_pixel_scale (sheet, FALSE); + pixels[0] = go_fake_floor (anchor->offset[0] * h); + pixels[1] = go_fake_floor (anchor->offset[1] * v); + pixels[2] = go_fake_floor ((anchor->offset[0] + anchor->offset[2]) * h); + pixels[3] = go_fake_floor ((anchor->offset[1] + anchor->offset[3]) * v); + } direction = anchor->base.direction; if (direction == GOD_ANCHOR_DIR_UNKNOWN) @@ -3957,7 +4001,7 @@ scg_paste_image (SheetControlGUI *scg, GnmRange *where, SheetObjectAnchor anchor; sheet_object_anchor_init (&anchor, where, NULL, - GOD_ANCHOR_DIR_DOWN_RIGHT); + GOD_ANCHOR_DIR_DOWN_RIGHT, GNM_SO_ANCHOR_TWO_CELLS); scg_image_create (scg, &anchor, data, len); } @@ -3969,7 +4013,7 @@ scg_drag_receive_img_data (SheetControlGUI *scg, double x, double y, SheetObjectAnchor anchor; sheet_object_anchor_init (&anchor, NULL, NULL, - GOD_ANCHOR_DIR_DOWN_RIGHT); + GOD_ANCHOR_DIR_DOWN_RIGHT, GNM_SO_ANCHOR_TWO_CELLS); coords[0] = coords[2] = x; coords[1] = coords[3] = y; scg_object_coords_to_anchor (scg, coords, &anchor); @@ -4037,7 +4081,7 @@ scg_paste_cellregion (SheetControlGUI *scg, double x, double y, double coords[4]; sheet_object_anchor_init (&anchor, NULL, NULL, - GOD_ANCHOR_DIR_DOWN_RIGHT); + GOD_ANCHOR_DIR_DOWN_RIGHT, GNM_SO_ANCHOR_TWO_CELLS); coords[0] = coords[2] = x; coords[1] = coords[3] = y; scg_object_coords_to_anchor (scg, coords, &anchor); diff --git a/src/sheet-filter.c b/src/sheet-filter.c index 056eebc45..3db6529aa 100644 --- a/src/sheet-filter.c +++ b/src/sheet-filter.c @@ -635,7 +635,7 @@ gnm_filter_add_field (GnmFilter *filter, int i) tmp.start.row = tmp.end.row = filter->r.start.row; tmp.start.col = tmp.end.col = filter->r.start.col + i; sheet_object_anchor_init (&anchor, &tmp, a_offsets, - GOD_ANCHOR_DIR_DOWN_RIGHT); + GOD_ANCHOR_DIR_DOWN_RIGHT, GNM_SO_ANCHOR_TWO_CELLS); sheet_object_set_anchor (GNM_SO (fcombo), &anchor); sheet_object_set_sheet (GNM_SO (fcombo), filter->sheet); diff --git a/src/sheet-object-cell-comment.c b/src/sheet-object-cell-comment.c index 002309489..51c3e0fec 100644 --- a/src/sheet-object-cell-comment.c +++ b/src/sheet-object-cell-comment.c @@ -443,7 +443,7 @@ cell_comment_set_pos (GnmComment *cc, GnmCellPos const *pos) r.start = r.end = *pos; sheet_object_anchor_init (&anchor, &r, a_offsets, - GOD_ANCHOR_DIR_DOWN_RIGHT); + GOD_ANCHOR_DIR_DOWN_RIGHT, GNM_SO_ANCHOR_TWO_CELLS); sheet_object_set_anchor (GNM_SO (cc), &anchor); } diff --git a/src/sheet-object-component.c b/src/sheet-object-component.c index f1c0a80bb..c9f14f7b0 100644 --- a/src/sheet-object-component.c +++ b/src/sheet-object-component.c @@ -481,7 +481,6 @@ sheet_object_component_set_component (SheetObject *so, GOComponent *component) { SheetObjectComponent *soc; GList *l = so->realized_list; - GnmPane *pane = (l && l->data)? GNM_PANE (GOC_ITEM (l->data)->canvas): NULL; g_return_if_fail (GNM_IS_SO_COMPONENT (so)); soc = GNM_SO_COMPONENT (so); @@ -503,26 +502,14 @@ sheet_object_component_set_component (SheetObject *so, GOComponent *component) go_component_stop_editing (component); if (go_component_is_resizable (component)) so->flags |= SHEET_OBJECT_CAN_RESIZE; - else - so->flags &= ~SHEET_OBJECT_CAN_RESIZE; + else { + so->flags &= ~(SHEET_OBJECT_CAN_RESIZE | SHEET_OBJECT_SIZE_WITH_CELLS); + so->anchor.mode = GNM_SO_ANCHOR_ONE_CELL; + } if (go_component_is_editable (component)) so->flags |= SHEET_OBJECT_CAN_EDIT; else so->flags &= ~SHEET_OBJECT_CAN_EDIT; - if (pane != NULL && !(so->flags & SHEET_OBJECT_CAN_RESIZE)) { - SheetControlGUI *scg = pane->simple.scg; - double coords[4], w, h; - SheetObjectAnchor anchor; - /* the size must be updated */ - scg_object_anchor_to_coords (scg, sheet_object_get_anchor (so), coords); - coords[0] = MIN (coords [0], coords[2]); - coords[1] = MIN (coords [1], coords[3]); - go_component_get_size (component, &w, &h); - coords[2] = coords[0] + w * gnm_app_display_dpi_get (TRUE); - coords[3] = coords[1] + h * gnm_app_display_dpi_get (FALSE); - scg_object_coords_to_anchor (scg, coords, &anchor); - sheet_object_set_anchor (so, &anchor); - } } } diff --git a/src/sheet-object-graph.c b/src/sheet-object-graph.c index 58e9517c3..743680878 100644 --- a/src/sheet-object-graph.c +++ b/src/sheet-object-graph.c @@ -622,9 +622,13 @@ GSF_CLASS_FULL (SheetObjectGraph, sheet_object_graph, SheetObject * sheet_object_graph_new (GogGraph *graph) { - SheetObjectGraph *sog = g_object_new (GNM_SO_GRAPH_TYPE, NULL); - sheet_object_graph_set_gog (GNM_SO (sog), graph); - return GNM_SO (sog); + SheetObject *sog = g_object_new (GNM_SO_GRAPH_TYPE, NULL); + GnmGraphDataClosure *data = (GnmGraphDataClosure *) g_object_get_data (G_OBJECT (graph), "data-closure"); + sheet_object_graph_set_gog (sog, graph); + if (data != NULL) + sog->anchor.mode = data->anchor_mode; + + return sog; } /** @@ -776,6 +780,7 @@ sheet_object_graph_guru (WBCGtk *wbcg, GogGraph *graph, g_signal_connect (G_OBJECT (w), "toggled", G_CALLBACK (cb_sheet_target_changed), data); gtk_grid_attach (GTK_GRID (custom), w, 0, 2, 2, 1); data->obj = G_OBJECT (custom); + data->anchor_mode = GNM_SO_ANCHOR_ONE_CELL; /* don't resize graphs with cells, see # */ gog_guru_add_custom_widget (dialog, custom); object = (GObject*) g_object_get_data (data->obj, "graph"); if (object) diff --git a/src/sheet-object-image.c b/src/sheet-object-image.c index 8857226c8..258c97369 100644 --- a/src/sheet-object-image.c +++ b/src/sheet-object-image.c @@ -597,6 +597,7 @@ gnm_soi_init (GObject *obj) so = GNM_SO (obj); so->anchor.base.direction = GOD_ANCHOR_DIR_DOWN_RIGHT; + so->anchor.mode = GNM_SO_ANCHOR_ONE_CELL; } static void diff --git a/src/sheet-object.c b/src/sheet-object.c index 4704ea3b6..a857813bd 100644 --- a/src/sheet-object.c +++ b/src/sheet-object.c @@ -1,5 +1,3 @@ -/* vim: set sw=8: -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ - /* * sheet-object.c: Implements the sheet object manipulation for Gnumeric * @@ -477,22 +475,37 @@ sheet_object_update_bounds (SheetObject *so, GnmCellPos const *pos) so->anchor.cell_bound.end.row < pos->row) return; - /* Are all cols hidden ? */ - end = so->anchor.cell_bound.end.col; - i = so->anchor.cell_bound.start.col; - while (i <= end && is_hidden) - is_hidden &= sheet_col_is_hidden (so->sheet, i++); - - /* Are all rows hidden ? */ - if (!is_hidden) { - is_hidden = TRUE; - end = so->anchor.cell_bound.end.row; - i = so->anchor.cell_bound.start.row; + switch (so->anchor.mode) { + default: + case GNM_SO_ANCHOR_TWO_CELLS: + /* Are all cols hidden ? */ + end = so->anchor.cell_bound.end.col; + i = so->anchor.cell_bound.start.col; while (i <= end && is_hidden) - is_hidden &= sheet_row_is_hidden (so->sheet, i++); - so->flags |= SHEET_OBJECT_IS_VISIBLE; - } else + is_hidden &= sheet_col_is_hidden (so->sheet, i++); + + /* Are all rows hidden ? */ + if (!is_hidden) { + is_hidden = TRUE; + end = so->anchor.cell_bound.end.row; + i = so->anchor.cell_bound.start.row; + while (i <= end && is_hidden) + is_hidden &= sheet_row_is_hidden (so->sheet, i++); + } + break; + case GNM_SO_ANCHOR_ONE_CELL: + /* Should we really hide if the row or column is hidden? */ + is_hidden = sheet_col_is_hidden (so->sheet, so->anchor.cell_bound.start.col) || + sheet_row_is_hidden (so->sheet, so->anchor.cell_bound.start.row); + break; + case GNM_SO_ANCHOR_ABSOLUTE: + is_hidden = FALSE; + break; + } + if (is_hidden) so->flags &= ~SHEET_OBJECT_IS_VISIBLE; + else + so->flags |= SHEET_OBJECT_IS_VISIBLE; g_signal_emit (so, signals [BOUNDS_CHANGED], 0); } @@ -863,23 +876,137 @@ sheet_object_anchor_to_pts (SheetObjectAnchor const *anchor, r = &anchor->cell_bound; - res_pts [0] = sheet_col_get_distance_pts (sheet, 0, - r->start.col); - res_pts [2] = res_pts [0] + sheet_col_get_distance_pts (sheet, - r->start.col, r->end.col); - res_pts [1] = sheet_row_get_distance_pts (sheet, 0, - r->start.row); - res_pts [3] = res_pts [1] + sheet_row_get_distance_pts (sheet, - r->start.row, r->end.row); - - res_pts [0] += cell_offset_calc_pt (sheet, r->start.col, - TRUE, anchor->offset [0]); - res_pts [1] += cell_offset_calc_pt (sheet, r->start.row, - FALSE, anchor->offset [1]); - res_pts [2] += cell_offset_calc_pt (sheet, r->end.col, - TRUE, anchor->offset [2]); - res_pts [3] += cell_offset_calc_pt (sheet, r->end.row, - FALSE, anchor->offset [3]); + if (anchor->mode != GNM_SO_ANCHOR_ABSOLUTE) { + res_pts [0] = sheet_col_get_distance_pts (sheet, 0, + r->start.col); + res_pts [1] = sheet_row_get_distance_pts (sheet, 0, + r->start.row); + if (anchor->mode == GNM_SO_ANCHOR_TWO_CELLS) { + res_pts [2] = res_pts [0] + sheet_col_get_distance_pts (sheet, + r->start.col, r->end.col); + res_pts [3] = res_pts [1] + sheet_row_get_distance_pts (sheet, + r->start.row, r->end.row); + + res_pts [0] += cell_offset_calc_pt (sheet, r->start.col, + TRUE, anchor->offset [0]); + res_pts [1] += cell_offset_calc_pt (sheet, r->start.row, + FALSE, anchor->offset [1]); + res_pts [2] += cell_offset_calc_pt (sheet, r->end.col, + TRUE, anchor->offset [2]); + res_pts [3] += cell_offset_calc_pt (sheet, r->end.row, + FALSE, anchor->offset [3]); + } else { + res_pts [0] += cell_offset_calc_pt (sheet, r->start.col, + TRUE, anchor->offset [0]); + res_pts [1] += cell_offset_calc_pt (sheet, r->start.row, + FALSE, anchor->offset [1]); + res_pts[2] = res_pts [0] + anchor->offset [2]; + res_pts[3] = res_pts [1] + anchor->offset [3]; + } + } else { + res_pts [0] = anchor->offset [0]; + res_pts [1] = anchor->offset [1]; + res_pts[2] = res_pts [0] + anchor->offset [2]; + res_pts[3] = res_pts [1] + anchor->offset [3]; + } +} + +void +sheet_object_pts_to_anchor (SheetObjectAnchor *anchor, + Sheet const *sheet, double const *res_pts) +{ + int col, row; + double x, y, tmp = 0; + ColRowInfo const *ci; + if (anchor->mode == GNM_SO_ANCHOR_ABSOLUTE) { + anchor->cell_bound.start.col = 0; + anchor->cell_bound.start.row = 0; + anchor->cell_bound.end.col = 0; + anchor->cell_bound.end.row = 0; + anchor->offset[0] = res_pts[0]; + anchor->offset[1] = res_pts[1]; + anchor->offset[2] = res_pts[2] - res_pts[0]; + anchor->offset[3] = res_pts[3] - res_pts[1]; + return; + } + /* find end column */ + col = x = 0; + do { + ci = sheet_col_get_info (sheet, col); + if (ci->visible) { + tmp = ci->size_pts; + if (res_pts[0] <= x + tmp) + break; + x += tmp; + } + } while (++col < gnm_sheet_get_last_col (sheet)); + if (col == gnm_sheet_get_last_col (sheet)) { + /* not sure this will occur */ + col--; + x -= tmp; + } + anchor->cell_bound.start.col = col; + anchor->offset[0] = (res_pts[0] - x) / tmp; + /* find start row */ + row = y = 0; + do { + ci = sheet_row_get_info (sheet, row); + if (ci->visible) { + tmp = ci->size_pts; + if (res_pts[1] <= y + tmp) + break; + y += tmp; + } + } while (++row < gnm_sheet_get_last_row (sheet)); + if (row == gnm_sheet_get_last_row (sheet)) { + /* not sure this will occur */ + row--; + y -= tmp; + } + anchor->cell_bound.start.row = row; + anchor->offset[1] = (res_pts[1] - y) / tmp; + if (anchor->mode == GNM_SO_ANCHOR_ONE_CELL) { + anchor->cell_bound.end.col = col; + anchor->cell_bound.end.row = row; + anchor->offset[2] = res_pts[2] - res_pts[0]; + anchor->offset[3] = res_pts[3] - res_pts[1]; + return; + } + + /* find end column */ + do { + ci = sheet_col_get_info (sheet, col); + if (ci->visible) { + tmp = ci->size_pts; + if (res_pts[2] <= x + tmp) + break; + x += tmp; + } + } while (++col < gnm_sheet_get_last_col (sheet)); + if (col == gnm_sheet_get_last_col (sheet)) { + /* not sure this will occur */ + col--; + x -= tmp; + } + anchor->cell_bound.end.col = col; + anchor->offset[2] = (res_pts[2] - x) / tmp; + /* find end row */ + do { + ci = sheet_row_get_info (sheet, row); + if (ci->visible) { + tmp = ci->size_pts; + if (res_pts[3] <= y + tmp) + break; + y += tmp; + } + } while (++row < gnm_sheet_get_last_row (sheet)); + if (row == gnm_sheet_get_last_row (sheet)) { + /* not sure this will occur */ + row--; + y -= tmp; + } + anchor->cell_bound.end.row = row; + anchor->offset[3] = (res_pts[3] - y) / tmp; } void @@ -892,14 +1019,18 @@ sheet_object_anchor_to_offset_pts (SheetObjectAnchor const *anchor, r = &anchor->cell_bound; - res_pts [0] = cell_offset_calc_pt (sheet, r->start.col, - TRUE, anchor->offset [0]); - res_pts [1] = cell_offset_calc_pt (sheet, r->start.row, - FALSE, anchor->offset [1]); - res_pts [2] = cell_offset_calc_pt (sheet, r->end.col, - TRUE, anchor->offset [2]); - res_pts [3] = cell_offset_calc_pt (sheet, r->end.row, - FALSE, anchor->offset [3]); + if (anchor->mode != GNM_SO_ANCHOR_ABSOLUTE) { + res_pts [0] = cell_offset_calc_pt (sheet, r->start.col, + TRUE, anchor->offset [0]); + res_pts [1] = cell_offset_calc_pt (sheet, r->start.row, + FALSE, anchor->offset [1]); + if (anchor->mode == GNM_SO_ANCHOR_TWO_CELLS) { + res_pts [2] = cell_offset_calc_pt (sheet, r->end.col, + TRUE, anchor->offset [2]); + res_pts [3] = cell_offset_calc_pt (sheet, r->end.row, + FALSE, anchor->offset [3]); + } + } } static void @@ -965,7 +1096,8 @@ sheet_objects_relocate (GnmExprRelocateInfo const *rinfo, gboolean update, GnmRange r = so->anchor.cell_bound; next = ptr->next; - if (update && 0 == (so->flags & SHEET_OBJECT_MOVE_WITH_CELLS)) + if ((so->anchor.mode == GNM_SO_ANCHOR_ABSOLUTE) || + (update && 0 == (so->flags & SHEET_OBJECT_MOVE_WITH_CELLS))) continue; if (range_contains (&rinfo->origin, r.start.col, r.start.row)) { /* FIXME : just moving the range is insufficent for all anchor types */ @@ -1178,6 +1310,7 @@ sheet_object_rubber_band_directly (G_GNUC_UNUSED SheetObject const *so) * @cell_bound: #GnmRange * @offsets: double[4] * @direction: #GODrawingAnchorDir + * @mode: #GnmSOAnchorMode * * A utility routine to initialize an anchor. Useful in case we change fields * in the future and want to ensure that everything is initialized. @@ -1185,7 +1318,8 @@ sheet_object_rubber_band_directly (G_GNUC_UNUSED SheetObject const *so) void sheet_object_anchor_init (SheetObjectAnchor *anchor, GnmRange const *r, const double *offsets, - GODrawingAnchorDir direction) + GODrawingAnchorDir direction, + GnmSOAnchorMode mode) { int i; @@ -1203,6 +1337,7 @@ sheet_object_anchor_init (SheetObjectAnchor *anchor, anchor->offset[i] = offsets [i]; anchor->base.direction = direction; + anchor->mode = mode; /* TODO : add sanity checking to handle offsets past edges of col/row */ } @@ -1266,6 +1401,19 @@ sheet_object_adjust_stacking (SheetObject *so, gint offset) return cur - i; } +void +sheet_object_set_anchor_mode (SheetObject *so, GnmSOAnchorMode const *mode) +{ + /* FIXME: adjust offsets according to the old and new modes */ + double pts[4]; + + if (so->anchor.mode == *mode) + return; + sheet_object_anchor_to_pts (&so->anchor, so->sheet, pts); + so->anchor.mode = *mode; + sheet_object_pts_to_anchor (&so->anchor, so->sheet, pts); +} + /*****************************************************************************/ static GObjectClass *view_parent_class; diff --git a/src/sheet-object.h b/src/sheet-object.h index 245d90cee..4d035bf59 100644 --- a/src/sheet-object.h +++ b/src/sheet-object.h @@ -17,11 +17,18 @@ typedef enum { GNM_SO_RESIZE_NONE /* can't be resized like some sheet components */ } GnmSOResizeMode; +typedef enum { + GNM_SO_ANCHOR_TWO_CELLS, /* move and size (if sizeable) with cells) */ + GNM_SO_ANCHOR_ONE_CELL, /* move with cells */ + GNM_SO_ANCHOR_ABSOLUTE /* anchored to the sheet */ +} GnmSOAnchorMode; + struct _SheetObjectAnchor { GODrawingAnchor base; GnmRange cell_bound; /* cellpos containing corners */ double offset[4]; /* offsets from the top left (in LTR of cell_bound) */ + GnmSOAnchorMode mode; }; GType sheet_object_anchor_get_type (void); /* Boxed type */ @@ -99,6 +106,7 @@ void sheet_objects_dup (Sheet const *src, Sheet *dst, GnmRange *range); void sheet_object_direction_set (SheetObject *so, gdouble const *coords); gboolean sheet_object_rubber_band_directly (SheetObject const *so); +void sheet_object_set_anchor_mode (SheetObject *so, GnmSOAnchorMode const *mode); /* Anchor utilities */ void sheet_object_anchor_to_pts (SheetObjectAnchor const *anchor, @@ -108,7 +116,10 @@ void sheet_object_anchor_to_offset_pts (SheetObjectAnchor const *anchor, void sheet_object_anchor_init (SheetObjectAnchor *anchor, GnmRange const *cell_bound, const double *offsets, - GODrawingAnchorDir direction); + GODrawingAnchorDir direction, + GnmSOAnchorMode mode); +void sheet_object_pts_to_anchor (SheetObjectAnchor *anchor, + Sheet const *sheet, double const *res_pts); SheetObjectAnchor * sheet_object_anchor_dup (SheetObjectAnchor const *src); diff --git a/src/tools/ChangeLog b/src/tools/ChangeLog index dec458bf4..f548e7e7d 100644 --- a/src/tools/ChangeLog +++ b/src/tools/ChangeLog @@ -1,3 +1,9 @@ +2015-03-30 Jean Brefort + + reviewed by: + + * dao.c (dao_set_sheet_object): + 2015-03-04 Morten Welinder * Release 1.12.21 diff --git a/src/tools/dao.c b/src/tools/dao.c index 7381be9ba..7e45cee60 100644 --- a/src/tools/dao.c +++ b/src/tools/dao.c @@ -1183,7 +1183,8 @@ dao_set_sheet_object (data_analysis_output_t *dao, int col, int row, SheetObject dao->start_col + ((dao->cols < 5) ? dao->cols : 5), dao->start_row + ((dao->rows < 20) ? dao->rows : 20)); - sheet_object_anchor_init (&anchor, &anchor_r, NULL, GOD_ANCHOR_DIR_UNKNOWN); + sheet_object_anchor_init (&anchor, &anchor_r, NULL, GOD_ANCHOR_DIR_UNKNOWN, + GNM_SO_ANCHOR_TWO_CELLS); sheet_object_set_anchor (so, &anchor); sheet_object_set_sheet (so, dao->sheet); diff --git a/src/widgets/ChangeLog b/src/widgets/ChangeLog index 74edf4dfa..f69ae07bc 100644 --- a/src/widgets/ChangeLog +++ b/src/widgets/ChangeLog @@ -1,3 +1,8 @@ +2015-03-30 Jean Brefort + + * Makefile.am: new widget for sheet objects anchor mode support. + * gnm-so-anchor-mode-chooser.[c,h]: ditto. + 2015-03-04 Morten Welinder * Release 1.12.21 diff --git a/src/widgets/Makefile.am b/src/widgets/Makefile.am index b10b8237c..07a3dc226 100644 --- a/src/widgets/Makefile.am +++ b/src/widgets/Makefile.am @@ -27,6 +27,8 @@ libwidgets_la_SOURCES = \ gnm-validation-combo-view.h \ gnm-sheet-slicer-combo-view.c \ gnm-sheet-slicer-combo-view.h \ + gnm-so-anchor-mode-chooser.c \ + gnm-so-anchor-mode-chooser.h \ gnumeric-cell-renderer-text.c \ gnumeric-cell-renderer-text.h \ gnumeric-cell-renderer-expr-entry.c \ diff --git a/src/widgets/gnm-so-anchor-mode-chooser.c b/src/widgets/gnm-so-anchor-mode-chooser.c new file mode 100644 index 000000000..9ec8a9957 --- /dev/null +++ b/src/widgets/gnm-so-anchor-mode-chooser.c @@ -0,0 +1,97 @@ +/* vim: set sw=8: -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ +/* + * gnm-so-anchor-mode-chooser.c + * + * Copyright (C) 2015 Jean Bréfort + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + * USA + */ + +#include +#include +#include "gnm-so-anchor-mode-chooser.h" +#include +#include + +struct _GnmSOAnchorModeChooser{ + GtkComboBox parent; +}; +typedef GtkComboBoxClass GnmSOAnchorModeChooserClass; + + +GtkWidget * +gnm_so_anchor_mode_chooser_new (gboolean resize) +{ + GtkWidget *widget = g_object_new (GNM_SO_ANCHOR_MODE_CHOOSER_TYPE, NULL); + GtkListStore *model = gtk_list_store_new (2, G_TYPE_STRING, G_TYPE_INT); + GtkCellRenderer *cell = gtk_cell_renderer_text_new (); + GtkTreeIter iter; + gtk_combo_box_set_model (GTK_COMBO_BOX (widget), GTK_TREE_MODEL (model)); + gtk_cell_layout_pack_start (GTK_CELL_LAYOUT (widget), cell, TRUE); + gtk_cell_layout_set_attributes (GTK_CELL_LAYOUT (widget), cell, + "text", 0, NULL); + if (resize) { + gtk_list_store_append (model, &iter); + gtk_list_store_set (model, &iter, 0, _("Move and resize with cells"), 1, GNM_SO_ANCHOR_TWO_CELLS, -1); + } + gtk_list_store_append (model, &iter); + gtk_list_store_set (model, &iter, 0, _("Move with cells"), 1, GNM_SO_ANCHOR_ONE_CELL, -1); + gtk_list_store_append (model, &iter); + gtk_list_store_set (model, &iter, 0, _("Absolute size and position"), 1, GNM_SO_ANCHOR_ABSOLUTE, -1); + return widget; +} + +void +gnm_so_anchor_mode_chooser_set_mode (GnmSOAnchorModeChooser *chooser, + GnmSOAnchorMode mode) +{ + GtkTreeModel *model; + GtkTreeIter iter; + GtkComboBox *combo; + GnmSOAnchorMode cur; + g_return_if_fail (GNM_IS_SO_ANCHOR_MODE_CHOOSER (chooser)); + + combo = GTK_COMBO_BOX (chooser); + model = gtk_combo_box_get_model (combo); + if (!gtk_tree_model_get_iter_first (model, &iter)) + return; + do { + gtk_tree_model_get (model, &iter, 1, &cur, -1); + if (cur == mode) { + gtk_combo_box_set_active_iter (combo, &iter); + return; + } + } while (gtk_tree_model_iter_next (model, &iter)); +} + +GnmSOAnchorMode +gnm_so_anchor_mode_chooser_get_mode (GnmSOAnchorModeChooser const *chooser) +{ + GtkTreeIter iter; + GtkComboBox *combo; + GnmSOAnchorMode mode; + g_return_val_if_fail (GNM_IS_SO_ANCHOR_MODE_CHOOSER (chooser), GNM_SO_ANCHOR_ONE_CELL); + + combo = GTK_COMBO_BOX (chooser); + if (!gtk_combo_box_get_active_iter (combo, &iter)) + return GNM_SO_ANCHOR_ONE_CELL; + gtk_tree_model_get (gtk_combo_box_get_model (combo), &iter, 1, &mode, -1); + return mode; +} + +GSF_CLASS (GnmSOAnchorModeChooser, gnm_so_anchor_mode_chooser, + NULL, NULL, + GTK_TYPE_COMBO_BOX) diff --git a/src/widgets/gnm-so-anchor-mode-chooser.h b/src/widgets/gnm-so-anchor-mode-chooser.h new file mode 100644 index 000000000..d32cea46d --- /dev/null +++ b/src/widgets/gnm-so-anchor-mode-chooser.h @@ -0,0 +1,42 @@ +/* vim: set sw=8: -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ +/* + * gnm-so-anchor-mode-chooser.h + * + * Copyright (C) 2015 Jean Bréfort + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + * USA + */ + +#ifndef GNM_SO_ANCHOR_MODE_CHOOSER_H +#define GNM_SO_ANCHOR_MODE_CHOOSER_H + +#include "gnumeric.h" +#include "sheet-object.h" +#include + +typedef struct _GnmSOAnchorModeChooser GnmSOAnchorModeChooser; + +#define GNM_SO_ANCHOR_MODE_CHOOSER_TYPE (gnm_so_anchor_mode_chooser_get_type ()) +#define GNM_SO_ANCHOR_MODE_CHOOSER(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), GNM_SO_ANCHOR_MODE_CHOOSER_TYPE, GnmSOAnchorModeChooser)) +#define GNM_IS_SO_ANCHOR_MODE_CHOOSER(o) (G_TYPE_CHECK_INSTANCE_TYPE((o), GNM_SO_ANCHOR_MODE_CHOOSER_TYPE)) +GType gnm_so_anchor_mode_chooser_get_type (void); + +GtkWidget *gnm_so_anchor_mode_chooser_new (gboolean resize); +void gnm_so_anchor_mode_chooser_set_mode (GnmSOAnchorModeChooser *chooser, + GnmSOAnchorMode mode); +GnmSOAnchorMode gnm_so_anchor_mode_chooser_get_mode (GnmSOAnchorModeChooser const *chooser); + +#endif /* GNM_SO_ANCHOR_MODE_CHOOSER_H */ diff --git a/src/workbook-view.c b/src/workbook-view.c index d439b9dc4..d9ba25c61 100644 --- a/src/workbook-view.c +++ b/src/workbook-view.c @@ -341,7 +341,7 @@ wb_view_style_feedback (WorkbookView *wbv) GnmRange const *r; if (NULL == (r = gnm_sheet_merge_contains_pos (sv->sheet, &sv->edit_pos))) r = range_init_cellpos (&corner, &sv->edit_pos); - sheet_object_anchor_init (&anchor, r, a_offsets, GOD_ANCHOR_DIR_DOWN_RIGHT); + sheet_object_anchor_init (&anchor, r, a_offsets, GOD_ANCHOR_DIR_DOWN_RIGHT, GNM_SO_ANCHOR_TWO_CELLS); sheet_object_set_anchor (wbv->in_cell_combo, &anchor); sheet_object_set_sheet (wbv->in_cell_combo, sv->sheet); } diff --git a/src/xml-sax-read.c b/src/xml-sax-read.c index acf6d446b..8f334b765 100644 --- a/src/xml-sax-read.c +++ b/src/xml-sax-read.c @@ -2327,6 +2327,7 @@ xml_sax_read_obj (GsfXMLIn *xin, gboolean needs_cleanup, SheetObjectClass *klass; GnmRange anchor_r; GODrawingAnchorDir anchor_dir; + GnmSOAnchorMode anchor_mode; SheetObjectAnchor anchor; double f_tmp[4], *anchor_offset = NULL; @@ -2390,13 +2391,25 @@ xml_sax_read_obj (GsfXMLIn *xin, gboolean needs_cleanup, state->so = so; anchor_dir = GOD_ANCHOR_DIR_UNKNOWN; + anchor_mode = GNM_SO_ANCHOR_TWO_CELLS; /* Provide a default. */ anchor_r = sheet_object_get_anchor (so)->cell_bound; for (i = 0; attrs != NULL && attrs[i] && attrs[i + 1] ; i += 2) { if (attr_eq (attrs[i], "Name")) sheet_object_set_name (so, CXML2C (attrs[i + 1])); - else if (attr_eq (attrs[i], "ObjectBound")) + else if (!strcmp (attrs[i], "AnchorMode")) { + if (!strcmp (attrs[i+1], "one cell")) + anchor_mode = GNM_SO_ANCHOR_ONE_CELL; + else if (!strcmp (attrs[i+1], "absolute") ) + anchor_mode = GNM_SO_ANCHOR_ABSOLUTE; + else { + char *str = g_strdup_printf (_("Unknown object anchor mode '%s'"), + attrs[i+1]); + go_io_warning_unsupported_feature (state->context, str); + g_free (str); + } + } else if (attr_eq (attrs[i], "ObjectBound")) range_parse (&anchor_r, CXML2C (attrs[i + 1]), gnm_sheet_get_size (state->sheet)); else if (attr_eq (attrs[i], "ObjectOffset") && 4 == sscanf (CXML2C (attrs[i + 1]), "%lg %lg %lg %lg", @@ -2416,7 +2429,7 @@ xml_sax_read_obj (GsfXMLIn *xin, gboolean needs_cleanup, if (G_OBJECT_TYPE (so) == GNM_CELL_COMMENT_TYPE) anchor_r.end = anchor_r.start; - sheet_object_anchor_init (&anchor, &anchor_r, anchor_offset, anchor_dir); + sheet_object_anchor_init (&anchor, &anchor_r, anchor_offset, anchor_dir, anchor_mode); sheet_object_set_anchor (so, &anchor); if (NULL != klass->prep_sax_parser) diff --git a/src/xml-sax-write.c b/src/xml-sax-write.c index 5055b8fc9..1a5ead048 100644 --- a/src/xml-sax-write.c +++ b/src/xml-sax-write.c @@ -1263,7 +1263,12 @@ xml_write_objects (GnmOutputXML *state, GSList *objects) gsf_xml_out_start_element (state->output, tmp); if (so->name) gsf_xml_out_add_cstr (state->output, "Name", so->name); - gsf_xml_out_add_cstr (state->output, "ObjectBound", range_as_string (&so->anchor.cell_bound)); + if (so->anchor.mode != GNM_SO_ANCHOR_ABSOLUTE) + gsf_xml_out_add_cstr (state->output, "ObjectBound", range_as_string (&so->anchor.cell_bound)); + if (so->anchor.mode != GNM_SO_ANCHOR_TWO_CELLS) + gsf_xml_out_add_cstr_unchecked (state->output, "AnchorMode", + (so->anchor.mode == GNM_SO_ANCHOR_ONE_CELL)? + "one cell": "absolute"); snprintf (buffer, sizeof (buffer), "%.3g %.3g %.3g %.3g", so->anchor.offset [0], so->anchor.offset [1], so->anchor.offset [2], so->anchor.offset [3]); -- 2.11.4.GIT