blob: 6c53f1eb9b34ca4bf0c187663cdfc0f4019904e1 [file] [log] [blame]
/**********************************************************************
* Copyright (c) 2005, 2016 IBM Corporation, Ericsson
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License 2.0
* which accompanies this distribution, and is available at
* https://www.eclipse.org/legal/epl-2.0/
*
* SPDX-License-Identifier: EPL-2.0
*
* Contributors:
* IBM - Initial API and implementation
* Bernd Hufmann - Updated for TMF
**********************************************************************/
package org.eclipse.tracecompass.tmf.ui.views.uml2sd;
import java.util.Timer;
import java.util.TimerTask;
import org.eclipse.swt.SWT;
import org.eclipse.swt.events.ControlListener;
import org.eclipse.swt.events.FocusEvent;
import org.eclipse.swt.events.FocusListener;
import org.eclipse.swt.events.KeyEvent;
import org.eclipse.swt.events.KeyListener;
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.events.PaintListener;
import org.eclipse.swt.events.SelectionEvent;
import org.eclipse.swt.events.SelectionListener;
import org.eclipse.swt.events.TypedEvent;
import org.eclipse.swt.graphics.Color;
import org.eclipse.swt.graphics.Cursor;
import org.eclipse.swt.graphics.GC;
import org.eclipse.swt.graphics.ImageData;
import org.eclipse.swt.graphics.PaletteData;
import org.eclipse.swt.graphics.Point;
import org.eclipse.swt.graphics.RGB;
import org.eclipse.swt.graphics.Rectangle;
import org.eclipse.swt.widgets.Button;
import org.eclipse.swt.widgets.Canvas;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Control;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Layout;
import org.eclipse.swt.widgets.ScrollBar;
import org.eclipse.swt.widgets.Scrollable;
import org.eclipse.swt.widgets.Shell;
import org.eclipse.tracecompass.tmf.ui.views.uml2sd.util.Messages;
/**
* ScrollView widget provides a scrolling area with on-demand scroll bars.
* Overview scrollable panel can be used (@see setOverviewEnabled()).
*
* @author Eric Miravete
* @version 1.0
*/
public class ScrollView extends Composite {
// ------------------------------------------------------------------------
// Constants
// ------------------------------------------------------------------------
/**
* Scroll bar mode AUTO
*/
public static final int AUTO = 0;
/**
* Scroll bar mode ALWAYS_ON
*/
public static final int ALWAYS_ON = 1;
/**
* Scroll bar mode ALWAYS_OFF
*/
public static final int ALWAYS_OFF = 2;
/**
* Bit mask for visible vertical scroll bar
*/
public static final int VBAR = 0x01;
/**
* Bit mask for visible horizontal scroll bar
*/
public static final int HBAR = 0x02;
private static final int DEFAULT_H_SCROLL_INCREMENT = 10;
private static final int DEFAULT_V_SCROLL_INCREMENT = 10;
private static final int DEFAULT_AUTO_SCROLL_PERIOD = 75;
private static final int DEFAULT_OVERVIEW_SIZE = 100;
// ------------------------------------------------------------------------
// Attributes
// ------------------------------------------------------------------------
/**
* Value of the contents height property.
*/
private int fContentsHeight = 0;
/**
* Value of the contents width property.
*/
private int fContentsWidth = 0;
/**
* Value of the contents x coordinate property
*/
private int fContentsX = 0;
/**
* Value of the contents y coordinate property
*/
private int fContentsY = 0;
/**
* Scroll bar mode of horizontal scroll bar.
*/
private int fHorScrollbarMode = AUTO;
/**
* Scroll bar mode of vertical scroll bar.
*/
private int fVertScrollbarMode = AUTO;
/**
* Increment for the horizontal scroll bar.
*/
private int fHorScrollbarIncrement = DEFAULT_H_SCROLL_INCREMENT;
/**
* Increment for the vertical scroll bar.
*/
private int fVertScrollbarIncrement = DEFAULT_V_SCROLL_INCREMENT;
/**
* Flag whether auto scroll is enabled or not.
*/
private boolean fAutoScrollEnabled = true;
/**
* Value of the auto scroll period.
*/
private int fAutoScrollPeriod = DEFAULT_AUTO_SCROLL_PERIOD;
/**
* The local paint listener reference.
*/
private PaintListener fLocalPaintListener = null;
/**
* The local mouse move listener reference.
*/
private MouseMoveListener fLocalMouseMoveListener = null;
/**
* The local mouse listener reference.
*/
private MouseListener fLocalMouseListener = null;
/**
* The local control listener reference.
*/
private ControlListener fLocalControlListener = null;
/**
* The local key listener reference.
*/
private KeyListener fLocalKeyListener = null;
// Canvas for vertical/horizontal Scroll Bar only ... because new ScrollBar() does works.
/**
* Canvas for horizontal scroll bar.
*/
private Canvas fHorScrollBar;
/**
* Canvas for vertical scroll bar.
*/
private Canvas fVertScrollBar;
/**
* Canvas for the view control.
*/
private Canvas fViewControl;
/**
* Control used in the bottom right corner @see setCornerControl() and @see setOverviewEnabled(true)
*/
private Control fCornerControl;
/**
* Size of overview widget.
*/
private int fOverviewSize = DEFAULT_OVERVIEW_SIZE; // default size for overview
/**
* Timer for auto_scroll feature
*/
private AutoScroll fAutoScroll = null;
/**
* TimerTask for auto_scroll feature !=null when auto scroll is running
*/
private Timer fAutoScrollTimer = null;
/**
* where mouse down appear on contents area (x coordinate)
*/
private int fMouseDownX = -1;
/**
* where mouse down appear on contents area (y coordinate)
*/
private int fMousDownY = -1;
// ------------------------------------------------------------------------
// Constructors
// ------------------------------------------------------------------------
/**
* Create a ScrollView, child of composite c. Both scroll bar have the mode AUTO. Auto scroll feature is enabled
* using a delay of 250ms. Overview feature is not enabled by default (use setOverviewEnabled()).
*
* @param c The parent composite
* @param style The SWT style bits @see SWT
*/
public ScrollView(Composite c, int style) {
this(c, style, true);
}
/**
* Create a ScrollView, child of composite c. Both scroll bar have the mode AUTO. Auto scroll feature is enabled
* using a delay of 250ms. Overview feature is not enabled by default (use setOverviewEnabled()).
*
* @param c The parent composite.
* @param style The SWT style bits @see SWT
* @param mouseWheel Flag to force scrollView to handles mouse wheel
*/
public ScrollView(Composite c, int style, boolean mouseWheel) {
super(c, SWT.NONE);
fHorScrollBar = new Canvas(this, SWT.H_SCROLL);
if (mouseWheel) {
// force scroll bar to get mouse wheel, those scrollbar will be hidden
fViewControl = new Canvas(this, style | SWT.H_SCROLL | SWT.V_SCROLL);
} else {
fViewControl = new Canvas(this, style);
}
fViewControl.setBackground(getBackground());
// hide scroll bar as their are replaced by fHorScrollBar and fVertScrollBar.
if (mouseWheel) {
fViewControl.getVerticalBar().setVisible(false);
fViewControl.getHorizontalBar().setVisible(false);
}
fVertScrollBar = new Canvas(this, SWT.V_SCROLL);
setLayout(new SVLayout());
fLocalPaintListener = event -> {
// use clipping, to reduce cost of paint.
Rectangle r = event.gc.getClipping();
int cx = viewToContentsX(r.x);
int cy = viewToContentsY(r.y);
drawContents(event.gc, cx, cy, r.width, r.height);
};
fViewControl.addPaintListener(fLocalPaintListener);
fLocalMouseMoveListener = e -> {
int ox = e.x, oy = e.y;
e.x = viewToContentsX(e.x);
e.y = viewToContentsY(e.y);
contentsMouseMoveEvent(e);
e.x = ox;
e.y = oy;
};
fViewControl.addMouseMoveListener(fLocalMouseMoveListener);
MouseTrackListener localMouseTrackListener = new MouseTrackListener() {
@Override
public void mouseEnter(MouseEvent e) {
int ox = e.x, oy = e.y;
e.x = viewToContentsX(e.x);
e.y = viewToContentsY(e.y);
contentsMouseEnter(e);
e.x = ox;
e.y = oy;
}
@Override
public void mouseHover(MouseEvent e) {
int ox = e.x, oy = e.y;
e.x = viewToContentsX(e.x);
e.y = viewToContentsY(e.y);
contentsMouseHover(e);
e.x = ox;
e.y = oy;
}
@Override
public void mouseExit(MouseEvent e) {
int ox = e.x, oy = e.y;
e.x = viewToContentsX(e.x);
e.y = viewToContentsY(e.y);
contentsMouseExit(e);
e.x = ox;
e.y = oy;
}
};
fViewControl.addMouseTrackListener(localMouseTrackListener);
fLocalMouseListener = new MouseListener() {
@Override
public void mouseDoubleClick(MouseEvent e) {
int ox = e.x, oy = e.y;
e.x = viewToContentsX(e.x);
e.y = viewToContentsY(e.y);
contentsMouseDoubleClickEvent(e);
e.x = ox;
e.y = oy;
}
@Override
public void mouseDown(MouseEvent e) {
int ox = e.x, oy = e.y;
e.x = viewToContentsX(e.x);
fMouseDownX = e.x;
e.y = viewToContentsY(e.y);
fMousDownY = e.y;
contentsMouseDownEvent(e);
e.x = ox;
e.y = oy;
}
@Override
public void mouseUp(MouseEvent e) {
int ox = e.x, oy = e.y;
e.x = viewToContentsX(e.x);
e.y = viewToContentsY(e.y);
contentsMouseUpEvent(e);
e.x = ox;
e.y = oy;
// here because class extending me can catch mouse Up and want to scroll...
fMouseDownX = -1;
fMousDownY = -1;
}
};
fViewControl.addMouseListener(fLocalMouseListener);
fLocalKeyListener = new KeyListener() {
@Override
public void keyPressed(KeyEvent e) {
keyPressedEvent(e);
}
@Override
public void keyReleased(KeyEvent e) {
keyReleasedEvent(e);
}
};
fViewControl.addKeyListener(fLocalKeyListener);
getVerticalBar().addSelectionListener(new SelectionListener() {
@Override
public void widgetSelected(SelectionEvent e) {
setContentsPos(fContentsX, getVerticalBar().getSelection());
// need to change "hidden" vertical bar value ?
// force focus on fViewControl so we got future mouse wheel's scroll events
if (!fViewControl.isFocusControl()) {
fViewControl.setFocus();
}
}
@Override
public void widgetDefaultSelected(SelectionEvent e) {
// Do nothing
}
});
if (fViewControl.getVerticalBar() != null) {
// add fViewControl hidden scrollbar listener to get mouse wheel ...
fViewControl.getVerticalBar().addSelectionListener(new SelectionListener() {
@Override
public void widgetSelected(SelectionEvent e) {
ScrollBar b = fViewControl.getVerticalBar();
setContentsPos(fContentsX, b.getSelection());
// change "real" vertical bar selection too
getVerticalBar().setSelection(b.getSelection());
}
@Override
public void widgetDefaultSelected(SelectionEvent e) {
// Do nothing
}
});
}
getHorizontalBar().addSelectionListener(new SelectionListener() {
@Override
public void widgetSelected(SelectionEvent e) {
setContentsPos(getHorizontalBar().getSelection(), fContentsY);
// need to change "real" horizontal bar too ?
// force focus on fViewControl so we got future mouse wheel's scroll events
if (!fViewControl.isFocusControl()) {
fViewControl.setFocus();
}
}
@Override
public void widgetDefaultSelected(SelectionEvent e) {
// Do nothing
}
});
if (fViewControl.getHorizontalBar() != null) {
fViewControl.getHorizontalBar().addSelectionListener(new SelectionListener() {
@Override
public void widgetSelected(SelectionEvent e) {
ScrollBar b = fViewControl.getHorizontalBar();
setContentsPos(b.getSelection(), fContentsY);
// change "real" vertical bar selection too
getHorizontalBar().setSelection(b.getSelection());
}
@Override
public void widgetDefaultSelected(SelectionEvent e) {
// Do nothing
}
});
}
addDisposeListener((e) -> {
if (fAutoScroll != null) {
fAutoScroll.cancel();
fAutoScroll = null;
}
fViewControl = null;
fVertScrollBar = null;
fHorScrollBar = null;
if (fCornerControl != null) {
Object data = fCornerControl.getData();
if (data instanceof Overview) {
((Overview) data).dispose();
}
}
fCornerControl = null;
});
}
// ------------------------------------------------------------------------
// Methods
// ------------------------------------------------------------------------
@Override
public boolean setFocus() {
return fViewControl.forceFocus();
}
@Override
public void setCursor(Cursor cursor) {
fViewControl.setCursor(cursor);
}
@Override
public Rectangle getClientArea() {
Rectangle area = fViewControl.getClientArea();
/* Clamp the size of the returned area to 1x1 minimum */
area.width = Math.max(area.width, 1);
area.height = Math.max(area.height, 1);
return area;
}
@Override
public void setBackground(Color c) {
super.setBackground(c);
fViewControl.setBackground(c);
}
@Override
public void setToolTipText(String text) {
fViewControl.setToolTipText(text);
}
/**
* Draw overview area, @see setOverviewEnabled. By default draw a rectangle corresponding to the visible area of
* scroll view. You can redefine this method to draw the contents as drawContents does... ...in an other magnify
* factor.
*
* @param gc GC to used to draw.
* @param r Rectangle corresponding to the client area of overview.
*/
protected void drawOverview(GC gc, Rectangle r) {
int x = (int) (r.width * fContentsX / (float) fContentsWidth);
int y = (int) (r.height * fContentsY / (float) fContentsHeight);
int vw = getVisibleWidth();
int vh = getVisibleHeight();
int w = r.width - 1;
if (fContentsWidth > vw) {
w = (int) (r.width * vw / (float) fContentsWidth);
}
int h = r.height - 1;
if (fContentsHeight > vh) {
h = (int) (r.height * vh / (float) fContentsHeight);
}
gc.setForeground(getForeground());
// too small rectangle ?
if (w < 5 || h < 5) {
// use a cross ...
gc.drawLine(x, 0, x, r.height);
gc.drawLine(0, y, r.width, y);
} else {
gc.drawRectangle(x, y, w, h);
}
}
/**
* Remove the local Listener and add the new listener.
*
* @param nlistener the new listener
*/
public void replaceControlListener(ControlListener nlistener) {
if (fLocalControlListener != null) {
removeControlListener(fLocalControlListener);
fLocalControlListener = null;
}
addControlListener(nlistener);
}
/**
* Remove the local Listener and add the new listener.
*
* @param nlistener the new listener
*/
public void replaceKeyListener(KeyListener nlistener) {
if (fLocalKeyListener != null) {
removeKeyListener(fLocalKeyListener);
fLocalKeyListener = null;
}
addKeyListener(nlistener);
}
/**
* Remove the local Listener and add the new listener.
*
* @param nlistener the new listener
*/
public void replaceMouseListener(MouseListener nlistener) {
if (fLocalMouseListener != null) {
removeMouseListener(fLocalMouseListener);
fLocalMouseListener = null;
}
fViewControl.addMouseListener(nlistener);
}
/**
* Remove the local Listener and add the new listener.
*
* @param nlistener the new listener
*/
public void replaceMouseMoveListener(MouseMoveListener nlistener) {
if (fLocalMouseMoveListener != null) {
removeMouseMoveListener(fLocalMouseMoveListener);
fLocalMouseMoveListener = null;
}
fViewControl.addMouseMoveListener(nlistener);
}
/**
* Remove the local Listener and add the new listener.
*
* @param nlistener the new listener
*/
public void replacePaintListener(PaintListener nlistener) {
if (fLocalPaintListener != null) {
removePaintListener(fLocalPaintListener);
fLocalPaintListener = null;
}
fViewControl.addPaintListener(nlistener);
}
/**
* Access method for the contentsHeight property.
*
* @return the current value of the contentsHeight property
*/
public int getContentsHeight() {
return fContentsHeight;
}
/**
* Access method for the contentsWidth property.
*
* @return the current value of the contentsWidth property
*/
public int getContentsWidth() {
return fContentsWidth;
}
/**
* Access method for the contentsX property.
*
* @return the current value of the contentsX property
*/
public int getContentsX() {
return fContentsX;
}
/**
* Access method for the contentsY property.
*
* @return the current value of the contentsY property
*/
public int getContentsY() {
return fContentsY;
}
/**
* Determines if the dragAutoScroll property is true.
*
* @return <code>true<code> if the dragAutoScroll property is true
*/
public boolean isDragAutoScroll() {
return fAutoScrollEnabled;
}
/**
* Sets the value of the dragAutoScroll property.
*
* @param aDragAutoScroll the new value of the dragAutoScroll property
*/
public void setDragAutoScroll(boolean aDragAutoScroll) {
fAutoScrollEnabled = aDragAutoScroll;
if (!fAutoScrollEnabled && (fAutoScroll != null)) {
fAutoScroll.cancel();
fAutoScroll = null;
}
}
/**
* Change delay (in millisec) used for auto scroll feature.
*
* @param period new period between to auto scroll
*/
public void setDragAutoScrollPeriod(int period) {
fAutoScrollPeriod = Math.max(0, period);
}
/**
* Return auto scroll period.
*
* @return The period
*/
public int getDragAutoScrollPeriod() {
return fAutoScrollPeriod;
}
/**
* Access method for the hScrollBarMode property.
*
* @return the current value of the hScrollBarMode property
*/
public int getHScrollBarMode() {
return fHorScrollbarMode;
}
/**
* Sets the value of the hScrollBarMode property.
*
* @param aHScrollBarMode the new value of the hScrollBarMode property
*/
public void setHScrollBarMode(int aHScrollBarMode) {
fHorScrollbarMode = aHScrollBarMode;
}
/**
* Access method for the vScrollBarMode property.
*
* @return the current value of the vScrollBarMode property
*/
public int getVScrollBarMode() {
return fVertScrollbarMode;
}
/**
* Sets the value of the vScrollBarMode property.
*
* @param aVScrollBarMode the new value of the vScrollBarMode property
*/
public void setVScrollBarMode(int aVScrollBarMode) {
fVertScrollbarMode = aVScrollBarMode;
}
/**
* Return horizontal scroll bar increment, default:1
*
* @return The increment
*/
public int getHScrollBarIncrement() {
return fHorScrollbarIncrement;
}
/**
* Return vertical scroll bar increment, default:1
*
* @return The increment
*/
public int getVScrollBarIncrement() {
return fVertScrollbarIncrement;
}
/**
* Change horizontal scroll bar increment, minimum:1. Page increment is
* always set to visible width.
*
* @param inc
* Increment value to set
*/
public void setHScrollBarIncrement(int inc) {
fHorScrollbarIncrement = Math.max(1, inc);
}
/**
* Change vertical scroll bar increment, minimum:1. Page increment is always
* set to visible height.
*
* @param inc
* Increment value to set
*/
public void setVScrollBarIncrement(int inc) {
fVertScrollbarIncrement = Math.max(1, inc);
}
/**
* Enable or disable overview feature. Enabling overview, dispose and replace existing corner control by a button.
* Clicking in it open overview, move mouse cursor holding button to move scroll view and release button to hide
* overview. Tip: hold control and/or shift key while moving mouse when overview is open made fine scroll.
*
* @param value true to engage overview feature
*/
public void setOverviewEnabled(boolean value) {
if (isOverviewEnabled() == value) {
return;
}
Control cc = null;
if (value) {
Button b = new Button(this, SWT.NONE);
b.setText("+"); //$NON-NLS-1$
Overview ovr = new Overview();
ovr.useControl(b);
b.setData(ovr);
cc = b;
b.setToolTipText(Messages.SequenceDiagram_OpenOverviewTooltip);
}
setCornerControl(cc);
}
/**
* Change overview size (at ratio 1:1), default is 100
*
* @param size
* The new size
*/
public void setOverviewSize(int size) {
fOverviewSize = Math.abs(size);
}
/**
* Returns whether the overview is enabled or not.
*
* @return true is overview feature is enabled
*/
public boolean isOverviewEnabled() {
if (fCornerControl instanceof Button) {
Object data = ((Button) fCornerControl).getData();
// overview alreay
if (data instanceof Overview) {
return true;
}
}
return false;
}
/**
* Returns the overview size at ratio 1:1.
*
* @return current overview size at ratio 1:1
*/
public int getOverviewSize() {
return fOverviewSize;
}
/**
* Returns control used to display view (might not be this object). Use this control to add/remove listener on the
* draw area.
*
* @return control used to display view (might not be this object).
*/
public Control getViewControl() {
return fViewControl;
}
/**
* Called when the mouse enter the ScrollView area
*
* @param e
* Mouse event
*/
protected void contentsMouseExit(MouseEvent e) {
// Do nothing
}
/**
* Called when the mouse enter the ScrollView area after and system defined
* time
*
* @param e
* Mouse event
*/
protected void contentsMouseHover(MouseEvent e) {
// Do nothing
}
/**
* Called when the mouse enter the ScrollView area
*
* @param e
* Mouse event
*/
protected void contentsMouseEnter(MouseEvent e) {
// Do nothing
}
/**
* Called when user double on contents area.
*
* @param e
* Mouse event
*/
protected void contentsMouseDoubleClickEvent(MouseEvent e) {
// Do nothing
}
/**
* Called when mouse is on contents area and button is pressed.
*
* @param e
* Mouse event
*/
protected void contentsMouseDownEvent(MouseEvent e) {
fMouseDownX = e.x;
fMousDownY = e.y;
}
/**
* TimerTask for auto scroll feature.
*/
protected static class AutoScroll extends TimerTask {
/** X delta */
private int deltaX;
/** Y delta */
private int deltaY;
/** ScrollView object */
private ScrollView scrollView;
/**
* Constructor.
*
* @param sv
* ScrollView object to use
* @param dx
* X delta
* @param dy
* Y delta
*/
public AutoScroll(ScrollView sv, int dx, int dy) {
scrollView = sv;
deltaX = dx;
deltaY = dy;
}
@Override
public void run() {
final Display display = Display.getDefault();
if ((display == null) || display.isDisposed()) {
return;
}
display.asyncExec(() -> {
if (!scrollView.isDisposed()) {
scrollView.scrollBy(deltaX, deltaY);
}
});
}
}
/**
* Called when mouse is on contents area and mode.
*
* @param event
* Mouse event
*/
protected void contentsMouseMoveEvent(MouseEvent event) {
if ((event.stateMask & SWT.BUTTON_MASK) != 0) {
if (!fAutoScrollEnabled) {
scrollBy(-(event.x - fMouseDownX), -(event.y - fMousDownY));
return;
}
int sx = 0, sy = 0;
int vRight = getContentsX() + getVisibleWidth();
int vBottom = getContentsY() + getVisibleHeight();
// auto scroll... ?
if (event.x < getContentsX()) {
sx = (getContentsX() - event.x);
fMouseDownX = getContentsX();
} else if (event.x > vRight) {
sx = -event.x + vRight;
fMouseDownX = vRight;
}
if (event.y < getContentsY()) {
sy = (getContentsY() - event.y);
fMousDownY = getContentsY();
} else if (event.y > vBottom) {
sy = -event.y + vBottom;
fMousDownY = vBottom;
}
if (sx != 0 || sy != 0) {
// start auto scroll...
if (fAutoScroll == null) {
if (fAutoScrollTimer == null) {
fAutoScrollTimer = new Timer(true);
}
fAutoScroll = new AutoScroll(this, sx, sy);
fAutoScrollTimer.schedule(fAutoScroll, 0, fAutoScrollPeriod);
} else {
fAutoScroll.deltaX = sx;
fAutoScroll.deltaY = sy;
}
} else {
if (fAutoScroll != null) {
fAutoScroll.cancel();
fAutoScroll = null;
}
scrollBy(-(event.x - fMouseDownX), -(event.y - fMousDownY));
}
}
}
/**
* Called when mouse is on contents area and button is released
*
* @param event
* Mouse event
*/
protected void contentsMouseUpEvent(MouseEvent event) {
// reset auto scroll if it's engaged
if (fAutoScroll != null) {
fAutoScroll.cancel();
fAutoScroll = null;
}
}
/**
* Responsible to draw contents area. At least rectangle clipX must be
* redrawn. This rectangle is given in contents coordinates. By default, no
* paint is produced.
*
* @param gc
* Graphics context
* @param clipx
* X clip
* @param clipy
* Y clip
* @param clipw
* W clip
* @param cliph
* H clip
*/
protected void drawContents(GC gc, int clipx, int clipy, int clipw, int cliph) {
// Do nothing
}
/**
* Change the size of the contents area.
*
* @param width new width of the area.
* @param height new height of the area.
*/
public void resizeContents(int width, int height) {
int localWidth = width;
int localHeight = height;
if (localWidth < 0) {
localWidth = 0;
}
if (localHeight < 0) {
localHeight = 0;
}
int oldW = fContentsWidth;
int oldH = fContentsHeight;
if (localWidth == oldW && localHeight == oldH) {
return;
}
fContentsWidth = localWidth;
fContentsHeight = localHeight;
if (oldW > localWidth) {
int s = localWidth;
localWidth = oldW;
oldW = s;
}
int visWidth = getVisibleWidth();
int visHeight = getVisibleHeight();
if (oldW < visWidth) {
if (localWidth > visWidth) {
localWidth = visWidth;
}
fViewControl.redraw(getContentsX() + oldW, 0, localWidth - oldW, visHeight, true);
}
if (oldH > localHeight) {
int s = localHeight;
localHeight = oldH;
oldH = s;
}
if (oldH < visHeight) {
if (localHeight > visHeight) {
localHeight = visHeight;
}
fViewControl.redraw(0, getContentsY() + oldH, visWidth, localHeight - oldH, true);
}
if (updateScrollBarVisiblity()) {
layout();
} else {
updateScrollBarsValues();
}
}
// redefined for internal use ..
@Override
public void redraw() {
super.redraw();
// ..need to redraw this already:
fViewControl.redraw();
}
/**
* @param delataX The delta in X
* @param deltaY the delta in Y
*/
public void scrollBy(int delataX, int deltaY) {
setContentsPos(getContentsX() + delataX, getContentsY() + deltaY);
}
/**
* Scroll to ensure point(in contents coordinates) is visible.
*
* @param px Point's x position
* @param py Point's y position
*/
public void ensureVisible(int px, int py) {
int cx = getContentsX(), cy = getContentsY();
int right = getContentsX() + getVisibleWidth();
int bottom = getContentsY() + getVisibleHeight();
if (px < getContentsX()) {
cx = px;
} else if (px > right) {
cx = px - getVisibleWidth();
}
if (py < getContentsY()) {
cy = py;
} else if (py > bottom) {
cy = py - getVisibleHeight();
}
setContentsPos(cx, cy);
}
/**
* Make rectangle (x,y,w,h, in contents coordinates) visible. if rectangle cannot be completely visible, use
* align flags.
*
* @param xValue x contents coordinates of rectangle.
* @param yValue y contents coordinates of rectangle.
* @param width width of rectangle.
* @param height height of rectangle.
* @param align bit or'ed SWT flag like SWT.LEFT,RIGHT,CENTER,TOP,BOTTOM,VERTICAL used only for bigger rectangle
* than visible area. By default CENTER/VERTICAL
*/
public void ensureVisible(int xValue, int yValue, int width, int height, int align) {
ensureVisible(xValue, yValue, width, height, align, false);
}
/**
* Make rectangle (xValue,yValue,width,height, in contents coordinates) visible. if rectangle cannot be completely visible, use
* align flags.
*
* @param xValue x contents coordinates of rectangle.
* @param yValue y contents coordinates of rectangle.
* @param width width of rectangle.
* @param height height of rectangle.
* @param align bit or'ed SWT flag like SWT.LEFT,RIGHT,CENTER,TOP,BOTTOM,VERTICAL used only for bigger rectangle
* than visible area. By default CENTER/VERTICAL
* @param forceAlign force alignment for rectangle smaller than the visible area
*/
protected void ensureVisible(int xValue, int yValue, int width, int height, int align, boolean forceAlign) {
int localX = xValue;
int localY = yValue;
int localWidth = width;
int localHeight = height;
if (localWidth < 0) {
localX = localX + localWidth;
localWidth = -localWidth;
}
if (localHeight < 0) {
localY = localY + localHeight;
localHeight = -localHeight;
}
int hbar = getHorizontalBarHeight();
int vbar = getVerticalBarWidth();
int cx = getContentsX();
int cy = getContentsY();
int right = getContentsX() + getVisibleWidth() - vbar;
int bottom = getContentsY() + getVisibleHeight() - hbar;
boolean alignH = false, alignV = false;
if (localX < getContentsX()) {
cx = localX;
} else if (localX + localWidth > right) {
cx = localX - localWidth;
}
if (localY < getContentsY()) {
cy = localY;
} else if (localY + localHeight > bottom) {
cy = localY - localHeight;
}
if (localWidth > getVisibleWidth()) {
alignH = true;
}
if (localHeight > getVisibleHeight()) {
alignV = true;
}
// compute alignment on visible area horizontally
if (alignH || (forceAlign && localX + localWidth > right)) {
// use align flags
if ((align & SWT.LEFT) != 0) {
cx = localX;
} else if ((align & SWT.RIGHT) != 0) {
cx = right - localWidth;
} else { // center
cx = localX + (localWidth - getVisibleWidth()) / 2;
}
}
// compute alignment on visible area vertically
if (alignV || (forceAlign && localY + localHeight > bottom)) {
// use align flags
if ((align & SWT.TOP) != 0) {
cy = localY;
} else if ((align & SWT.BOTTOM) != 0) {
cy = bottom - localHeight;
} else { // center
cy = localY + (localHeight - getVisibleHeight()) / 2;
}
}
setContentsPos(cx, cy);
}
/**
* Returns true if point is visible (expressed in contents coordinates).
*
* @param px Point's x position
* @param py Point's y position
* @return true if point is visible (expressed in contents coordinates)
*/
public boolean isVisible(int px, int py) {
if (px < getContentsX()) {
return false;
}
if (py < getContentsY()) {
return false;
}
if (px > (getContentsX() + getVisibleWidth())) {
return false;
}
return (py <= (getContentsY() + getVisibleHeight()));
}
/**
* Returns true if rectangle if partially visible.
*
* @param xValue x contents coordinates of rectangle.
* @param yValue y contents coordinates of rectangle.
* @param width width of rectangle.
* @param height height of rectangle.
* @return true if rectangle if partially visible.
*/
public boolean isVisible(int xValue, int yValue, int width, int height) {
if (xValue + width < getContentsX()) {
return false;
}
if (yValue + height < getContentsY()) {
return false;
}
int vr = getContentsX() + getVisibleWidth();
int vb = getContentsY() + getVisibleHeight();
if (xValue > vr) {
return false;
}
return (yValue <= vb);
}
/**
* Returns visible part of rectangle, or null if rectangle is not visible.
* Rectangle is expressed in contents coordinates.
*
* @param xValue
* x contents coordinates of rectangle.
* @param yValue
* y contents coordinates of rectangle.
* @param width
* width of rectangle.
* @param height
* height of rectangle.
* @return visible part of rectangle, or null if rectangle is not visible.
*/
public Rectangle getVisiblePart(int xValue, int yValue, int width, int height) {
if (xValue + width < getContentsX()) {
return null;
}
if (yValue + height < getContentsY()) {
return null;
}
int vr = getContentsX() + getVisibleWidth();
int vb = getContentsY() + getVisibleHeight();
if (xValue > vr) {
return null;
}
if (yValue > vb) {
return null;
}
int rr = xValue + width, rb = yValue + height;
int nl = Math.max(xValue, getContentsX()), nt = Math.max(yValue, getContentsY()), nr = Math.min(rr, vr), nb = Math.min(rb, vb);
return new Rectangle(nl, nt, nr - nl, nb - nt);
}
/**
* Returns the visible part for given rectangle.
*
* @param rect A rectangle
*
* @return gets visible part of rectangle (or <code>null</code>)
*/
public final Rectangle getVisiblePart(Rectangle rect) {
if (rect == null) {
return null;
}
return getVisiblePart(rect.x, rect.y, rect.width, rect.height);
}
/**
* Change top left position of visible area. Check if the given point is inside contents area.
*
* @param xValue x contents coordinates of visible area.
* @param yValue y contents coordinates of visible area.
* @return true if view really moves
*/
public boolean setContentsPos(int xValue, int yValue) {
int nx = xValue, ny = yValue;
if (getVisibleWidth() >= getContentsWidth()) {
nx = 0;
} else {
if (xValue < 0) {
nx = 0;
} else if (xValue + getVisibleWidth() > getContentsWidth()) {
nx = getContentsWidth() - getVisibleWidth();
}
}
if (getVisibleHeight() >= getContentsHeight()) {
ny = 0;
} else {
if (yValue <= 0) {
ny = 0;
} else if (yValue + getVisibleHeight() > getContentsHeight()) {
ny = getContentsHeight() - getVisibleHeight();
}
}
// no move
if (nx == fContentsX && ny == fContentsY) {
return false;
}
fContentsX = nx;
fContentsY = ny;
updateScrollBarsValues();
// ? find smallest area to redraw only them ?
fViewControl.redraw();
return true;
}
@Override
public ScrollBar getVerticalBar() {
return fVertScrollBar.getVerticalBar();
}
@Override
public ScrollBar getHorizontalBar() {
return fHorScrollBar.getHorizontalBar();
}
/**
* Compute visibility of vertical/horizontal bar using given width/height and current visibility (i.e. is bar size are already in
* for_xxx)
* @param forWidth width of foreground
* @param forHeight height of foreground
* @param currHorVis The current visibility state of horizontal scroll bar
* @param currVertvis The current visibility state of vertical scroll bar
* @return <code>true</code> if visibility changed else <code>false</code>
*/
public int computeBarVisibility(int forWidth, int forHeight, boolean currHorVis, boolean currVertvis) {
int localForWidth = forWidth;
int vis = 0x00;
switch (fVertScrollbarMode) {
case ALWAYS_OFF:
break;
case ALWAYS_ON:
vis |= VBAR;
break;
case AUTO:
if (getContentsHeight() > forHeight) {
vis = VBAR;
// v bar size is already in for_width.
if (!currVertvis) {// (curr_vis&0x01)==0)
localForWidth -= getVerticalBarWidth();
}
}
break;
default:
break;
}
switch (fHorScrollbarMode) {
case ALWAYS_OFF:
break;
case ALWAYS_ON:
vis |= HBAR;
break;
case AUTO:
if (getContentsWidth() > localForWidth) {
vis |= HBAR;
// h bar is not in for_height
if ((!currHorVis) && (getContentsHeight() > (forHeight - getHorizontalBarHeight()))) {// (curr_vis&0x02)==0 )
vis |= VBAR;
}
}
break;
default:
break;
}
return vis;
}
/**
* Setup scroll bars visibility.
*
* @return True if one of visibility changed.
*/
protected boolean updateScrollBarVisiblity() {
boolean change = false;
boolean currVertVis = fVertScrollBar.getVisible();
boolean currHorVis = fHorScrollBar.getVisible();
int barNewVis = computeBarVisibility(getVisibleWidth(), getVisibleHeight(), currHorVis, currVertVis);
boolean newVertVis = (barNewVis & VBAR) != 0;
boolean newHorVis = (barNewVis & HBAR) != 0;
if (currVertVis ^ newVertVis) { // vertsb_.getVisible() )
fVertScrollBar.setVisible(newVertVis);
change = true;
}
if (currHorVis ^ newHorVis) {
fHorScrollBar.setVisible(newHorVis);
change = true;
}
// update corner control visibility:
if (fCornerControl != null && change) {
boolean vis = newVertVis || newHorVis;
if (vis ^ fCornerControl.getVisible()) {
fCornerControl.setVisible(vis);
change = true; // but must be already the case
}
}
return change;
}
/**
* Setup scroll bar using contents, visible and scroll bar mode properties.
*/
protected void updateScrollBarsValues() {
/* update vertical scrollbar */
ScrollBar b = getVerticalBar();
if (b != null) {
b.setMinimum(0);
b.setMaximum(getContentsHeight());
b.setThumb(getVisibleHeight());
b.setPageIncrement(getVisibleHeight());
b.setIncrement(fVertScrollbarIncrement);
b.setSelection(getContentsY());
}
// update "hidden" vertical bar too
b = fViewControl.getVerticalBar();
if (b != null) {
b.setMinimum(0);
b.setMaximum(getContentsHeight());
b.setThumb(getVisibleHeight());
b.setPageIncrement(getVisibleHeight());
b.setIncrement(fVertScrollbarIncrement);
b.setSelection(getContentsY());
}
/* update horizontal scrollbar */
b = getHorizontalBar();
if (b != null) {
b.setMinimum(0);
b.setMaximum(getContentsWidth());
b.setThumb(getVisibleWidth());
b.setSelection(getContentsX());
b.setPageIncrement(getVisibleWidth());
b.setIncrement(fHorScrollbarIncrement);
}
// update "hidden" horizontal bar too
b = fViewControl.getHorizontalBar();
if (b != null) {
b.setMinimum(0);
b.setMaximum(getContentsWidth());
b.setThumb(getVisibleWidth());
b.setSelection(getContentsX());
b.setPageIncrement(getVisibleWidth());
b.setIncrement(fHorScrollbarIncrement);
}
}
/**
* Change the control used in the bottom right corner (between two scrollbar), if control is null reset previous
* corner control. This control is visible only if at least one scrollbar is visible. Given control will be disposed
* by ScrollView, at dispose() time, at next setCornetControl() call or when calling setOverviewEnabled(). Pay
* attention calling this reset overview feature until setOverviewEnabled(true) if called.
* @param control The control for the overview
*/
public void setCornerControl(Control control) {
if (fCornerControl != null) {
fCornerControl.dispose();
}
fCornerControl = control;
if (fCornerControl != null) {
ScrollBar vb = getVerticalBar();
ScrollBar hb = getHorizontalBar();
boolean vis = vb.getVisible() || hb.getVisible();
fCornerControl.setVisible(vis);
}
}
/**
* Transform (x,y) point in widget coordinates to contents coordinates.
*
* @param x The x widget coordinate.
* @param y The y widget coordinate.
* @return org.eclipse.swt.graphics.Point with content coordinates.
*/
public final Point viewToContents(int x, int y) {
return new Point(viewToContentsX(x), viewToContentsY(y));
}
/**
* Transform x in widget coordinates to contents coordinates
*
* @param x The y widget coordinate.
* @return the x content coordinate.
*/
public int viewToContentsX(int x) {
return fContentsX + x;
}
/**
* Transform y in widget coordinates to contents coordinates
*
* @param y The y widget coordinate.
* @return the y content coordinate.
*/
public int viewToContentsY(int y) {
return fContentsY + y;
}
/**
* Transform (x,y) point from contents coordinates, to widget coordinates.
*
* @param x The x content coordinate.
* @param y The y content coordinate.
* @return coordinates widget area as.
*/
public final Point contentsToView(int x, int y) {
return new Point(contentsToViewX(x), contentsToViewY(y));
}
/**
* Transform X axis coordinates from contents to widgets.
*
* @param x contents coordinate to transform.
* @return x coordinate in widget area
*/
public int contentsToViewX(int x) {
return x - fContentsX;
}
/**
* Transform Y axis coordinates from contents to widgets.
*
* @param y contents coordinate to transform
* @return y coordinate in widget area
*/
public int contentsToViewY(int y) {
return y - fContentsY;
}
/**
* Return the visible height of scroll view, might be > contentsHeight
*
* @return the visible height of scroll view, might be > contentsHeight()
*/
public int getVisibleHeight() {
return fViewControl.getClientArea().height;
}
/**
* Return int the visible width of scroll view, might be > contentsWidth().
*
* @return int the visible width of scroll view, might be > contentsWidth()
*/
public int getVisibleWidth() {
return fViewControl.getClientArea().width;
}
/**
* Add support for arrow key, scroll the ... scroll view. But you can
* redefine this method for your convenience.
*
* @param event
* Keyboard event
*/
protected void keyPressedEvent(KeyEvent event) {
switch (event.keyCode) {
case SWT.ARROW_UP:
scrollBy(0, -getVisibleHeight());
break;
case SWT.ARROW_DOWN:
scrollBy(0, +getVisibleHeight());
break;
case SWT.ARROW_LEFT:
scrollBy(-getVisibleWidth(), 0);
break;
case SWT.ARROW_RIGHT:
scrollBy(+getVisibleWidth(), 0);
break;
default:
break;
}
}
/**
* Redefine this method at your convenience
*
* @param event The key event.
*/
protected void keyReleasedEvent(KeyEvent event) {
// Do nothing
}
/**
* Returns vertical bar width, even if bar isn't visible.
*
* @return vertical bar width, even if bar isn't visible
*/
public int getVerticalBarWidth() {
// include vertical bar width and trimming of scrollable used
int bw = fVertScrollBar.computeTrim(0, 0, 0, 0).width;
return bw + 1;
}
/**
* Returns horizontal bar height even if bar isn't visible.
*
* @return horizontal bar height even if bar isn't visible
*/
public int getHorizontalBarHeight() {
// include horiz. bar height and trimming of scrollable used
int bh = fHorScrollBar.computeTrim(0, 0, 0, 0).height;
// +1 because win32 H.bar need 1 pixel canvas size to appear ! (strange no ?)
return bh + 1;
}
@Override
public Rectangle computeTrim(int x, int y, int w, int h) {
Rectangle r = new Rectangle(x, y, w, h);
int barVis = computeBarVisibility(w, h, false, false);
if ((barVis & VBAR) != 0) {
r.width += getVerticalBarWidth();
}
if ((barVis & HBAR) != 0) {
r.height += getHorizontalBarHeight();
}
return r;
}
/**
* Internal layout for ScrollView, handle scrollbars, drawzone and corner control
*/
protected class SVLayout extends Layout {
private static final int DEFAULT_X = 250;
private static final int DEFAULT_Y = 250;
private static final int MAX_SEEK = 10;
private static final int MIN_SEEK = 0;
/**
* The seek value
*/
private int seek = 0;
/**
* The do-it-not flag
*/
private boolean dontLayout = false;
@Override
protected Point computeSize(Composite composite, int wHint, int hHint, boolean flushCache) {
Point p = new Point(DEFAULT_X, DEFAULT_Y);
if (fContentsWidth < p.x) {
p.x = fContentsWidth;
}
if (fContentsHeight < p.y) {
p.y = fContentsHeight;
}
return p;
}
@Override
protected void layout(Composite composite, boolean flushCache) {
if (dontLayout) {
return;
}
seek++;
if (seek > MAX_SEEK) {
dontLayout = true;
}
Point cs = composite.getSize();
int barVis = computeBarVisibility(cs.x, cs.y, false, false);
boolean vbVis = (barVis & VBAR) != 0;
boolean hbVis = (barVis & HBAR) != 0;
fVertScrollBar.setVisible(vbVis);
fHorScrollBar.setVisible(hbVis);
int vbw = getVerticalBarWidth();
int hbh = getHorizontalBarHeight();
int wb = vbVis ? vbw : 0;
int hb = hbVis ? hbh : 0;
int cww = 0, cwh = 0;
if (fCornerControl != null && (vbVis || hbVis)) { // corner_control_.getVisible())
fCornerControl.setVisible(true);
cww = vbw;
cwh = hbh;
if (wb == 0) {
wb = vbw;
}
if (hb == 0) {
hb = hbh;
}
} else if (vbVis && hbVis) {
if (fCornerControl != null) {
fCornerControl.setVisible(false);
}
cww = vbw;
cwh = hbh;
}
if (vbVis || hbVis) {
updateScrollBarsValues();
}
int vw = cs.x - (vbVis ? vbw : 0);
int vh = cs.y - (hbVis ? hbh : 0);
int vbx = cs.x - wb;
int hby = cs.y - hb;
fViewControl.setBounds(0, 0, vw, vh);
if (vbVis) {
fVertScrollBar.setBounds(vbx, 0, wb, cs.y - cwh);
}
if (hbVis) {
fHorScrollBar.setBounds(0, hby, cs.x - cww, hb);
}
if (fCornerControl != null && fCornerControl.getVisible()) {
fCornerControl.setBounds(vbx, hby, vbw, hbh);
}
updateScrollBarsValues();
seek--;
if (seek == MIN_SEEK) {
dontLayout = false;
}
}
boolean isDontLayout() {
return dontLayout;
}
void setSontLayout(boolean dontLayout) {
this.dontLayout = dontLayout;
}
}
// static must take place here... cursor is created once.
private static volatile Cursor fOverviewCursor;
/** Support for click-and-see overview shell on this ScrollView */
protected class Overview {
private static final int REFRESH_FREQ = 4;
/**
* factor for X from real and overview sizes, for mouse move speed.
*/
private float fOverviewFactorX;
/**
* factor for Y from real and overview sizes, for mouse move speed.
*/
private float fOverviewFactorY;
/**
* shell use to show overview
*/
private Shell fOverview;
/**
* save mouse X cursor location for disappear();
*/
private int fSaveCursorX;
/**
* save mouse Y cursor location for disappear();
*/
private int fSaveCursorY;
/**
* Apply overview support on a control. Replace existing corner_widget
*
* @param control
* The control to use
*/
public void useControl(Control control) {
final Point pos = control.getLocation();
control.addMouseListener(new MouseListener() {
@Override
public void mouseDoubleClick(MouseEvent e) {
// Do nothing
}
@Override
public void mouseDown(MouseEvent e) {
overviewAppear(e.x, e.y);
}
@Override
public void mouseUp(MouseEvent e) {
overviewDisappear();
}
});
control.addFocusListener(new FocusListener() {
@Override
public void focusGained(FocusEvent e) {
// Do nothing
}
@Override
public void focusLost(FocusEvent e) {
if (overviewing()) {
overviewDisappear(false);
}
}
});
control.addKeyListener(new KeyListener() {
@Override
public void keyPressed(KeyEvent event) {
if (event.keyCode == 32 && !overviewing()) {
overviewAppear(pos.x, pos.y);
} else if (event.keyCode == 32) {
overviewDisappear();
}
if (event.keyCode == SWT.ARROW_DOWN) {
overviewMove(0, 1, event);
}
if (event.keyCode == SWT.ARROW_UP) {
overviewMove(0, -1, event);
}
if (event.keyCode == SWT.ARROW_RIGHT) {
overviewMove(1, 0, event);
}
if (event.keyCode == SWT.ARROW_LEFT) {
overviewMove(-1, 0, event);
}
}
@Override
public void keyReleased(KeyEvent e) {
// Do nothing
}
});
control.addMouseMoveListener(new MouseMoveListener() {
private int refReshCount = 0;
@Override
public void mouseMove(MouseEvent event) {
if (overviewing()) {
// Slow down the refresh
if (refReshCount % REFRESH_FREQ == 0) {
overviewMove(event);
}
refReshCount++;
}
}
});
}
/**
* Dispose controls of overview
*/
public void dispose() {
if (fOverview != null) {
fOverview.dispose();
}
}
/**
* @return true if overview is currently on screen
*/
protected boolean overviewing() {
return (fOverview != null && fOverview.isVisible());
}
/**
* Process overview appear
*
* @param mx
* X coordinate
* @param my
* Y coordinate
*/
protected void overviewAppear(int mx, int my) {
if (fOverview == null) {
fOverview = new Shell(getShell(), SWT.ON_TOP | SWT.NO_BACKGROUND);
fOverview.addPaintListener(e -> drawOverview(e.gc, fOverview.getClientArea()));
}
// always the same..
fOverview.setForeground(fViewControl.getForeground());
// get location of shell (in screeen coordinates)
Point p = toGlobalCoordinates(fCornerControl, 0, 0);
int x = p.x;
int y = p.y;
int w, h;
h = fOverviewSize;
w = h;
Rectangle scr = getDisplay().getBounds();
Point ccs = fCornerControl.getSize();
try {
if (fContentsWidth > fContentsHeight) {
float ratio = fContentsHeight / (float) fContentsWidth;
h = (int) (w * ratio);
if (h < ccs.y) {
h = ccs.y;
} else if (h >= scr.height / 2) {
h = scr.height / 2;
}
} else {
float ratio = fContentsWidth / (float) fContentsHeight;
w = (int) (h * ratio);
if (w < ccs.x) {
w = ccs.x;
} else if (w >= scr.width / 2) {
w = scr.width / 2;
}
}
fOverviewFactorX = fContentsWidth / (float) w;
fOverviewFactorY = fContentsHeight / (float) h;
}
// no contents size set ?
catch (java.lang.ArithmeticException e) {
}
// try pop-up on button, extending to bottom right,
if (x <= 0) {
x = 1;
}
if (y <= 0) {
y = 1;
}
x = x - w + ccs.x;
y = y - h + ccs.y;
fOverview.setBounds(x, y, w, h);
fOverview.setVisible(true);
fOverview.redraw();
// mouse cursor disappear, so set invisible mouse cursor ...
if (fOverviewCursor == null) {
RGB rgb[] = { new RGB(0, 0, 0), new RGB(255, 0, 0) };
PaletteData palette = new PaletteData(rgb);
int s = 1;
byte src[] = new byte[s * s];
byte msk[] = new byte[s * s];
for (int i = 0; i < s * s; ++i) {
src[i] = (byte) 0xFF;
}
ImageData i_src = new ImageData(s, s, 1, palette, 1, src);
ImageData i_msk = new ImageData(s, s, 1, palette, 1, msk);
fOverviewCursor = new Cursor(null, i_src, i_msk, 0, 0);
}
fCornerControl.setCursor(fOverviewCursor);
// convert to global coordinates
p = toGlobalCoordinates(fCornerControl, mx, my);
fSaveCursorX = p.x;
fSaveCursorY = p.y;
Rectangle r = fOverview.getClientArea();
int cx = (int) (r.width * fContentsX / (float) fContentsWidth);
int cy = (int) (r.height * fContentsY / (float) fContentsHeight);
// cx,cy to display's global coordinates
p = toGlobalCoordinates(fOverview.getParent(), cx, cy);
}
/**
* Process disappear of overview
*/
protected void overviewDisappear() {
overviewDisappear(true);
}
/**
* Process disappear of overview
* @param restoreCursorLoc A flag to restore cursor location
*/
protected void overviewDisappear(boolean restoreCursorLoc) {
if (fOverview == null) {
return;
}
fOverview.setVisible(false);
fCornerControl.setCursor(null);
if (restoreCursorLoc) {
getDisplay().setCursorLocation(fSaveCursorX, fSaveCursorY);
}
fOverview.dispose();
fOverview = null;
}
/**
* Process mouse move in overview
* @param event The mouse event
*/
protected void overviewMove(MouseEvent event) {
Point p = toGlobalCoordinates(fCornerControl, event.x, event.y);
int dx = p.x - fSaveCursorX;
int dy = p.y - fSaveCursorY;
overviewMove(dx, dy, event);
}
/**
* Process mouse move event when overviewing
*
* @param dx The x coordinates delta
* @param dy The y coordinates delta
* @param event The typed event
*/
protected void overviewMove(int dx, int dy, TypedEvent event) {
boolean ctrl = false;
boolean shift = false;
if (event instanceof MouseEvent) {
MouseEvent e = (MouseEvent) event;
getDisplay().setCursorLocation(fSaveCursorX, fSaveCursorY);
ctrl = (e.stateMask & SWT.CONTROL) != 0;
shift = (e.stateMask & SWT.SHIFT) != 0;
} else if (event instanceof KeyEvent) {
KeyEvent e = (KeyEvent) event;
ctrl = (e.stateMask & SWT.CONTROL) != 0;
shift = (e.stateMask & SWT.SHIFT) != 0;
}
int cx = fContentsX;
int cy = fContentsY;
float fx = fOverviewFactorX;
float fy = fOverviewFactorY;
if (ctrl && shift) {
if ((fx * 0.25f > 1) && (fy * 0.25 > 1)) {
fx = fy = 1.0f;
} else {
fx *= 0.1f;
fy *= 0.1f;
}
} else if (ctrl) {
fx *= 0.5f;
fy *= 0.5f;
} else if (shift) {
fx *= 0.5f;
fy *= 0.5f;
}
scrollBy((int) (fx * dx), (int) (fy * dy));
if (cx != fContentsX || cy != fContentsY) {
fOverview.redraw();
fOverview.update(); // draw now !
}
}
/**
* Convert overview coordinates to global coordinates.
*
* @param loc
* the control reference
* @param x
* The x coordinate to convert
* @param y
* The y coordinate to convert
* @return The new converted Point
*/
protected Point toGlobalCoordinates(Control loc, int x, int y) {
Point p = new Point(x, y);
for (Control c = loc; c != null; c = c.getParent()) {
// control might have client area with 'decorations'
int trimX = 0, trimY = 0;
// other kind of widget with trimming ??
if (c instanceof Scrollable) {
Scrollable s = (Scrollable) c;
Rectangle rr = s.getClientArea();
Rectangle tr = s.computeTrim(rr.x, rr.y, rr.width, rr.height);
trimX = rr.x - tr.x;
trimY = rr.y - tr.y;
}
p.x += c.getLocation().x + trimX;
p.y += c.getLocation().y + trimY;
}
return p;
}
}
}