cycfi / elements

Elements C++ GUI library
http://cycfi.github.io/elements/
3.06k stars 232 forks source link

Checkbox checkmark is not updated when linking controls. #179

Closed wsberry closed 10 months ago

wsberry commented 4 years ago

I may be using the control incorrectly.

The workflow is such that when a checkbox is clicked then I would like other checkboxes to also be updated. i.e. Click checkbox A and have checkbox B reflect the same checked state as A.

Example Code:

pragma once

include

include

namespace experimental::elements { namespace colors_rgba { constexpr auto alpha = 200; constexpr auto default_dark = cycfi::elements::rgba(32, 32, 32, alpha); constexpr auto slate_gray = cycfi::elements::rgba(112, 128, 144, alpha); constexpr auto antique_white = cycfi::elements::rgba(250, 235, 215, alpha); constexpr auto doger_blue = cycfi::elements::rgba(16, 78, 139, alpha); }

namespace colors_rgb { constexpr auto default_dark = cycfi::elements::rgb(32, 32, 32); constexpr auto slate_gray = cycfi::elements::rgb(112, 128, 144); constexpr auto antique_white = cycfi::elements::rgb(250, 235, 215); constexpr auto doger_blue = cycfi::elements::rgb(16, 78, 139); }

using check_box_t = cycfi::elements::basic_toggle_button<cycfi::elements::proxy<cycfi::elements::check_box_element, cycfi::elements::basic_button>>;

namespace grpc::controller { // TODO: Load from config file. // auto constexpr default_path = "";

  // Main window background color
  // Is it possible to effect forground colors_rgba?
  //
  auto constexpr bkd_color = elements::colors_rgba::slate_gray;

  class test_options_dialog final
  {
     const cycfi::elements::box_element background = cycfi::elements::box(bkd_color);

     elements::check_box_t check_box1 = cycfi::elements::check_box("gRPC Simulations Server");
     elements::check_box_t check_box2 = cycfi::elements::check_box("gRPC GPS Simulator");
     elements::check_box_t check_box3 = cycfi::elements::check_box("gRPC UAV Simulator");

     // This works, but the repainting of check_box1, 2, and 3 does not.
     // Therefore the user does not receive the desired feedback.
     //
     elements::check_box_t check_box_select_all = cycfi::elements::check_box("Select All");

     std::size_t uav_instances_to_create_ = 5;

     auto make_selection_menu()
     {
        return cycfi::elements::selection_menu(
           [&](std::string_view& select)
           {
              const char* count = select.data();
              uav_instances_to_create_ = std::atol(count);
           },
  {
     "5",
     "10",
     "15",
     "20",
  }

  ).first; // We return only the first, the menu. the second is a shared pointer to the label.
     }

     void run_selected_options() const
     {
        using namespace cycfi::elements;

        const auto simulations_data_bus = std::string(default_path).append("simulations_data_bus.exe");
        const auto gps_device_emulator = std::string(default_path).append("gps_device_emulator.exe");
        const auto uav_entity_simulator = std::string(default_path).append("uav_emulator.exe");

        std::string args = "-ignore";

        if (check_box1.value())
        {
           //system::process::start_process(simulations_data_bus.c_str(), args);
        }

        if (check_box2.value())
        {
           //system::process::start_process(gps_device_emulator.c_str(), args);
        }

        if (check_box3.value())
        {
           auto* uav_fmt = " -uav:\"UAV ";
           const auto end = uav_instances_to_create_;
           for (auto n = 0; n < end; ++n)
           {
              auto arg = uav_fmt + std::to_string(n).append("\"");
              //system::process::start_process(uav_entity_simulator.c_str(), arg);
           }
        }
     }

     auto options_button_layout(cycfi::elements::view& window_view)
     {
        using namespace cycfi::elements;

        auto run_options_button = button("Run Selected Options");

        run_options_button.on_click =
           [&](bool) mutable
        {
           run_selected_options();
        };

        return
           margin({ 20, 0, 20, 20 },
              vtile(
                 top_margin(20, run_options_button),
                 top_margin(10,

                    htile(
                       margin({ 0, 0, 10, 0 },
                          label("UAV Count:")
                          .text_align(canvas::right)),
                       hmin_size(30, make_selection_menu()))
                 ),
                 top_margin(10, check_box_select_all)
              )
           );
     }

     void assign_checkbox_event_handlers(cycfi::elements::view& window_view)
     {
        check_box_select_all.on_click =
           [&](bool) mutable
           {
              check_box_select_all.value(!check_box_select_all.value());

              // ' window_view.refresh(check_box1);' code is not working...
              //
              const auto update = check_box_select_all.value();

              check_box1.on_click(update);
              check_box2.on_click(update);
              check_box3.on_click(update);

              return true;
           };

        check_box1.on_click =
           [&](bool) mutable
           {
              check_box1.value(!check_box1.value());
              window_view.refresh(check_box1);
           };

        check_box2.on_click =
           [&](bool) mutable
           {
              check_box2.value(!check_box2.value());
              window_view.refresh(check_box2);
           };

        check_box3.on_click =
           [&](bool) mutable
           {
              check_box3.value(!check_box3.value());
              window_view.refresh(check_box3);
           };
     }

     auto create_view_models(cycfi::elements::view& window_view)
     {
        using namespace cycfi::elements;

        check_box1.value(false);
        check_box2.value(false);
        check_box3.value(false);

        assign_checkbox_event_handlers(window_view);

        auto  check_boxes =
           group("Components",
              margin({ 10, 10, 20, 20 },
                 top_margin(25,
                    vtile(
                       top_margin(10, align_left(check_box1)),
                       top_margin(10, align_left(check_box2)),
                       top_margin(10, align_left(check_box3))
                    )
                 )
              )
           );

        return
           vtile(
              htile(
                 options_button_layout(window_view),
                 vtile(
                    margin({ 20, 20, 20, 20 }, check_boxes)
                 )
              )
           );
     }

  public:

     auto show(const int argc = 0, char* argv[] = nullptr)
     {
        using namespace cycfi::elements;

        app app_instance(argc, argv, "gRPC - Simulations (Munitions) Data Bus", "");
        window window_model(app_instance.name());
        window_model.on_close = [&app_instance]() { app_instance.stop(); };
        view window_view(window_model);
        window_view.content(create_view_models(window_view), background);
        app_instance.run();
     }
  };
  inline int show_dialog(const int argc, char* argv[])
  {
     test_options_dialog dialog;
     dialog.show(argc, argv);
     return 0;
  }

} } // using namespace experimental::elements;

//#include "grpc-startup-controller.hh"

using namespace experimental::elements::grpc;

/**

Again, this is awesome work you are doing. Thanks so so much!

djowel commented 4 years ago

I suggest either 1) placing the controls in a composite (e.g. a pane or something) and refreshing the whole composite window_view.refresh(a_pane) or 2) simply refreshing the whole view window_view.refresh().

wsberry commented 4 years ago

Thanks!

I will try it out.

Bill Berry

On Thu, Jul 9, 2020 at 5:01 PM Joel de Guzman notifications@github.com wrote:

I suggest either 1) placing the controls in a composite (e.g. a pane or something) and refreshing the whole composite window_view.refresh(a_pane) or 2) simply refreshing the whole view window_view.refresh().

— You are receiving this because you authored the thread. Reply to this email directly, view it on GitHub https://github.com/cycfi/elements/issues/179#issuecomment-656372043, or unsubscribe https://github.com/notifications/unsubscribe-auth/ABOKC7SW6TMGDGXCVKAOD6LR2Y42BANCNFSM4OV7VUTA .

djowel commented 4 years ago

Feel free to ask more questions, or even suggest improvements.

djowel commented 4 years ago

@wsberry were you able to solve your issue? Is it good to close this now?

wsberry commented 4 years ago

I was working on a presentation for work and will be trying the fix later this week.

Thanks

Bill

On Tue, Jul 14, 2020 at 6:21 PM Joel de Guzman notifications@github.com wrote:

@wsberry https://github.com/wsberry were you able to solve your issue? Is it good to close this now?

— You are receiving this because you were mentioned.

Reply to this email directly, view it on GitHub https://github.com/cycfi/elements/issues/179#issuecomment-658459886, or unsubscribe https://github.com/notifications/unsubscribe-auth/ABOKC7VDNFRBIQZ3DYRU4E3R3TSAJANCNFSM4OV7VUTA .

wsberry commented 4 years ago

Joel,

The following did not work:

 check_box1.on_click =
           [&](bool) mutable
        {
           check_box1.value(!check_box1.value());

           // Does not work:
              window_view.refresh();
           // also does not work
              window_view.refresh(check_box1);
        }

I did not have time to test a 'panel' since I need to look up how to use it...i.e. I was hoping to do something like this:

check_box_panel = top_margin(25, vtile( top_margin(10, align_left(check_box1)), top_margin(10, align_left(check_box2)), top_margin(10, align_left(check_box3)) ) ); The above code is not supported. I plan to take a look at this tomorrow when I have more time.

Also, I will have time to trace through the code tomorrow to see why a standard refresh won't work on the control itself. This will give me an opportunity to learn better what I am doing with the elements framework.

Thanks,

Bill Berry

On Tue, Jul 14, 2020 at 8:56 PM William Berry wberry.cpp@gmail.com wrote:

I was working on a presentation for work and will be trying the fix later this week.

Thanks

Bill

On Tue, Jul 14, 2020 at 6:21 PM Joel de Guzman notifications@github.com wrote:

@wsberry https://github.com/wsberry were you able to solve your issue? Is it good to close this now?

— You are receiving this because you were mentioned.

Reply to this email directly, view it on GitHub https://github.com/cycfi/elements/issues/179#issuecomment-658459886, or unsubscribe https://github.com/notifications/unsubscribe-auth/ABOKC7VDNFRBIQZ3DYRU4E3R3TSAJANCNFSM4OV7VUTA .

djowel commented 4 years ago

Joel, The following did not work:

Hrmmm... Well, if you post an MVCE (as minimal as you can get it to be), I can try it out myself to see what's happening. The view refresh mechanism should work. The radio buttons and menus do something similar to what you are doing.

djowel commented 4 years ago

@wsberry is this still an issue and will you post an MVCE if it is?

wsberry commented 4 years ago

Yes I had looked into and your prior suggestions did not work for me.

I am using elements to write some support tools so fixing it has been on the bottom of my list. I.e. I am tracing through the problem during some of break times.

This said I can certainly post an MVCE and will try to do so today.

Bill Berry

On Wed, Aug 26, 2020 at 2:13 AM Joel de Guzman notifications@github.com wrote:

@wsberry https://github.com/wsberry is this still an issue and will you post an MVCE if it is?

— You are receiving this because you were mentioned. Reply to this email directly, view it on GitHub https://github.com/cycfi/elements/issues/179#issuecomment-680703449, or unsubscribe https://github.com/notifications/unsubscribe-auth/ABOKC7U4OBAGZQBV3ZJYVYTSCSYX5ANCNFSM4OV7VUTA .

djowel commented 4 years ago

Appreciated!

djowel commented 3 years ago

Any update?

wsberry commented 3 years ago

Joel,

Attached is a minimal test program. I have not had the time to debug the code but will if some time frees up for me.

I did try your earlier suggestions but none of them worked.

Thanks

Bill Berry

On Sun, Sep 13, 2020 at 7:25 AM Joel de Guzman notifications@github.com wrote:

Any update?

— You are receiving this because you were mentioned. Reply to this email directly, view it on GitHub https://github.com/cycfi/elements/issues/179#issuecomment-691665101, or unsubscribe https://github.com/notifications/unsubscribe-auth/ABOKC7RAUFNVRCFPXS3COI3SFS22LANCNFSM4OV7VUTA .

include

include

include

namespace colors { constexpr auto default_dark = cycfi::elements::rgba(32, 32, 32,/alpha:/155); auto constexpr bkd_color = colors::default_dark; }

// Basic check box type // using check_box_t = cycfi::elements::basic_toggle_button<cycfi::elements::proxy<cycfi::elements::check_box_element, cycfi::elements::basic_button>>;

class test_options_dialog final { const cycfi::elements::box_element background = cycfi::elements::box(colors::bkd_color); check_box_t check_box1 = cycfi::elements::check_box("A"); check_box_t check_box2 = cycfi::elements::check_box("B"); check_box_t check_box3 = cycfi::elements::check_box("C"); check_box_t check_box_select_all = cycfi::elements::check_box("Select All");

void run_selected_options() const { using namespace cycfi::elements;

  std::string args = "-ignore";

  if (check_box1.value())
  {
     std::cout << "1 selected\n";
  }

  if (check_box2.value())
  {
     std::cout << "2 selected\n";
  }

  if (check_box3.value())
  {
     std::cout << "1 selected\n";
  }

}

auto options_button_layout(cycfi::elements::view& window_view) { using namespace cycfi::elements;

  auto run_options_button = button("Run Selected Options");

  run_options_button.on_click =
     [&](bool) mutable
  {
     run_selected_options();
  };

  return
     margin({ 20, 0, 20, 20 },
        vtile(

           top_margin(20, run_options_button),
           top_margin(10, check_box_select_all)

        )

     );

}

auto create_view_models(cycfi::elements::view& window_view) { using namespace cycfi::elements;

  check_box1.value(false);
  check_box2.value(false);
  check_box3.value(false);

  // TODO: Not Working
  //
  check_box_select_all.on_click =
     [&](bool) mutable
  {
     check_box_select_all.value(!check_box_select_all.value());
     const auto update = check_box_select_all.value();

     // *** The following code is not working. The check_boxes are
     //     in a checked state, but do not reflect the state on
     //     the GUI (i.e. the box is not checked).
     //
     check_box1.on_click(update);
     check_box2.on_click(update);
     check_box3.on_click(update);

     window_view.refresh();

     return true;
  };

  check_box1.on_click =
     [&](bool) mutable
  {
     check_box1.value(!check_box1.value());
  };

  check_box2.on_click =
     [&](bool) mutable
  {
     check_box2.value(!check_box2.value());
  };

  check_box3.on_click =
     [&](bool) mutable
  {
     check_box3.value(!check_box3.value());
  };

  auto  check_boxes =
     group("Components",
        margin({ 10, 10, 20, 20 },
           top_margin(25,
              vtile(
                 top_margin(10, align_left(check_box1)),
                 top_margin(10, align_left(check_box2)),
                 top_margin(10, align_left(check_box3))
              )
           )
        )
     );

  return
     vtile(
        htile(
           options_button_layout(window_view),
           vtile(
              margin({ 20, 20, 20, 20 }, check_boxes)
           )
        )
     );

}

public:

auto show(const int argc = 0, char* argv[] = nullptr) { using namespace cycfi::elements;

  app app_instance(argc, argv, "Checkbox Tester", "anyar.research.experimental");

  window window_model(app_instance.name());

  window_model.on_close = [&app_instance]() { app_instance.stop(); };

  view window_view(window_model);

  window_view.content(
     create_view_models(window_view),
     background
  );

  app_instance.run();

} }; inline int show_dialog(const int argc, char* argv[]) { test_options_dialog dialog; dialog.show(argc, argv); return 0; }

int main(const int argc, char* argv[]) { return show_dialog(argc, argv); }

djowel commented 3 years ago

OK, got it. Thanks for the MVCE. It really helps!

The main issue here is that: if you want an element to interact with other elements, you need to "share" it and "hold" the shared element in the composition. There are a couple of unrelated changes I made to your code which I shall explain below. Here's the correct code:

#include <string>
#include <iostream>
#include <elements.hpp>

using namespace cycfi::elements;

namespace colors
{
    constexpr auto default_dark = rgba(32, 32, 32, 255);
    auto constexpr bkd_color = ::colors::default_dark;
}

// Basic check box type
//
using check_box_t = decltype(share(check_box("name")));

class test_options_dialog final
{
    const box_element background =      box(::colors::bkd_color);
    check_box_t check_box1 =            share(check_box("A"));
    check_box_t check_box2 =            share(check_box("B"));
    check_box_t check_box3 =            share(check_box("C"));
    check_box_t check_box_select_all =  share(check_box("Select All"));

    void run_selected_options() const
    {
        std::string args = "-ignore";

        if (check_box1->value())
        {
            std::cout << "1 selected\n";
        }
        else
        {
            std::cout << "1 not selected\n";
        }

        if (check_box2->value())
        {
            std::cout << "2 selected\n";
        }
        else
        {
            std::cout << "2 not selected\n";
        }

        if (check_box3->value())
        {
            std::cout << "3 selected\n";
        }
        else
        {
            std::cout << "3 not selected\n";
        }
    }

    auto options_button_layout(view& window_view)
    {
       auto run_options_button = button("Run Selected Options");

       run_options_button.on_click =
            [&](bool) mutable
            {
                run_selected_options();
            };

       return
            margin({ 20, 0, 20, 20 },
                vtile(
                    top_margin(20, run_options_button),
                    top_margin(10, hold(check_box_select_all))
                )
            );
    }

    auto create_view_models(view& window_view)
    {
       check_box1->value(false);
       check_box2->value(false);
       check_box3->value(false);

       check_box_select_all->on_click =
            [&](bool) mutable
            {
                const auto update = check_box_select_all->value();

                check_box1->value(update);
                check_box2->value(update);
                check_box3->value(update);

                window_view.refresh();

                return true;
            };

       auto  check_boxes =
            group("Components",
                margin({ 10, 10, 20, 20 },
                    top_margin(25,
                        vtile(
                            top_margin(10, align_left(hold(check_box1))),
                            top_margin(10, align_left(hold(check_box2))),
                            top_margin(10, align_left(hold(check_box3)))
                        )
                    )
                )
            );

       return
            vtile(
                htile(
                    options_button_layout(window_view),
                    vtile(
                        margin({ 20, 20, 20, 20 }, check_boxes)
                    )
                )
            );
    }

public:

    auto show(const int argc = 0, char* argv[] = nullptr)
    {
       app app_instance(argc, argv, "Checkbox Tester", "anyar.research.experimental");
       window window_model(app_instance.name());
       window_model.on_close = [&app_instance]() { app_instance.stop(); };
       view window_view(window_model);

       window_view.content(
            create_view_models(window_view),
            background
       );

       app_instance.run();
    }
};

inline int show_dialog(const int argc, char* argv[])
{
    test_options_dialog dialog;
    dialog.show(argc, argv);
    return 0;
}

int main(const int argc, char* argv[])
{
    return show_dialog(argc, argv);
}

A couple of things:

  1. Use decltype. It will make your life so much easier. See line 15.
  2. The interacting check-boxes are "shared".
  3. The interacting elements are held ("hold"). Lines 73 and 108-110.
  4. Don't set the value via on_click. Do it via btn->value(val); line 94-96

Aside: I removed the code where you changed the value of the button in the on_click (e.g. check_box3.value(!check_box3.value());). That is not necessary and is incorrect. Another aside: A non-opaque background might be confusing (in this case) because the previous drawing state persists.

I hope this helps! This will be clarified in the documentation currently WIP.

djowel commented 3 years ago

The reason why you need to "share" and "hold" interacting elements is that the elements uses value semantics everywhere. So, when you make a composition, the elements are actually copied. Therefore, if you do not share the element, it will not be the same element that is actually held in the composition. "share" and "hold" changes value semantics to reference semantics.

djowel commented 3 years ago

I'll close this now. Feel free to reopen if you are not satisfied with the answer.

djowel commented 3 years ago

Hmmm... actually, I'll reopen this for the sake of others who have the same problem, pending proper documentation.

wsberry commented 3 years ago

Thanks Joel!

This is a great help!

Thank you also for the tips, corrections, and other suggestions.

I am looking forward to getting deeper into elements.

On Mon, Sep 14, 2020 at 7:45 PM Joel de Guzman notifications@github.com wrote:

OK, got it. Thanks for the MVCE. It really helps!

The main issue here is that: if you want an element to interact with other elements, you need to "share" it and "hold" the shared element in the composition. There are a couple of unrelated changes I made to your code which I shall explain below. Here's the correct code:

include

include

include

using namespace cycfi::elements; namespace colors { constexpr auto default_dark = rgba(32, 32, 32, 255); auto constexpr bkd_color = ::colors::default_dark; } // Basic check box type//using check_box_t = decltype(share(check_box("name"))); class test_options_dialog final { const box_element background = box(::colors::bkd_color); check_box_t check_box1 = share(check_box("A")); check_box_t check_box2 = share(check_box("B")); check_box_t check_box3 = share(check_box("C")); check_box_t check_box_select_all = share(check_box("Select All"));

void run_selected_options() const
{
   std::string args = "-ignore";

   if (check_box1->value())
   {
      std::cout << "1 selected\n";
   }
   else
   {
      std::cout << "1 not selected\n";
   }

   if (check_box2->value())
   {
      std::cout << "2 selected\n";
   }
   else
   {
      std::cout << "2 not selected\n";
   }

   if (check_box3->value())
   {
      std::cout << "3 selected\n";
   }
   else
   {
      std::cout << "3 not selected\n";
   }
}

auto options_button_layout(view& window_view)
{
   auto run_options_button = button("Run Selected Options");

   run_options_button.on_click =
           [&](bool) mutable
           {
               run_selected_options();
           };

   return
           margin({ 20, 0, 20, 20 },
                  vtile(

                          top_margin(20, run_options_button),
                          top_margin(10, hold(check_box_select_all))

                  )

           );
}

auto create_view_models(view& window_view)
{
   check_box1->value(false);
   check_box2->value(false);
   check_box3->value(false);

   // TODO: Not Working
   //
   check_box_select_all->on_click =
           [&](bool) mutable
           {
            //    check_box_select_all->value(!check_box_select_all->value());
               const auto update = check_box_select_all->value();

               check_box1->value(update);
               check_box2->value(update);
               check_box3->value(update);

               window_view.refresh();

               return true;
           };

   auto  check_boxes =
           group("Components",
                 margin({ 10, 10, 20, 20 },
                        top_margin(25,
                                   vtile(
                                           top_margin(10, align_left(hold(check_box1))),
                                           top_margin(10, align_left(hold(check_box2))),
                                           top_margin(10, align_left(hold(check_box3)))
                                   )
                        )
                 )
           );

   return
           vtile(
                   htile(
                           options_button_layout(window_view),
                           vtile(
                                   margin({ 20, 20, 20, 20 }, check_boxes)
                           )
                   )
           );
}

public:

auto show(const int argc = 0, char* argv[] = nullptr)
{
   app app_instance(argc, argv, "Checkbox Tester", "anyar.research.experimental");

   window window_model(app_instance.name());

   window_model.on_close = [&app_instance]() { app_instance.stop(); };

   view window_view(window_model);

   window_view.content(
           create_view_models(window_view),
           background
   );

   app_instance.run();
}

};inline int show_dialog(const int argc, char argv[]) { test_options_dialog dialog; dialog.show(argc, argv); return 0; } int main(const int argc, char argv[]) { return show_dialog(argc, argv); }

A couple of things:

  1. Use decltype. It will make your life so much easier. See line 15.
  2. The interacting check-boxes are "shared".
  3. The interacting elements are held ("hold"). Lines 73 and 108-110.
  4. Don't set the value via on_click. Do it via btn->value(val); line 94-96

Aside: I removed the code where you changed the value of the button in the on_click (e.g. check_box3.value(!check_box3.value());). That is not necessary and is incorrect.

I hope this helps! This will be clarified in the documentation currently WIP.

— You are receiving this because you were mentioned. Reply to this email directly, view it on GitHub https://github.com/cycfi/elements/issues/179#issuecomment-692393200, or unsubscribe https://github.com/notifications/unsubscribe-auth/ABOKC7TR2IPX7OT7IT3IUCTSF22KPANCNFSM4OV7VUTA .

Xeverous commented 3 years ago

@djowel have you thought about different implementations of the event handling/bounds calculation? Something of ECS type or signal-slot? These are very far from elements implementation but I'm curious if you have considered them and if yes - what are your thoughts on them. IMO I have a feeling that ECS can have much more efficient handling (although every element would need to be connected to sort of cerntral registry - many elements require view anyway) and signal-slot can scale much better (instead of iterating over elemens, it's iterating over signals and connected slots).

djowel commented 3 years ago

@djowel have you thought about different implementations of the event handling/bounds calculation? Something of ECS type or signal-slot? These are very far from elements implementation but I'm curious if you have considered them and if yes - what are your thoughts on them. IMO I have a feeling that ECS can have much more efficient handling (although every element would need to be connected to sort of cerntral registry - many elements require view anyway) and signal-slot can scale much better (instead of iterating over elemens, it's iterating over signals and connected slots).

I was inclined to flag this as OT, but I didn't do it because it is tangentially related. I'll give my reply, but I'll make it short. If you want to discuss design issues further, well, this is not the place for it. There's the discord group chat for that.

Anyway, my answer will also be irrelevant primarily because at this point, it's too late in the design cycle to change things the way they are. As I pointed out elsewhere, I am no longer inclined to entertain substantial design changes.

But answering for the sake of answering... Focusing on the on* handlers only as relevant in this discussion, I prefer direct communication between components. Signals-and-slots has its place, for sure, but in terms of design, the analogy is a bulletin board where one posts messages and interested parties connect to be notified of such posts they are interested in. Essentially a one-to-many relationship. For elements, I prefer a one-to-one relationship, because generally that's what's happening. Moreover, direct communication via the on* handlers does not preclude one-to-many relationships. For instance, an on_click function is generic enough and can connect to an app specific signals/slots or "event bus". It's up to you, the app designer, if you want that. There is no system-wide "way of doing things" that is forced into the user. That follows the keep-it-simple design principle.

If you are thinking about replying further, please don't. Instead, move the discussion over to the discord chat group. I do not want to veer too much from the topic.

Xeverous commented 3 years ago

Ok, thanks for the response. This answer is enough.