/******************************************************************************* * Copyright 2013 Geoscience Australia * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. ******************************************************************************/ package au.gov.ga.earthsci.common.ui.widgets; import org.eclipse.swt.SWT; import org.eclipse.swt.custom.SashForm; import org.eclipse.swt.events.ControlAdapter; import org.eclipse.swt.events.ControlEvent; import org.eclipse.swt.events.ExpandEvent; import org.eclipse.swt.events.ExpandListener; import org.eclipse.swt.layout.FillLayout; import org.eclipse.swt.widgets.Button; import org.eclipse.swt.widgets.Composite; import org.eclipse.swt.widgets.Display; import org.eclipse.swt.widgets.ExpandBar; import org.eclipse.swt.widgets.ExpandItem; import org.eclipse.swt.widgets.Label; import org.eclipse.swt.widgets.Shell; /** * {@link SashForm} that contains two {@link ExpandBar}s with a sash between * them. Ensures that at least one of the bars is expanded at all times, such * that the SashForm is filled. * * @author Michael de Hoog (michael.dehoog@ga.gov.au) */ public class DoubleExpandSashForm extends SashForm { private final ExpandBar expandBar1, expandBar2; private final ExpandItem expandItem1, expandItem2; private final ExpandListener expandListener1, expandListener2; private ExpandBar expandingBar; private int[] weights; public DoubleExpandSashForm(Composite parent, int style) { super(parent, style | SWT.VERTICAL | SWT.SMOOTH); expandBar1 = new ExpandBar(this, SWT.V_SCROLL); expandBar1.setBackground(getBackground()); expandBar1.setSpacing(0); expandBar2 = new ExpandBar(this, SWT.V_SCROLL); expandBar2.setBackground(getBackground()); expandBar2.setSpacing(0); expandItem1 = new ExpandItem(expandBar1, SWT.NONE); expandItem1.setExpanded(true); expandItem2 = new ExpandItem(expandBar2, SWT.NONE); expandItem2.setExpanded(true); expandListener1 = setupListeners(expandBar1, expandItem1); expandListener2 = setupListeners(expandBar2, expandItem2); addControlListener(new ControlAdapter() { @Override public void controlResized(ControlEvent e) { expandingBar = expandBar1; if (!expandItem1.getExpanded()) { setWeights(weightsForOneCollapsed(true)); } else if (!expandItem2.getExpanded()) { setWeights(weightsForOneCollapsed(false)); } expandingBar = null; } }); } protected ExpandListener setupListeners(final ExpandBar expandBar, final ExpandItem expandItem) { final boolean lastItem = expandBar == expandBar2; expandBar.addControlListener(new ControlAdapter() { @Override public void controlResized(ControlEvent e) { int height = expandBar.getBounds().height - expandItem.getHeaderHeight() - expandBar.getSpacing() * 2; boolean expand = height > 0; if (expandingBar != expandBar && expandItem.getExpanded() != expand) { expandItem.setExpanded(expand); } if (expand) { expandItem.setHeight(height); } } }); ExpandListener expandListener = new ExpandListener() { @Override public void itemExpanded(ExpandEvent e) { expand(true); } @Override public void itemCollapsed(ExpandEvent e) { expand(false); } private void expand(boolean expand) { try { expandingBar = expandBar; ExpandItem otherExpandItem = lastItem ? expandItem1 : expandItem2; int[] weights; if (expand && otherExpandItem.getExpanded()) { if (DoubleExpandSashForm.this.weights != null) { weights = DoubleExpandSashForm.this.weights; } else { weights = new int[] { 1, 1 }; } } else { weights = weightsForOneCollapsed(lastItem == expand); } if (weights[0] > 0 && weights[1] > 0) { setWeights(weights); } } finally { expandingBar = null; } } }; expandBar.addExpandListener(expandListener); return expandListener; } private int[] weightsForOneCollapsed(boolean firstCollapsed) { int[] weights = new int[2]; int availableHeight = getBounds().height - getSashWidth(); if (firstCollapsed) { weights[0] = expandBar1.getSpacing() * 2 + expandItem1.getHeaderHeight(); weights[1] = availableHeight - weights[0]; } else { weights[1] = expandBar2.getSpacing() * 2 + expandItem2.getHeaderHeight(); weights[0] = availableHeight - weights[1]; } weights[1]--; //bugfix return weights; } @Override public void setWeights(int[] weights) { super.setWeights(weights); if (expandingBar == null) { this.weights = weights; } } public ExpandBar getExpandBar1() { return expandBar1; } public ExpandBar getExpandBar2() { return expandBar2; } public ExpandItem getExpandItem1() { return expandItem1; } public ExpandItem getExpandItem2() { return expandItem2; } public void setExpandItem1Expanded(boolean expand) { expandItem(expandItem1, expandListener1, expand); } public void setExpandItem2Expanded(boolean expand) { expandItem(expandItem2, expandListener2, expand); } private void expandItem(ExpandItem expandItem, ExpandListener expandListener, boolean expand) { if (expand != expandItem.getExpanded()) { expandItem.setExpanded(expand); if (expand) { expandListener.itemExpanded(null); } else { expandListener.itemCollapsed(null); } } } public static void main(String[] args) { final Display display = new Display(); Shell shell = new Shell(display); shell.setLayout(new FillLayout()); DoubleExpandSashForm form = new DoubleExpandSashForm(shell, SWT.NONE); form.setLayout(new FillLayout()); ExpandBar expandBar1 = form.getExpandBar1(); Composite child1 = new Composite(expandBar1, SWT.NONE); child1.setLayout(new FillLayout()); new Label(child1, SWT.NONE).setText("Label in pane 1"); //$NON-NLS-1$ form.getExpandItem1().setControl(child1); ExpandBar expandBar2 = form.getExpandBar2(); Composite child2 = new Composite(expandBar2, SWT.NONE); child2.setLayout(new FillLayout()); new Button(child2, SWT.PUSH).setText("Button in pane2"); //$NON-NLS-1$ form.getExpandItem2().setControl(child2); form.setWeights(new int[] { 70, 30 }); shell.open(); while (!shell.isDisposed()) { if (!display.readAndDispatch()) { display.sleep(); } } display.dispose(); } }