Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

🐛 Flyouts with large submenus not constraining to nested navigators #1104

Closed
Lootwig opened this issue Aug 25, 2024 · 1 comment · Fixed by #1131
Closed

🐛 Flyouts with large submenus not constraining to nested navigators #1104

Lootwig opened this issue Aug 25, 2024 · 1 comment · Fixed by #1131
Labels
bug Something isn't working

Comments

@Lootwig
Copy link

Lootwig commented Aug 25, 2024

When running the following example (*), the submenu does not respect its parent container's dimensions:

image

class Example extends StatelessWidget {
  const Example({super.key});

  @override
  Widget build(BuildContext context) {
    return FluentApp(
      home: NavigationView(
        pane: NavigationPane(
          items: [
            PaneItem(
              title: Text('hi'),
              icon: SizedBox.square(
                dimension: 28,
                child: Placeholder(),
              ),
              body: Column(
                crossAxisAlignment: CrossAxisAlignment.stretch,
                children: [
                  Container(color: Colors.blue, height: 150),
                  Expanded(
                    child: Navigator(
                      pages: [
                        FluentPage(
                          child: Container(
                            color: Colors.yellow,
                            alignment: Alignment.topLeft,
                            child: BrokenMenu(),
                          ),
                        ),
                      ],
                      onDidRemovePage: (_) {},
                    ),
                  ),
                ],
              ),
            ),
          ],
        ),
      ),
    );
  }
}

class BrokenMenu extends StatefulWidget {
  const BrokenMenu({
    super.key,
  });

  @override
  State<BrokenMenu> createState() => _BrokenMenuState();
}

class _BrokenMenuState extends State<BrokenMenu> {
  final _controller = FlyoutController();
  @override
  Widget build(BuildContext context) {
    return FlyoutTarget(
      controller: _controller,
      child: Button(
        child: Text('click'),
        onPressed: _openMenu,
      ),
    );
  }

  void _openMenu() {
    _controller.showFlyout(
      forceAvailableSpace: true,
      placementMode: FlyoutPlacementMode.bottomCenter,
      builder: (context) => MenuFlyout(
        items: [
          ...Iterable.generate(
            5,
            (_) => MenuFlyoutItem(text: Text('hi there'), onPressed: () {}),
          ),
          MenuFlyoutSubItem(
            text: Text('Subitems'),
            items: (_) => [
              ...Iterable.generate(
                25,
                (_) => MenuFlyoutItem(text: Text('hi there'), onPressed: () {}),
              ),
            ],
          ),
        ],
      ),
    );
  }
}

* Note, the MouseRegion inserted in src/controls/flyouts/menu.dart does not consider the translation of the nested Navigator, causing the test for whether the cursor is on the submenu item to always fail and the submenu to close whenever the mouse moves. I used this dirty fix to get around that:

// ...

    if (keys.isNotEmpty) {
      content = MouseRegion(
        onHover: (event) {
          for (final subItem
              in keys.whereType<GlobalKey<_MenuFlyoutSubItemState>>()) {
            final state = subItem.currentState;
            if (state == null || subItem.currentContext == null) continue;
            if (!state.isShowing(menuInfo)) continue;

            final itemBox =
                subItem.currentContext!.findRenderObject() as RenderBox;
            final b= (parent?.widget.root?.context.findRenderObject() as RenderBox);
            final translation = b.getTransformTo(null).getTranslation();
            final offset = Offset(translation[0], translation[1]);
            final itemRect = (itemBox.localToGlobal(
              Offset.zero,
              ancestor: parent?.widget.root?.context.findRenderObject(),
            ) + offset) &
            itemBox.size;

            if (!itemRect.contains(event.position)) {
              state.close(menuInfo);
            }
          }
        },
        child: content,
      );
    }

// ...
@bdlukaa bdlukaa added the bug Something isn't working label Aug 25, 2024
@Lootwig
Copy link
Author

Lootwig commented Oct 14, 2024

It looks like you integrated the workaround for the unrelated mouse movement issue, but the actual issue seems to not have been addressed, at least with 4.9.2 the menu in the provided example still disappears behind the blue layer and can't be scrolled.

@web-liuyang web-liuyang mentioned this issue Oct 25, 2024
3 tasks
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working
Projects
None yet
Development

Successfully merging a pull request may close this issue.

2 participants