# HG changeset patch
# User Pantxo Diribarne <pantxo.diribarne@gmail.com>
# Date 1508094407 -7200
#      Sun Oct 15 21:06:47 2017 +0200
# Node ID 2aa4373637313f069aea64bb1a51af8c561f6700
# Parent  950e00e5f3f362f1b1af8dc953cfab6262b4fb33
Add support for text background area for opengl toolkits (bug #39692)

* gl-render.h, gl-render.cc (opengl_renderer::draw_text_background): new method.
  (opengl_renderer::draw_text) call draw_text_background prior to drawing text

* gl2ps-print.cc (gl2ps_renderer::draw_text): dito

* genpropdoc.m (get_doc): document relevant text properties.

* text.m: modify second demo to include background properties

diff -r 950e00e5f3f3 -r 2aa437363731 doc/interpreter/genpropdoc.m
--- a/doc/interpreter/genpropdoc.m	Sun Mar 12 18:08:41 2017 +0100
+++ b/doc/interpreter/genpropdoc.m	Sun Oct 15 21:06:47 2017 +0200
@@ -1004,7 +1004,8 @@
 
       ## Specific properties
       case "backgroundcolor"
-        s.doc = sprintf (doc_notimpl, "Background area");
+        s.doc = "Color of the background area.  \
+@xref{Colors, , colorspec}.";
         s.valid = valid_color;
 
       case "color"
@@ -1013,7 +1014,8 @@
 
       case "displayname"
       case "edgecolor"
-        s.doc = sprintf (doc_notimpl, "Background area");
+        s.doc = "Color of the outline of the background area.  \
+@xref{Colors, , colorspec}.";
         s.valid = valid_color;
 
       case "editing"
@@ -1048,14 +1050,16 @@
 @xref{XREFinterpreterusage, , @w{Use of the interpreter property}}.";
 
       case "linestyle"
-        s.doc = sprintf (doc_notimpl, "Background area");
+        s.doc = "Style of the outline.  @xref{Line Styles}.";
 
       case "linewidth"
-        s.doc = sprintf (doc_notimpl, "Background area");
+        s.doc = "Width of the outline.";
         s.valid = "scalar";
 
       case "margin"
-        s.doc = sprintf (doc_notimpl, "Background area");
+        s.doc = "Margins between the borders of the background area \
+and the texts.  The value is currently interpreted as pixels, whatever \
+the @qcode{\"fontunits\"} property.";
         s.valid = "scalar";
 
       case "position"
diff -r 950e00e5f3f3 -r 2aa437363731 libinterp/corefcn/gl-render.cc
--- a/libinterp/corefcn/gl-render.cc	Sun Mar 12 18:08:41 2017 +0100
+++ b/libinterp/corefcn/gl-render.cc	Sun Oct 15 21:06:47 2017 +0200
@@ -3430,13 +3430,14 @@
 
     if (props.get_string ().isempty ())
       return;
+    
+    draw_text_background (props);
 
     set_font (props);
-
     Matrix pos = xform.scale (props.get_data_position ());
+
     const Matrix bbox = props.get_extent_matrix ();
 
-    // FIXME: handle margin and surrounding box
     bool blend = glIsEnabled (GL_BLEND);
 
     glEnable (GL_BLEND);
@@ -3462,6 +3463,112 @@
   }
 
   void
+  opengl_renderer::draw_text_background (const text::properties& props,
+                                         bool do_rotate)
+  {
+#if defined (HAVE_OPENGL)
+
+    Matrix bgcol = props.get_backgroundcolor_rgb ();
+    Matrix ecol = props.get_edgecolor_rgb ();
+
+    if (bgcol.isempty () && ecol.isempty ())
+      return;
+    
+    Matrix pos = xform.scale (props.get_data_position ());
+    ColumnVector pixpos = get_transform ().transform (pos(0), pos(1), 
+                                                      pos(2), false);
+    const Matrix bbox = props.get_extent_matrix ();
+
+#  if defined (HAVE_FRAMEWORK_OPENGL)
+    GLint vp[4];
+#  else
+    int vp[4];
+#  endif
+
+    glGetIntegerv (GL_VIEWPORT, vp);
+
+    // Save current transform matrices and set orthogonal window coordinates
+    glMatrixMode (GL_PROJECTION);
+    glPushMatrix ();
+    glLoadIdentity ();
+    glOrtho (0, vp[2], vp[3], 0, xZ1, xZ2);
+    glMatrixMode (GL_MODELVIEW);
+    glPushMatrix ();
+    glLoadIdentity ();    
+
+    // Translate coordinates so that the text anchor is (0,0)
+    glTranslated (pixpos(0), pixpos(1), -pixpos(2));
+
+    // FIXME: only multiples of 90° are handled by the text renderer. 
+    // Handle others here
+    double rotation = props.get_rotation ();
+    
+    if (do_rotate && rotation != 0.0 && rotation != 90.0
+        && rotation != 180.0 && rotation != 270.0)
+      glRotated (rotation, 0.0, 0.0, 1.0);
+
+    
+    double m = props.get_margin ();
+    double x0 = bbox (0) - m;
+    double x1 = x0 + bbox(2) + 2 * m;
+    double y0 = -(bbox (1) - m);
+    double y1 = y0 - (bbox(3) + 2 * m);
+
+    if (! bgcol.isempty ())
+      {
+        glColor3f (bgcol(0), bgcol(1), bgcol(2));
+
+        if (glIsEnabled (GL_DEPTH_TEST))
+          set_polygon_offset (true, 8);
+
+        glBegin (GL_QUADS);
+        glVertex2d (x0, y0);
+        glVertex2d (x1, y0);
+        glVertex2d (x1, y1);
+        glVertex2d (x0, y1);
+        glEnd ();
+      }
+
+    if (! ecol.isempty ())
+      {
+        glColor3f (ecol(0), ecol(1), ecol(2));
+
+        if (glIsEnabled (GL_DEPTH_TEST))
+          set_polygon_offset (true, 0);
+
+        set_linestyle (props.get_linestyle (), false, props.get_linewidth ());
+        set_linewidth (props.get_linewidth ());
+
+        glBegin (GL_LINE_STRIP);
+        glVertex2d (x0, y0);
+        glVertex2d (x1, y0);
+        glVertex2d (x1, y1);
+        glVertex2d (x0, y1);
+        glVertex2d (x0, y0);
+        glEnd ();
+      }
+
+    set_polygon_offset (false);
+
+    // Restore previous coordinate system
+    glPopMatrix();
+    glMatrixMode (GL_PROJECTION);
+    glPopMatrix();
+
+#else
+
+    octave_unused_parameter (props);
+    octave_unused_parameter (do_rotate);
+
+    // This shouldn't happen because construction of opengl_renderer
+    // objects is supposed to be impossible if OpenGL is not available.
+
+    panic_impossible ();
+
+#endif
+  }
+
+  void
   opengl_renderer::draw_image (const image::properties& props)
   {
 #if defined (HAVE_OPENGL)
diff -r 950e00e5f3f3 -r 2aa437363731 libinterp/corefcn/gl-render.h
--- a/libinterp/corefcn/gl-render.h	Sun Mar 12 18:08:41 2017 +0100
+++ b/libinterp/corefcn/gl-render.h	Sun Oct 15 21:06:47 2017 +0200
@@ -76,6 +76,8 @@
     virtual void draw_light (const light::properties& props);
     virtual void draw_hggroup (const hggroup::properties& props);
     virtual void draw_text (const text::properties& props);
+    virtual void draw_text_background (const text::properties& props,
+                                       bool do_rotate = false);
     virtual void draw_image (const image::properties& props);
     virtual void draw_uipanel (const uipanel::properties& props,
                                const graphics_object& go);
diff -r 950e00e5f3f3 -r 2aa437363731 libinterp/corefcn/gl2ps-print.cc
--- a/libinterp/corefcn/gl2ps-print.cc	Sun Mar 12 18:08:41 2017 +0100
+++ b/libinterp/corefcn/gl2ps-print.cc	Sun Oct 15 21:06:47 2017 +0200
@@ -954,6 +954,8 @@
     if (props.get_string ().isempty ())
       return;
 
+    draw_text_background (props, true);
+
     // First set font properties: freetype will use them to compute
     // coordinates and gl2ps will retrieve the color directly from the
     // feedback buffer
diff -r 950e00e5f3f3 -r 2aa437363731 scripts/plot/appearance/text.m
--- a/scripts/plot/appearance/text.m	Sun Mar 12 18:08:41 2017 +0100
+++ b/scripts/plot/appearance/text.m	Sun Oct 15 21:06:47 2017 +0200
@@ -201,10 +201,15 @@
 %! h = mesh (peaks, "edgecolor", 0.7 * [1 1 1], ...
 %!                  "facecolor", "none", ...
 %!                  "facealpha", 0);
+%! colors = jet (9);
+%! ii = 1;
 %! for t = 0:45:359;
+%!   ii = ii +1;
 %!   text (25, 25, 0, "Vertical Alignment = Bottom", ...
 %!                    "rotation", t, ...
 %!                    "horizontalalignment", "left", ...
+%!                    "backgroundcolor", colors(ii,:), ...
+%!                    "edgecolor", "k", ...
 %!                    "verticalalignment", "bottom");
 %! endfor
 %! caxis ([-100 100]);
