# HG changeset patch
# User Ben Abbott  <bpabbott@mac.com>
# Date 1313165916 14400
# Branch stable
# Node ID 514fb4251aab45d1d8f1ecad654307fbb6588b03
# Parent  818299a39ae13641a73251be189206180e6b5784
Support multi-line text objects.

* graphics.h.in: Change string from string_property to any_property.
* graphics.cc: Support the above change.
* gl-render.cc: Ditto.
* gl2ps-renderer.cc: Ditto.
* text.m: Add support for multiline text. Add demos.
* __go_draw_axes__.m: Add support for multiline text.

diff --git a/scripts/plot/__go_draw_axes__.m b/scripts/plot/__go_draw_axes__.m
--- a/scripts/plot/__go_draw_axes__.m
+++ b/scripts/plot/__go_draw_axes__.m
@@ -1250,6 +1250,11 @@
             colorspec = get_text_colorspec (color, mono);
           endif
 
+          if (ischar (obj.string))
+            num_lines = size (obj.string, 1);
+          else
+            num_lines = numel (obj.string);
+          endif
           switch valign
             ## Text offset in characters. This relies on gnuplot for font metrics.
             case "top"
@@ -1257,17 +1262,18 @@
             case "cap"
               dy = -0.5;
             case "middle"
-              dy = 0;
+              dy = 0.5 * (num_lines - 1);
             case "baseline"
-              dy = 0.5;
+              dy = 0.5 + (num_lines - 1);
             case "bottom"
-              dy = 0.5;
+              dy = 0.5 + (num_lines - 1);
           endswitch
           ## Gnuplot's Character units are different for x/y and vary with fontsize. The aspect ratio
           ## of 1:1.7 was determined by experiment to work for eps/ps/etc. For the MacOS aqua terminal
           ## a value of 2.5 is needed. However, the difference is barely noticable.
           dx_and_dy = [(-dy * sind (angle)), (dy * cosd(angle))] .* [1.7 1];
 
+          ## FIXME - Multiline text produced the gnuplot "warning: ft_render: skipping glyph"
           if (nd == 3)
             ## This produces the desired vertical alignment in 3D.
             fprintf (plot_stream,
@@ -2129,10 +2135,24 @@
     bld = false;
   endif
 
+  ## The text object maybe multiline
   str = getfield (obj, fld);
+  if (ischar (str) && size (str, 1) > 1)
+    str = cellstr (str);
+  endif
+  if (iscellstr (str))
+    str = sprintf ("%s\n", str{:})(1:end-1);
+  endif
+
   if (enhanced)
     if (strcmpi (obj.interpreter, "tex"))
-      str = __tex2enhanced__ (str, fnt, it, bld);
+      if (iscellstr (str))
+        for n = 1:numel(str)
+          str{n} = __tex2enhanced__ (str{n}, fnt, it, bld);
+        endfor
+      else
+        str = __tex2enhanced__ (str, fnt, it, bld);
+      endif
     elseif (strcmpi (obj.interpreter, "latex"))
       if (! warned_latex)
         warning ("latex markup not supported for text objects");
diff --git a/scripts/plot/text.m b/scripts/plot/text.m
--- a/scripts/plot/text.m
+++ b/scripts/plot/text.m
@@ -47,23 +47,32 @@
     endif
 
     label = varargin{offset};
-    if (ischar (label) || iscellstr (label))
-      varargin(1:offset) = [];
-      if (ischar (label))
+    varargin(1:offset) = [];
+
+    nt = numel (label);
+    nx = numel (x);
+    ny = numel (y);
+    nz = numel (z);
+    if (ischar (label))
+      if (size (label, 1) == 1 && nx > 1)
+        ## Mutiple text objects with same string
+        label = cellstr (label);
+        label(2:numel(x),1) = label(1);
+      elseif (size (label, 1) == nx && nx > 1)
+        ## Mutiple text objects with different strings
+        label = cellstr (label);
+      elseif (ischar (label))
+        ## Single text object with one or more lines
         label = cellstr (label);
       endif
-      n = numel (label);
-      nx = numel (x);
-      ny = numel (y);
-      nz = numel (z);
-    else
+    elseif (! iscellstr (label))
       error ("text: expecting LABEL to be a character string or cell array of character strings");
     endif
   else
     x = y = z = 0;
     nx = ny = nz = 1;
     label = {""};
-    n = 1;
+    nt = 1;
   endif
 
   if (rem (numel (varargin), 2) == 0)
@@ -71,20 +80,19 @@
     if (nx == ny && nx == nz)
       pos = [x(:), y(:), z(:)];
       ca = gca ();
-      tmp = zeros (n, 1);
-      if (n == 1)
-        label = label{1};
-        for i = 1:nx
-          tmp(i) = __go_text__ (ca, "string", label,
+      tmp = zeros (nt, 1);
+      if (nx == 1)
+        ## TODO - Modify __go_text__() to accept cell-strings
+        tmp = __go_text__ (ca, "string", label{1},
+                           varargin{:},
+                           "position", pos);
+        ## TODO - the string property should have the same class as the input to text()
+        set (tmp, "string", label);
+      elseif (nt == nx)
+        for n = 1:nt
+          tmp(n) = __go_text__ (ca, "string", label{n},
                                 varargin{:},
-                                "position", pos(i,:));
-        endfor
-        __request_drawnow__ ();
-      elseif (n == nx)
-        for i = 1:nx
-          tmp(i) = __go_text__ (ca, "string", label{i},
-                                varargin{:},
-                                "position", pos(i,:));
+                                "position", pos(n,:));
         endfor
         __request_drawnow__ ();
       else
@@ -142,3 +150,30 @@
 %! endfor
 %! caxis ([-100 100])
 %! title ("Vertically Aligned at Bottom")
+
+%!demo
+%! clf
+%! axis ([0 8 0 8])
+%! title (["First title";"Second title"])
+%! xlabel (["First xlabel";"Second xlabel"])
+%! ylabel (["First ylabel";"Second ylabel"])
+%! text (4, 4, {"Hello", "World"}, ...
+%!       "horizontalalignment", "center", ...
+%!       "verticalalignment", "middle")
+%! grid on
+
+%!demo
+%! clf
+%! h = mesh (peaks, "edgecolor", 0.7 * [1 1 1], ...
+%!                  "facecolor", "none", ...
+%!                  "facealpha", 0);
+%! title (["First title";"Second title"])
+%! xlabel (["First xlabel";"Second xlabel"])
+%! ylabel (["First ylabel";"Second ylabel"])
+%! zlabel (["First zlabel";"Second zlabel"])
+%! text (0, 0, 5, {"Hello", "World"}, ...
+%!       "horizontalalignment", "center", ...
+%!       "verticalalignment", "middle")
+%! hold on
+%! plot3 (0, 0, 5, "+k")
+%! 
diff --git a/src/gl-render.cc b/src/gl-render.cc
--- a/src/gl-render.cc
+++ b/src/gl-render.cc
@@ -2421,7 +2421,7 @@
 void
 opengl_renderer::draw_text (const text::properties& props)
 {
-  if (props.get_string ().empty ())
+  if (props.get_string ().is_empty ())
     return;
 
   const Matrix pos = xform.scale (props.get_data_position ());
diff --git a/src/gl2ps-renderer.cc b/src/gl2ps-renderer.cc
--- a/src/gl2ps-renderer.cc
+++ b/src/gl2ps-renderer.cc
@@ -199,7 +199,7 @@
 void
 glps_renderer::draw_text (const text::properties& props)
 {
-  if (props.get_string ().empty ())
+  if (props.get_string ().is_empty ())
     return;
 
   set_font (props);
@@ -223,9 +223,15 @@
   // FIXME: handle margin and surrounding box
 
   glRasterPos3d (pos(0), pos(1), pos(2));
-  gl2psTextOpt (props.get_string ().c_str (), fontname.c_str (), fontsize,
-                alignment_to_mode (halign, valign), props.get_rotation ());
-
+  // FIXME: only octave_string text is rendered, everything else is rendered ""
+  if (props.get_string ().is_string ()) {
+    gl2psTextOpt (props.get_string ().string_value ().c_str (), 
+                  fontname.c_str (), fontsize, 
+                  alignment_to_mode (halign, valign), props.get_rotation ());
+  } else {
+    gl2psTextOpt ("", fontname.c_str (), fontsize, 
+                  alignment_to_mode (halign, valign), props.get_rotation ());
+  }
 }
 
 #endif
diff --git a/src/graphics.cc b/src/graphics.cc
--- a/src/graphics.cc
+++ b/src/graphics.cc
@@ -4229,7 +4229,7 @@
   text::properties& xlabel_props = reinterpret_cast<text::properties&>
     (gh_manager::get_object (get_xlabel ()).get_properties ());
 
-  bool is_empty = xlabel_props.get_string ().empty ();
+  bool is_empty = xlabel_props.get_string ().is_empty ();
 
   xlabel_props.set_autopos_tag ("none");
 
@@ -4315,7 +4315,7 @@
   text::properties& ylabel_props = reinterpret_cast<text::properties&>
     (gh_manager::get_object (get_ylabel ()).get_properties ());
 
-  bool is_empty = ylabel_props.get_string ().empty ();
+  bool is_empty = ylabel_props.get_string ().is_empty ();
 
   ylabel_props.set_autopos_tag ("none");
 
@@ -4402,7 +4402,7 @@
     (gh_manager::get_object (get_zlabel ()).get_properties ());
 
   bool camAuto = cameraupvectormode_is ("auto");
-  bool is_empty = zlabel_props.get_string ().empty ();
+  bool is_empty = zlabel_props.get_string ().is_empty ();
 
   zlabel_props.set_autopos_tag ("none");
 
@@ -4756,7 +4756,7 @@
 
           Matrix text_pos = text_props.get_position ().matrix_value ();
           text_pos = xform.transform (text_pos(0), text_pos(1), text_pos(2));
-          if (text_props.get_string ().empty ())
+          if (text_props.get_string ().is_empty ())
             {
               ext(0) = std::min (ext(0), text_pos(0));
               ext(1) = std::min (ext(1), text_pos(1));
@@ -5885,8 +5885,24 @@
 
   Matrix bbox;
   // FIXME: string should be parsed only when modified, for efficiency
-  renderer.text_to_pixels (get_string (), pixels, bbox,
+  octave_value ov_string;
+  ov_string = get_string ();
+  if (ov_string.is_string ()) {
+    renderer.text_to_pixels (ov_string.string_value (), pixels, bbox,
+                             halign, valign, get_rotation ());
+  } else if (ov_string.is_char_matrix () || ov_string.is_cellstr ()) {
+    string_vector sv = ov_string.all_strings ();
+
+    std::string s("");
+    if (sv.length () > 0) {
+        octave_idx_type i = 0;
+        for (i = 0; i < sv.length () - 1; i++)
+          s += sv[i] + "\n";
+        s += sv[i];
+    }
+    renderer.text_to_pixels (s, pixels, bbox,
                            halign, valign, get_rotation ());
+  }
 
   set_extent (bbox);
 #endif
diff --git a/src/graphics.h.in b/src/graphics.h.in
--- a/src/graphics.h.in
+++ b/src/graphics.h.in
@@ -3671,7 +3671,7 @@
     // properties declarations.
 
     BEGIN_PROPERTIES (text)
-      string_property string u , ""
+      any_property string u , ""
       radio_property units u , "{data}|pixels|normalized|inches|centimeters|points"
       array_property position mu , Matrix (1, 3, 0.0)
       double_property rotation mu , 0
