changeset 27730:5b9067c17e4b

Keep track of children in uibuttongroup (bug #55230). * graphics.in.h (uibuttongroup::properties::adopt, uibuttongroup::properties::remove_child): Add new functions. * graphics.cc (uicontrol::properties::set_style, uibuttongroup::properties::adopt, uibuttongroup::properties::remove_child): Update "selectedobject" and "value". * uibuttongroup.m: Make the demo resizable. Add BISTs for programmatic interaction.
author Markus Mützel <markus.muetzel@gmx.de>
date Sat, 15 Dec 2018 12:53:18 +0100
parents 718845eb3c7a
children f9c334a207bb
files libinterp/corefcn/graphics.cc libinterp/corefcn/graphics.in.h scripts/gui/uibuttongroup.m
diffstat 3 files changed, 180 insertions(+), 22 deletions(-) [+]
line wrap: on
line diff
--- a/libinterp/corefcn/graphics.cc	Wed Nov 20 19:34:15 2019 -0600
+++ b/libinterp/corefcn/graphics.cc	Sat Dec 15 12:53:18 2018 +0100
@@ -10885,6 +10885,29 @@
 void
 uicontrol::properties::set_style (const octave_value& st)
 {
+  gh_manager& gh_mgr
+    = octave::__get_gh_manager__ ("uicontrol::properties::set_style");
+
+  graphics_object go_parent = gh_mgr.get_object (get_parent ());
+  if (go_parent.valid_object () && go_parent.isa ("uibuttongroup"))
+    {
+      bool was_button = style_is ("radiobutton") || style_is ("togglebutton");
+      style = st;
+      bool now_button = style_is ("radiobutton") || style_is ("togglebutton");
+      uibuttongroup::properties& props =
+        dynamic_cast<uibuttongroup::properties&> (go_parent.get_properties ());
+      // update selectedobject
+      if (! was_button && now_button && ! props.get_selectedobject ().ok ())
+        {
+          props.set_selectedobject (get___myhandle__ ().value ());
+          value.set (octave_value (1));
+        }
+      else if (was_button && ! now_button
+               && (props.get_selectedobject ().value ()
+                   == get___myhandle__ ().value ()))
+        props.set_selectedobject (Matrix ());
+    }
+
   // Don't notify the style change until the "value" property is fixed
   bool modified = style.set (st, true, false);
 
@@ -10900,9 +10923,6 @@
 
       // Notify toolkit
 
-      gh_manager& gh_mgr
-        = octave::__get_gh_manager__ ("uicontrol::properties::set_style");
-
       graphics_object go = gh_mgr.get_object (get___myhandle__ ());
 
       if (go)
@@ -11190,6 +11210,39 @@
   err_set_invalid ("selectedobject");
 }
 
+void
+uibuttongroup::properties::remove_child (const graphics_handle& h,
+                                         bool from_root)
+{
+  graphics_handle current_selected = get_selectedobject ();
+  if (h.value () == current_selected.value ())
+    set_selectedobject (Matrix ());
+
+  base_properties::remove_child (h, from_root);
+}
+
+void
+uibuttongroup::properties::adopt (const graphics_handle& h)
+{
+  base_properties::adopt (h);
+
+  graphics_handle current_selected = get_selectedobject ();
+  bool has_selected = current_selected.ok ();
+
+  gh_manager& gh_mgr
+    = octave::__get_gh_manager__ ("uibuttongroup::properties::adopt");
+
+  graphics_object go = gh_mgr.get_object (h);
+
+  if (! has_selected && go.valid_object () && go.isa ("uicontrol"))
+    {
+      const uicontrol::properties& props =
+        dynamic_cast<const uicontrol::properties&> (go.get_properties ());
+      if (props.style_is ("radiobutton") || props.style_is ("togglebutton"))
+        set_selectedobject (h.value ());
+    }
+}
+
 // ---------------------------------------------------------------------
 
 Matrix
--- a/libinterp/corefcn/graphics.in.h	Wed Nov 20 19:34:15 2019 -0600
+++ b/libinterp/corefcn/graphics.in.h	Sat Dec 15 12:53:18 2018 +0100
@@ -5602,6 +5602,10 @@
   class OCTINTERP_API properties : public base_properties
   {
   public:
+    void remove_child (const graphics_handle& h, bool from_root = false);
+
+    void adopt (const graphics_handle& h);
+
     Matrix get_boundingbox (bool internal = false,
                             const Matrix& parent_pix_size = Matrix ()) const;
 
--- a/scripts/gui/uibuttongroup.m	Wed Nov 20 19:34:15 2019 -0600
+++ b/scripts/gui/uibuttongroup.m	Sat Dec 15 12:53:18 2018 +0100
@@ -81,29 +81,130 @@
 
 
 %!demo
-%! f = figure;
-%! gp = uibuttongroup (f, "Position", [ 0 0.5 1 1], ...
+%! f = clf ();
+%! gp = uibuttongroup (f, "position", [0 0.5 1 0.5], ...
 %!                     "selectionchangedfcn", ...
-%!                     @(x, y) display (['Selection Changed: ' get(y.NewValue, 'String')]));
+%!                     @(h, e) fprintf ("Selection changed: %s\n", get (e.NewValue, "string")));
 %! b1 = uicontrol (gp, "style", "radiobutton", ...
-%!                 "string", "Choice 1", ...
-%!                 "Position", [ 10 150 100 50 ]);
+%!                     "string", "Choice 1", ...
+%!                     "units", "normalized", ...
+%!                     "position", [0.01 0.5 0.98 0.5]);
 %! b2 = uicontrol (gp, "style", "radiobutton", ...
-%!                 "string", "Choice 2", ...
-%!                 "Position", [ 10 50 100 30 ]);
+%!                     "string", "Choice 2", ...
+%!                     "units", "normalized", ...
+%!                     "position", [0.01 0 0.98 0.5]);
 %! b3 = uicontrol (f, "style", "radiobutton", ...
-%!                 "string", "Not in the group", ...
-%!                 "Position", [ 10 50 100 50 ]);
-%! disp (['Current selected: ' get(get(gp, 'selectedobject'), 'String')]);
+%!                    "string", "Not in the group", ...
+%!                    "units", "normalized", ...
+%!                    "position", [ 0.01 0 0.98 0.5 ]);
+%! fprintf ("Current selected: %s\n", get (get (gp, "selectedobject"), "string"));
 %! pause (0.5);
-%! disp (['Select None']);
-%! set (gp, 'selectedobject', []);
+%! disp ("Select b2");
+%! set (gp, "selectedobject", b2);
+%! fprintf ("Current selected: %s\n", get (get (gp, "selectedobject"), "string"));
+%! pause (0.5);
+%! disp ("Select None");
+%! set (gp, "selectedobject", []);
 %! pause (0.1);
-%! disp (['Current selected: ' get(get(gp, 'selectedobject'), 'String')]);
-%! pause (0.5);
-%! disp (['Select b1']);
-%! set (gp, 'selectedobject', b1);
-%! disp (['Current selected: ' get(get(gp, 'selectedobject'), 'String')]);
+%! fprintf ("Current selected: %s\n", get (get (gp, "selectedobject"), "string"));
 
-## Uncertain if tests can be performed
-%!assert (1)
+## Test mutual selection logic for radiobuttons
+## FIXME: commented out until a test can be found that doesn't rely on
+##        long values for pause() which still can occasionally fail.
+%!#test <*55230>
+%! hf = figure ("visible", "off");
+%! unwind_protect
+%!   bg = uibuttongroup (hf);
+%!   b1 = uicontrol (bg, "style", "radiobutton", "units", "normalized", ...
+%!                       "position", [0, 0, 1, 0.5]);
+%!   b2 = uicontrol (bg, "style", "radiobutton", "units", "normalized", ...
+%!                       "position", [0, 0.5, 1, 0.5]);
+%!   assert (get (bg, "selectedobject"), b1);
+%!   assert (get (b1, "value"), 1);
+%!   assert (get (b2, "value"), 0);
+%!   ## select radiobutton 2
+%!   set (bg, "selectedobject", b2);
+%!   pause (0.5);
+%!   assert (get (b1, "value"), 0);
+%!   assert (get (b2, "value"), 1);
+%!   ## set radiobutton 1
+%!   set (b1, "value", 1);
+%!   pause (0.5);
+%!   assert (get (bg, "selectedobject"), b1);
+%!   assert (get (b1, "value"), 1);
+%!   assert (get (b2, "value"), 0);
+%!   ## unset all radiobuttons
+%!   set (bg, "selectedobject", []);
+%!   pause (0.5);
+%!   assert (get (b1, "value"), 0);
+%!   assert (get (b2, "value"), 0);
+%!   ## change style of selected button
+%!   set (b1, "value", 1);
+%!   pause (0.5);
+%!   assert (get (bg, "selectedobject"), b1);
+%!   set (b1, "style", "pushbutton");
+%!   pause (0.5);
+%!   assert (get (bg, "selectedobject"), []);
+%!   ## add new button
+%!   b3 = uicontrol (bg, "style", "togglebutton");
+%!   pause (0.5);
+%!   assert (get (bg, "selectedobject"), b3);
+%!   assert (get (b2, "value"), 0);
+%!   assert (get (b3, "value"), 1);
+%!   ## remove selected button
+%!   delete (b3);
+%!   pause (0.5);
+%!   assert (get (bg, "selectedobject"), []);
+%! unwind_protect_cleanup
+%!   close (hf);
+%! end_unwind_protect
+
+## Test mutual selection logic for togglebuttons
+## FIXME: commented out until a test can be found that doesn't rely on
+##        long values for pause() which still can occasionally fail.
+%!#test <*55230>
+%! hf = figure ("visible", "off");
+%! unwind_protect
+%!   bg = uibuttongroup (hf);
+%!   b1 = uicontrol (bg, "style", "togglebutton", "units", "normalized", ...
+%!                       "position", [0, 0, 1, 0.5]);
+%!   b2 = uicontrol (bg, "style", "togglebutton", "units", "normalized", ...
+%!                       "position", [0, 0.5, 1, 0.5]);
+%!   assert (get (bg, "selectedobject"), b1);
+%!   assert (get (b1, "value"), 1);
+%!   assert (get (b2, "value"), 0);
+%!   ## select togglebutton 2
+%!   set (bg, "selectedobject", b2);
+%!   pause (0.5);
+%!   assert (get (b1, "value"), 0);
+%!   assert (get (b2, "value"), 1);
+%!   ## set togglebutton 1
+%!   set (b1, "value", 1);
+%!   pause (0.5);
+%!   assert (get (bg, "selectedobject"), b1);
+%!   assert (get (b1, "value"), 1);
+%!   assert (get (b2, "value"), 0);
+%!   ## unset all togglebuttons
+%!   set (bg, "selectedobject", []);
+%!   pause (0.5);
+%!   assert (get (b1, "value"), 0);
+%!   assert (get (b2, "value"), 0);
+%!   ## change style of selected button
+%!   set (b1, "value", 1);
+%!   pause (0.5);
+%!   assert (get (bg, "selectedobject"), b1);
+%!   set (b1, "style", "pushbutton");
+%!   assert (get (bg, "selectedobject"), []);
+%!   ## add new button
+%!   b3 = uicontrol (bg, "style", "togglebutton");
+%!   pause (0.5);
+%!   assert (get (bg, "selectedobject"), b3);
+%!   assert (get (b2, "value"), 0);
+%!   assert (get (b3, "value"), 1);
+%!   ## remove selected button
+%!   delete (b3);
+%!   pause (0.5);
+%!   assert (get (bg, "selectedobject"), []);
+%! unwind_protect_cleanup
+%!   close (hf);
+%! end_unwind_protect