class ScrollPanelLayoutManager implements LayoutManager {

        boolean hasChanged;

        public ScrollPanelLayoutManager() {
            hasChanged = true;
        }


        @Override
        public TerminalSize getPreferredSize(List<Component> components) {
            TerminalSize sizeA = compA.getPreferredSize();
            int aWidth = sizeA.getColumns();
            int aHeight = sizeA.getRows();
            TerminalSize sizeB = compB.getPreferredSize();
            int bWidth = sizeB.getColumns();
            int bHeight = sizeB.getRows();

            int tWidth = thumb.getPreferredSize().getColumns();
            int tHeight = thumb.getPreferredSize().getRows();

            if (isHorizontal) {
                return new TerminalSize(aWidth + tWidth + bWidth, Math.max(aHeight, Math.max(tHeight, bHeight)));
            } else {
                return new TerminalSize(Math.max(aWidth, Math.max(tWidth, bWidth)), aHeight + tHeight + bHeight);
            }
        }

        @Override
        public void doLayout(TerminalSize area, List<Component> components) {<FILL_FUNCTION_BODY>}

        @Override
        public boolean hasChanged() {
            return hasChanged;
        }
    }

            TerminalSize size = getSize();

            // xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
            // TODO: themed
            int length = isHorizontal ? size.getRows() : size.getColumns();
            TerminalSize tsize = new TerminalSize(isHorizontal ? 1 : length, !isHorizontal ? 1 : length);
            TextImage textImage = new BasicTextImage(tsize);
            Theme theme = getTheme();
            ThemeDefinition themeDefinition = theme.getDefaultDefinition();
            ThemeStyle themeStyle = themeDefinition.getNormal();

            TextCharacter thumbRenderer = TextCharacter.fromCharacter(
                    isHorizontal ? Symbols.SINGLE_LINE_VERTICAL : Symbols.SINGLE_LINE_HORIZONTAL,
                    themeStyle.getForeground(),
                    themeStyle.getBackground());
            if (thumb.isFocused()) {
                thumbRenderer = thumbRenderer.withModifier(SGR.BOLD);
            }

            textImage.setAll(thumbRenderer);
            thumb.setTextImage(textImage);
            // xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx

            int tWidth = thumb.getPreferredSize().getColumns();
            int tHeight = thumb.getPreferredSize().getRows();

            int w = size.getColumns();
            int h = size.getRows();

            if (isHorizontal) {
                w -= tWidth;
            } else {
                h -= tHeight;
            }

            TerminalSize compAPrevSize = compA.getSize();
            TerminalSize compBPrevSize = compB.getSize();
            TerminalSize thumbPrevSize = thumb.getSize();
            TerminalPosition compAPrevPos = compA.getPosition();
            TerminalPosition compBPrevPos = compB.getPosition();
            TerminalPosition thumbPrevPos = thumb.getPosition();

            if (isHorizontal) {
                int leftWidth = Math.max(0, (int) (w * ratio));
                int leftHeight = Math.max(0, Math.min(compA.getPreferredSize().getRows(), h));

                int rightWidth = Math.max(0, w - leftWidth);
                int rightHeight = Math.max(0, Math.min(compB.getPreferredSize().getRows(), h));

                compA.setSize(new TerminalSize(leftWidth, leftHeight));
                thumb.setSize(thumb.getPreferredSize());
                compB.setSize(new TerminalSize(rightWidth, rightHeight));

                compA.setPosition(new TerminalPosition(0, 0));
                thumb.setPosition(new TerminalPosition(leftWidth, h / 2 - tHeight / 2));
                compB.setPosition(new TerminalPosition(leftWidth + tWidth, 0));
            } else {
                int leftWidth = Math.max(0, Math.min(compA.getPreferredSize().getColumns(), w));
                int leftHeight = Math.max(0, (int) (h * ratio));

                int rightWidth = Math.max(0, Math.min(compB.getPreferredSize().getColumns(), w));
                int rightHeight = Math.max(0, h - leftHeight);

                compA.setSize(new TerminalSize(leftWidth, leftHeight));
                thumb.setSize(thumb.getPreferredSize());
                compB.setSize(new TerminalSize(rightWidth, rightHeight));

                compA.setPosition(new TerminalPosition(0, 0));
                thumb.setPosition(new TerminalPosition(w / 2 - tWidth / 2, leftHeight));
                compB.setPosition(new TerminalPosition(0, leftHeight + tHeight));
            }

            hasChanged = !compAPrevPos.equals(compA.getPosition()) ||
                    !compAPrevSize.equals(compA.getSize()) ||
                    !compBPrevPos.equals(compB.getPosition()) ||
                    !compBPrevSize.equals(compB.getSize()) ||
                    !thumbPrevPos.equals(thumb.getPosition()) ||
                    !thumbPrevSize.equals(thumb.getSize());
        
<methods>public void <init>() ,public void <init>(com.googlecode.lanterna.gui2.LayoutManager) ,public com.googlecode.lanterna.gui2.Panel addComponent(com.googlecode.lanterna.gui2.Component) ,public com.googlecode.lanterna.gui2.Panel addComponent(int, com.googlecode.lanterna.gui2.Component) ,public com.googlecode.lanterna.gui2.Panel addComponent(com.googlecode.lanterna.gui2.Component, com.googlecode.lanterna.gui2.LayoutData) ,public com.googlecode.lanterna.TerminalSize calculatePreferredSize() ,public boolean containsComponent(com.googlecode.lanterna.gui2.Component) ,public int getChildCount() ,public Collection<com.googlecode.lanterna.gui2.Component> getChildren() ,public List<com.googlecode.lanterna.gui2.Component> getChildrenList() ,public com.googlecode.lanterna.TextColor getFillColorOverride() ,public com.googlecode.lanterna.gui2.LayoutManager getLayoutManager() ,public boolean handleInput(com.googlecode.lanterna.input.KeyStroke) ,public void invalidate() ,public boolean isInvalid() ,public com.googlecode.lanterna.gui2.Interactable nextFocus(com.googlecode.lanterna.gui2.Interactable) ,public com.googlecode.lanterna.gui2.Interactable previousFocus(com.googlecode.lanterna.gui2.Interactable) ,public com.googlecode.lanterna.gui2.Panel removeAllComponents() ,public boolean removeComponent(com.googlecode.lanterna.gui2.Component) ,public void setFillColorOverride(com.googlecode.lanterna.TextColor) ,public synchronized com.googlecode.lanterna.gui2.Panel setLayoutManager(com.googlecode.lanterna.gui2.LayoutManager) ,public void updateLookupMap(com.googlecode.lanterna.gui2.InteractableLookupMap) <variables>private com.googlecode.lanterna.TerminalSize cachedPreferredSize,private final non-sealed List<com.googlecode.lanterna.gui2.Component> components,private com.googlecode.lanterna.TextColor fillColorOverride,private com.googlecode.lanterna.gui2.LayoutManager layoutManager