Issue with layered RichText input

We are trying to utilize the RichText component and are running into an input issue. RichText input seems to be disabled if the object it is attached to, or any object below it in the hierarchy (render wise) has input enabled. So in a test environment it works fine but try to use RichText in a real world case, it will not work at all.

Here is some sample code that shows the problem in as simple a way as I could make it:

  auto visibleSize = Director::getInstance()->getVisibleSize();
  auto size = Size(150.0f, visibleSize.height);

  auto rt1 = ui::RichText::create();
  rt1->ignoreContentAdaptWithSize(false);
  rt1->setContentSize(size);
  rt1->setPositionType(ui::Widget::PositionType::PERCENT);
  rt1->setPositionPercent(Vec2(0.25f, 0.5f));
  rt1->setAnchorPoint(Vec2::ANCHOR_MIDDLE);
  rt1->setOpenUrlHandler([](std::string url){
    if(url == "hit_here") {
      static int i1 = 0;
      CCLOG("Hit Left: %d", i1++);
    }
  });
 
  auto layout = ui::Layout::create();
  layout->setContentSize(size);
  layout->setPositionType(ui::Widget::PositionType::PERCENT);
  layout->setPositionPercent(Vec2(0.75f, 0.5f));
  layout->setAnchorPoint(Vec2::ANCHOR_MIDDLE);
  
  // Comment out this line and the input will be detected correctly on rt2
  layout->setTouchEnabled(true);

  auto rt2 = ui::RichText::create();
  rt2->ignoreContentAdaptWithSize(false);
  rt2->setContentSize(layout->getContentSize());
  rt2->setPositionType(ui::Widget::PositionType::PERCENT);
  rt2->setPositionPercent(Vec2::ANCHOR_MIDDLE);
  rt2->setAnchorPoint(Vec2::ANCHOR_MIDDLE);
  rt2->setOpenUrlHandler([](std::string url){
    if(url == "hit_here") {
      static int i2 = 0;
      CCLOG("Hit Right: %d", i2++);
    }
  });
  
  layout->addChild(rt2);
  addChild(layout);
  addChild(rt1);

  rt1->pushBackElement(ui::RichElementText::create(1, Color3B::GRAY, 255, "This will detect clicks.  ", "fonts/arial.ttf", 30));
  rt1->pushBackElement(ui::RichElementText::create(2, Color3B::RED, 255, "Click Here", "fonts/arial.ttf", 30, ui::RichElementText::URL_FLAG, "hit_here"));

  rt2->pushBackElement(ui::RichElementText::create(1, Color3B::GRAY, 255, "This will not detect clicks.  ", "fonts/arial.ttf", 30));
  rt2->pushBackElement(ui::RichElementText::create(2, Color3B::RED, 255, "Click Here", "fonts/arial.ttf", 30, ui::RichElementText::URL_FLAG, "hit_here"));

Comment out the setTouchEnabled line and the RichText will get its input.

I’m going to continue to investigate this and will post a reply if I find the problem. In the meantime if any one smarter than me finds a solution, please post it here!

I ended up finding a solution to this that involves two changes to the (RichText) ListenerComponent:

  1. Replace the EventListenerTouchAllAtOnce event handler with EventListenerTouchOneByOne. Most nodes use EventListenerTouchOneByOne for event handling, but RichText used EventListenerTouchAllAtOnce. It appears that intermixing these two is not a good idea. If anything using EventListenerTouchOneByOne was swallowing events (a scrim for example) at ANY render order it would prevent EventListenerTouchAllAtOnce from getting input.
  2. Update the render order node to the RichText container. The priority of the Event handler is defined by the parent node. In this case the parent of the ‘ListenerComponent’ are the Labels used by RichText. This all seems fine until you realize that the Labels are not children of the RichText, and therefore are not part of the scene tree and so they have no priority order.

I will formulate a PR for the cocos repository to fix this for everyone.