package com.peterhi.ui;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.SortedSet;
import java.util.TreeSet;
import org.eclipse.swt.SWT;
import org.eclipse.swt.custom.CTabFolder;
import org.eclipse.swt.custom.CTabItem;
import org.eclipse.swt.graphics.Cursor;
import org.eclipse.swt.graphics.Image;
import org.eclipse.swt.graphics.Point;
import org.eclipse.swt.graphics.Rectangle;
import org.eclipse.swt.layout.FillLayout;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Control;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Event;
import org.eclipse.swt.widgets.Label;
import org.eclipse.swt.widgets.Layout;
import org.eclipse.swt.widgets.Listener;
import org.eclipse.swt.widgets.Shell;
import com.peterhi.Util;
public final class ViewPanel extends Composite {
public static final String ID = "id";
public static final String TITLE = "title";
public static final String DESCRIPTION = "description";
public static final String ICON = "icon";
public static final String REF_VIEW = "refView";
public static final String POSITION = "position";
public static final String EXTENT = "extent";
public static final String BOUNDS = "bounds";
static final int MIN_EXTENT = 100;
private static final String ITEM = "item";
public static enum Position {
TAB_AFTER,
TAB_BEFORE,
SPLIT_LEFT,
SPLIT_TOP,
SPLIT_RIGHT,
SPLIT_BOTTOM,
DOCK_LEFTMOST,
DOCK_TOPMOST,
DOCK_RIGHTMOST,
DOCK_BOTTOMMOST,
AUTOHIDE_WEST,
AUTOHIDE_NORTH,
AUTOHIDE_EAST,
AUTOHIDE_SOUTH,
FLOAT;
public boolean isTabbed() {
return this == TAB_AFTER || this == TAB_BEFORE;
}
public boolean isSplit() {
return this == SPLIT_LEFT || this == SPLIT_TOP ||
this == SPLIT_RIGHT || this == SPLIT_BOTTOM;
}
public boolean isDocked() {
return this == DOCK_LEFTMOST || this == DOCK_TOPMOST ||
this == DOCK_RIGHTMOST || this == DOCK_BOTTOMMOST;
}
public boolean isAutohidden() {
return this == AUTOHIDE_WEST || this == AUTOHIDE_NORTH ||
this == AUTOHIDE_EAST || this == AUTOHIDE_SOUTH;
}
public boolean isFloated() {
return this == FLOAT;
}
public boolean isPositiveDirection() {
return this == TAB_AFTER || this == SPLIT_RIGHT ||
this == SPLIT_BOTTOM || this == DOCK_RIGHTMOST ||
this == DOCK_BOTTOMMOST || this == AUTOHIDE_EAST ||
this == AUTOHIDE_SOUTH;
}
public boolean isNegativeDirection() {
return this == TAB_BEFORE || this == SPLIT_LEFT ||
this == SPLIT_TOP || this == DOCK_LEFTMOST ||
this == DOCK_TOPMOST || this == AUTOHIDE_WEST ||
this == AUTOHIDE_NORTH;
}
public boolean isHorizontal() {
return this == SPLIT_LEFT || this == SPLIT_RIGHT ||
this == DOCK_LEFTMOST || this == DOCK_RIGHTMOST ||
this == AUTOHIDE_WEST || this == AUTOHIDE_EAST;
}
public boolean isVertical() {
return this == SPLIT_TOP || this == SPLIT_BOTTOM ||
this == DOCK_TOPMOST || this == DOCK_BOTTOMMOST ||
this == AUTOHIDE_NORTH || this == AUTOHIDE_SOUTH;
}
public boolean isLeft() {
return isHorizontal() && isNegativeDirection();
}
public boolean isTop() {
return isVertical() && isNegativeDirection();
}
public boolean isRight() {
return isHorizontal() && isPositiveDirection();
}
public boolean isBottom() {
return isVertical() && isPositiveDirection();
}
}
public static void main(String[] args) {
Display display = Display.getDefault();
Shell shell = new Shell(display);
shell.setLayout(new FillLayout());
ViewPanel panel = new ViewPanel(shell, SWT.NONE);
shell.setSize(1152, 640);
Label view0 = new Label(panel, SWT.NONE);
{
view0.setText("View 0");
view0.setData(ID, "view0");
view0.setData(TITLE, "View 0");
view0.setData(DESCRIPTION, "Description of view0.");
view0.setData(ICON, UiImages.T.about16());
panel.add(view0);
}
Label view1 = new Label(panel, SWT.NONE);
{
view1.setText("View 1");
view1.setData(ID, "view1");
view1.setData(TITLE, "View 1");
view1.setData(DESCRIPTION, "Description of view1.");
view1.setData(REF_VIEW, view0);
view1.setData(POSITION, Position.SPLIT_BOTTOM);
panel.add(view1);
}
Label view2 = new Label(panel, SWT.NONE);
{
view2.setText("View 2");
view2.setData(ID, "view2");
view2.setData(TITLE, "View 2");
view2.setData(DESCRIPTION, "Description of view2");
view2.setData(REF_VIEW, view0);
view2.setData(POSITION, Position.SPLIT_RIGHT);
panel.add(view2);
}
Label view3 = new Label(panel, SWT.NONE);
{
view3.setText("View 3");
view3.setData(ID, "view3");
view3.setData(TITLE, "View 3");
view3.setData(DESCRIPTION, "Description of view3");
view3.setData(REF_VIEW, view1);
view3.setData(POSITION, Position.SPLIT_LEFT);
view3.setData(EXTENT, "0.33");
panel.add(view3);
}
Label view4 = new Label(panel, SWT.NONE);
{
view4.setText("View 4");
view4.setData(ID, "view4");
view4.setData(TITLE, "View 4");
view4.setData(DESCRIPTION, "Description of view4");
view4.setData(REF_VIEW, view1);
view4.setData(POSITION, Position.SPLIT_RIGHT);
view4.setData(EXTENT, "0.50");
panel.add(view4);
}
/*Label view0 = new Label(panel, SWT.NONE);
{
view0.setText("View 0");
view0.setData(ID, "view0");
view0.setData(TITLE, "View 0");
view0.setData(DESCRIPTION, "Description of view 0.");
view0.setData(ICON, UiImages.T.about16());
panel.add(view0);
}
Label view1 = new Label(panel, SWT.NONE);
{
view1.setText("View 1");
view1.setData(ID, "view1");
view1.setData(TITLE, "View 1");
view1.setData(DESCRIPTION, "Description of view 1.");
view1.setData(REF_VIEW, view0);
panel.add(view1);
}
Label view2 = new Label(panel, SWT.NONE);
{
view2.setText("View 2");
view2.setData(ID, "view2");
view2.setData(TITLE, "View 2");
view2.setData(DESCRIPTION, "Description of view 2.");
view2.setData(REF_VIEW, view1);
view2.setData(POSITION, Position.TAB_BEFORE);
panel.add(view2);
}
Label view3 = new Label(panel, SWT.NONE);
{
view3.setText("View 3");
view3.setData(ID, "view3");
view3.setData(TITLE, "View 3");
view3.setData(DESCRIPTION, "Description of view 3.");
view3.setData(REF_VIEW, view1);
view3.setData(POSITION, Position.SPLIT_BOTTOM);
view3.setData(EXTENT, "0.3");
panel.add(view3);
}
Label view4 = new Label(panel, SWT.NONE);
{
view4.setText("View 4");
view4.setData(ID, "view4");
view4.setData(TITLE, "View 4");
view4.setData(DESCRIPTION, "Description of view 4.");
view4.setData(REF_VIEW, view1);
view4.setData(POSITION, Position.SPLIT_RIGHT);
view4.setData(EXTENT, "0.3");
panel.add(view4);
}
Label view5 = new Label(panel, SWT.NONE);
{
view5.setText("View 5");
view5.setData(ID, "view5");
view5.setData(TITLE, "View 5");
view5.setData(DESCRIPTION, "Description of view 5.");
view5.setData(REF_VIEW, view2);
view5.setData(POSITION, Position.SPLIT_LEFT);
view5.setData(EXTENT, "0.4");
panel.add(view5);
}
Label view6 = new Label(panel, SWT.NONE);
{
view6.setText("View 6");
view6.setData(ID, "view6");
view6.setData(TITLE, "View 6");
view6.setData(DESCRIPTION, "Description of view 6.");
view6.setData(REF_VIEW, view2);
view6.setData(POSITION, Position.SPLIT_TOP);
panel.add(view6);
}*/
shell.open();
while (!shell.isDisposed()) {
if (!display.readAndDispatch()) {
display.sleep();
}
}
}
private final SplitDockPanel centerPanel;
private final AutohidePanel leftPanel;
private final AutohidePanel topPanel;
private final AutohidePanel rightPanel;
private final AutohidePanel bottomPanel;
private int spacing;
private Control activeView;
public ViewPanel(Composite parent, int style) {
super(parent, style);
centerPanel = new SplitDockPanel(this, SWT.CENTER);
leftPanel = new AutohidePanel(this, SWT.LEFT);
topPanel = new AutohidePanel(this, SWT.TOP);
rightPanel = new AutohidePanel(this, SWT.RIGHT);
bottomPanel = new AutohidePanel(this, SWT.BOTTOM);
spacing = 10;
addListener(SWT.Resize, new Listener() {
@Override
public void handleEvent(Event event) {
layout();
}
});
}
@Override
public void layout(boolean changed) {
Rectangle c = getClientArea();
Point l = leftPanel.computeSize(SWT.DEFAULT, SWT.DEFAULT);
Point t = topPanel.computeSize(SWT.DEFAULT, SWT.DEFAULT);
Point r = rightPanel.computeSize(SWT.DEFAULT, SWT.DEFAULT);
Point b = bottomPanel.computeSize(SWT.DEFAULT, SWT.DEFAULT);
centerPanel.setBounds(c.x + l.x, c.y + t.y, c.width - l.x - r.x,
c.height - t.y - b.y);
leftPanel.setBounds(c.x, c.y + t.y, l.x, c.height - t.y - b.y);
topPanel.setBounds(c.x + l.x, c.y, c.width - l.x - r.x, t.y);
rightPanel.setBounds(c.x + c.width - r.x, c.y + t.y, r.x,
c.height - t.y - b.y);
bottomPanel.setBounds(c.x + l.x, c.y + c.height - b.y,
c.width - l.x - r.x, b.y);
}
@Override
public void setLayout(Layout layout) {
}
@Override
public Point computeSize(int wHint, int hHint, boolean changed) {
Point size = super.computeSize(wHint, hHint, changed);
Point min = new Point(0, 0);
Point l = leftPanel.computeSize(SWT.DEFAULT, SWT.DEFAULT);
Point t = topPanel.computeSize(SWT.DEFAULT, SWT.DEFAULT);
Point r = rightPanel.computeSize(SWT.DEFAULT, SWT.DEFAULT);
Point b = bottomPanel.computeSize(SWT.DEFAULT, SWT.DEFAULT);
min.x += l.x + r.x;
min.y += t.y + b.y;
if (size.x < min.x) {
size.x = min.x;
}
if (size.y < min.y) {
size.y = min.y;
}
return size;
}
public boolean add(Control view) {
if (contains(view)) {
setActiveView(view);
return false;
}
String id = (String )view.getData(ID);
String title = (String )view.getData(TITLE);
String description = (String )view.getData(DESCRIPTION);
Image icon = (Image )view.getData(ICON);
Control refView = (Control )view.getData(REF_VIEW);
Position position = (Position )view.getData(POSITION);
String extentExpr = (String )view.getData(EXTENT);
String boundsExpr = (String )view.getData(BOUNDS);
if (Util.isEmpty(id)) {
return false;
}
if (title == null) {
title = id;
}
if (description == null) {
description = "";
}
if (icon == null) {
icon = UiImages.T.defaultView();
}
if (refView == null) {
refView = getActiveView();
}
if (position == null) {
position = Position.TAB_AFTER;
}
if (Util.isEmpty(extentExpr)) {
extentExpr = "0.5";
}
Extent extent = new Extent(extentExpr);
Bounds bounds = null;
if (!Util.isEmpty(boundsExpr)) {
bounds = new Bounds(boundsExpr);
}
if (isEmpty()) {
addInitialView(view, title, description, icon);
} else if (position.isTabbed()) {
addTabbedView(view, refView, position, title, description, icon);
} else if (position.isSplit()) {
addSplitView(view, refView, position, extent, title,
description, icon);
}
view.setData(TITLE, null);
view.setData(DESCRIPTION, null);
view.setData(ICON, null);
view.setData(REF_VIEW, null);
view.setData(POSITION, null);
view.setData(EXTENT, null);
view.setData(BOUNDS, null);
setActiveView(view);
return true;
}
public Control getActiveView() {
return activeView;
}
public boolean setActiveView(Control view) {
Object data = view.getData(ITEM);
if (data instanceof CTabItem) {
CTabItem item = (CTabItem )data;
CTabFolder folder = item.getParent();
folder.setSelection(item);
return true;
}
return false;
}
public int getSpacing() {
return spacing;
}
private boolean isEmpty() {
Control[] views = getViews();
return Util.isEmpty(views);
}
private boolean contains(Control v) {
Control[] views = getViews();
for (Control view : views) {
if (view == v) {
return true;
}
}
return false;
}
private Control[] getViews() {
List<Control> views = new ArrayList<Control>();
Control[] children = centerPanel.getChildren();
for (Control child : children) {
TabPanel panel = (TabPanel )child;
CTabFolder folder = panel.getTabFolder();
CTabItem[] items = folder.getItems();
for (CTabItem item : items) {
Control control = item.getControl();
views.add(control);
}
}
return views.toArray(new Control[views.size()]);
}
private boolean addInitialView(Control view, String title,
String description, Image icon) {
Rectangle clientArea = centerPanel.getClientArea();
TabPanel tab = new TabPanel(centerPanel, SWT.NONE);
tab.setBounds(clientArea);
addAfter(tab, view, null, title, description, icon);
return true;
}
private boolean addTabbedView(Control view, Control refView,
Position position, String title, String description, Image icon) {
if (refView == null) {
return false;
}
CTabItem item = (CTabItem )refView.getData(ITEM);
if (item == null) {
return false;
}
CTabFolder folder = item.getParent();
TabPanel panel = (TabPanel )folder.getParent();
if (position.isNegativeDirection()) {
addBefore(panel, view, refView, title, description, icon);
} else {
addAfter(panel, view, refView, title, description, icon);
}
return true;
}
private boolean addSplitView(Control view, Control refView,
Position position, Extent extent, String title, String description,
Image icon) {
CTabItem refItem = (CTabItem )refView.getData(ITEM);
CTabFolder refFolder = refItem.getParent();
TabPanel refPanel = (TabPanel )refFolder.getParent();
Rectangle full = refPanel.getBounds();
Rectangle old = new Rectangle(full.x, full.y, full.width, full.height);
Rectangle neo = new Rectangle(full.x, full.y, full.width, full.height);
int size = position.isVertical() ? full.height : full.width;
size -= spacing;
size = extent.getValue(size);
if (size < MIN_EXTENT) {
size = MIN_EXTENT;
}
if (position.isLeft()) {
old.x += spacing + size;
old.width -= spacing + size;
neo.width = size;
} else if (position.isTop()) {
old.y += spacing + size;
old.height -= spacing + size;
neo.height = size;
} else if (position.isBottom()) {
old.height -= spacing + size;
neo.y += old.height + spacing;
neo.height = size;
} else {
old.width -= spacing + size;
neo.x += old.width + spacing;
neo.width = size;
}
if (old.width < MIN_EXTENT || old.height < MIN_EXTENT ||
neo.width < MIN_EXTENT || neo.height < MIN_EXTENT) {
return false;
}
TabPanel newPanel = new TabPanel(centerPanel, SWT.NONE);
add(newPanel, view, title, description, icon, -1);
refPanel.setBounds(old);
newPanel.setBounds(neo);
centerPanel.layout();
return true;
}
private CTabItem addBefore(TabPanel tab, Control view, Control refView,
String title, String description, Image icon) {
CTabFolder folder = tab.getTabFolder();
CTabItem item = (CTabItem )refView.getData(ITEM);
int count = folder.getItemCount();
int index = -1;
if (item != null) {
index = folder.indexOf(item);
}
if (index < 0) {
index = count;
}
return add(tab, view, title, description, icon, index);
}
private CTabItem addAfter(TabPanel tab, Control view, Control refView,
String title, String description, Image icon) {
CTabFolder folder = tab.getTabFolder();
CTabItem item = null;
if (refView != null) {
item = (CTabItem )refView.getData(ITEM);
}
int count = folder.getItemCount();
int index = -1;
if (item != null) {
index = folder.indexOf(item);
}
if (index < 0) {
index = count;
}
return add(tab, view, title, description, icon, index + 1);
}
private CTabItem add(TabPanel tab, Control view, String title,
String description, Image icon, int index) {
CTabFolder folder = tab.getTabFolder();
int count = folder.getItemCount();
if (index < 0 || index > count) {
index = count;
}
CTabItem item = new CTabItem(folder, SWT.CLOSE, index);
item.setText(title);
item.setToolTipText(description);
item.setImage(icon);
view.setParent(folder);
item.setControl(view);
view.setData(ITEM, item);
return item;
}
}
final class AutohidePanel extends Composite {
public AutohidePanel(Composite parent, int style) {
super(parent, style);
addListener(SWT.Resize, new Listener() {
@Override
public void handleEvent(Event event) {
layout();
}
});
}
@Override
public ViewPanel getParent() {
return (ViewPanel )super.getParent();
}
@Override
public boolean setParent(Composite parent) {
if (!(parent instanceof ViewPanel)) {
return false;
}
return super.setParent(parent);
}
@Override
public void layout(boolean changed) {
}
@Override
public void setLayout(Layout layout) {
}
@Override
public Point computeSize(int wHint, int hHint, boolean changed) {
Point size = super.computeSize(wHint, hHint, changed);
if (isHorizontal()) {
size.y = 2;
} else if (isVertical()) {
size.x = 2;
}
return size;
}
public boolean isLeft() {
int style = getStyle();
return (style & SWT.LEFT) == SWT.LEFT;
}
public boolean isTop() {
int style = getStyle();
return (style & SWT.TOP) == SWT.TOP;
}
public boolean isRight() {
int style = getStyle();
return (style & SWT.RIGHT) == SWT.RIGHT;
}
public boolean isBottom() {
int style = getStyle();
return (style & SWT.BOTTOM) == SWT.BOTTOM;
}
public boolean isHorizontal() {
if (isTop()) {
return true;
}
if (isBottom()) {
return true;
}
int style = getStyle();
return (style & SWT.HORIZONTAL) == SWT.HORIZONTAL;
}
public boolean isVertical() {
if (isLeft()) {
return true;
}
if (isRight()) {
return true;
}
int style = getStyle();
return (style & SWT.VERTICAL) == SWT.VERTICAL;
}
}
final class SplitDockPanel extends Composite {
private Rectangle oldClientArea;
private Set<LWSplitBar> splitBars;
private Set<LWSplitCorner> splitCorners;
private Point down;
private Point offset;
private LWSplitGroup[] groups;
private Set<TabPanel>[] affected;
private Set<Rectangle>[] collided;
private Map<TabPanel, Rectangle> downCache;
private Integer minX;
private Integer minY;
private Integer maxX;
private Integer maxY;
public SplitDockPanel(ViewPanel parent, int style) {
super(parent, style);
addListener(SWT.Resize, new Listener() {
@Override
public void handleEvent(Event event) {
layout();
}
});
Listener cursorListener = new Listener() {
@Override
public void handleEvent(Event event) {
if (down != null) {
return;
}
Display d = event.display;
LWSplitControl splitControl =
findSplitControl(event.x, event.y);
if (splitControl instanceof LWSplitCorner) {
Cursor cursor = d.getSystemCursor(SWT.CURSOR_SIZEALL);
setCursor(cursor);
} else if (splitControl instanceof LWSplitBar) {
LWSplitBar splitBar = (LWSplitBar )splitControl;
Cursor cursor = d.getSystemCursor(splitBar.isVertical() ?
SWT.CURSOR_SIZEWE : SWT.CURSOR_SIZENS);
setCursor(cursor);
}
}
};
addListener(SWT.MouseEnter, cursorListener);
addListener(SWT.MouseMove, cursorListener);
addListener(SWT.MouseExit, new Listener() {
@Override
public void handleEvent(Event event) {
Display d = event.display;
Cursor cursor = d.getSystemCursor(SWT.CURSOR_ARROW);
setCursor(cursor);
groups = null;
}
});
addListener(SWT.MouseDown, new Listener() {
@SuppressWarnings("unchecked")
@Override
public void handleEvent(Event event) {
LWSplitControl splitControl = findSplitControl(event.x, event.y);
Rectangle cBounds = splitControl.bounds();
down = new Point(event.x, event.y);
offset = new Point(event.x - cBounds.x, event.y - cBounds.y);
if ((event.stateMask & SWT.ALT) == SWT.ALT) {
groups = makeGroups(splitControl);
} else {
groups = makeSimpleGroups(splitControl);
}
affected = new Set[groups.length * 2];
collided = new Set[groups.length * 2];
downCache = new HashMap<TabPanel, Rectangle>();
for (int i = 0; i < groups.length; i++) {
LWSplitGroup activeGroup = groups[i];
System.arraycopy(affected(activeGroup), 0, affected,
i * 2, 2);
System.arraycopy(collided(activeGroup), 0, collided,
i * 2, 2);
}
for (Set<TabPanel> affectedPanelSet : affected) {
for (TabPanel affectedPanel : affectedPanelSet) {
downCache.put(affectedPanel, affectedPanel.getBounds());
}
}
for (int i = 0; i < groups.length; i++) {
LWSplitGroup group = groups[i];
Set<TabPanel> affectedBefore = affected[i * 2 + 0];
Set<TabPanel> affectedAfter = affected[i * 2 + 1];
for (TabPanel b : affectedBefore) {
Rectangle bBounds = b.getBounds();
if (group.isVertical()) {
if (minX == null ||
bBounds.x + ViewPanel.MIN_EXTENT > minX) {
minX = bBounds.x + ViewPanel.MIN_EXTENT;
}
} else {
if (minY == null ||
bBounds.y + ViewPanel.MIN_EXTENT > minY) {
minY = bBounds.y + ViewPanel.MIN_EXTENT;
}
}
}
for (TabPanel a : affectedAfter) {
Rectangle aBounds = a.getBounds();
if (group.isVertical()) {
if (maxX == null || aBounds.x + aBounds.width -
ViewPanel.MIN_EXTENT < maxX) {
maxX = aBounds.x + aBounds.width -
ViewPanel.MIN_EXTENT;
}
} else {
if (maxY == null || aBounds.y + aBounds.height -
ViewPanel.MIN_EXTENT < maxY) {
maxY = aBounds.y + aBounds.height -
ViewPanel.MIN_EXTENT;
}
}
}
}
}
});
addListener(SWT.MouseMove, new Listener() {
@Override
public void handleEvent(Event event) {
if (down == null) {
return;
}
Map<TabPanel, Rectangle> moveCache = new HashMap<TabPanel, Rectangle>();
for (Set<TabPanel> affectedPanelSet : affected) {
for (TabPanel affectedPanel : affectedPanelSet) {
moveCache.put(affectedPanel, affectedPanel.getBounds());
}
}
int spacing = getParent().getSpacing();
int locX = event.x - offset.x;
int locY = event.y - offset.y;
for (int i = 0; i < groups.length; i++) {
LWSplitGroup activeGroup = groups[i];
Set<Rectangle> before = collided[i * 2 + 0];
Set<Rectangle> after = collided[i * 2 + 1];
for (Rectangle b : before) {
int bLeft = b.x;
int bTop = b.y;
int bRight = b.x + b.width;
int bBottom = b.y + b.height;
if (activeGroup.isVertical()) {
if (locX <= bRight && locX + spacing >= bLeft) {
event.x = bLeft + offset.x;
}
} else {
if (locY <= bBottom && locY + spacing >= bTop) {
event.y = bTop + offset.y;
}
}
}
for (Rectangle a : after) {
int bLeft = a.x;
int bTop = a.y;
int bRight = a.x + a.width;
int bBottom = a.y + a.height;
if (activeGroup.isVertical()) {
if (locX <= bRight && locX + spacing >= bLeft) {
event.x = bLeft + offset.x;
}
} else {
if (locY <= bBottom && locY + spacing >= bTop) {
event.y = bTop + offset.y;
}
}
}
}
if (minX != null && event.x < minX) {
event.x = minX;
}
if (minY != null && event.y < minY) {
event.y = minY;
}
if (maxX != null && event.x > maxX) {
event.x = maxX;
}
if (maxY != null && event.y > maxY) {
event.y = maxY;
}
int dx = event.x - down.x;
int dy = event.y - down.y;
for (int i = 0; i < groups.length; i++) {
LWSplitGroup activeGroup = groups[i];
Set<TabPanel> before = affected[i * 2 + 0];
Set<TabPanel> after = affected[i * 2 + 1];
for (TabPanel b : before) {
Rectangle downCached = downCache.get(b);
Rectangle moveCached = moveCache.get(b);
if (activeGroup.isVertical()) {
moveCached.width = downCached.width + dx;
} else {
moveCached.height = downCached.height + dy;
}
}
for (TabPanel a : after) {
Rectangle downCached = downCache.get(a);
Rectangle moveCached = moveCache.get(a);
if (activeGroup.isVertical()) {
moveCached.x = downCached.x + dx;
moveCached.width = downCached.width - dx;
} else {
moveCached.y = downCached.y + dy;
moveCached.height = downCached.height - dy;
}
}
}
for (Set<TabPanel> affectedPanelSet : affected) {
for (TabPanel affectedPanel : affectedPanelSet) {
Rectangle moveCached = moveCache.get(affectedPanel);
affectedPanel.setBounds(moveCached);
}
}
}
});
addListener(SWT.MouseUp, new Listener() {
@Override
public void handleEvent(Event event) {
down = null;
offset = null;
groups = null;
affected = null;
downCache = null;
minX = null;
minY = null;
maxX = null;
maxY = null;
updateSplitControls();
}
});
}
private LWSplitGroup[] makeGroups(LWSplitControl control) {
if (control instanceof LWSplitBar) {
LWSplitBar splitBar = (LWSplitBar )control;
Set<LWSplitBar> barsBefore = new HashSet<LWSplitBar>();
Set<LWSplitCorner> cornersBefore = new HashSet<LWSplitCorner>();
Set<LWSplitBar> barsAfter = new HashSet<LWSplitBar>();
Set<LWSplitCorner> cornersAfter = new HashSet<LWSplitCorner>();
adjacents(splitBar, splitBar.isVertical(), true, barsBefore,
cornersBefore);
adjacents(splitBar, splitBar.isVertical(), false, barsAfter,
cornersAfter);
Set<LWSplitBar> bars = new HashSet<LWSplitBar>();
Set<LWSplitCorner> corners = new HashSet<LWSplitCorner>();
bars.addAll(barsBefore);
bars.addAll(barsAfter);
corners.addAll(cornersBefore);
corners.addAll(cornersAfter);
bars.add(splitBar);
return new LWSplitGroup[] {
new LWSplitGroup(this, splitBar.getOrientation(), bars, corners)
};
} else if (control instanceof LWSplitCorner) {
LWSplitCorner splitCorner = (LWSplitCorner )control;
Set<LWSplitBar> hBarsBefore = new HashSet<LWSplitBar>();
Set<LWSplitCorner> hCornersBefore = new HashSet<LWSplitCorner>();
Set<LWSplitBar> hBarsAfter = new HashSet<LWSplitBar>();
Set<LWSplitCorner> hCornersAfter = new HashSet<LWSplitCorner>();
Set<LWSplitBar> vBarsBefore = new HashSet<LWSplitBar>();
Set<LWSplitCorner> vCornersBefore = new HashSet<LWSplitCorner>();
Set<LWSplitBar> vBarsAfter = new HashSet<LWSplitBar>();
Set<LWSplitCorner> vCornersAfter = new HashSet<LWSplitCorner>();
adjacents(splitCorner, false, true, hBarsBefore, hCornersBefore);
adjacents(splitCorner, false, false, hBarsAfter, hCornersAfter);
adjacents(splitCorner, true, true, vBarsBefore, vCornersBefore);
adjacents(splitCorner, true, false, vBarsAfter, vCornersAfter);
Set<LWSplitBar> hBars = new HashSet<LWSplitBar>();
Set<LWSplitCorner> hCorners = new HashSet<LWSplitCorner>();
Set<LWSplitBar> vBars = new HashSet<LWSplitBar>();
Set<LWSplitCorner> vCorners = new HashSet<LWSplitCorner>();
hBars.addAll(hBarsBefore);
hBars.addAll(hBarsAfter);
hCorners.addAll(hCornersBefore);
hCorners.addAll(hCornersAfter);
vBars.addAll(vBarsBefore);
vBars.addAll(vBarsAfter);
vCorners.addAll(vCornersBefore);
vCorners.addAll(vCornersAfter);
hCorners.add(splitCorner);
vCorners.add(splitCorner);
return new LWSplitGroup[] {
new LWSplitGroup(this, SWT.HORIZONTAL, hBars, hCorners),
new LWSplitGroup(this, SWT.VERTICAL, vBars, vCorners)
};
}
return null;
}
private LWSplitGroup[] makeSimpleGroups(LWSplitControl control) {
Rectangle clientArea = getClientArea();
LWSplitGroup[] groups = makeGroups(control);
for (int i = 0; i < groups.length; i++) {
final LWSplitGroup group = groups[i];
List<LWSplitBar> splitBars = new ArrayList<LWSplitBar>(
group.splitBars());
List<LWSplitCorner> splitCorners = new ArrayList<LWSplitCorner>(
group.splitCorners());
Collections.sort(splitBars, new Comparator<LWSplitBar>() {
@Override
public int compare(LWSplitBar b0, LWSplitBar b1) {
if (group.isVertical()) {
return b0.bounds().y - b1.bounds().y;
} else {
return b0.bounds().x - b1.bounds().x;
}
}
});
Collections.sort(splitCorners, new Comparator<LWSplitCorner>() {
@Override
public int compare(LWSplitCorner c0, LWSplitCorner c1) {
if (group.isVertical()) {
return c0.bounds().y - c1.bounds().y;
} else {
return c0.bounds().x - c1.bounds().x;
}
}
});
LWSplitCorner crossingBefore = crossingBefore(control,
group.isVertical());
LWSplitCorner crossingAfter = crossingAfter(control,
group.isVertical());
int min;
int max;
if (crossingBefore != null) {
min = group.isVertical() ? crossingBefore.bounds().y :
crossingBefore.bounds().x;
} else {
min = group.isVertical() ? clientArea.y :
clientArea.x;
}
if (crossingAfter != null) {
max = group.isVertical() ? crossingAfter.bounds().y :
crossingAfter.bounds().x;
} else {
max = group.isVertical() ? clientArea.y + clientArea.height :
clientArea.x + clientArea.width;
}
for (Iterator<LWSplitBar> itor = splitBars.iterator();
itor.hasNext();) {
LWSplitBar next = itor.next();
if (group.isVertical()) {
if (next.bounds().y < min || next.bounds().y > max) {
itor.remove();
}
} else {
if (next.bounds().x < min || next.bounds().x > max) {
itor.remove();
}
}
}
for (Iterator<LWSplitCorner> itor = splitCorners.iterator();
itor.hasNext();) {
LWSplitCorner next = itor.next();
if (group.isVertical()) {
if (next.bounds().y < min || next.bounds().y > max) {
itor.remove();
}
} else {
if (next.bounds().x < min || next.bounds().x > max) {
itor.remove();
}
}
}
groups[i] = new LWSplitGroup(this, group.getOrientation(),
new HashSet<LWSplitBar>(splitBars),
new HashSet<LWSplitCorner>(splitCorners));
}
return groups;
}
private LWSplitCorner crossingBefore(final LWSplitControl control,
final boolean vertical) {
SortedSet<LWSplitBar> splitBars =
new TreeSet<LWSplitBar>(new Comparator<LWSplitBar>() {
@Override
public int compare(LWSplitBar b0, LWSplitBar b1) {
if (vertical) {
return b0.bounds().y - b1.bounds().y;
} else {
return b0.bounds().x - b1.bounds().x;
}
}
});
SortedSet<LWSplitCorner> splitCorners =
new TreeSet<LWSplitCorner>(new Comparator<LWSplitCorner>() {
@Override
public int compare(LWSplitCorner b0, LWSplitCorner b1) {
if (vertical) {
return b0.bounds().y - b1.bounds().y;
} else {
return b0.bounds().x - b1.bounds().x;
}
}
});
adjacents(control, vertical, true,
splitBars, splitCorners);
LWSplitCorner[] array = splitCorners.toArray(
new LWSplitCorner[splitCorners.size()]);
for (int i = array.length - 1; i >= 0; i--) {
LWSplitCorner item = array[i];
if (isCrossing(item)) {
return item;
}
}
return null;
}
private LWSplitCorner crossingAfter(final LWSplitControl control,
final boolean vertical) {
SortedSet<LWSplitBar> splitBars =
new TreeSet<LWSplitBar>(new Comparator<LWSplitBar>() {
@Override
public int compare(LWSplitBar b0, LWSplitBar b1) {
if (vertical) {
return b0.bounds().y - b1.bounds().y;
} else {
return b0.bounds().x - b1.bounds().x;
}
}
});
SortedSet<LWSplitCorner> splitCorners =
new TreeSet<LWSplitCorner>(new Comparator<LWSplitCorner>() {
@Override
public int compare(LWSplitCorner b0, LWSplitCorner b1) {
if (vertical) {
return b0.bounds().y - b1.bounds().y;
} else {
return b0.bounds().x - b1.bounds().x;
}
}
});
adjacents(control, vertical, false,
splitBars, splitCorners);
LWSplitCorner[] array = splitCorners.toArray(
new LWSplitCorner[splitCorners.size()]);
for (int i = 0; i < array.length; i++) {
LWSplitCorner item = array[i];
if (isCrossing(item)) {
return item;
}
}
return null;
}
private boolean isCrossing(LWSplitCorner corner) {
int spacing = getParent().getSpacing();
Rectangle cBounds = corner.bounds();
int cLeft = cBounds.x;
int cTop = cBounds.y;
int cRight = cBounds.x + cBounds.width;
int cBottom = cBounds.y + cBounds.height;
Point ptLeft = new Point(cLeft - spacing / 2, cTop + spacing / 2);
Point ptTop = new Point(cLeft + spacing / 2, cTop - spacing / 2);
Point ptRight = new Point(cRight + spacing / 2, cTop + spacing / 2);
Point ptBottom = new Point(cLeft + spacing / 2, cBottom + spacing / 2);
LWSplitControl ctlLeft = findSplitControl(ptLeft.x, ptLeft.y);
LWSplitControl ctlTop = findSplitControl(ptTop.x, ptTop.y);
LWSplitControl ctlRight = findSplitControl(ptRight.x, ptRight.y);
LWSplitControl ctlBottom = findSplitControl(ptBottom.x, ptBottom.y);
return ctlLeft != null && ctlTop != null && ctlRight != null &&
ctlBottom != null;
}
private void adjacents(LWSplitControl current, boolean vertical,
boolean negative, Set<LWSplitBar> splitBars,
Set<LWSplitCorner> splitCorners) {
LWSplitControl adjacent = adjacent(current, vertical, negative);
if (adjacent == null) {
return;
}
if (adjacent instanceof LWSplitBar) {
LWSplitBar splitBar = (LWSplitBar )adjacent;
splitBars.add(splitBar);
} else if (adjacent instanceof LWSplitCorner) {
LWSplitCorner splitCorner = (LWSplitCorner )adjacent;
splitCorners.add(splitCorner);
}
adjacents(adjacent, vertical, negative, splitBars, splitCorners);
}
@SuppressWarnings("unchecked")
private Set<LWSplitBar>[] affectedSplitBars(LWSplitGroup splitGroup) {
Set<LWSplitBar>[] affected = new Set[] {
new HashSet<LWSplitBar>(),
new HashSet<LWSplitBar>()
};
Rectangle gBounds = splitGroup.getBounds();
int gLeft = gBounds.x;
int gTop = gBounds.y;
int gRight = gBounds.x + gBounds.width;
int gBottom = gBounds.y + gBounds.height;
for (LWSplitBar splitBar : splitBars) {
Rectangle sBounds = splitBar.bounds();
int sLeft = sBounds.x;
int sTop = sBounds.y;
int sRight = sBounds.x + sBounds.width;
int sBottom = sBounds.y + sBounds.height;
if (splitGroup.isVertical()) {
if (sTop < gBottom && sBottom > gTop) {
if (sRight == gLeft) {
affected[0].add(splitBar);
}
if (gRight == sLeft) {
affected[1].add(splitBar);
}
}
} else {
if (sLeft < gRight && sRight > gLeft) {
if (sBottom == gTop) {
affected[0].add(splitBar);
}
if (gBottom == sTop) {
affected[1].add(splitBar);
}
}
}
}
return affected;
}
@SuppressWarnings("unchecked")
private Set<Rectangle>[] collided(LWSplitGroup splitGroup) {
Set<Rectangle>[] collided = new Set[] {
new HashSet<Rectangle>(),
new HashSet<Rectangle>()
};
int index = splitGroup.isVertical() ? 0 : 1;
LWSplitControl min = splitGroup.getMin();
LWSplitControl max = splitGroup.getMax();
if (min instanceof LWSplitCorner) {
LWSplitGroup minCollideGroup = makeGroups(min)[index];
Set<LWSplitCorner> minCollideCorners = new HashSet<LWSplitCorner>(
minCollideGroup.splitCorners());
for (LWSplitCorner minCollideCorner : minCollideCorners) {
collided[0].add(minCollideCorner.bounds());
}
}
if (max instanceof LWSplitCorner) {
LWSplitGroup maxCollideGroup = makeGroups(max)[index];
Set<LWSplitCorner> maxCollideCorners = new HashSet<LWSplitCorner>(
maxCollideGroup.splitCorners());
for (LWSplitCorner maxCollideCorner : maxCollideCorners) {
collided[1].add(maxCollideCorner.bounds());
}
}
return collided;
}
@SuppressWarnings("unchecked")
private Set<TabPanel>[] affected(LWSplitGroup splitGroup) {
Set<TabPanel>[] affected = new Set[] {
new HashSet<TabPanel>(),
new HashSet<TabPanel>()
};
TabPanel[] children = getChildren();
Rectangle gBounds = splitGroup.getBounds();
int gLeft = gBounds.x;
int gTop = gBounds.y;
int gRight = gBounds.x + gBounds.width;
int gBottom = gBounds.y + gBounds.height;
for (TabPanel child : children) {
Rectangle cBounds = child.getBounds();
int cLeft = cBounds.x;
int cTop = cBounds.y;
int cRight = cBounds.x + cBounds.width;
int cBottom = cBounds.y + cBounds.height;
if (splitGroup.isVertical()) {
if (cTop < gBottom && cBottom > gTop) {
if (cRight == gLeft) {
affected[0].add(child);
}
if (gRight == cLeft) {
affected[1].add(child);
}
}
} else {
if (cLeft < gRight && cRight > gLeft) {
if (cBottom == gTop) {
affected[0].add(child);
}
if (gBottom == cTop) {
affected[1].add(child);
}
}
}
}
return affected;
}
private LWSplitControl adjacent(LWSplitControl splitControl0,
boolean vertical, boolean negative) {
Rectangle bounds0 = splitControl0.bounds();
int left0 = bounds0.x;
int top0 = bounds0.y;
int right0 = bounds0.x + bounds0.width;
int bottom0 = bounds0.y + bounds0.height;
Set<LWSplitControl>[] splitControlSets = new Set[] {
splitBars, splitCorners
};
for (Set<LWSplitControl> splitControlSet : splitControlSets) {
for (LWSplitControl splitControl1 : splitControlSet) {
if (splitControl1 == splitControl0) {
continue;
}
Rectangle bounds1 = splitControl1.bounds();
int left1 = bounds1.x;
int top1 = bounds1.y;
int right1 = bounds1.x + bounds1.width;
int bottom1 = bounds1.y + bounds1.height;
if (vertical) {
if (left0 == left1) {
if (negative) {
if (top1 < bottom0 && bottom1 >= top0) {
return splitControl1;
}
} else {
if (top0 < bottom1 && bottom0 >= top1) {
return splitControl1;
}
}
}
} else {
if (top0 == top1) {
if (negative) {
if (left1 < right0 && right1 >= left0) {
return splitControl1;
}
} else {
if (left0 < right1 && right0 >= left1) {
return splitControl1;
}
}
}
}
}
}
return null;
}
@Override
public ViewPanel getParent() {
return (ViewPanel )super.getParent();
}
@Override
public boolean setParent(Composite parent) {
if (!(parent instanceof ViewPanel)) {
return false;
}
return super.setParent(parent);
}
@Override
public TabPanel[] getChildren() {
Control[] controls = super.getChildren();
TabPanel[] children = new TabPanel[controls.length];
for (int i = 0; i < children.length; i++) {
children[i] = (TabPanel )controls[i];
}
return children;
}
@Override
public void layout(boolean changed) {
Rectangle newClientArea = getClientArea();
if (oldClientArea == null) {
oldClientArea = new Rectangle(newClientArea.x, newClientArea.y,
newClientArea.width, newClientArea.height);
}
if (oldClientArea.width != newClientArea.width ||
oldClientArea.height != newClientArea.height) {
zoom(oldClientArea, newClientArea);
}
updateSplitControls();
oldClientArea = newClientArea;
}
@Override
public void setLayout(Layout layout) {
}
@Override
public Point computeSize(int wHint, int hHint, boolean changed) {
return super.computeSize(wHint, hHint, changed);
}
private void zoom(Rectangle oldClientArea, Rectangle newClientArea) {
Map<TabPanel, Rectangle> caches = new HashMap<TabPanel, Rectangle>();
Map<TabPanel, Surrounds> surrounds = new HashMap<TabPanel, Surrounds>();
TabPanel[] children = getChildren();
int spacing = getParent().getSpacing();
for (TabPanel child : children) {
Set<TabPanel> lefts = findSurround(child, SWT.LEFT);
Set<TabPanel> tops = findSurround(child, SWT.TOP);
Set<TabPanel> rights = findSurround(child, SWT.RIGHT);
Set<TabPanel> bottoms = findSurround(child, SWT.BOTTOM);
surrounds.put(child, new Surrounds(lefts, tops, rights, bottoms));
}
for (TabPanel child : children) {
Rectangle cache = child.getBounds();
inflate(cache, oldClientArea, spacing / 2);
caches.put(child, cache);
}
float xScale = 1.0f;
float yScale = 1.0f;
if (oldClientArea.width != 0 && newClientArea.width != 0) {
xScale = (float )newClientArea.width / oldClientArea.width;
}
if (oldClientArea.height != 0 && newClientArea.height != 0) {
yScale = (float )newClientArea.height / oldClientArea.height;
}
for (TabPanel child : children) {
Rectangle cache = caches.get(child);
cache.width = Math.round(cache.width * xScale);
cache.height = Math.round(cache.height * yScale);
}
TabPanel upperLeft = findUpperLeft();
lineUpPanels(upperLeft, caches, surrounds);
for (TabPanel child : children) {
Rectangle cBounds = caches.get(child);
int cLeft = cBounds.x;
int cTop = cBounds.y;
int cRight = cBounds.x + cBounds.width;
int cBottom = cBounds.y + cBounds.height;
Surrounds surround = surrounds.get(child);
Set<TabPanel> ls = surround.getLefts();
Set<TabPanel> ts = surround.getTops();
Set<TabPanel> rs = surround.getRights();
Set<TabPanel> bs = surround.getBottoms();
if (ls.size() == 1) {
TabPanel l = ls.iterator().next();
Rectangle lBounds = caches.get(l);
int lRight = lBounds.x + lBounds.width;
if (cLeft != lRight) {
cLeft = lRight;
}
}
if (ts.size() == 1) {
TabPanel t = ts.iterator().next();
Rectangle tBounds = caches.get(t);
int tBottom = tBounds.y + tBounds.height;
if (cTop != tBottom) {
cTop = tBottom;
}
}
if (rs.isEmpty()) {
int ncaRight = newClientArea.x + newClientArea.width;
int dx = ncaRight - cRight;
cRight += dx;
} else if (rs.size() == 1) {
TabPanel r = rs.iterator().next();
Rectangle rBounds = caches.get(r);
int rLeft = rBounds.x;
if (cRight != rLeft) {
cRight = rLeft;
}
}
if (bs.isEmpty()) {
int ncaBottom = newClientArea.y + newClientArea.height;
int dy = ncaBottom - cBottom;
cBottom += dy;
} else if (bs.size() == 1) {
TabPanel b = bs.iterator().next();
Rectangle bBounds = caches.get(b);
int bTop = bBounds.y;
if (cBottom != bTop) {
cBottom = bTop;
}
}
cBounds.x = cLeft;
cBounds.y = cTop;
cBounds.width = cRight - cLeft;
cBounds.height = cBottom - cTop;
}
for (TabPanel child : children) {
Rectangle cache = caches.get(child);
inflate(cache, newClientArea, -spacing / 2);
child.setBounds(cache);
}
}
private void lineUpPanels(TabPanel current, Map<TabPanel, Rectangle> caches,
Map<TabPanel, Surrounds> surrounds) {
Rectangle cache = caches.get(current);
Surrounds surround = surrounds.get(current);
Set<TabPanel> rights = surround.getRights();
for (TabPanel right : rights) {
Rectangle rCache = caches.get(right);
rCache.x = cache.x + cache.width;
lineUpPanels(right, caches, surrounds);
}
Set<TabPanel> bottoms = surround.getBottoms();
for (TabPanel bottom : bottoms) {
Rectangle bCache = caches.get(bottom);
bCache.y = cache.y + cache.height;
lineUpPanels(bottom, caches, surrounds);
}
}
private TabPanel findUpperLeft() {
TabPanel[] children = getChildren();
for (TabPanel child : children) {
Rectangle bounds = child.getBounds();
if (bounds.x == 0 && bounds.y == 0) {
return child;
}
}
return null;
}
private void inflate(Rectangle bounds, Rectangle clientArea, int amount) {
int left = bounds.x;
int top = bounds.y;
int right = bounds.x + bounds.width;
int bottom = bounds.y + bounds.height;
int cLeft = clientArea.x;
int cTop = clientArea.y;
int cRight = clientArea.x + clientArea.width;
int cBottom = clientArea.y + clientArea.height;
if (left > cLeft) {
left -= amount;
}
if (top > cTop) {
top -= amount;
}
if (right < cRight) {
right += amount;
}
if (bottom < cBottom) {
bottom += amount;
}
bounds.x = left;
bounds.y = top;
bounds.width = right - left;
bounds.height = bottom - top;
}
private LWSplitControl findSplitControl(int x, int y) {
if (splitBars != null) {
for (LWSplitBar splitBar : splitBars) {
Rectangle bounds = splitBar.bounds();
if (bounds.contains(x, y)) {
return splitBar;
}
}
}
if (splitCorners != null) {
for (LWSplitCorner splitCorner : splitCorners) {
Rectangle bounds = splitCorner.bounds();
if (bounds.contains(x, y)) {
return splitCorner;
}
}
}
return null;
}
private void updateSplitControls() {
splitBars = findSplitBars();
splitCorners = findSplitCorners(splitBars);
}
private Set<LWSplitCorner> findSplitCorners(Set<LWSplitBar> splitBars) {
Set<LWSplitCorner> corners = new HashSet<LWSplitCorner>();
Rectangle clientArea = getClientArea();
int spacing = getParent().getSpacing();
int cLeft = clientArea.x;
int cTop = clientArea.y;
int cRight = clientArea.x + clientArea.width;
int cBottom = clientArea.y + clientArea.height;
for (LWSplitBar splitBar : splitBars) {
Rectangle bounds = splitBar.bounds();
int left = bounds.x;
int top = bounds.y;
int right = bounds.x + bounds.width;
int bottom = bounds.y + bounds.height;
if (splitBar.isVertical()) {
if (top > cTop) {
corners.add(new LWSplitCorner(this, new Rectangle(
left, top - spacing, spacing, spacing)));
}
if (bottom < cBottom) {
corners.add(new LWSplitCorner(this, new Rectangle(
left, bottom, spacing, spacing)));
}
} else {
if (left > cLeft) {
corners.add(new LWSplitCorner(this, new Rectangle(
left - spacing, top, spacing, spacing)));
}
if (right < cRight) {
corners.add(new LWSplitCorner(this, new Rectangle(
right, top, spacing, spacing)));
}
}
}
return corners;
}
private Set<LWSplitBar> findSplitBars() {
Set<LWSplitBar> splitBars = new HashSet<LWSplitBar>();
TabPanel[] children0 = getChildren();
TabPanel[] children1 = getChildren();
int spacing = getParent().getSpacing();
for (TabPanel child0 : children0) {
Rectangle bounds0 = child0.getBounds();
int left0 = bounds0.x;
int top0 = bounds0.y;
int right0 = bounds0.x + bounds0.width;
int bottom0 = bounds0.y + bounds0.height;
for (TabPanel child1 : children1) {
if (child0 == child1) {
continue;
}
Rectangle bounds1 = child1.getBounds();
int left1 = bounds1.x;
int top1 = bounds1.y;
int right1 = bounds1.x + bounds1.width;
int bottom1 = bounds1.y + bounds1.height;
if (right0 + spacing == left1 || right1 + spacing == left0) {
if (top0 < bottom1 && bottom0 > top1) {
int l = Math.min(right0, right1);
int r = Math.max(left0, left1);
int t = Math.max(top0, top1);
int b = Math.min(bottom0, bottom1);
int o = SWT.VERTICAL;
Rectangle rt = new Rectangle(l, t, r - l, b - t);
LWSplitBar s = new LWSplitBar(this, o, rt);
splitBars.add(s);
}
}
if (bottom0 + spacing == top1 || bottom1 + spacing == top0) {
if (left0 < right1 && right0 > left1) {
int l = Math.max(left0, left1);
int r = Math.min(right0, right1);
int t = Math.min(bottom0, bottom1);
int b = Math.max(top0, top1);
int o = SWT.HORIZONTAL;
Rectangle rt = new Rectangle(l, t, r - l, b - t);
LWSplitBar s = new LWSplitBar(this, o, rt);
splitBars.add(s);
}
}
}
}
return splitBars;
}
private Set<TabPanel> findSurround(TabPanel panel, int direction) {
Set<TabPanel> panels = new HashSet<TabPanel>();
Rectangle pBounds = panel.getBounds();
int pLeft = pBounds.x;
int pTop = pBounds.y;
int pRight = pBounds.x + pBounds.width;
int pBottom = pBounds.y + pBounds.height;
int spacing = getParent().getSpacing();
TabPanel[] children = getChildren();
for (TabPanel child : children) {
if (child == panel) {
continue;
}
Rectangle cBounds = child.getBounds();
int cLeft = cBounds.x;
int cTop = cBounds.y;
int cRight = cBounds.x + cBounds.width;
int cBottom = cBounds.y + cBounds.height;
if (direction == SWT.LEFT && cTop < pBottom && cBottom > pTop &&
cRight + spacing == pLeft) {
panels.add(child);
}
if (direction == SWT.TOP && cLeft < pRight && cRight > pLeft &&
cBottom + spacing == pTop) {
panels.add(child);
}
if (direction == SWT.RIGHT && pTop < cBottom && pBottom > cTop &&
pRight + spacing == cLeft) {
panels.add(child);
}
if (direction == SWT.BOTTOM && pLeft < cRight && pRight > cLeft &&
pBottom + spacing == cTop) {
panels.add(child);
}
}
return panels;
}
}
final class Surrounds {
private final Set<TabPanel> lefts;
private final Set<TabPanel> tops;
private final Set<TabPanel> rights;
private final Set<TabPanel> bottoms;
public Surrounds(Set<TabPanel> lefts, Set<TabPanel> tops,
Set<TabPanel> rights, Set<TabPanel> bottoms) {
this.lefts = lefts;
this.tops = tops;
this.rights = rights;
this.bottoms = bottoms;
}
public Set<TabPanel> getLefts() {
return lefts;
}
public Set<TabPanel> getTops() {
return tops;
}
public Set<TabPanel> getRights() {
return rights;
}
public Set<TabPanel> getBottoms() {
return bottoms;
}
}
interface LWSplitControl {
Rectangle bounds();
}
final class LWSplitBar implements LWSplitControl {
private final SplitDockPanel parent;
private final int orientation;
private final Rectangle bounds;
public LWSplitBar(SplitDockPanel parent, int orientation,
Rectangle bounds) {
this.parent = parent;
this.orientation = orientation;
this.bounds = bounds;
}
public SplitDockPanel getParent() {
return parent;
}
public int getOrientation() {
return orientation;
}
public boolean isHorizontal() {
return (orientation & SWT.HORIZONTAL) == SWT.HORIZONTAL;
}
public boolean isVertical() {
return (orientation & SWT.VERTICAL) == SWT.VERTICAL;
}
public Rectangle bounds() {
return bounds;
}
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + ((bounds == null) ? 0 : bounds.hashCode());
result = prime * result + orientation;
result = prime * result + ((parent == null) ? 0 : parent.hashCode());
return result;
}
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
LWSplitBar other = (LWSplitBar) obj;
if (bounds == null) {
if (other.bounds != null)
return false;
} else if (!bounds.equals(other.bounds))
return false;
if (orientation != other.orientation)
return false;
if (parent == null) {
if (other.parent != null)
return false;
} else if (!parent.equals(other.parent))
return false;
return true;
}
}
final class LWSplitCorner implements LWSplitControl {
private final SplitDockPanel parent;
private final Rectangle bounds;
public LWSplitCorner(SplitDockPanel parent, Rectangle bounds) {
this.parent = parent;
this.bounds = bounds;
}
public SplitDockPanel getParent() {
return parent;
}
public Rectangle bounds() {
return bounds;
}
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + ((bounds == null) ? 0 : bounds.hashCode());
result = prime * result + ((parent == null) ? 0 : parent.hashCode());
return result;
}
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
LWSplitCorner other = (LWSplitCorner) obj;
if (bounds == null) {
if (other.bounds != null)
return false;
} else if (!bounds.equals(other.bounds))
return false;
if (parent == null) {
if (other.parent != null)
return false;
} else if (!parent.equals(other.parent))
return false;
return true;
}
}
final class LWSplitGroup {
private final SplitDockPanel parent;
private final int orientation;
private final Set<LWSplitBar> splitBars;
private final Set<LWSplitCorner> splitCorners;
public LWSplitGroup(SplitDockPanel parent, int orientation,
Set<LWSplitBar> splitBars, Set<LWSplitCorner> splitCorners) {
this.parent = parent;
this.orientation = orientation;
this.splitBars = splitBars;
this.splitCorners = splitCorners;
}
public SplitDockPanel getParent() {
return parent;
}
public int getOrientation() {
return orientation;
}
public boolean isHorizontal() {
return orientation == SWT.HORIZONTAL;
}
public boolean isVertical() {
return orientation == SWT.VERTICAL;
}
public Set<LWSplitBar> splitBars() {
return splitBars;
}
public Set<LWSplitCorner> splitCorners() {
return splitCorners;
}
public LWSplitControl getMax() {
LWSplitControl max = null;
for (LWSplitBar splitBar : splitBars) {
if (max == null) {
max = splitBar;
} else {
Rectangle mBounds = max.bounds();
Rectangle bBounds = splitBar.bounds();
if (isVertical() && bBounds.y > mBounds.y) {
max = splitBar;
} else if (isHorizontal() && bBounds.x > mBounds.x) {
max = splitBar;
}
}
}
for (LWSplitCorner splitCorner : splitCorners) {
if (max == null) {
max = splitCorner;
} else {
Rectangle mBounds = max.bounds();
Rectangle cBounds = splitCorner.bounds();
if (isVertical() && cBounds.y > mBounds.y) {
max = splitCorner;
} else if (isHorizontal() && cBounds.x > mBounds.x) {
max = splitCorner;
}
}
}
return max;
}
public LWSplitControl getMin() {
LWSplitControl min = null;
for (LWSplitBar splitBar : splitBars) {
if (min == null) {
min = splitBar;
} else {
Rectangle mBounds = min.bounds();
Rectangle bBounds = splitBar.bounds();
if (isVertical() && bBounds.y < mBounds.y) {
min = splitBar;
} else if (isHorizontal() && bBounds.x < mBounds.x) {
min = splitBar;
}
}
}
for (LWSplitCorner splitCorner : splitCorners) {
if (min == null) {
min = splitCorner;
} else {
Rectangle mBounds = min.bounds();
Rectangle cBounds = splitCorner.bounds();
if (isVertical() && cBounds.y < mBounds.y) {
min = splitCorner;
} else if (isHorizontal() && cBounds.x < mBounds.x) {
min = splitCorner;
}
}
}
return min;
}
public Rectangle getBounds() {
boolean ready = false;
int left = 0;
int top = 0;
int right = 0;
int bottom = 0;
for (LWSplitBar splitBar : splitBars) {
if (!ready) {
Rectangle bounds = splitBar.bounds();
left = bounds.x;
top = bounds.y;
right = bounds.x + bounds.width;
bottom = bounds.y + bounds.height;
ready = true;
}
}
for (LWSplitCorner splitCorner : splitCorners) {
if (!ready) {
Rectangle bounds = splitCorner.bounds();
left = bounds.x;
top = bounds.y;
right = bounds.x + bounds.width;
bottom = bounds.y + bounds.height;
ready = true;
}
}
if (!ready) {
return new Rectangle(0, 0, 0, 0);
}
for (LWSplitBar splitBar : splitBars) {
Rectangle bounds = splitBar.bounds();
int bLeft = bounds.x;
int bTop = bounds.y;
int bRight = bounds.x + bounds.width;
int bBottom = bounds.y + bounds.height;
if (bLeft < left) {
left = bLeft;
}
if (bTop < top) {
top = bTop;
}
if (bRight > right) {
right = bRight;
}
if (bBottom > bottom) {
bottom = bBottom;
}
}
for (LWSplitCorner splitCorner : splitCorners) {
Rectangle bounds = splitCorner.bounds();
int cLeft = bounds.x;
int cTop = bounds.y;
int cRight = bounds.x + bounds.width;
int cBottom = bounds.y + bounds.height;
if (cLeft < left) {
left = cLeft;
}
if (cTop < top) {
top = cTop;
}
if (cRight > right) {
right = cRight;
}
if (cBottom > bottom) {
bottom = cBottom;
}
}
return new Rectangle(left, top, right - left, bottom - top);
}
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + orientation;
result = prime * result + ((parent == null) ? 0 : parent.hashCode());
result = prime * result
+ ((splitBars == null) ? 0 : splitBars.hashCode());
result = prime * result
+ ((splitCorners == null) ? 0 : splitCorners.hashCode());
return result;
}
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
LWSplitGroup other = (LWSplitGroup) obj;
if (orientation != other.orientation)
return false;
if (parent == null) {
if (other.parent != null)
return false;
} else if (!parent.equals(other.parent))
return false;
if (splitBars == null) {
if (other.splitBars != null)
return false;
} else if (!splitBars.equals(other.splitBars))
return false;
if (splitCorners == null) {
if (other.splitCorners != null)
return false;
} else if (!splitCorners.equals(other.splitCorners))
return false;
return true;
}
}
final class TabPanel extends Composite {
private final CTabFolder tabFolder;
public TabPanel(SplitDockPanel parent, int style) {
super(parent, style);
setLayout(new FillLayout());
tabFolder = new CTabFolder(this, SWT.NONE);
tabFolder.setBorderVisible(true);
}
@Override
public TabPanel getParent() {
return (TabPanel )super.getParent();
}
@Override
public boolean setParent(Composite parent) {
if (!(parent instanceof SplitDockPanel)) {
return false;
}
return super.setParent(parent);
}
CTabFolder getTabFolder() {
return tabFolder;
}
@Override
public String toString() {
String string = super.toString();
if (tabFolder.getItemCount() > 0) {
string = tabFolder.getItems()[0].getText();
}
return string;
}
}
final class Bounds {
private static final String REG_EXP = "[ ]*[,][ ]*|[ ]*[;][ ]*|[ ]+";
private final Extent left;
private final Extent top;
private final Extent width;
private final Extent height;
private final Extent right;
private final Extent bottom;
public Bounds(String expr) {
int open = expr.indexOf('(');
int closed = expr.indexOf(')');
if (open < 0) {
open = 0;
}
if (closed < 0) {
closed = expr.length();
}
String head = expr.substring(0, open);
String body = expr.substring(open + 1, closed);
String[] parts = body.split(REG_EXP);
if (head.trim().equals("ltrb")) {
left = new Extent(parts[0]);
top = new Extent(parts[1]);
width = null;
height = null;
right = new Extent(parts[2]);
bottom = new Extent(parts[3]);
} else {
left = new Extent(parts[0]);
top = new Extent(parts[1]);
width = new Extent(parts[2]);
height = new Extent(parts[3]);
right = null;
bottom = null;
}
}
public Rectangle getBounds(Rectangle area) {
if (area == null) {
area = new Rectangle(0, 0, 0, 0);
}
int tl = area.x + left.getValue(area.width);
int tt = area.y + top.getValue(area.height);
int tr = 0;
int tb = 0;
if (right == null && bottom == null) {
int tw = width.getValue(area.width);
int th = height.getValue(area.height);
tr = tl + tw;
tb = tt + th;
} else {
tr = area.x + right.getValue(area.width);
tb = area.y + bottom.getValue(area.height);
}
int fl = Math.min(tl, tr);
int ft = Math.min(tt, tb);
int fr = Math.max(tl, tr);
int fb = Math.max(tt, tb);
return new Rectangle(fl, ft, fr - fl, fb - ft);
}
}
final class Extent {
private final int value;
private final boolean relativeMetrics;
private final boolean negativeDirection;
public Extent(String expr) {
negativeDirection = expr.startsWith("-");
relativeMetrics = expr.contains(".");
float f = Math.abs(Float.parseFloat(expr));
if (relativeMetrics) {
f = f * 100;
f = Math.max(f, 0);
f = Math.min(f, 100);
} else {
f = Math.max(f, 0);
}
value = (int )f;
}
public int getValue(int length) {
float abs = relativeMetrics ? (length * value / 100.0f) : value;
return Math.round(negativeDirection ? (length - abs) : abs);
}
}