[gnumeric] Make graphs (and images) not resize with cells by default. [#684450]



commit a57d6d8ccf7783813775be632de589942613cc2d
Author: Jean Brefort <jean brefort normalesup org>
Date:   Mon Mar 30 17:00:54 2015 +0200

    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(-)
---
diff --git a/ChangeLog b/ChangeLog
index 9fce848..232941d 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,20 @@
+2015-03-30  Jean Brefort  <jean brefort normalesup org>
+
+       * 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  <terra gnome org>
 
        * src/xml-sax-read.c (grammar): Use new libgsf check for "2nd".
diff --git a/NEWS b/NEWS
index 95c1ea8..a89be5e 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 c9280da..3798843 100644
--- a/plugins/excel/ChangeLog
+++ b/plugins/excel/ChangeLog
@@ -1,3 +1,18 @@
+2015-03-30  Jean Brefort  <jean brefort normalesup org>
+
+       * 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  <terra gnome org>
 
        * 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 31dab39..e90d9e5 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 379b092..a265dca 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 4b54323..b547de2 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 7daf59b..cc2ab5c 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 887ab8e..d557e7e 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 33708e4..61ef640 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 da6bd6d..e64ab84 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 c3801af..fd4d9f1 100644
--- a/plugins/openoffice/ChangeLog
+++ b/plugins/openoffice/ChangeLog
@@ -1,3 +1,10 @@
+2015-03-30  Jean Brefort  <jean brefort normalesup org>
+
+       * 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 <aguelzow pyrshep ca>
 
        * openoffice-write.c (-odf_write_circle_axes_styles): deleted
diff --git a/plugins/openoffice/openoffice-read.c b/plugins/openoffice/openoffice-read.c
index 0712a62..a36d27b 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 a1e5c4d..ad6e316 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 35dd15b..17d1c7c 100644
--- a/src/dialogs/ChangeLog
+++ b/src/dialogs/ChangeLog
@@ -1,3 +1,10 @@
+2015-03-30  Jean Brefort  <jean brefort normalesup org>
+
+       * 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 <terra gnome org>
 
        * Release 1.12.21
diff --git a/src/dialogs/dialog-sheetobject-size.c b/src/dialogs/dialog-sheetobject-size.c
index d083356..b7a980c 100644
--- a/src/dialogs/dialog-sheetobject-size.c
+++ b/src/dialogs/dialog-sheetobject-size.c
@@ -40,6 +40,7 @@
 #include <sheet-object-widget.h>
 #include <sheet-object-impl.h>
 #include <sheet-control-gui.h>
+#include <widgets/gnm-so-anchor-mode-chooser.h>
 
 #include <gtk/gtk.h>
 
@@ -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 35e47f4..0fa2c86 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 9afe91f..ecf321d 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 08aa88f..1e01bfb 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 056eebc..3db6529 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 0023094..51c3e0f 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 f1c0a80..c9f14f7 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 58e9517..7436808 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 8857226..258c973 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 4704ea3..a857813 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 245d90c..4d035bf 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 dec458b..f548e7e 100644
--- a/src/tools/ChangeLog
+++ b/src/tools/ChangeLog
@@ -1,3 +1,9 @@
+2015-03-30  Jean Brefort  <jean brefort normalesup org>
+
+       reviewed by: <delete if not using a buddy>
+
+       * dao.c (dao_set_sheet_object):
+
 2015-03-04  Morten Welinder <terra gnome org>
 
        * Release 1.12.21
diff --git a/src/tools/dao.c b/src/tools/dao.c
index 7381be9..7e45cee 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 74edf4d..f69ae07 100644
--- a/src/widgets/ChangeLog
+++ b/src/widgets/ChangeLog
@@ -1,3 +1,8 @@
+2015-03-30  Jean Brefort  <jean brefort normalesup org>
+
+       * Makefile.am: new widget for sheet objects anchor mode support.
+       * gnm-so-anchor-mode-chooser.[c,h]: ditto.
+
 2015-03-04  Morten Welinder <terra gnome org>
 
        * Release 1.12.21
diff --git a/src/widgets/Makefile.am b/src/widgets/Makefile.am
index b10b823..07a3dc2 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 0000000..9ec8a99
--- /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 <jean brefort normalesup org>
+ *
+ * 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 <gnumeric-config.h>
+#include <gtk/gtk.h>
+#include "gnm-so-anchor-mode-chooser.h"
+#include <gsf/gsf-impl-utils.h>
+#include <glib/gi18n-lib.h>
+
+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 0000000..d32cea4
--- /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 <jean brefort normalesup org>
+ *
+ * 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 <glib-object.h>
+
+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 d439b9d..d9ba25c 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 acf6d44..8f334b7 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 5055b8f..1a5ead0 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]);


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]