changeset 24173:730227072acb

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_axes_planes) Increase polygon_offset to 9 for axes planes. (opengl_renderer::draw_text) Call draw_text_background prior to drawing text. * gl2ps-print.cc (gl2ps_renderer::draw_text): Ditto. * genpropdoc.m (get_doc): Document relevant text properties. * text.m: Modify second demo to include background properties. * NEWS: Announce new functionality.
author Pantxo Diribarne <pantxo.diribarne@gmail.com>
date Sun, 15 Oct 2017 21:06:47 +0200
parents 90903d915625
children cc631e9926e1
files NEWS doc/interpreter/genpropdoc.m libinterp/corefcn/gl-render.cc libinterp/corefcn/gl-render.h libinterp/corefcn/gl2ps-print.cc scripts/plot/appearance/text.m
diffstat 6 files changed, 140 insertions(+), 9 deletions(-) [+]
line wrap: on
line diff
--- a/NEWS	Mon Oct 23 18:21:12 2017 -0400
+++ b/NEWS	Sun Oct 15 21:06:47 2017 +0200
@@ -59,6 +59,10 @@
 
       warning ("off", "Octave:quadcc:RelTol-conversion")
 
+ ** The properties "BackgroundColor", "EdgeColor", "LineStyle",
+    "LineWidth", and "Margin" are now implemented for text objects using
+    an OpenGL toolkit.
+
  ** Other new functions added in 4.4:
 
       camlookat
--- a/doc/interpreter/genpropdoc.m	Mon Oct 23 18:21:12 2017 -0400
+++ 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, regardless \
+of the @qcode{\"fontunits\"} property.";
         s.valid = "scalar";
 
       case "position"
--- a/libinterp/corefcn/gl-render.cc	Mon Oct 23 18:21:12 2017 -0400
+++ b/libinterp/corefcn/gl-render.cc	Sun Oct 15 21:06:47 2017 +0200
@@ -1196,7 +1196,7 @@
 
     // Axes planes
     set_color (axe_color);
-    set_polygon_offset (true, 2.5);
+    set_polygon_offset (true, 9.0);
 
     glBegin (GL_QUADS);
 
@@ -2401,7 +2401,7 @@
               glEnable (GL_LIGHTING);
             glShadeModel ((fc_mode == INTERP || fl_mode == GOURAUD)
                           ? GL_SMOOTH : GL_FLAT);
-            set_polygon_offset (true, 1);
+            set_polygon_offset (true, 1.0);
             if (fc_mode == TEXTURE)
               glEnable (GL_TEXTURE_2D);
 
@@ -3431,12 +3431,22 @@
     if (props.get_string ().isempty ())
       return;
 
+    Matrix pos = xform.scale (props.get_data_position ());
+
+    // Handle clipping manually when drawing text background
+    if (! props.is_clipping () ||
+        (clip_code (pos(0), pos(1), pos.numel () > 2 ? pos(2) : 0.0) ==
+         octave_uint8 (0x40)))
+      {
+        set_clipping (false);
+        draw_text_background (props);
+        set_clipping (props.is_clipping ());
+      }
+
     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 +3472,110 @@
   }
 
   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));
+
+        bool depth_test = glIsEnabled (GL_DEPTH_TEST);
+        if (depth_test)
+          set_polygon_offset (true, 4.0);
+
+        glBegin (GL_QUADS);
+        glVertex2d (x0, y0);
+        glVertex2d (x1, y0);
+        glVertex2d (x1, y1);
+        glVertex2d (x0, y1);
+        glEnd ();
+
+        if (depth_test)
+          set_polygon_offset (false);
+      }
+
+    if (! ecol.isempty ())
+      {
+        glColor3f (ecol(0), ecol(1), ecol(2));
+
+        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 ();
+      }
+
+    // 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)
--- a/libinterp/corefcn/gl-render.h	Mon Oct 23 18:21:12 2017 -0400
+++ 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);
--- a/libinterp/corefcn/gl2ps-print.cc	Mon Oct 23 18:21:12 2017 -0400
+++ b/libinterp/corefcn/gl2ps-print.cc	Sun Oct 15 21:06:47 2017 +0200
@@ -947,6 +947,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
--- a/scripts/plot/appearance/text.m	Mon Oct 23 18:21:12 2017 -0400
+++ 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]);