iTwin / appui

Monorepo for iTwin.js AppUi
MIT License
8 stars 2 forks source link

Ability to get information about specific widget container #450

Closed DenisMicha closed 3 weeks ago

DenisMicha commented 1 year ago

There is a need to set the state of a specific widget (open/closed/etc.) on element selection based on whether the widget is alone in its container or not, but currently it is not possible to get that information to check the condition.

For that on element selection it should be possible to get information about what is the container/container Id for a specific widget, and about what widgets that container contains/number of widgets in that container, or to check the condition mentioned above in any other way if possible.

raplemie commented 1 year ago

As a widget can typically be dragged to any panel/floating panel, what is the usecase where this condition would not be confusing to the user ?

DenisMicha commented 1 year ago

It shouldn't be confusing to the user. Lets say I have a widget A, and a couple of widgets B and C. No matter in which panel it is, when A is in the same container as B or C or both, the goal is to make sure that on element selection the A will not be auto-focused/auto-selected, and if the A widget is alone in its container, then of course it will be focused/open. So we need to be able to set widget A state on element selection to open ONLY when it is alone in its container, otherwise it should be set to closed at that moment.

raplemie commented 1 year ago

You would get this exact behavior by simply always setting the widget state to "Closed" whenever the widget is not already "Open": If the panel is empty (so hidden), the panel will show with your widget open, as it will be the only widget in the panel, (be it side or floating) If the panel is visible but the widget is hidden, it will show the tab, but not set it active.

DenisMicha commented 1 year ago

Do you mean just

if (widget.state !== Open) { widget.setState(Closed) } on element selection? If so, it does not work in my case:

raplemie commented 1 year ago

Hi, if it needs to be completely hidden when there is no selection, this must be in the condition, I was thinking of something like that:

SyncUiEventDispatcher.onSyncUiEvent.addListener(({eventIds}) => {
  if(!eventIds.has(SyncUiEventId.SelectionSetChanged)) return;
  const widget = UiFramework.frontstages.activeFrontstageDef?.findWidgetDef("myWidget");
  if(!widget) return;

  const selected = UiFramework.getIModelConnection()?.selectionSet.size ?? 0 > 0;
  if(!selected) {
    widget.setWidgetState(WidgetState.Hidden);
    return;
  }
  if(widget.state === WidgetState.Open || widget.state === WidgetState.Floating) return;
  widget.setWidgetState(WidgetState.Closed);
})

However, I apprently did something wrong in my initial testing as indeed, when the widget is to float back alone in its container, it open collapsed. I'll see what we can do about it and how the API could be improved.

GerardasB commented 3 weeks ago

Looking for a valid use case. Closing this issue for now. I'd advise using a combination of useWidget to figure out if the widget is docked vs popout vs floating(and its state i.e. whether it's hidden or not) and something like media queries or useWidgetDirection to figure out the appropriate widget content layout.