Any support for Split Buttons?

Anyone know if there is support for a Split Button? If not, any ideas on how I could implement it either as a custom component or component composition?

They have this type of component in Ext JS:
http://www.extjs.com/deploy/dev/examples/button/buttons.html

Basically I want a button that acts both as a button and a menu depending on where you click on it.

Thanks.

Maybe the
PopupButton
is what you’re looking for?

Another solution might be to style the Select component with CSS to look like a button. Well, I don’t know how easy that would be.

I suppose you could do it with composition as well, perhaps from a Button and a (Native)Select, though that would require some heavy styling as well (half-a-button + half-a-select).

Unfortunately the PopupButton won’t work for me.

As in the example on the page I linked to:
If you click on the left side of the button (to the left of the down arrow) it reacts exactly like a button.
If you click on the down array, it reacts like a menu.

So basically I want to combine the 2 components.
I want the style of the button around the entire component, but have the inside of the component to be part button and part menu. As for the menu, I would even want sub menus.

Ok, I see, I thought it would also act as a Button as it actually inherits it. Perhaps Henri adds that feature in future.

Meanwhile, you could try compositing the split button, perhaps from a Button and the PopupButton. You’ll need to crop the components a bit.

I thought that this would make a nice example of CustomComponent capabilities, so here:

/** A Button + Select compoment. */
class SplitButton extends CustomComponent {
    Button button;
    Select select;

    public SplitButton(String caption, Container dataSource) {
        addStyleName("splitbutton");
        
        HorizontalLayout layout = new HorizontalLayout();

        // Create the Button part on the left
        button = new Button(caption);
        layout.addComponent(button);
        
        // Create the Select part on the right
        select = new Select();
        select.setNullSelectionAllowed(false);
        select.setWidth("26px"); // Truncate to get only the button
        select.setContainerDataSource(dataSource);
        select.setImmediate(true); // Immediate by default
        layout.addComponent(select);
        
        setCompositionRoot(layout);
    }
    
    /* Forward various methods to the proper subcomponent. */
    public void addListener(Button.ClickListener listener) {
        button.addListener(listener);
    }
    
    public void addListener(Property.ValueChangeListener listener) {
        select.addListener(listener);
    }
    
    public void setIcon(Resource icon) {
        button.setIcon(icon);
    }

    public void setCaption(String caption) {
        button.setCaption(caption);
    }
    
    public void setContainerDataSource(Container newDataSource) {
        select.setContainerDataSource(newDataSource);
    }
}

void joining() {
    VerticalLayout layout = new VerticalLayout();
    
    // Items for the drop-down menu
    IndexedContainer container = new IndexedContainer();
    String items[] = new String[]
 {"Hard", "Harder", "Even harder"};
    for (String item: items)
        container.addItem(item);
    
    SplitButton splitbutton = new SplitButton("Kick me", container);
    
    // Handle clicks in the Button part
    splitbutton.addListener(new Button.ClickListener() {
        public void buttonClick(ClickEvent event) {
            getWindow().showNotification("Aaaaagh!");
        }
    });

    // Handle selections in the drop-down list
    splitbutton.addListener(new Property.ValueChangeListener() {
        public void valueChange(ValueChangeEvent event) {
            getWindow().showNotification((String) event.getProperty().getValue());
        }
    });
    
    layout.addComponent(splitbutton);

You’ll also need to tweak the CSS a little:

.splitbutton .v-filterselect-input {
    display: none;
}

.splitbutton .v-filterselect-button {
    border-left: thin solid gray;
}

.splitbutton .v-button-wrap {
    margin-right: -10px; /* Crop the right side of the Button. */
}

Check out the
live example
. I tested it on Firefox; hopefully the CSS trick works in other browsers as well.

The v-filterselect-button (Select button) may need a bit further tweaking, the image doesn’t fit exactly with the Button part.

Quite ingenious, Marko, I must say.

Though I’d change the composition root from HorizontalLayout to CssLayout, making it a bit more light-weight to render. Other than that, and the obvious additional styling, this should be enough.

The UIDL message overhead shouldn’t be much, but of course the ComboBox will render some unneeded DOM elements, which slow down rendering by some factor.

And it works in Safari as well. No reason it shouldn’t work in other browsers as well.

This demonstrates that server-side only composition also works and reasonable to be used instead of creating a new client widget :wink: I supose, the UIDL overhead will be the same - both button and combo box are working as usual and independent.