changeset 12401:88e8779f525e release-3-4-x

implement autopositioning requests from text objects to axes
author Konstantinos Poulios <logari81@googlemail.com>
date Sun, 06 Feb 2011 17:17:12 +0100
parents f16a5244d93a
children 766426578c14
files src/ChangeLog src/graphics.cc src/graphics.h.in
diffstat 3 files changed, 374 insertions(+), 258 deletions(-) [+]
line wrap: on
line diff
--- a/src/ChangeLog
+++ b/src/ChangeLog
@@ -1,3 +1,32 @@
+2011-02-06  Konstantinos Poulios  <logari81@googlemail.com>
+
+	* graphics.h.in (class axes::properties): Tag positionmode,
+	rotationmode, horizontalalignmentmode, verticalalignmentmode
+	with "u" qualifier.	New hidden property autopos_tag.
+	(axes::properties::request_autopos,
+	axes::properties::update_positionmode,
+	axes::properties::update_rotationmode,
+	axes::properties::update_horizontalalignmentmode,
+	axes::properties::update_verticalalignmentmode): New functions
+	(base_properties::update_autopos): New virtual function.
+	(axes::properties::update_xlabel_position,
+	axes::properties::update_ylabel_position,
+	axes::properties::update_zlabel_position,
+	axes::properties::update_title_position): Made public.
+	* graphics.cc (base_properties::update_autopos,
+	axes::properties::update_autopos,
+	text::properties::request_autopos): New functions.
+	(axes::properties::init, axes::properties::set_defaults,
+	axes::properties::set_xlabel, axes::properties::set_ylabel,
+	axes::properties::set_zlabel, axes::properties::set_title):
+	Set autopos_tag for {x,y,z}label and title.
+	(axes::properties::update_xlabel_position,
+	axes::properties::update_ylabel_position,
+	axes::properties::update_zlabel_position,
+	axes::properties::update_title_position): Run only for non-empty
+	strings. Set autopos_tag temporarily to none in order to prevent
+	race conditions.
+
 2011-02-06  Konstantinos Poulios  <logari81@googlemail.com>
 
 	* graphics.cc: Untabify and improve indentation.
--- a/src/graphics.cc
+++ b/src/graphics.cc
@@ -2271,6 +2271,15 @@
 }
 
 void
+base_properties::update_autopos (const std::string& elem_type)
+{
+  graphics_object parent_obj = gh_manager::get_object (get_parent ());
+
+  if (parent_obj.valid_object ())
+    parent_obj.get_properties ().update_autopos (elem_type);
+}
+
+void
 base_properties::add_listener (const caseless_str& nm, const octave_value& v,
                                listener_mode mode)
 {
@@ -3209,6 +3218,11 @@
   xset (zlabel.handle_value (), "clipping", "off");
   xset (title.handle_value (), "clipping", "off");
 
+  xset (xlabel.handle_value (), "autopos_tag", "xlabel");
+  xset (ylabel.handle_value (), "autopos_tag", "ylabel");
+  xset (zlabel.handle_value (), "autopos_tag", "zlabel");
+  xset (title.handle_value (), "autopos_tag", "title");
+
   adopt (xlabel.handle_value ());
   adopt (ylabel.handle_value ());
   adopt (zlabel.handle_value ());
@@ -3301,6 +3315,7 @@
   xset (xlabel.handle_value (), "verticalalignmentmode", "auto");
   xset (xlabel.handle_value (), "clipping", "off");
   xset (xlabel.handle_value (), "color", get_xcolor ());
+  xset (xlabel.handle_value (), "autopos_tag", "xlabel");
   update_xlabel_position ();
 }
 
@@ -3314,6 +3329,7 @@
   xset (ylabel.handle_value (), "verticalalignmentmode", "auto");
   xset (ylabel.handle_value (), "clipping", "off");
   xset (ylabel.handle_value (), "color", get_ycolor ());
+  xset (ylabel.handle_value (), "autopos_tag", "ylabel");
   update_ylabel_position ();
 }
 
@@ -3327,6 +3343,7 @@
   xset (zlabel.handle_value (), "verticalalignmentmode", "auto");
   xset (zlabel.handle_value (), "clipping", "off");
   xset (zlabel.handle_value (), "color", get_zcolor ());
+  xset (zlabel.handle_value (), "autopos_tag", "zlabel");
   update_zlabel_position ();
 }
 
@@ -3340,6 +3357,7 @@
   xset (title.handle_value (), "verticalalignment", "bottom");
   xset (title.handle_value (), "verticalalignmentmode", "auto");
   xset (title.handle_value (), "clipping", "off");
+  xset (title.handle_value (), "autopos_tag", "title");
   update_title_position ();
 }
 
@@ -3485,6 +3503,11 @@
   xset (zlabel.handle_value (), "clipping", "off");
   xset (title.handle_value (), "clipping", "off");
 
+  xset (xlabel.handle_value (), "autopos_tag", "xlabel");
+  xset (ylabel.handle_value (), "autopos_tag", "ylabel");
+  xset (zlabel.handle_value (), "autopos_tag", "zlabel");
+  xset (title.handle_value (), "autopos_tag", "title");
+
   adopt (xlabel.handle_value ());
   adopt (ylabel.handle_value ());
   adopt (zlabel.handle_value ());
@@ -4103,72 +4126,79 @@
   text::properties& xlabel_props = reinterpret_cast<text::properties&>
     (gh_manager::get_object (get_xlabel ()).get_properties ());
 
-  if (xlabel_props.horizontalalignmentmode_is ("auto"))
-    {
-      xlabel_props.set_horizontalalignment
-        (xstate > AXE_DEPTH_DIR
-         ? "center" : (xyzSym ? "left" : "right"));
-
-      xlabel_props.set_horizontalalignmentmode ("auto");
-    }
-
-  if (xlabel_props.verticalalignmentmode_is ("auto"))
-    {
-      xlabel_props.set_verticalalignment
-        (xstate == AXE_VERT_DIR || x2Dtop ? "bottom" : "top");
-
-      xlabel_props.set_verticalalignmentmode ("auto");
-    }
-
-  if (xlabel_props.positionmode_is ("auto")
-      || xlabel_props.rotationmode_is ("auto"))
-    {
-      Matrix ext (1, 2, 0.0);
-      ext = get_ticklabel_extents (get_xtick ().matrix_value (),
-                                   get_xticklabel ().all_strings (),
-                                   get_xlim ().matrix_value ());
-
-      double wmax = ext(0), hmax = ext(1), angle = 0;
-      ColumnVector p =
-        graphics_xform::xform_vector ((xpTickN+xpTick)/2, ypTick, zpTick);
-
-      bool tick_along_z = nearhoriz || xisinf (fy);
-      if (tick_along_z)
-        p(2) += (signum(zpTick-zpTickN)*fz*xtickoffset);
-      else
-        p(1) += (signum(ypTick-ypTickN)*fy*xtickoffset);
-
-      p = xform.transform (p(0), p(1), p(2), false);
-
-      switch (xstate)
-        {
-          case AXE_ANY_DIR:
-            p(0) += (xyzSym ? wmax : -wmax);
-            p(1) += hmax;
-            break;
-
-          case AXE_VERT_DIR:
-            p(0) -= wmax;
-            angle = 90;
-            break;
-
-          case AXE_HORZ_DIR:
-            p(1) += (x2Dtop ? -hmax : hmax);
-            break;
-        }
-
-      if (xlabel_props.positionmode_is ("auto"))
-        {
-          p = xform.untransform (p(0), p(1), p(2), true);
-          xlabel_props.set_position (p.extract_n (0, 3).transpose ());
-          xlabel_props.set_positionmode ("auto");
-        }
-
-      if (xlabel_props.rotationmode_is ("auto"))
-        {
-          xlabel_props.set_rotation (angle);
-          xlabel_props.set_rotationmode ("auto");
-        }
+  if (! xlabel_props.get_string ().empty ())
+    {
+      xlabel_props.set_autopos_tag ("none");
+
+      if (xlabel_props.horizontalalignmentmode_is ("auto"))
+        {
+          xlabel_props.set_horizontalalignment
+            (xstate > AXE_DEPTH_DIR
+             ? "center" : (xyzSym ? "left" : "right"));
+
+          xlabel_props.set_horizontalalignmentmode ("auto");
+        }
+
+      if (xlabel_props.verticalalignmentmode_is ("auto"))
+        {
+          xlabel_props.set_verticalalignment
+            (xstate == AXE_VERT_DIR || x2Dtop ? "bottom" : "top");
+
+          xlabel_props.set_verticalalignmentmode ("auto");
+        }
+
+      if (xlabel_props.positionmode_is ("auto")
+          || xlabel_props.rotationmode_is ("auto"))
+        {
+          Matrix ext (1, 2, 0.0);
+          ext = get_ticklabel_extents (get_xtick ().matrix_value (),
+                                       get_xticklabel ().all_strings (),
+                                       get_xlim ().matrix_value ());
+
+          double wmax = ext(0), hmax = ext(1), angle = 0;
+          ColumnVector p =
+            graphics_xform::xform_vector ((xpTickN+xpTick)/2, ypTick, zpTick);
+
+          bool tick_along_z = nearhoriz || xisinf (fy);
+          if (tick_along_z)
+            p(2) += (signum(zpTick-zpTickN)*fz*xtickoffset);
+          else
+            p(1) += (signum(ypTick-ypTickN)*fy*xtickoffset);
+
+          p = xform.transform (p(0), p(1), p(2), false);
+
+          switch (xstate)
+            {
+              case AXE_ANY_DIR:
+                p(0) += (xyzSym ? wmax : -wmax);
+                p(1) += hmax;
+                break;
+
+              case AXE_VERT_DIR:
+                p(0) -= wmax;
+                angle = 90;
+                break;
+
+              case AXE_HORZ_DIR:
+                p(1) += (x2Dtop ? -hmax : hmax);
+                break;
+            }
+
+          if (xlabel_props.positionmode_is ("auto"))
+            {
+              p = xform.untransform (p(0), p(1), p(2), true);
+              xlabel_props.set_position (p.extract_n (0, 3).transpose ());
+              xlabel_props.set_positionmode ("auto");
+            }
+
+          if (xlabel_props.rotationmode_is ("auto"))
+            {
+              xlabel_props.set_rotation (angle);
+              xlabel_props.set_rotationmode ("auto");
+            }
+        }
+
+      xlabel_props.set_autopos_tag ("xlabel");
     }
 }
 
@@ -4180,72 +4210,79 @@
   text::properties& ylabel_props = reinterpret_cast<text::properties&>
     (gh_manager::get_object (get_ylabel ()).get_properties ());
 
-  if (ylabel_props.horizontalalignmentmode_is ("auto"))
-    {
-      ylabel_props.set_horizontalalignment
-        (ystate > AXE_DEPTH_DIR
-         ? "center" : (!xyzSym ? "left" : "right"));
-
-      ylabel_props.set_horizontalalignmentmode ("auto");
-    }
-
-  if (ylabel_props.verticalalignmentmode_is ("auto"))
-    {
-      ylabel_props.set_verticalalignment
-        (ystate == AXE_VERT_DIR && !y2Dright ? "bottom" : "top");
-
-      ylabel_props.set_verticalalignmentmode ("auto");
-    }
-
-  if (ylabel_props.positionmode_is ("auto")
-      || ylabel_props.rotationmode_is ("auto"))
-    {
-      Matrix ext (1, 2, 0.0);
-      ext = get_ticklabel_extents (get_ytick ().matrix_value (),
-                                   get_yticklabel ().all_strings (),
-                                   get_ylim ().matrix_value ());
-
-      double wmax = ext(0), hmax = ext(1), angle = 0;
-      ColumnVector p =
-        graphics_xform::xform_vector (xpTick, (ypTickN+ypTick)/2, zpTick);
-
-      bool tick_along_z = nearhoriz || xisinf (fx);
-      if (tick_along_z)
-        p(2) += (signum(zpTick-zpTickN)*fz*ytickoffset);
-      else
-        p(0) += (signum(xpTick-xpTickN)*fx*ytickoffset);
-
-      p = xform.transform (p(0), p(1), p(2), false);
-
-      switch (ystate)
-        {
-          case AXE_ANY_DIR:
-            p(0) += (!xyzSym ? wmax : -wmax);
-            p(1) += hmax;
-            break;
-
-          case AXE_VERT_DIR:
-            p(0) += (y2Dright ? wmax : -wmax);
-            angle = 90;
-            break;
-
-          case AXE_HORZ_DIR:
-            p(1) += hmax;
-            break;
-        }
-
-      if (ylabel_props.positionmode_is ("auto"))
-        {
-          p = xform.untransform (p(0), p(1), p(2), true);
-          ylabel_props.set_position (p.extract_n (0, 3).transpose ());
-          ylabel_props.set_positionmode ("auto");
-        }
-
-      if (ylabel_props.rotationmode_is ("auto"))
-        {
-          ylabel_props.set_rotation (angle);
-          ylabel_props.set_rotationmode ("auto");
-        }
+  if (! ylabel_props.get_string ().empty ())
+    {
+      ylabel_props.set_autopos_tag ("none");
+
+      if (ylabel_props.horizontalalignmentmode_is ("auto"))
+        {
+          ylabel_props.set_horizontalalignment
+            (ystate > AXE_DEPTH_DIR
+             ? "center" : (!xyzSym ? "left" : "right"));
+
+          ylabel_props.set_horizontalalignmentmode ("auto");
+        }
+
+      if (ylabel_props.verticalalignmentmode_is ("auto"))
+        {
+          ylabel_props.set_verticalalignment
+            (ystate == AXE_VERT_DIR && !y2Dright ? "bottom" : "top");
+
+          ylabel_props.set_verticalalignmentmode ("auto");
+        }
+
+      if (ylabel_props.positionmode_is ("auto")
+          || ylabel_props.rotationmode_is ("auto"))
+        {
+          Matrix ext (1, 2, 0.0);
+          ext = get_ticklabel_extents (get_ytick ().matrix_value (),
+                                       get_yticklabel ().all_strings (),
+                                       get_ylim ().matrix_value ());
+
+          double wmax = ext(0), hmax = ext(1), angle = 0;
+          ColumnVector p =
+            graphics_xform::xform_vector (xpTick, (ypTickN+ypTick)/2, zpTick);
+
+          bool tick_along_z = nearhoriz || xisinf (fx);
+          if (tick_along_z)
+            p(2) += (signum(zpTick-zpTickN)*fz*ytickoffset);
+          else
+            p(0) += (signum(xpTick-xpTickN)*fx*ytickoffset);
+
+          p = xform.transform (p(0), p(1), p(2), false);
+
+          switch (ystate)
+            {
+              case AXE_ANY_DIR:
+                p(0) += (!xyzSym ? wmax : -wmax);
+                p(1) += hmax;
+                break;
+
+              case AXE_VERT_DIR:
+                p(0) += (y2Dright ? wmax : -wmax);
+                angle = 90;
+                break;
+
+              case AXE_HORZ_DIR:
+                p(1) += hmax;
+                break;
+            }
+
+          if (ylabel_props.positionmode_is ("auto"))
+            {
+              p = xform.untransform (p(0), p(1), p(2), true);
+              ylabel_props.set_position (p.extract_n (0, 3).transpose ());
+              ylabel_props.set_positionmode ("auto");
+            }
+
+          if (ylabel_props.rotationmode_is ("auto"))
+            {
+              ylabel_props.set_rotation (angle);
+              ylabel_props.set_rotationmode ("auto");
+            }
+        }
+
+      ylabel_props.set_autopos_tag ("ylabel");
     }
 }
 
@@ -4257,95 +4294,102 @@
   text::properties& zlabel_props = reinterpret_cast<text::properties&>
     (gh_manager::get_object (get_zlabel ()).get_properties ());
 
-  bool camAuto = cameraupvectormode_is ("auto");
-
-  if (zlabel_props.horizontalalignmentmode_is ("auto"))
-    {
-      zlabel_props.set_horizontalalignment
-        ((zstate > AXE_DEPTH_DIR || camAuto) ? "center" : "right");
-
-      zlabel_props.set_horizontalalignmentmode ("auto");
-    }
-
-  if (zlabel_props.verticalalignmentmode_is ("auto"))
-    {
-      zlabel_props.set_verticalalignment
-        (zstate == AXE_VERT_DIR
-         ? "bottom" : ((zSign || camAuto) ? "bottom" : "top"));
-
-      zlabel_props.set_verticalalignmentmode ("auto");
-    }
-
-  if (zlabel_props.positionmode_is ("auto")
-      || zlabel_props.rotationmode_is ("auto"))
-    {
-      Matrix ext (1, 2, 0.0);
-      ext = get_ticklabel_extents (get_ztick ().matrix_value (),
-                                   get_zticklabel ().all_strings (),
-                                   get_zlim ().matrix_value ());
-
-      double wmax = ext(0), hmax = ext(1), angle = 0;
-      ColumnVector p;
-
-      if (xySym)
-        {
-          p = graphics_xform::xform_vector (xPlaneN, yPlane,
-                                            (zpTickN+zpTick)/2);
-          if (xisinf (fy))
-            p(0) += (signum(xPlaneN-xPlane)*fx*ztickoffset);
+  if (! zlabel_props.get_string ().empty ())
+    {
+      zlabel_props.set_autopos_tag ("none");
+
+      bool camAuto = cameraupvectormode_is ("auto");
+
+      if (zlabel_props.horizontalalignmentmode_is ("auto"))
+        {
+          zlabel_props.set_horizontalalignment
+            ((zstate > AXE_DEPTH_DIR || camAuto) ? "center" : "right");
+
+          zlabel_props.set_horizontalalignmentmode ("auto");
+        }
+
+      if (zlabel_props.verticalalignmentmode_is ("auto"))
+        {
+          zlabel_props.set_verticalalignment
+            (zstate == AXE_VERT_DIR
+             ? "bottom" : ((zSign || camAuto) ? "bottom" : "top"));
+
+          zlabel_props.set_verticalalignmentmode ("auto");
+        }
+
+      if (zlabel_props.positionmode_is ("auto")
+          || zlabel_props.rotationmode_is ("auto"))
+        {
+          Matrix ext (1, 2, 0.0);
+          ext = get_ticklabel_extents (get_ztick ().matrix_value (),
+                                       get_zticklabel ().all_strings (),
+                                       get_zlim ().matrix_value ());
+
+          double wmax = ext(0), hmax = ext(1), angle = 0;
+          ColumnVector p;
+
+          if (xySym)
+            {
+              p = graphics_xform::xform_vector (xPlaneN, yPlane,
+                                                (zpTickN+zpTick)/2);
+              if (xisinf (fy))
+                p(0) += (signum(xPlaneN-xPlane)*fx*ztickoffset);
+              else
+                p(1) += (signum(yPlane-yPlaneN)*fy*ztickoffset);
+            }
           else
-            p(1) += (signum(yPlane-yPlaneN)*fy*ztickoffset);
-        }
-      else
-        {
-          p = graphics_xform::xform_vector (xPlane, yPlaneN,
-                                            (zpTickN+zpTick)/2);
-          if (xisinf (fx))
-            p(1) += (signum(yPlaneN-yPlane)*fy*ztickoffset);
-          else
-            p(0) += (signum(xPlane-xPlaneN)*fx*ztickoffset);
-        }
-
-      p = xform.transform (p(0), p(1), p(2), false);
-
-      switch (zstate)
-        {
-          case AXE_ANY_DIR:
-            if (camAuto)
-              {
+            {
+              p = graphics_xform::xform_vector (xPlane, yPlaneN,
+                                                (zpTickN+zpTick)/2);
+              if (xisinf (fx))
+                p(1) += (signum(yPlaneN-yPlane)*fy*ztickoffset);
+              else
+                p(0) += (signum(xPlane-xPlaneN)*fx*ztickoffset);
+            }
+
+          p = xform.transform (p(0), p(1), p(2), false);
+
+          switch (zstate)
+            {
+              case AXE_ANY_DIR:
+                if (camAuto)
+                  {
+                    p(0) -= wmax;
+                    angle = 90;
+                  }
+
+                // FIXME -- what's the correct offset?
+                //
+                //   p[0] += (!xySym ? wmax : -wmax);
+                //   p[1] += (zSign ? hmax : -hmax);
+
+                break;
+
+              case AXE_VERT_DIR:
                 p(0) -= wmax;
                 angle = 90;
-              }
-
-            // FIXME -- what's the correct offset?
-            //
-            //   p[0] += (!xySym ? wmax : -wmax);
-            //   p[1] += (zSign ? hmax : -hmax);
-
-            break;
-
-          case AXE_VERT_DIR:
-            p(0) -= wmax;
-            angle = 90;
-            break;
-
-          case AXE_HORZ_DIR:
-            p(1) += hmax;
-            break;
-        }
-
-      if (zlabel_props.positionmode_is ("auto"))
-        {
-          p = xform.untransform (p(0), p(1), p(2), true);
-          zlabel_props.set_position (p.extract_n (0, 3).transpose ());
-          zlabel_props.set_positionmode ("auto");
-        }
-
-      if (zlabel_props.rotationmode_is ("auto"))
-        {
-          zlabel_props.set_rotation (angle);
-          zlabel_props.set_rotationmode ("auto");
-        }
+                break;
+
+              case AXE_HORZ_DIR:
+                p(1) += hmax;
+                break;
+            }
+
+          if (zlabel_props.positionmode_is ("auto"))
+            {
+              p = xform.untransform (p(0), p(1), p(2), true);
+              zlabel_props.set_position (p.extract_n (0, 3).transpose ());
+              zlabel_props.set_positionmode ("auto");
+            }
+
+          if (zlabel_props.rotationmode_is ("auto"))
+            {
+              zlabel_props.set_rotation (angle);
+              zlabel_props.set_rotationmode ("auto");
+            }
+        }
+
+      zlabel_props.set_autopos_tag ("zlabel");
     }
 }
 
@@ -4357,36 +4401,56 @@
   text::properties& title_props = reinterpret_cast<text::properties&>
     (gh_manager::get_object (get_title ()).get_properties ());
 
-  if (title_props.positionmode_is ("auto"))
-    {
-      // FIXME: bbox should be stored in axes::properties
-      ColumnVector bbox(4);
-      bbox(0) = octave_Inf;
-      bbox(1) = octave_Inf;
-      bbox(2) = -octave_Inf;
-      bbox(3) = -octave_Inf;
-      for (int i = 0; i <= 1; i++)
-        for (int j = 0; j <= 1; j++)
-          for (int k = 0; k <= 1; k++)
-            {
-              ColumnVector p = xform.transform (i ? xPlaneN : xPlane,
-                                                j ? yPlaneN : yPlane,
-                                                k ? zPlaneN : zPlane, false);
-              bbox(0) = std::min (bbox(0), p(0));
-              bbox(1) = std::min (bbox(1), p(1));
-              bbox(2) = std::max (bbox(2), p(0));
-              bbox(3) = std::max (bbox(3), p(1));
-            }
-    
-      bbox(2) = bbox(2)-bbox(0);
-      bbox(3) = bbox(3)-bbox(1);
-
-      ColumnVector p = xform.untransform (bbox(0)+bbox(2)/2, (bbox(1)-10),
-                                          (x_zlim(0)+x_zlim(1))/2, true);
-
-      title_props.set_position (p.extract_n(0, 3).transpose ());
-      title_props.set_positionmode ("auto");
-    }
+  if (! title_props.get_string ().empty ())
+    {
+      title_props.set_autopos_tag ("none");
+
+      if (title_props.positionmode_is ("auto"))
+        {
+          // FIXME: bbox should be stored in axes::properties
+          ColumnVector bbox(4);
+          bbox(0) = octave_Inf;
+          bbox(1) = octave_Inf;
+          bbox(2) = -octave_Inf;
+          bbox(3) = -octave_Inf;
+          for (int i = 0; i <= 1; i++)
+            for (int j = 0; j <= 1; j++)
+              for (int k = 0; k <= 1; k++)
+                {
+                  ColumnVector p = xform.transform (i ? xPlaneN : xPlane,
+                                                    j ? yPlaneN : yPlane,
+                                                    k ? zPlaneN : zPlane, false);
+                  bbox(0) = std::min (bbox(0), p(0));
+                  bbox(1) = std::min (bbox(1), p(1));
+                  bbox(2) = std::max (bbox(2), p(0));
+                  bbox(3) = std::max (bbox(3), p(1));
+                }
+
+          bbox(2) = bbox(2)-bbox(0);
+          bbox(3) = bbox(3)-bbox(1);
+
+          ColumnVector p = xform.untransform (bbox(0)+bbox(2)/2, (bbox(1)-10),
+                                              (x_zlim(0)+x_zlim(1))/2, true);
+
+          title_props.set_position (p.extract_n(0, 3).transpose ());
+          title_props.set_positionmode ("auto");
+        }
+
+      title_props.set_autopos_tag ("title");
+    }
+}
+
+void
+axes::properties::update_autopos (const std::string& elem_type)
+{
+  if (elem_type == "xlabel")
+    update_xlabel_position ();
+  else if (elem_type == "ylabel")
+    update_ylabel_position ();
+  else if (elem_type == "zlabel")
+    update_zlabel_position ();
+  else if (elem_type == "title")
+    update_title_position ();
 }
 
 static void
@@ -5663,6 +5727,19 @@
 }
 
 void
+text::properties::request_autopos (void)
+{
+  if (autopos_tag_is ("xlabel") || autopos_tag_is ("ylabel") ||
+      autopos_tag_is ("zlabel") || autopos_tag_is ("title"))
+    {
+      const std::string text_type = get_autopos_tag ();
+      set_autopos_tag ("none");
+      update_autopos (text_type);
+      set_autopos_tag (text_type);
+    }
+}
+
+void
 text::properties::update_units (void)
 {
   if (! units_is ("data"))
--- a/src/graphics.h.in
+++ b/src/graphics.h.in
@@ -2065,6 +2065,8 @@
 
   virtual void update_boundingbox (void);
 
+  virtual void update_autopos (const std::string& elem_type);
+
   virtual void add_listener (const caseless_str&, const octave_value&,
                              listener_mode = POSTSET);
 
@@ -3095,6 +3097,12 @@
         update_axes_layout ();
       }
 
+    void update_autopos (const std::string& elem_type);
+    void update_xlabel_position (void);
+    void update_ylabel_position (void);
+    void update_zlabel_position (void);
+    void update_title_position (void);
+
     graphics_xform get_transform (void) const
       { return graphics_xform (x_render, x_render_inv, sx, sy, sz, x_zlim); }
 
@@ -3311,11 +3319,6 @@
     void update_ydir (void) { update_camera (); update_axes_layout (); }
     void update_zdir (void) { update_camera (); update_axes_layout (); }
 
-    void update_xlabel_position (void);
-    void update_ylabel_position (void);
-    void update_zlabel_position (void);
-    void update_title_position (void);
-
     void update_ticklengths (void);
     void update_tickdir (void) { update_ticklengths (); }
     void update_tickdirmode (void) { update_ticklengths (); }
@@ -3654,10 +3657,11 @@
       bool_property yliminclude hl , "off"
       bool_property zliminclude hl , "off"
       // hidden properties for auto-positioning
-      radio_property positionmode h , "{auto}|manual"
-      radio_property rotationmode h , "{auto}|manual"
-      radio_property horizontalalignmentmode h , "{auto}|manual"
-      radio_property verticalalignmentmode h , "{auto}|manual"
+      radio_property positionmode hu , "{auto}|manual"
+      radio_property rotationmode hu , "{auto}|manual"
+      radio_property horizontalalignmentmode hu , "{auto}|manual"
+      radio_property verticalalignmentmode hu , "{auto}|manual"
+      radio_property autopos_tag h , "{none}|xlabel|ylabel|zlabel|title"
     END_PROPERTIES
 
     Matrix get_data_position (void) const;
@@ -3703,7 +3707,13 @@
 
     void update_text_extent (void);
 
-    void update_string (void) { update_text_extent (); }
+    void request_autopos (void);
+    void update_positionmode (void) { request_autopos (); }
+    void update_rotationmode (void) { request_autopos (); }
+    void update_horizontalalignmentmode (void) { request_autopos (); }
+    void update_verticalalignmentmode (void) { request_autopos (); }
+
+    void update_string (void) { update_text_extent ();  request_autopos ();}
     void update_rotation (void) { update_text_extent (); }
     void update_fontname (void) { update_text_extent (); }
     void update_fontsize (void) { update_text_extent (); }