/*******************************************************************************
* Copyright (c) 2012 Google, Inc.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* Google, Inc. - initial API and implementation
*******************************************************************************/
package com.windowtester.eclipse.ui.layout;
import org.eclipse.swt.*;
import org.eclipse.swt.graphics.*;
import org.eclipse.swt.widgets.*;
public class CardLayout extends Layout
{
/**
* The maximum of the widths of all of the children.
*/
protected int maxWidth = -1;
/**
* The maximum of the heights of all of the children.
*/
protected int maxHeight = -1;
/**
* The composite for whom this layout lays out the children.
*/
protected Composite owner;
/**
* The identifier of the child that was last made visible.
*/
protected String visibleChildId;
////////////////////////////////////////////////////////////////////////////
//
// Constructors
//
////////////////////////////////////////////////////////////////////////////
/**
* Initialize a newly created layout for the given owner.
*
* @param owner the composite whose controls will be layed out by this layout
*/
public CardLayout(Composite owner)
{
this.owner = owner;
}
////////////////////////////////////////////////////////////////////////////
//
// Visibility Control
//
////////////////////////////////////////////////////////////////////////////
/**
* Cause the child of the owning composite with the given identifier to be
* made visible and the previously visible control to be hidden.
*
* @param identifier the identifier of the control to be made visible
*/
public void show(String identifier)
{
Control[] children;
int oldIndex, newIndex;
if (owner.isDisposed())
return;
children = owner.getChildren();
oldIndex = indexOfVisibleChild(children);
visibleChildId = identifier;
newIndex = indexOfVisibleChild(children);
if (newIndex >= 0 && newIndex != oldIndex) {
children[newIndex].setVisible(true);
if (oldIndex >= 0) {
children[oldIndex].setVisible(false);
}
}
}
////////////////////////////////////////////////////////////////////////////
//
// Layout Methods
//
////////////////////////////////////////////////////////////////////////////
/**
* Computes and returns the size of the specified composite's client area
* according to this layout.
* <p>
* This method computes the minimum size that the client area of the
* composite must be in order to position all children at their minimum
* size inside the composite according to the layout algorithm encoded by
* this layout.
* <p>
* When a width or height hint is supplied, it is used to constrain the
* result. For example, if a width hint is provided that is less than the
* minimum width of the client area, the layout may choose to wrap and
* increase height, clip, overlap, or otherwise constrain the children.
*
* @param composite a composite widget using this layout
* @param wHint width (SWT.DEFAULT for minimum)
* @param hHint height (SWT.DEFAULT for minimum)
* @param flushCache true means flush cached layout values
*
* @return a point containing the computed size (width, height)
*/
protected Point computeSize(Composite composite, int wHint, int hHint, boolean flushCache)
{
int width, height;
initialize(composite, flushCache);
width = wHint;
height = hHint;
if (wHint == SWT.DEFAULT) {
width = maxWidth;
}
if (hHint == SWT.DEFAULT) {
height = maxHeight;
}
return new Point(width, height);
}
/**
* Lays out the children of the specified composite according to this layout.
* <p>
* This method positions and sizes the children of a composite using the
* layout algorithm encoded by this layout. Children of the composite are
* positioned in the client area of the composite. The position of the
* composite is not altered by this method.
* <p>
* When the flush cache hint is true, the layout is instructed to flush any
* cached values associated with the children. Typically, a layout will cache
* the preferred sizes of the children to avoid the expense of computing
* these values each time the widget is layed out.
* <p>
* When layout is triggered explicitly by the programmer the flush cache hint
* is true. When layout is triggered by a resize, either caused by the
* programmer or by the user, the hint is false.
*
* @param composite a composite widget using this layout
* @param flushCache <code>true</code> means flush cached layout values
*/
protected void layout(Composite composite, boolean flushCache)
{
Rectangle clientArea;
Control[] children;
int visibleIndex;
clientArea = composite.getClientArea();
children = composite.getChildren();
visibleIndex = indexOfVisibleChild(children);
for (int i = 0; i < children.length; i++) {
children[i].setBounds(clientArea);
children[i].setVisible(i == visibleIndex);
}
}
////////////////////////////////////////////////////////////////////////////
//
// Utilities
//
////////////////////////////////////////////////////////////////////////////
/**
* Initialize the maximum width and height from the given composite if they
* have not already been computed or if the given flag is <code>true</code>.
*
* @param composite a composite widget using this layout
* @param flushCache <code>true</code> means flush cached layout values
*/
protected void initialize(Composite composite, boolean flushCache)
{
Control[] children;
Point size;
if (flushCache || maxWidth < 0 || maxHeight < 0) {
children = composite.getChildren();
maxWidth = 0;
maxHeight = 0;
for (int i = 0; i < children.length; i++) {
size = children[i].computeSize(SWT.DEFAULT, SWT.DEFAULT, true);
maxWidth = Math.max(maxWidth, size.x);
maxHeight = Math.max(maxHeight, size.y);
}
}
}
/**
* Return the index of the visible child in the given list of children.
* If the visible child has not yet been initialized, or if it is no
* longer in the list, then make the first control in the list be the
* visible child. If the list is empty, return <code>-1</code>.
*
* @param children the list of children
*
* @return the index of the visible child
*/
protected int indexOfVisibleChild(Control[] children)
{
if (visibleChildId != null) {
for (int i = 0; i < children.length; i++) {
if (visibleChildId.equals(children[i].getLayoutData())) {
return i;
}
}
}
if (children.length > 0) {
visibleChildId = (String) children[0].getLayoutData();
return 0;
}
return -1;
}
}