/* ImageBar.java (c) 2009-2013 Edward Swartz 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 */ package v9t9.gui.client.swt.bars; import org.eclipse.jface.layout.GridDataFactory; import org.eclipse.swt.SWT; import org.eclipse.swt.events.MouseAdapter; import org.eclipse.swt.events.MouseEvent; import org.eclipse.swt.events.MouseListener; import org.eclipse.swt.events.MouseMoveListener; import org.eclipse.swt.events.MouseTrackListener; import org.eclipse.swt.graphics.Point; import org.eclipse.swt.graphics.Rectangle; import org.eclipse.swt.layout.GridData; import org.eclipse.swt.widgets.Composite; import org.eclipse.swt.widgets.Control; import org.eclipse.swt.widgets.Layout; import v9t9.gui.client.swt.IFocusRestorer; import ejs.base.timer.FastTimer; import ejs.base.utils.ListenerList; import ejs.base.utils.ListenerList.IFire; public class ImageBar extends ImageCanvas implements IImageBar { private static final int MIN_ICON_SIZE = 24; private static final int MAX_ICON_SIZE = 96; private static final int RETRACT_VISIBLE = 0; private ButtonBarLayout bblayout; private int minIconSize = MIN_ICON_SIZE; private int maxIconSize = MAX_ICON_SIZE; private boolean canRetract; private MouseListener retractListener; private MouseMoveListener retractMoveListener; private MouseTrackListener retractTrackListener; private boolean retracted; /** when non-null, transitioning to the !retracted state */ private Runnable retractTask; private boolean offerRetract; private Runnable retractCursorTask; private static FastTimer retractTimer = new FastTimer("Retractor"); private Point targetPos; private Point origPos; private int retractTarget; private int retractStep; private ListenerList<IPaintOffsetListener> paintOffsListenerList = new ListenerList<IImageBar.IPaintOffsetListener>(); private ImageBar pairedBar; private boolean changingPairedBar; /** * Create a button bar with the given orientation. This must be in a parent with a GridLayout. * @param parent * @param style * @param midPoint * @param videoRenderer */ public ImageBar(Composite parent, int style, Gradient gradient, IFocusRestorer focusRestorer, boolean smoothResize) { super(parent, style, gradient, focusRestorer, smoothResize); // the inner composite contains the buttons, tightly packed bblayout = new ButtonBarLayout(); buttonComposite.setLayout(bblayout); } public void setPairedBar(ImageBar pairedBar) { this.pairedBar = pairedBar; } public int getMinIconSize() { return minIconSize; } public void setMinIconSize(int minIconSize) { this.minIconSize = minIconSize; } public int getMaxIconSize() { return maxIconSize; } public void setMaxIconSize(int maxIconSize) { this.maxIconSize = maxIconSize; } class ButtonBarLayout extends Layout { private Point prevSize; @Override protected Point computeSize(Composite composite, int whint, int hhint, boolean flushCache) { int w, h; Control[] kids = composite.getChildren(); int num = getIncludedKids(kids); int size; int axis; Point cursize = composite.getParent().getSize(); if (isHorizontal) { axis = cursize.x; size = hhint != SWT.DEFAULT ? Math.min(hhint, cursize.y) : cursize.y; } else { axis = cursize.y; size = whint != SWT.DEFAULT ? Math.min(whint, cursize.x) : cursize.x; } if (smoothResize) { axis = axis * 7 / 8; size = axis / num; if (isHorizontal) { w = axis; h = Math.min(maxIconSize, Math.max(minIconSize, size)); } else { w = Math.min(maxIconSize, Math.max(minIconSize, size)); h = axis; } } else { int scale = isHorizontal ? 4 : 3; while (scale < 7 && (num * (1 << (scale + 1))) < axis) { scale++; } size = 1 << scale; if (isHorizontal) { w = whint >= 0 ? whint : size * num; h = hhint >= 0 ? hhint : size; } else { w = whint >= 0 ? whint : size; h = hhint >= 0 ? hhint : size * num; } } prevSize = new Point(w, h); if (isHorizontal) ((GridData) ImageBar.this.getLayoutData()).heightHint = h; else ((GridData) ImageBar.this.getLayoutData()).widthHint = w; // System.out.println("computeSize: " + prevSize); return prevSize; } private int getIncludedKids(Control[] kids) { int cnt = 0; for (Control kid : kids) { if (kid.getLayoutData() instanceof GridData) { if (!((GridData) kid.getLayoutData()).exclude) { cnt++; } } } return cnt; } @Override protected void layout(Composite composite, boolean flushCache) { Control[] kids = composite.getChildren(); int num = kids.length; //getIncludedKids(kids); Point curSize; if (true||!flushCache) { Rectangle cli = composite.getClientArea(); curSize = new Point(cli.width, cli.height); } else { curSize = computeSize(composite, SWT.DEFAULT, SWT.DEFAULT, flushCache); } int size; int x = 0, y = 0; int axisSize; if (isHorizontal) { axisSize = Math.min(curSize.y, curSize.x / num); if (axisSize < minIconSize) size = minIconSize; else if (axisSize > maxIconSize) size = maxIconSize; else size = axisSize; x = (curSize.x - size * num) / 2; } else { axisSize = Math.min(curSize.x, curSize.y / num); if (axisSize < minIconSize) size = minIconSize; else if (axisSize > maxIconSize) size = maxIconSize; else size = axisSize; y = (curSize.y - size * num) / 2; } int min = 0, max = isHorizontal ? curSize.x : curSize.y; GridData empty = GridDataFactory.fillDefaults().create(); for (Control kid : kids) { GridData data = empty; if (kid.getLayoutData() instanceof GridData) { data = (GridData) kid.getLayoutData(); } if (isHorizontal) { if (!data.exclude) { kid.setBounds(x + data.horizontalIndent, y + data.verticalIndent, size - data.horizontalIndent*2, size - data.verticalIndent*2); x += size; } else { if (data.horizontalAlignment == SWT.LEFT) { kid.setBounds(min + data.horizontalIndent, y + data.verticalIndent, size - data.horizontalIndent*2, size - data.verticalIndent*2); min += size; } else { kid.setBounds(max - size - data.horizontalIndent, y + data.verticalIndent, size - data.horizontalIndent*2, size - data.verticalIndent*2); max -= size; } } } else { if (!data.exclude) { kid.setBounds(x + data.horizontalIndent, y + data.verticalIndent, size - data.horizontalIndent*2, size - data.verticalIndent*2); y += size; } else { if (data.verticalAlignment == SWT.TOP) { kid.setBounds(x + data.horizontalIndent, min + data.verticalIndent, size - data.horizontalIndent*2, size - data.verticalIndent*2); min += size; } else { kid.setBounds(x + data.horizontalIndent, max - size - data.verticalIndent, size - data.horizontalIndent*2, size - data.verticalIndent*2); max -= size; } } } } } } public synchronized void setRetractable(boolean retractable) { if (canRetract) { removeMouseListener(retractListener); removeMouseMoveListener(retractMoveListener); removeMouseTrackListener(retractTrackListener); } this.canRetract = retractable; stopRetractOffer(); if (canRetract) { retractListener = new MouseAdapter() { @Override public void mouseUp(MouseEvent e) { if (e.button == 1 && e.count == 1) { if (offerRetract) { startRetractTask(); } else { startRetractOffer(); } } } @Override public void mouseDoubleClick(MouseEvent e) { if (e.button == 1) { startRetractTask(); } } }; retractMoveListener = new MouseMoveListener() { @Override public void mouseMove(MouseEvent e) { updateCursor(); } }; retractTrackListener = new MouseTrackListener() { @Override public void mouseEnter(MouseEvent e) { updateCursor(); //startRetractTask(); } @Override public void mouseExit(MouseEvent e) { // if (retractTask != null) { // if (fullBounds != null) { // Point realPos = ((Control) e.widget).getParent().toControl(((Control) e.widget).toDisplay(e.x, e.y)); // if (!fullBounds.contains(realPos)) // return; // } // retractTimer.cancelTask(retractTask); // // retractTask = null; // // setLocation(origPos); // } setCursor(null); } @Override public void mouseHover(MouseEvent e) { // long now = System.currentTimeMillis(); // long hoverTime = now - enterTime; // System.out.println("hover: " + hoverTime); // updateCursor(); } }; addMouseListener(retractListener); addMouseMoveListener(retractMoveListener); addMouseTrackListener(retractTrackListener); } } /** * */ private void startRetractOffer() { if (!offerRetract) { offerRetract = true; updateCursor(); retractCursorTask = new Runnable() { long timeout = System.currentTimeMillis() + getDisplay().getDoubleClickTime() * 2; @Override public void run() { synchronized (ImageBar.this) { if (System.currentTimeMillis() >= timeout) { getDisplay().asyncExec(new Runnable() { public void run() { stopRetractOffer(); } }); } } } }; retractTimer.scheduleTask(retractCursorTask, 20); } } /** * */ private void stopRetractOffer() { if (offerRetract) { offerRetract = false; setCursor(null); retractTimer.cancelTask(retractCursorTask); retractCursorTask = null; } } private void updateCursor() { updateCursor(offerRetract); } private void updateCursor(boolean actionPossible) { if (actionPossible) { int cursor; if (isHorizontal) if (((edging & SWT.TOP) != 0) != retracted) cursor = SWT.CURSOR_SIZEN; else //if ((edging & SWT.BOTTOM) != 0) cursor = SWT.CURSOR_SIZES; else if (((edging & SWT.LEFT) != 0) != retracted) cursor = SWT.CURSOR_SIZEW; else cursor = SWT.CURSOR_SIZEE; setCursor(getDisplay().getSystemCursor(cursor)); } else { setCursor(null); } } /** * */ protected synchronized void startRetractTask() { if (retractTask == null) { retractTask = new Runnable() { @Override public void run() { getDisplay().syncExec(new Runnable() { public void run() { synchronized (ImageBar.this) { ++retractStep; int x = origPos.x + (targetPos.x - origPos.x) * retractStep / retractTarget; int y = origPos.y + (targetPos.y - origPos.y) * retractStep / retractTarget; if (retractStep >= retractTarget) { retractTimer.cancelTask(retractTask); retractTask = null; x = targetPos.x; y = targetPos.y; updateCursor(retracted); } setPaintOffset(x, y); redrawAll(); } } }); } }; //origPos = getLocation(); if (!retracted) { origPos = new Point(0, 0); targetPos = getRetractedOffs(); } else { //targetPos = getNormalPos(); origPos = getPaintOffset(); targetPos = new Point(0, 0); } retractTarget = 10; retractStep = 0; setRetracted(!retracted); stopRetractOffer(); retractTimer.scheduleTask(retractTask, 60); } if (pairedBar != null && !changingPairedBar) { changingPairedBar = true; try { pairedBar.startRetractTask(); } finally { changingPairedBar = false; } } } /** * @param b */ private void setRetracted(boolean b) { this.retracted = b; for (Control kid : getChildren()) { // if (kid instanceof ImageBarChild) // ((ImageBarChild) kid).setRetracted(b); kid.setEnabled(!b); } } protected synchronized Point getRetractedPos() { if (!isHorizontal) { int sz = getSize().x; if ((edging & SWT.LEFT) != 0) { return new Point(-sz + RETRACT_VISIBLE, getLocation().y); } else { return new Point(getParent().getSize().x - RETRACT_VISIBLE, getLocation().y); } } else { int sz = getSize().y; if ((edging & SWT.TOP) != 0) { return new Point(getLocation().x, -sz + RETRACT_VISIBLE); } else { return new Point(getLocation().x, getParent().getSize().y - RETRACT_VISIBLE); } } } protected synchronized Point getRetractedOffs() { Point sz = getSize(); if (!isHorizontal) { if ((edging & SWT.LEFT) != 0) { return new Point(-sz.x + RETRACT_VISIBLE, 0); } else { return new Point(sz.x - RETRACT_VISIBLE, 0); } } else { if ((edging & SWT.TOP) != 0) { return new Point(0, -sz.y + RETRACT_VISIBLE); } else { return new Point(0, sz.y - RETRACT_VISIBLE); } } } protected synchronized Point getNormalPos() { if (!isHorizontal) { int sz = getSize().x; if ((edging & SWT.LEFT) != 0) { return new Point(0, getLocation().y); } else { return new Point(getParent().getSize().x - sz, getLocation().y); } } else { int sz = getSize().y; if ((edging & SWT.TOP) != 0) { return new Point(getLocation().x, 0); } else { return new Point(getLocation().x, getParent().getSize().y - sz); } } } @Override public synchronized boolean isRetracted() { return retracted; } private void setPaintOffset(int x, int y) { paintOffsX = x; paintOffsY = y; if (!paintOffsListenerList.isEmpty()) { final Point po = getPaintOffset(); paintOffsListenerList.fire(new IFire<IImageBar.IPaintOffsetListener>() { @Override public void fire(IPaintOffsetListener listener) { listener.offsetChanged(po); } }); } } /* (non-Javadoc) * @see v9t9.gui.client.swt.bars.IImageBar#getPaintOffset() */ @Override public Point getPaintOffset() { return new Point(paintOffsX, paintOffsY); } public void addPaintOffsetListener(IPaintOffsetListener paintListener) { this.paintOffsListenerList.add(paintListener); } }