/*******************************************************************************
* Copyright (c) 2001, 2005 IBM Corporation and others.
* 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:
* IBM Corporation - initial API and implementation
* Sybase, Inc. - extended for DTP
*******************************************************************************/
/*
* DBeaver - Universal Database Manager
* Copyright (C) 2010-2017 Serge Rider (serge@jkiss.org)
*
* 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 org.jkiss.dbeaver.ui.controls;
/*
* CustomSashForm
*/
import java.util.*;
import java.util.List;
import org.eclipse.swt.SWT;
import org.eclipse.swt.custom.SashForm;
import org.eclipse.swt.events.*;
import org.eclipse.swt.graphics.*;
import org.eclipse.swt.widgets.*;
/**
* A SashForm that allows hide/restore controls on sash.
*
* It only works with one sash (two children). It doesn't make sense
* for the arrows when there is more than one sash. Things get confusing for
* a restore position.
*
*/
public class CustomSashForm extends SashForm {
/**
* Custom style bits. They set whether hide to one side of the other
* is not permitted. For example, if NO_HIDE_UP, then there will be only
* one arrow. When not hidden, it will point down (and will do a hide down),
* and when hidden down, it will point up (and will do a restore to the
* previous weight). There won't be a hide to the top arrow.
*/
public static final int
NO_HIDE_LEFT = 0x1, // Custom style bit for not allow hide left
NO_HIDE_UP = NO_HIDE_LEFT, // Custom style bit for not allow hide up
NO_HIDE_RIGHT = 0x2, // Custom style bit for not allow hide right
NO_HIDE_DOWN = NO_HIDE_RIGHT; // Custom style bit for not allow hide down
private static final int NO_WEIGHT = -1;
private static final int NO_ARROW = -1;
private class SashInfo {
public Sash sash;
public boolean enabled; // Whether this sashinfo is enabled (i.e. if there is more than one, this will be disabled).
public int restoreWeight = NO_WEIGHT; // If slammed to an edge this is the restore weight. -1 means not slammed. This is the restoreWeight in the 2nd section form, i.e. weights[1].
public int cursorOver = NO_ARROW; // Which arrow is cursor over,
public boolean sashBorderLeft; // Draw sash border left/top
public boolean sashBorderRight; // Draw sash border right/bottom
public int[][] sashLocs; // There is one entry for each arrow, It is arrowType/arrowDrawn/x/y/height/width of the arrow area.
// There may not be a second entry, in which case we have only one arrow.
public Point[] savedSizes = new Point[2]; // Saved sizes of controls - saved whenever a control is hidden or restored
public SashInfo(Sash sash) {
this.sash = sash;
}
};
public interface ICustomSashFormListener{
void dividerMoved(int firstControlWeight, int secondControlWeight);
}
protected SashInfo currentSashInfo = null; // When the sash goes away, its entry is made null.
protected boolean inMouseClick = false; // Because we can't stop drag even when we are in the arrow area, we need
// to know that mouse down is in process so that when drag is completed, we
// know not to recompute our position because a mouse up is about to happen
// and we want the correct arrow handled correctly.
protected boolean sashBorders[]; // Whether corresponding control needs a sash border
protected boolean noHideUp, noHideDown;
protected List customSashFormListeners = null;
protected static final int
UP_RESTORE_ARROW = 0,
UP_HIDE_ARROW = 1,
DOWN_RESTORE_ARROW = 2,
DOWN_HIDE_ARROW = 3,
HIDE_ARROWS = 4;
protected static final int
ARROW_TYPE_INDEX = 0,
ARROW_DRAWN_INDEX = 1,
X_INDEX = 2,
Y_INDEX = 3,
WIDTH_INDEX = 4,
HEIGHT_INDEX = 5;
// These are for the up/down arrow. Just swap them for left/right arrow.
protected static final int
ARROW_WIDTH = 8,
ARROW_HEIGHT = 8,
ARROW_MARGIN = 3; // Margin on each side of arrow
protected Color arrowColor, borderColor;
public CustomSashForm(Composite parent, int style) {
this(parent, style, SWT.NONE);
}
/**
* Constructor taking a custom style too.
* Or in the Custom style bits defined above (e.g. NO_HIDE_RIGHT,...)
*/
public CustomSashForm(Composite parent, int style, int customStyle) {
super(parent, style);
// Need listener to force a layout
this.addListener(SWT.Resize, new Listener() {
public void handleEvent(Event e) {
layout(true);
}
});
noHideUp = ((customStyle & NO_HIDE_UP) != 0);
noHideDown = ((customStyle & NO_HIDE_DOWN) != 0);
if (noHideUp & noHideDown)
return; // If you can't hide up or down, there there is no need for arrows.
SASH_WIDTH = 3 + getOrientation() == SWT.VERTICAL ? ARROW_HEIGHT : ARROW_WIDTH;
arrowColor = new Color(parent.getDisplay(), 99, 101, 156);
borderColor = new Color(parent.getDisplay(), 132, 130, 132);
addDisposeListener(new DisposeListener() {
/**
* @see org.eclipse.swt.events.DisposeListener#widgetDisposed(DisposeEvent)
*/
public void widgetDisposed(DisposeEvent e) {
arrowColor.dispose();
borderColor.dispose();
arrowColor = borderColor = null;
}
});
}
/**
* Returns the <code>noHideUp</code> setting for vertical CustomSashForm.
*/
public boolean isNoHideUp(){
return noHideUp;
}
/**
* Returns the <code>noHideDown</code> setting for vertical CustomSashForm.
*/
public boolean isNoHideDown(){
return noHideDown;
}
/**
* Returns the <code>noHideLeft</code> setting for horizontal CustomSashForm.
*/
public boolean isNoHideLeft(){
return noHideUp;
}
/**
* Returns the <code>noHideRight</code> setting for horizontal CustomSashForm.
*/
public boolean isNoHideRight(){
return noHideDown;
}
/**
* Sets the <code>noHideUp</code> setting for vertical CustomSashForm.
*/
public void setNoHideUp(boolean bHide) {
noHideUp = bHide;
}
/**
* Sets the <code>noHideDown</code> setting for vertical CustomSashForm.
*/
public void setNoHideDown(boolean bHide) {
noHideDown = bHide;
}
/**
* Sets the <code>noHideLeft</code> setting for horizontal CustomSashForm.
*/
public void setNoHideLeft(boolean bHide) {
setNoHideUp(bHide);
}
/**
* Sets the <code>noHideRight</code> setting for horizontal CustomSashForm.
*/
public void setNoHideRight(boolean bHide) {
setNoHideDown(bHide);
}
/**
* Call to set to hide up
*/
public void hideUp() {
if (noHideUp)
return;
if (currentSashInfo == null)
currentSashInfo = new SashInfo(null);
upHideClicked(currentSashInfo);
}
/**
* Call to set to hide left
*/
public void hideLeft() {
hideUp();
}
/**
* Call to set to hide down
*/
public void hideDown() {
if (noHideDown)
return;
if (currentSashInfo == null)
currentSashInfo = new SashInfo(null);
downHideClicked(currentSashInfo);
}
/**
* Call to set to hide right
*/
public void hideRight() {
hideDown();
}
/**
* Set the need sash borders for the controls.
*/
public void setSashBorders(boolean[] sashBorders) {
int[] weights = getWeights(); // KLUDGE This is a kludge just to see how many controls we have.
if (weights.length != 2 || (sashBorders != null && sashBorders.length != 2)) {
SWT.error(SWT.ERROR_INVALID_ARGUMENT);
}
this.sashBorders = sashBorders;
}
/**
* @see org.eclipse.swt.widgets.Composite#layout(boolean)
*/
public void layout(boolean changed) {
super.layout(changed);
if (noHideUp && noHideDown)
return; // No arrows to handle in this case.
if (getMaximizedControl() != null)
return; // We have a maximized control, so we don't need to worry about the sash.
// Let's get the list of all sashes the sash form now has. If there is more than one then just disable the sashinfo.
// If there is no current sash, and there is only one sash, then create the sashinfo for it.
Control[] children = getChildren();
Sash newSash = null;
for (int i = 0; i < children.length; i++) {
if (children[i] instanceof Sash)
if (newSash == null)
newSash = (Sash) children[i];
else {
// We have more than one sash, so need to disable current sash, if we have one.
if (currentSashInfo != null)
currentSashInfo.enabled = false;
return; // Don't go on.
}
}
if (newSash == null)
return; // We have no sashes at all.
// Now we need to see if this is a new sash.
if (currentSashInfo == null || currentSashInfo.sash == null) {
if (currentSashInfo == null)
currentSashInfo = new SashInfo(newSash);
else
currentSashInfo.sash = newSash;
newSash.addPaintListener(new PaintListener() {
/**
* @see org.eclipse.swt.events.PaintListener#paintControl(PaintEvent)
*/
public void paintControl(PaintEvent e) {
// Need to find the index of the sash we're interested in.
GC gc = e.gc;
Color oldFg = gc.getForeground();
Color oldBg = gc.getBackground();
drawArrow(gc, currentSashInfo.sashLocs[0], currentSashInfo.cursorOver == 0); // Draw first arrow
if (currentSashInfo.sashLocs.length > 1)
drawArrow(gc, currentSashInfo.sashLocs[1], currentSashInfo.cursorOver == 1); // Draw second arrow
if (currentSashInfo.sashBorderLeft)
drawSashBorder(gc, currentSashInfo.sash, true);
if (currentSashInfo.sashBorderRight)
drawSashBorder(gc, currentSashInfo.sash, false);
gc.setForeground(oldFg);
gc.setBackground(oldBg);
}
});
newSash.addControlListener(new ControlListener() {
/**
* @see org.eclipse.swt.events.ControlAdapter#controlMoved(ControlEvent)
*/
public void controlMoved(ControlEvent e) {
//System.out.println("controlMoved");
recomputeSashInfo();
}
/**
* @see org.eclipse.swt.events.ControlAdapter#controlResized(ControlEvent)
*/
public void controlResized(ControlEvent e) {
recomputeSashInfo();
}
});
newSash.addDisposeListener(new DisposeListener() {
/**
* @see org.eclipse.swt.events.DisposeListener#widgetDisposed(DisposeEvent)
*/
public void widgetDisposed(DisposeEvent e) {
// Need to clear out the widget from current.
currentSashInfo= null;
}
});
// This is a kludge because we can't override the set cursor hit test.
newSash.addMouseMoveListener(new MouseMoveListener() {
/**
* @see org.eclipse.swt.events.MouseMoveListener#mouseMove(MouseEvent)
*/
public void mouseMove(MouseEvent e) {
// See if within one of the arrows.
int x = e.x;
int y = e.y;
for (int i=0; i<currentSashInfo.sashLocs.length; i++) {
int[] locs = currentSashInfo.sashLocs[i];
boolean vertical = getOrientation() == SWT.VERTICAL;
int loc = vertical ? x : y;
int locIndex = vertical ? X_INDEX : Y_INDEX;
int sizeIndex = vertical ? WIDTH_INDEX : HEIGHT_INDEX;
// Does the mouse position lie within the bounds of the arrow?
if (locs[locIndex] <= loc && loc <= locs[locIndex]+locs[sizeIndex]) {
if (currentSashInfo.cursorOver == NO_ARROW) {
currentSashInfo.sash.setCursor(getDisplay().getSystemCursor(SWT.CURSOR_ARROW));
}
if (currentSashInfo.cursorOver != i) {
currentSashInfo.cursorOver = i;
currentSashInfo.sash.redraw();
switch (locs[ARROW_TYPE_INDEX]) {
case UP_RESTORE_ARROW:
case DOWN_RESTORE_ARROW:
currentSashInfo.sash.setToolTipText("Restore");
break;
case UP_HIDE_ARROW:
case DOWN_HIDE_ARROW:
currentSashInfo.sash.setToolTipText("Hide");
break;
}
}
return;
}
}
// If we got here, the mouse position does not lie within the bounds of an arrow
if (currentSashInfo.cursorOver != NO_ARROW) {
currentSashInfo.sash.setCursor(null);
currentSashInfo.cursorOver = NO_ARROW;
currentSashInfo.sash.redraw();
currentSashInfo.sash.setToolTipText(null);
}
}
});
// Need to know when we leave so that we can clear the cursor feedback if set.
newSash.addMouseTrackListener(new MouseTrackAdapter() {
/**
* @see org.eclipse.swt.events.MouseTrackAdapter#mouseExit(MouseEvent)
*/
public void mouseExit(MouseEvent e) {
if (currentSashInfo.cursorOver != NO_ARROW) {
// Undo the cursor.
currentSashInfo.sash.setCursor(null);
currentSashInfo.cursorOver = NO_ARROW;
currentSashInfo.sash.redraw();
currentSashInfo.sash.setToolTipText(null);
}
}
});
// Want to handle mouse down as a selection.
newSash.addMouseListener(new MouseAdapter() {
/**
* @see org.eclipse.swt.events.MouseAdapter#mouseDown(MouseEvent)
*/
public void mouseDown(MouseEvent e) {
//System.out.println("mouseDown");
inMouseClick = true;
// If we're within a button, then redraw to wipe out stipple and get button push effect.
int x = e.x;
int y = e.y;
for (int i=0; i<currentSashInfo.sashLocs.length; i++) {
int[] locs = currentSashInfo.sashLocs[i];
boolean vertical = getOrientation() == SWT.VERTICAL;
int loc = vertical ? x : y;
int locIndex = vertical ? X_INDEX : Y_INDEX;
int sizeIndex = vertical ? WIDTH_INDEX : HEIGHT_INDEX;
if (locs[locIndex] <= loc && loc <= locs[locIndex]+locs[sizeIndex]) {
currentSashInfo.sash.redraw();
break;
}
}
}
/**
* @see org.eclipse.swt.events.MouseListener#mouseDown(MouseEvent)
*/
public void mouseUp(MouseEvent e) {
//System.out.println("mouseUp");
// See if within one of the arrows.
inMouseClick = false; // No longer in down click
int x = e.x;
int y = e.y;
for (int i=0; i<currentSashInfo.sashLocs.length; i++) {
int[] locs = currentSashInfo.sashLocs[i];
boolean vertical = getOrientation() == SWT.VERTICAL;
int loc = vertical ? x : y;
int locIndex = vertical ? X_INDEX : Y_INDEX;
int sizeIndex = vertical ? WIDTH_INDEX : HEIGHT_INDEX;
// Does the mouse position lie within the bounds of the arrow?
if (locs[locIndex] <= loc && loc <= locs[locIndex]+locs[sizeIndex]) {
// We found it.
switch (locs[ARROW_TYPE_INDEX]) {
case UP_RESTORE_ARROW:
upRestoreClicked(currentSashInfo);
break;
case UP_HIDE_ARROW:
upHideClicked(currentSashInfo);
break;
case DOWN_RESTORE_ARROW:
downRestoreClicked(currentSashInfo);
break;
case DOWN_HIDE_ARROW:
downHideClicked(currentSashInfo);
break;
}
break;
}
}
currentSashInfo.sash.redraw(); // Make sure stipple goes away from the mouse up if not over an arrow button.
fireDividerMoved();
}
});
recomputeSashInfo(); // Get initial setting
}
}
/*
* Constants for recording whether the sash is slammed to the top/bottom or not slammed
*/
private final static int NOT_SLAMMED = 1;
private final static int SLAMMED_TO_BOTTOM = 2;
private final static int SLAMMED_TO_TOP = 3;
protected void recomputeSashInfo() {
if (inMouseClick && currentSashInfo.cursorOver != NO_ARROW){
return; // Don't process because we are in the down mouse button on an arrow.
}
// addArrows are the types of the arrows - hide/restore/up/down and
// drawArrows are the types of the arrows actually drawn. Here
// drawArrows are always RESTORE arrow types, so that the UI only
// has a single arrow type showing.
int[] addArrows;
int[] drawArrows;
// We need to refigure size for the sash arrows.
int[] weights = getWeights(); // This should be two entries only. We shouldn't have got here if there were more than two.
// TODO: Use of DRAG_MINIMUM is a kludge, required because SashForm only allows you to close each part so far
final int DRAG_MINIMUM = 20; // TODO: kludge see SashForm.DRAG_MINIMUM
Rectangle sashBounds = currentSashInfo.sash.getBounds();
Rectangle clientArea = getClientArea();
boolean vertical = getOrientation() == SWT.VERTICAL;
//
// Work out whether the sash is slammed to the top / bottom or not slammed
//
int slammed = NOT_SLAMMED;
if (weights[1] == 0){
slammed = SLAMMED_TO_BOTTOM;
}
else if (weights[0] == 0){
slammed = SLAMMED_TO_TOP;
}
else if (vertical){
if (currentSashInfo.restoreWeight != NO_WEIGHT && sashBounds.y <= DRAG_MINIMUM){
slammed = SLAMMED_TO_TOP;
}
else if (currentSashInfo.restoreWeight != NO_WEIGHT && sashBounds.y+sashBounds.height >= clientArea.height-DRAG_MINIMUM){
slammed = SLAMMED_TO_BOTTOM;
}
}
else {
if (currentSashInfo.restoreWeight != NO_WEIGHT && sashBounds.x <= DRAG_MINIMUM){
slammed = SLAMMED_TO_TOP;
}
else if (currentSashInfo.restoreWeight != NO_WEIGHT && sashBounds.x+sashBounds.width >= clientArea.width-DRAG_MINIMUM){
slammed = SLAMMED_TO_BOTTOM;
}
}
//
// Now decide which arrows to add, according to whether noHideUp, noHideDown and the slammed status.
//
if (noHideUp) {
if (slammed == SLAMMED_TO_BOTTOM) {
addArrows = new int[1];
drawArrows = new int[1];
addArrows[0] = UP_RESTORE_ARROW;
drawArrows[0] = UP_RESTORE_ARROW;
currentSashInfo.sashBorderLeft = sashBorders != null && sashBorders[0];
currentSashInfo.sashBorderRight = false;
} else {
//Not slammed
addArrows = new int[1];
drawArrows = new int[1];
addArrows[0] = DOWN_HIDE_ARROW;
drawArrows[0] = DOWN_RESTORE_ARROW;
currentSashInfo.restoreWeight = NO_WEIGHT; // Since we are in the middle, there is no restoreWeight. We've could of been dragged here.
currentSashInfo.sashBorderLeft = sashBorders != null && sashBorders[0];
currentSashInfo.sashBorderRight = sashBorders != null && sashBorders[1];
}
} else if (noHideDown) {
if (slammed == SLAMMED_TO_TOP) {
addArrows = new int[1];
drawArrows = new int[1];
addArrows[0] = DOWN_RESTORE_ARROW;
drawArrows[0] = DOWN_RESTORE_ARROW;
currentSashInfo.sashBorderLeft = false;
currentSashInfo.sashBorderRight = sashBorders != null && sashBorders[1];
} else {
//Not slammed
addArrows = new int[1];
drawArrows = new int[1];
addArrows[0] = UP_HIDE_ARROW;
drawArrows[0] = UP_RESTORE_ARROW;
currentSashInfo.restoreWeight = NO_WEIGHT; // Since we are in the middle, there is no restoreWeight. We've could of been dragged here.
currentSashInfo.sashBorderLeft = sashBorders != null && sashBorders[0];
currentSashInfo.sashBorderRight = sashBorders != null && sashBorders[1];
}
} else {
if (slammed == SLAMMED_TO_TOP) {
addArrows = new int[1];
drawArrows = new int[1];
addArrows[0] = DOWN_RESTORE_ARROW;
drawArrows[0] = DOWN_RESTORE_ARROW;
currentSashInfo.sashBorderLeft = false;
currentSashInfo.sashBorderRight = sashBorders != null && sashBorders[1];
} else if (slammed == SLAMMED_TO_BOTTOM) {
addArrows = new int[1];
drawArrows = new int[1];
addArrows[0] = UP_RESTORE_ARROW;
drawArrows[0] = UP_RESTORE_ARROW;
currentSashInfo.sashBorderLeft = sashBorders != null && sashBorders[0];
currentSashInfo.sashBorderRight = false;
} else {
//Not slammed
addArrows = new int[2];
drawArrows = new int[2];
addArrows[0] = UP_HIDE_ARROW;
drawArrows[0] = UP_RESTORE_ARROW;
addArrows[1] = DOWN_HIDE_ARROW;
drawArrows[1] = DOWN_RESTORE_ARROW;
currentSashInfo.restoreWeight = NO_WEIGHT; // Since we are in the middle, there is no restoreWeight. We've could of been dragged here.
currentSashInfo.sashBorderLeft = sashBorders != null && sashBorders[0];
currentSashInfo.sashBorderRight = sashBorders != null && sashBorders[1];
}
}
getNewSashArray(currentSashInfo, addArrows, drawArrows);
currentSashInfo.sash.redraw(); // Need to schedule a redraw because it has already drawn the old ones during the set bounds in super layout.
}
protected void upRestoreClicked(SashInfo sashinfo) {
// This means restore just the sash below restoreWeight and reduce the above restoreWeight by the right amount.
int[] weights = getWeights();
weights[0] = 1000-sashinfo.restoreWeight; // Assume weights are always in units of 1000.
weights[1] = sashinfo.restoreWeight;
sashinfo.restoreWeight = NO_WEIGHT;
setWeights(weights);
fireDividerMoved();
}
protected void upHideClicked(SashInfo sashinfo) {
int[] weights = getWeights();
// Up hide, so save the current restoreWeight of 1 into the sash info, and move to the top.
if (currentSashInfo.restoreWeight == NO_WEIGHT){
currentSashInfo.restoreWeight = weights[1]; // Not currently maxed, save position.
saveChildControlSizes();
}
weights[0] = 0;
weights[1] = 1000;
// If the upper panel has focus, flip focus to the lower panel because the upper panel is now hidden.
Control[] children = getChildren();
boolean upperFocus = isFocusAncestorA(children[0]);
setWeights(weights);
if (upperFocus)
children[1].setFocus();
fireDividerMoved();
}
protected void downRestoreClicked(SashInfo sashinfo) {
// This means restore just the sash below restoreWeight and increase the above restoreWeight by that amount.
int[] weights = getWeights();
weights[0] = 1000-sashinfo.restoreWeight; // Assume weights are always in units of 1000.
weights[1] = sashinfo.restoreWeight;
sashinfo.restoreWeight = NO_WEIGHT;
setWeights(weights);
fireDividerMoved();
}
protected void downHideClicked(SashInfo sashinfo) {
int[] weights = getWeights();
// Down hide, so save the current restoreWeight of 1 into the sash info, and move to the bottom.
if (currentSashInfo.restoreWeight == NO_WEIGHT) {
currentSashInfo.restoreWeight = weights[1]; // Not currently maxed, save current restoreWeight.
saveChildControlSizes();
}
weights[0] = 1000;
weights[1] = 0;
// If the lower panel has focus, flip focus to the upper panel because the lower panel is now hidden.
Control[] children = getChildren();
boolean lowerFocus = isFocusAncestorA(children[1]);
setWeights(weights);
if (lowerFocus)
children[0].setFocus();
fireDividerMoved();
}
/*
* Helper method for upHideClicked / downHideClicked
*/
private void saveChildControlSizes() {
// Save control sizes
Control [] children = getChildren();
int iChildToSave = 0;
for (int i = 0; i < children.length && iChildToSave < 2; i++){
Control child = children[i];
if (! (child instanceof Sash)){
currentSashInfo.savedSizes[iChildToSave] = child.getSize();
iChildToSave++;
}
}
}
/*
* This determines if the control or one of its children
* has the focus. Control.isFocusAncestor is hidden by SWT, but it is really useful.
*/
protected boolean isFocusAncestorA (Control control) {
Display display = getDisplay ();
Control focusControl = display.getFocusControl ();
while (focusControl != null && focusControl != control) {
focusControl = focusControl. getParent();
}
return control == focusControl;
}
protected void getNewSashArray(SashInfo sashInfo, int[] addArrowTypes, int[] drawArrowTypes) {
// int[][] thisSash = sashInfo.sashLocs;
// if (thisSash == null)
sashInfo.sashLocs = new int[addArrowTypes.length][];
int[][] thisSash = sashInfo.sashLocs;
int aSize = ARROW_WIDTH; // Width of arrow
int tSize = aSize+2*ARROW_MARGIN; // Total Width (arrow + margin)
int neededSize = tSize*addArrowTypes.length;
boolean vertical = getOrientation() == SWT.VERTICAL;
Point s = sashInfo.sash.getSize();
int start;
int x;
int y;
int width;
int height;
if (vertical) {
start = (s.x - neededSize) / 2;
x = start;
y = (s.y - ARROW_HEIGHT) / 2; // Center vertically, no margin required.
width = tSize;
height = aSize;
} else {
start = (s.y - neededSize) / 2;
y = start;
x = (s.x - ARROW_HEIGHT) / 2; // Center horizontally, no margin required.
width = aSize;
height = tSize;
}
for (int j=0; j<addArrowTypes.length; j++) {
if (thisSash[j] == null)
thisSash[j] = new int[] {addArrowTypes[j], drawArrowTypes[j], x, y, width, height};
else {
// Reuse the array
thisSash[j][ARROW_TYPE_INDEX] = addArrowTypes[j];
thisSash[j][ARROW_DRAWN_INDEX] = drawArrowTypes[j];
thisSash[j][X_INDEX] = x;
thisSash[j][Y_INDEX] = y;
thisSash[j][WIDTH_INDEX] = width;
thisSash[j][HEIGHT_INDEX] = height;
}
if (vertical)
x+=tSize;
else
y+=tSize;
}
}
protected void drawSashBorder(GC gc, Sash sash, boolean leftBorder) {
gc.setForeground(borderColor);
if (getOrientation() == SWT.VERTICAL) {
Point s = sash.getSize();
if (leftBorder) // i.e. top for VERTICAL sash
gc.drawLine(0, 0, s.x-1, 0);
else // i.e. bottom for VERTICAL sash
gc.drawLine(0, s.y-1, s.x-1, s.y-1);
} else {
Point s = sash.getSize();
if (leftBorder)
gc.drawLine(0, 0, 0, s.y-1);
else
gc.drawLine(s.x-1, 0, s.x-1, s.y-1);
}
}
protected void drawArrow(GC gc, int[] sashLoc, boolean selected) {
int indent = 0;
if (selected) {
if (!inMouseClick) {
// Draw the selection box.
Color highlightShadow = getDisplay().getSystemColor(SWT.COLOR_WIDGET_HIGHLIGHT_SHADOW);
Color normalShadow = getDisplay().getSystemColor(SWT.COLOR_WIDGET_NORMAL_SHADOW);
gc.setForeground(highlightShadow);
gc.drawLine(sashLoc[X_INDEX], sashLoc[Y_INDEX]+sashLoc[HEIGHT_INDEX], sashLoc[X_INDEX], sashLoc[Y_INDEX]);
gc.drawLine(sashLoc[X_INDEX], sashLoc[Y_INDEX], sashLoc[X_INDEX]+sashLoc[WIDTH_INDEX], sashLoc[Y_INDEX]);
gc.setForeground(normalShadow);
gc.drawLine(sashLoc[X_INDEX], sashLoc[Y_INDEX]+sashLoc[HEIGHT_INDEX], sashLoc[X_INDEX]+sashLoc[WIDTH_INDEX], sashLoc[Y_INDEX]+sashLoc[HEIGHT_INDEX]);
gc.drawLine(sashLoc[X_INDEX]+sashLoc[WIDTH_INDEX], sashLoc[Y_INDEX]+sashLoc[HEIGHT_INDEX], sashLoc[X_INDEX]+sashLoc[WIDTH_INDEX], sashLoc[Y_INDEX]);
} else {
// Draw pushed selection box.
indent = 1;
Color highlightShadow = getDisplay().getSystemColor(SWT.COLOR_WIDGET_HIGHLIGHT_SHADOW);
Color normalShadow = getDisplay().getSystemColor(SWT.COLOR_WIDGET_NORMAL_SHADOW);
gc.setForeground(normalShadow);
gc.drawLine(sashLoc[X_INDEX], sashLoc[Y_INDEX]+sashLoc[HEIGHT_INDEX], sashLoc[X_INDEX], sashLoc[Y_INDEX]);
gc.drawLine(sashLoc[X_INDEX], sashLoc[Y_INDEX], sashLoc[X_INDEX]+sashLoc[WIDTH_INDEX], sashLoc[Y_INDEX]);
gc.setForeground(highlightShadow);
gc.drawLine(sashLoc[X_INDEX], sashLoc[Y_INDEX]+sashLoc[HEIGHT_INDEX], sashLoc[X_INDEX]+sashLoc[WIDTH_INDEX], sashLoc[Y_INDEX]+sashLoc[HEIGHT_INDEX]);
gc.drawLine(sashLoc[X_INDEX]+sashLoc[WIDTH_INDEX], sashLoc[Y_INDEX]+sashLoc[HEIGHT_INDEX], sashLoc[X_INDEX]+sashLoc[WIDTH_INDEX], sashLoc[Y_INDEX]);
}
}
if (getOrientation() == SWT.VERTICAL) {
switch (sashLoc[ARROW_DRAWN_INDEX]) {
case UP_RESTORE_ARROW:
drawUpRestoreArrow(gc, sashLoc[X_INDEX]+indent, sashLoc[Y_INDEX]+indent);
break;
case DOWN_RESTORE_ARROW:
drawDownRestoreArrow(gc, sashLoc[X_INDEX]+indent, sashLoc[Y_INDEX]+indent);
break;
case UP_HIDE_ARROW:
drawUpHideArrow(gc, sashLoc[X_INDEX]+indent, sashLoc[Y_INDEX]+indent);
break;
case DOWN_HIDE_ARROW:
drawDownHideArrow(gc, sashLoc[X_INDEX]+indent, sashLoc[Y_INDEX]+indent);
break;
}
} else {
switch (sashLoc[ARROW_DRAWN_INDEX]) {
case UP_RESTORE_ARROW:
drawLeftRestoreArrow(gc, sashLoc[X_INDEX]+indent, sashLoc[Y_INDEX]+indent);
break;
case DOWN_RESTORE_ARROW:
drawRightRestoreArrow(gc, sashLoc[X_INDEX]+indent, sashLoc[Y_INDEX]+indent);
break;
case UP_HIDE_ARROW:
drawLeftHideArrow(gc, sashLoc[X_INDEX]+indent, sashLoc[Y_INDEX]+indent);
break;
case DOWN_HIDE_ARROW:
drawRightHideArrow(gc, sashLoc[X_INDEX]+indent, sashLoc[Y_INDEX]+indent);
break;
}
}
}
// Draw at the given x/y (upper left corner of arrow area).
protected void drawUpRestoreArrow(GC gc, int x, int y) {
gc.setForeground(arrowColor);
x+=ARROW_MARGIN;
gc.drawLine(x+4, y+2, x+7, y+5);
gc.drawLine(x+3, y+2, x+3, y+2);
gc.drawLine(x+2, y+3, x+4, y+3);
gc.drawLine(x+1, y+4, x+5, y+4);
gc.drawLine(x, y+5, x+6, y+5);
}
// Draw at the given x/y (upper left corner of arrow area).
protected void drawUpHideArrow(GC gc, int x, int y) {
gc.setForeground(arrowColor);
x+=ARROW_MARGIN;
gc.drawLine(x, y, x+7, y);
gc.drawLine(x, y+1, x+7, y+1);
gc.drawLine(x+4, y+2, x+7, y+5);
gc.drawLine(x+3, y+2, x+3, y+2);
gc.drawLine(x+2, y+3, x+4, y+3);
gc.drawLine(x+1, y+4, x+5, y+4);
gc.drawLine(x, y+5, x+6, y+5);
}
// Draw at the given x/y (upper left corner of arrow area).
protected void drawDownRestoreArrow(GC gc, int x, int y) {
gc.setForeground(arrowColor);
x+=ARROW_MARGIN;
gc.drawLine(x, y+2, x+3, y+5);
gc.drawLine(x+4, y+5, x+4, y+5);
gc.drawLine(x+3, y+4, x+5, y+4);
gc.drawLine(x+1, y+3, x+6, y+3);
gc.drawLine(x+1, y+2, x+7, y+2);
}
// Draw at the given x/y (upper left corner of arrow area).
protected void drawDownHideArrow(GC gc, int x, int y) {
gc.setForeground(arrowColor);
x+=ARROW_MARGIN;
gc.drawLine(x, y+6, x+7, y+6);
gc.drawLine(x, y+7, x+7, y+7);
gc.drawLine(x, y+2, x+3, y+5);
gc.drawLine(x+4, y+5, x+4, y+5);
gc.drawLine(x+3, y+4, x+5, y+4);
gc.drawLine(x+1, y+3, x+6, y+3);
gc.drawLine(x+1, y+2, x+7, y+2);
}
// Draw at the given x/y (upper left corner of arrow area).
protected void drawLeftRestoreArrow(GC gc, int x, int y) {
gc.setForeground(arrowColor);
y+=ARROW_MARGIN;
gc.drawLine(x+2, y+4, x+5, y+7);
gc.drawLine(x+2, y+3, x+2, y+3);
gc.drawLine(x+3, y+2, x+3, y+4);
gc.drawLine(x+4, y+1, x+4, y+5);
gc.drawLine(x+5, y, x+5, y+6);
}
// Draw at the given x/y (upper left corner of arrow area).
protected void drawLeftHideArrow(GC gc, int x, int y) {
gc.setForeground(arrowColor);
y+=ARROW_MARGIN;
gc.drawLine(x, y, x, y+7);
gc.drawLine(x+1, y, x+1, y+7);
gc.drawLine(x+2, y+4, x+5, y+7);
gc.drawLine(x+2, y+3, x+2, y+3);
gc.drawLine(x+3, y+2, x+3, y+4);
gc.drawLine(x+4, y+1, x+4, y+5);
gc.drawLine(x+5, y, x+5, y+6);
}
// Draw at the given x/y (upper left corner of arrow area).
protected void drawRightRestoreArrow(GC gc, int x, int y) {
gc.setForeground(arrowColor);
y+=ARROW_MARGIN;
gc.drawLine(x+2, y, x+5, y+3);
gc.drawLine(x+5, y+4, x+5, y+4);
gc.drawLine(x+4, y+3, x+4, y+5);
gc.drawLine(x+3, y+1, x+3, y+6);
gc.drawLine(x+2, y+1, x+2, y+7);
}
// Draw at the given x/y (upper left corner of arrow area).
protected void drawRightHideArrow(GC gc, int x, int y) {
gc.setForeground(arrowColor);
y+=ARROW_MARGIN;
gc.drawLine(x+6, y, x+6, y+7);
gc.drawLine(x+7, y, x+7, y+7);
gc.drawLine(x+2, y, x+5, y+3);
gc.drawLine(x+5, y+4, x+5, y+4);
gc.drawLine(x+4, y+3, x+4, y+5);
gc.drawLine(x+3, y+1, x+3, y+6);
gc.drawLine(x+2, y+1, x+2, y+7);
}
public int getRestoreWeight() {
if (currentSashInfo!=null)
return currentSashInfo.restoreWeight;
else
return -1;
}
protected Sash getSash() {
Control[] kids = getChildren();
for (int i = 0; i < kids.length; i++) {
if (kids[i] instanceof Sash)
return (Sash)kids[i];
}
return null;
}
public void setRestoreWeight(int weight) {
if (weight>=0 && currentSashInfo!=null) {
//recomputeSashInfo();
currentSashInfo.restoreWeight=weight;
}
}
public Point[] getSavedSizes(){
if (currentSashInfo!=null){
return currentSashInfo.savedSizes;
}
else {
return null;
}
}
/**
* Adds a custom sashform listener. This listener will be removed when
* this control is disposed.
*
* @since 1.2.0
*/
public void addCustomSashFormListener(ICustomSashFormListener listener){
if(customSashFormListeners==null)
customSashFormListeners = new ArrayList();
customSashFormListeners.add(listener);
}
/**
* Removes the custom sashform listener.
*
* @since 1.2.0
*/
public void removeCustomSashFormListener(ICustomSashFormListener listener){
if(customSashFormListeners!=null){
customSashFormListeners.remove(listener);
}
}
protected void fireDividerMoved(){
if(customSashFormListeners!=null && customSashFormListeners.size()>0){
int[] weights = getWeights();
if(weights!=null && weights.length==2){
int firstControlWeight = weights[0];
int secondControlWeight = weights[1];
for (Iterator listenerItr = customSashFormListeners.iterator(); listenerItr.hasNext();) {
ICustomSashFormListener listener = (ICustomSashFormListener) listenerItr.next();
listener.dividerMoved(firstControlWeight, secondControlWeight);
}
}
}
}
}