mabe02 / lanterna

Java library for creating text-based GUIs
GNU Lesser General Public License v3.0
2.24k stars 243 forks source link

Add visible field to component #473

Open keithkml opened 4 years ago

keithkml commented 4 years ago

An invisible component would have no height/width, and would not have any inter-component border/spacing applied by the layout manager. This would be useful for components which are only relevant in some contexts.

mabe02 commented 4 years ago

I've avoided to add a visible flag on components so far because it makes the layout manager / focus / input handling more complicated and it would take time to go through all components and test. For LinearLayout/BorderLayout, I think it's easy to just remove/re-add the component you want to hide. GridLayout is possibly more complicated as it maintains the order. You could create a wrapper panel and remove/re-add the actual component from there.

keithkml commented 4 years ago

It's not that easy to re-add the component in the right spot (requires some ugly code IMO).

Creating a wrapper panel doesn't work if the layout has spacing between components.

keithkml commented 4 years ago

I’m working on a PR for this. I think full support would be a very large PR, so I’m wondering what you guys would consider acceptable at first. Which of these features do you consider mandatory?

  1. Visibility honored in layout managers 1a. LinearLayout flex mode 1b. LinearLayout legacy mode 1c. GridLayout 1d. BorderLayout 1e. (I think there’s one more layout manager but I’m on my phone right now and can’t look it up :)
  2. Focus support (probably by making enabled only true if visible)
  3. Mouse support

Are there any other areas that I’d need to address in an initial PR? Note that I personally don’t need mouse support and I only use LinearLayout and GridLayout, so I’d be happy with only implementing 1a, 1c, and 2 🙂

mabe02 commented 4 years ago

Well, unfortunately, I think we'll need to support it in all layout managers. Could split it up into multiple PRs. Focus will be a problem so that needs to be addressed too. Don't think mouse is that important, but you'll need probably need to set the component size to zero as well so the InteractableLookupMap still works and doesn't add the invisible component.

ginkoblongata commented 4 years ago

I think that if you make a builder component or utility method which solves this, the PR will not be too involved, it can leverage some object which applications can use in building their screens.

When the event occurs, they just update the Map<Component, Boolean> and re-call this utility.

Unless I misunderstand, you are talking about objects taking up zero space on screen and not receiving input unless they are visible, which is really that they are not there at all, they only reside there in the sense that there is some marker to spring them back into existence upon some event.

Instead of broad sweeping changes, a utility method which builds the screen can take all the components and a mapping of booleans of those components which are invisible. (these names not much thought out)

// or this may be utility method in AbstractComponent
public class SomeUtilityClassThing {
    // generally base pane
    public Component constructUi(UserUiBuilder lambda, Map<Component, Boolean> userManaged) {
        Component full = lambda.adhocUiLayoutStuff(userManaged);
        Component swiss = visitComponentTreeAndRemoveSome(full, userManaged);
        return swiss;
    }
}

// user applications will create a lambda which is their meat and potatoes
@Interface UserUiBuilder {
    Component adhocUiLayoutStuff()
}

Users can make use of the utility method by passing in a lambda of the above which does the construction of the screen, the user will manage the booleans in the map and provide it.

Upon relevant events, users just need to resubmit their lambda and their map to the utiltiy method and replace the base pane or whatever correlating part this comp tree is for.

Since it is the same comps being sent to adHocUiiLayoutStuff, any state of selection etc will be preserved.

ginkoblongata commented 4 years ago

This utility could reside in the container and then the components setVisibile() method can just turn around and call upwards to the container until the top and it can have the mapping and re-call the lambda.

In this way, no layout manager changes are needed.

mabe02 commented 4 years ago

Hmm, yes, maybe that would work. I'll take a look today.

mabe02 commented 4 years ago

@keithkml @ginkoblongata I've pushed to 3.1 and master the "visible" flag on Component and implemented it in each of the four available layout managers. Let's see if this works for everyone.