# HG changeset patch
# User Pantxo Diribarne <pantxo.diribarne@gmail.com>
# Date 1562852778 -7200
#      Thu Jul 11 15:46:18 2019 +0200
# Node ID b5cd29b82efdda0288e9d4befb0a48a0887f0cd8
# Parent  3d10834979f80c87e07757cb521e87337a883560
Let graphics toolkit compute the extent of uicontrol text strings (bug #48446)

* graphics-toolkit.h (base_graphics_toolkit::get_text_extent,
  graphics_toolkit::get_text_extent): New virtual methods.

* Backend.h, Backend.cc (Backend::get_text_extent): Reimplement virtual method.
  Compute the extent based on the string property of uicontrol objects.

* graphics.cc (uicontrol::properties::get_text_extent): Use toolkit method
  rather than a text renderer.

* genpropdoc.m: Document the uicontrol "extent" property.

diff -r 3d10834979f8 -r b5cd29b82efd doc/interpreter/genpropdoc.m
--- a/doc/interpreter/genpropdoc.m	Wed Jul 10 20:06:04 2019 -0700
+++ b/doc/interpreter/genpropdoc.m	Thu Jul 11 15:46:18 2019 +0200
@@ -1683,6 +1683,11 @@
       case "cdata"
       case "enable"
       case "extent"
+        s.doc = "Size of the text string associated to the uicontrol \
+ returned in the form @code{[0 0 width height]} (the two first elements \
+are always zero).\n\n\
+For multi-line strings the returned @code{width} and @code{height} \
+indicate the size of the rectangle enclosing all lines.";
         s.valid = valid_4elvec;
         s.printdefault = false;
 
diff -r 3d10834979f8 -r b5cd29b82efd libgui/graphics/Backend.cc
--- a/libgui/graphics/Backend.cc	Wed Jul 10 20:06:04 2019 -0700
+++ b/libgui/graphics/Backend.cc	Thu Jul 11 15:46:18 2019 +0200
@@ -28,12 +28,14 @@
 
 #include <QApplication>
 #include <QThread>
+#include <QFontMetrics>
 
 #include "Backend.h"
 #include "Logger.h"
 #include "Object.h"
 #include "ObjectFactory.h"
 #include "ObjectProxy.h"
+#include "QtHandlesUtils.h"
 
 //#if INTPTR_MAX == INT32_MAX
 //# define OCTAVE_PTR_TYPE octave_uint32
@@ -218,6 +220,56 @@
                     QString::fromStdString (term));
   }
 
+  Matrix
+  Backend::get_text_extent (const graphics_object& go) const
+  {
+    Matrix ext (1, 4, 0.0);
+
+    if (go.isa ("uicontrol"))
+      {
+        octave_value str = go.get ("string");
+        if (! str.isempty ())
+          {
+            const uicontrol::properties& up =
+              dynamic_cast<const uicontrol::properties&> (go.get_properties ());
+            Matrix bb = up.get_boundingbox (false);
+            QFont font = Utils::computeFont<uicontrol> (up, bb(3));
+            QFontMetrics fm (font);
+
+            QString s;
+            QSize sz;
+
+            if (str.is_string ())
+              {
+                s = QString::fromStdString (str.string_value ());
+                sz = fm.size (Qt::TextSingleLine, s);
+                ext(2) = sz.width ();
+                ext(3) = sz.height ();
+              }
+            else if (str.iscellstr ())
+              {
+                string_vector sv = str.string_vector_value ();
+                double wd = 0.0;
+                double hg = 0.0;
+                for (octave_idx_type ii = 0; ii < sv.numel (); ii++)
+                  {
+                    s = QString::fromStdString (sv(ii));
+                    sz = fm.size (Qt::TextSingleLine, s);
+                    wd = std::max (wd, static_cast<double> (sz.width ()));
+                    hg = std::max (hg, static_cast<double> (sz.height ()));
+                  }
+
+                ext(2) = wd;
+                // FIXME: Find a better way to determine the height of e.g.
+                // listbox uicontrol objects
+                ext(3) = hg * sv.numel ();
+              }
+          }
+      }
+
+    return ext;
+  }
+
   uint8NDArray
   Backend::get_pixels (const graphics_object& go) const
   {
diff -r 3d10834979f8 -r b5cd29b82efd libgui/graphics/Backend.h
--- a/libgui/graphics/Backend.h	Wed Jul 10 20:06:04 2019 -0700
+++ b/libgui/graphics/Backend.h	Thu Jul 11 15:46:18 2019 +0200
@@ -61,6 +61,8 @@
                        const std::string& file_cmd,
                        const std::string& /*debug_file*/) const;
 
+    Matrix get_text_extent (const graphics_object& go) const;
+
     uint8NDArray get_pixels (const graphics_object& go) const;
 
     static Object * toolkitObject (const graphics_object& go);
diff -r 3d10834979f8 -r b5cd29b82efd libinterp/corefcn/graphics-toolkit.h
--- a/libinterp/corefcn/graphics-toolkit.h	Wed Jul 10 20:06:04 2019 -0700
+++ b/libinterp/corefcn/graphics-toolkit.h	Thu Jul 11 15:46:18 2019 +0200
@@ -63,6 +63,12 @@
                              const std::string& = "") const
   { gripe_if_tkit_invalid ("print_figure"); }
 
+  virtual Matrix get_text_extent (const graphics_object&) const
+  {
+    gripe_if_tkit_invalid ("get_text_extent");
+    return Matrix ();
+  }
+
   virtual uint8NDArray get_pixels (const graphics_object&) const
   {
     gripe_if_tkit_invalid ("get_pixels");
@@ -186,6 +192,9 @@
                      const std::string& debug_file = "") const
   { rep->print_figure (go, term, file, debug_file); }
 
+  Matrix get_text_extent (const graphics_object& go) const
+  { return rep->get_text_extent (go); }
+
   uint8NDArray get_pixels (const graphics_object& go) const
   { return rep->get_pixels (go); }
 
diff -r 3d10834979f8 -r b5cd29b82efd libinterp/corefcn/graphics.cc
--- a/libinterp/corefcn/graphics.cc	Wed Jul 10 20:06:04 2019 -0700
+++ b/libinterp/corefcn/graphics.cc	Thu Jul 11 15:46:18 2019 +0200
@@ -10535,32 +10535,10 @@
 void
 uicontrol::properties::update_text_extent (void)
 {
-  octave::text_element *elt;
-  octave::text_renderer txt_renderer;
-  Matrix box;
-
-  // FIXME: parsed content should be cached for efficiency
   // FIXME: support multiline text
-
-  elt = octave::text_parser::parse (get_string_string (), "none");
-
-  gh_manager::auto_lock guard;
-  txt_renderer.set_font (get_fontname (), get_fontweight (),
-                         get_fontangle (), get_fontsize ());
-
-  box = txt_renderer.get_extent (elt, 0);
-
-  delete elt;
-
-  Matrix ext (1, 4);
-
-  // FIXME: also handle left and bottom components
-
-  ext(0) = ext(1) = 1;
-  ext(2) = box(0);
-  ext(3) = box(1);
-
-  set_extent (ext);
+  graphics_object go = gh_manager::get_object (get___myhandle__ ());
+
+  set_extent (go.get_toolkit ().get_text_extent (go));
 }
 
 void
