add first elements
This commit is contained in:
parent
806000c4cc
commit
5a372d0f90
Binary file not shown.
After Width: | Height: | Size: 307 B |
Binary file not shown.
After Width: | Height: | Size: 307 B |
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,95 @@
|
||||||
|
package com.minres.scviewer.database.ui.swt.internal;
|
||||||
|
|
||||||
|
import org.eclipse.swt.SWT;
|
||||||
|
import org.eclipse.swt.events.MouseAdapter;
|
||||||
|
import org.eclipse.swt.events.SelectionAdapter;
|
||||||
|
import org.eclipse.swt.events.SelectionEvent;
|
||||||
|
import org.eclipse.swt.graphics.Color;
|
||||||
|
import org.eclipse.swt.graphics.GC;
|
||||||
|
import org.eclipse.swt.layout.GridData;
|
||||||
|
import org.eclipse.swt.layout.GridLayout;
|
||||||
|
import org.eclipse.swt.widgets.Button;
|
||||||
|
import org.eclipse.swt.widgets.Composite;
|
||||||
|
import org.eclipse.swt.widgets.Slider;
|
||||||
|
import org.eclipse.wb.swt.SWTResourceManager;
|
||||||
|
|
||||||
|
public class WaveformSlider extends Composite {
|
||||||
|
|
||||||
|
Slider slider;
|
||||||
|
|
||||||
|
Color buttonColor;
|
||||||
|
|
||||||
|
public WaveformSlider(Composite parent, int style) {
|
||||||
|
super(parent, style);
|
||||||
|
GridLayout gridLayout = new GridLayout(3, false);
|
||||||
|
gridLayout.horizontalSpacing = 0;
|
||||||
|
gridLayout.verticalSpacing = 0;
|
||||||
|
gridLayout.marginWidth = 0;
|
||||||
|
gridLayout.marginHeight = 0;
|
||||||
|
setLayout(gridLayout);
|
||||||
|
|
||||||
|
buttonColor = getDisplay().getSystemColor(SWT.COLOR_DARK_GRAY);
|
||||||
|
|
||||||
|
Button scrlLeft = new Button(this, /*SWT.BORDER |*/ SWT.FLAT | SWT.CENTER);
|
||||||
|
scrlLeft.setFont(SWTResourceManager.getFont("Sans", 5, SWT.NORMAL));
|
||||||
|
GridData gd_scrlLeft = new GridData(SWT.RIGHT, SWT.CENTER, false, false, 1, 1);
|
||||||
|
gd_scrlLeft.heightHint = 16;
|
||||||
|
gd_scrlLeft.widthHint = 16;
|
||||||
|
scrlLeft.setLayoutData(gd_scrlLeft);
|
||||||
|
scrlLeft.addPaintListener(paintEvent -> {
|
||||||
|
GC gc = paintEvent.gc;
|
||||||
|
gc.setBackground(buttonColor);
|
||||||
|
gc.setForeground(buttonColor);
|
||||||
|
int left = paintEvent.x+4;
|
||||||
|
int top = paintEvent.y+5;
|
||||||
|
int width=paintEvent.width-11;
|
||||||
|
int height= paintEvent.height-10;
|
||||||
|
int[] triangle = new int[] {
|
||||||
|
left, top+height/2,
|
||||||
|
left+width, top,
|
||||||
|
left+width, top+height};
|
||||||
|
gc.fillPolygon( triangle );
|
||||||
|
gc.drawPolygon( triangle );
|
||||||
|
});
|
||||||
|
scrlLeft.addSelectionListener(new SelectionAdapter() {
|
||||||
|
public void widgetSelected (SelectionEvent e){
|
||||||
|
slider.setSelection(slider.getSelection()-10);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
scrlLeft.redraw();
|
||||||
|
|
||||||
|
slider = new Slider(this, SWT.NONE);
|
||||||
|
slider.setBackground(SWTResourceManager.getColor(SWT.COLOR_WIDGET_BACKGROUND));
|
||||||
|
GridData gd_canvas = new GridData(SWT.FILL, SWT.FILL, true, false, 1, 1);
|
||||||
|
gd_canvas.heightHint = 16;
|
||||||
|
slider.setLayoutData(gd_canvas);
|
||||||
|
|
||||||
|
Button scrlRight = new Button(this, /*SWT.BORDER |*/ SWT.FLAT | SWT.CENTER);
|
||||||
|
scrlRight.setAlignment(SWT.CENTER);
|
||||||
|
GridData gd_scrlRight = new GridData(SWT.LEFT, SWT.CENTER, false, false, 1, 1);
|
||||||
|
gd_scrlRight.heightHint = 16;
|
||||||
|
gd_scrlRight.widthHint = 16;
|
||||||
|
scrlRight.setLayoutData(gd_scrlRight);
|
||||||
|
scrlRight.addPaintListener(paintEvent -> {
|
||||||
|
GC gc = paintEvent.gc;
|
||||||
|
gc.setBackground(buttonColor);
|
||||||
|
gc.setForeground(buttonColor);
|
||||||
|
int left = paintEvent.x+6;
|
||||||
|
int top = paintEvent.y+5;
|
||||||
|
int width=paintEvent.width-11;
|
||||||
|
int height= paintEvent.height-10;
|
||||||
|
int[] triangle = new int[] {
|
||||||
|
left, top,
|
||||||
|
left+width, top+height/2,
|
||||||
|
left, top+height};
|
||||||
|
gc.fillPolygon( triangle );
|
||||||
|
gc.drawPolygon( triangle );
|
||||||
|
});
|
||||||
|
scrlRight.addSelectionListener(new SelectionAdapter() {
|
||||||
|
public void widgetSelected (SelectionEvent e){
|
||||||
|
slider.setSelection(slider.getSelection()+10);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
redraw();
|
||||||
|
}
|
||||||
|
}
|
|
@ -54,6 +54,7 @@ import org.eclipse.swt.events.PaintEvent;
|
||||||
import org.eclipse.swt.events.PaintListener;
|
import org.eclipse.swt.events.PaintListener;
|
||||||
import org.eclipse.swt.events.SelectionAdapter;
|
import org.eclipse.swt.events.SelectionAdapter;
|
||||||
import org.eclipse.swt.events.SelectionEvent;
|
import org.eclipse.swt.events.SelectionEvent;
|
||||||
|
import org.eclipse.swt.graphics.Color;
|
||||||
import org.eclipse.swt.graphics.GC;
|
import org.eclipse.swt.graphics.GC;
|
||||||
import org.eclipse.swt.graphics.Point;
|
import org.eclipse.swt.graphics.Point;
|
||||||
import org.eclipse.swt.graphics.Rectangle;
|
import org.eclipse.swt.graphics.Rectangle;
|
||||||
|
@ -61,6 +62,7 @@ import org.eclipse.swt.graphics.TextLayout;
|
||||||
import org.eclipse.swt.layout.FillLayout;
|
import org.eclipse.swt.layout.FillLayout;
|
||||||
import org.eclipse.swt.layout.GridData;
|
import org.eclipse.swt.layout.GridData;
|
||||||
import org.eclipse.swt.layout.GridLayout;
|
import org.eclipse.swt.layout.GridLayout;
|
||||||
|
import org.eclipse.swt.widgets.Button;
|
||||||
import org.eclipse.swt.widgets.Canvas;
|
import org.eclipse.swt.widgets.Canvas;
|
||||||
import org.eclipse.swt.widgets.Composite;
|
import org.eclipse.swt.widgets.Composite;
|
||||||
import org.eclipse.swt.widgets.Control;
|
import org.eclipse.swt.widgets.Control;
|
||||||
|
@ -69,6 +71,7 @@ import org.eclipse.swt.widgets.Label;
|
||||||
import org.eclipse.swt.widgets.Listener;
|
import org.eclipse.swt.widgets.Listener;
|
||||||
import org.eclipse.swt.widgets.Menu;
|
import org.eclipse.swt.widgets.Menu;
|
||||||
import org.eclipse.swt.widgets.ScrollBar;
|
import org.eclipse.swt.widgets.ScrollBar;
|
||||||
|
import org.eclipse.swt.widgets.Slider;
|
||||||
import org.eclipse.swt.widgets.Widget;
|
import org.eclipse.swt.widgets.Widget;
|
||||||
import org.eclipse.wb.swt.SWTResourceManager;
|
import org.eclipse.wb.swt.SWTResourceManager;
|
||||||
|
|
||||||
|
@ -91,6 +94,7 @@ import com.minres.scviewer.database.ui.IWaveformStyleProvider;
|
||||||
import com.minres.scviewer.database.ui.IWaveformView;
|
import com.minres.scviewer.database.ui.IWaveformView;
|
||||||
import com.minres.scviewer.database.ui.IWaveformZoom;
|
import com.minres.scviewer.database.ui.IWaveformZoom;
|
||||||
import com.minres.scviewer.database.ui.TrackEntry;
|
import com.minres.scviewer.database.ui.TrackEntry;
|
||||||
|
import com.minres.scviewer.database.ui.swt.sb.FlatScrollBar;
|
||||||
|
|
||||||
public class WaveformView implements IWaveformView {
|
public class WaveformView implements IWaveformView {
|
||||||
|
|
||||||
|
@ -330,8 +334,22 @@ public class WaveformView implements IWaveformView {
|
||||||
rightSash.setBackground(SWTResourceManager.getColor(SWT.COLOR_GRAY));
|
rightSash.setBackground(SWTResourceManager.getColor(SWT.COLOR_GRAY));
|
||||||
|
|
||||||
Composite valuePane = new Composite(rightSash, SWT.NONE);
|
Composite valuePane = new Composite(rightSash, SWT.NONE);
|
||||||
waveformCanvas = new WaveformCanvas(rightSash, SWT.NONE, styleProvider);
|
|
||||||
|
Composite waveformPane = new Composite(rightSash, SWT.NONE);
|
||||||
|
GridLayout gl_waveformPane = new GridLayout(1, false);
|
||||||
|
gl_waveformPane.verticalSpacing = 0;
|
||||||
|
gl_waveformPane.marginWidth = 0;
|
||||||
|
gl_waveformPane.marginHeight = 0;
|
||||||
|
waveformPane.setLayout(gl_waveformPane);
|
||||||
|
|
||||||
|
waveformCanvas = new WaveformCanvas(waveformPane, SWT.NONE | SWT.V_SCROLL /*| SWT.H_SCROLL*/, styleProvider);
|
||||||
|
waveformCanvas.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true, 1, 1));
|
||||||
|
|
||||||
|
Composite timeSliderPane = new WaveformSlider(waveformPane, SWT.NONE);
|
||||||
|
GridData gd_timeSlider = new GridData(SWT.FILL, SWT.BOTTOM, false, false, 1, 1);
|
||||||
|
gd_timeSlider.heightHint = 18;
|
||||||
|
timeSliderPane.setLayoutData(gd_timeSlider);
|
||||||
|
|
||||||
// create the name pane
|
// create the name pane
|
||||||
createTextPane(namePane, "Name");
|
createTextPane(namePane, "Name");
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,108 @@
|
||||||
|
package com.minres.scviewer.database.ui.swt.internal;
|
||||||
|
|
||||||
|
import org.eclipse.swt.widgets.Composite;
|
||||||
|
import org.eclipse.swt.layout.GridLayout;
|
||||||
|
import org.eclipse.swt.widgets.Button;
|
||||||
|
import org.eclipse.swt.SWT;
|
||||||
|
import org.eclipse.swt.widgets.Label;
|
||||||
|
import org.eclipse.swt.widgets.Canvas;
|
||||||
|
import org.eclipse.swt.layout.GridData;
|
||||||
|
import org.eclipse.wb.swt.ResourceManager;
|
||||||
|
import org.eclipse.swt.custom.SashForm;
|
||||||
|
import org.eclipse.swt.widgets.Slider;
|
||||||
|
import org.eclipse.wb.swt.SWTResourceManager;
|
||||||
|
import org.eclipse.swt.widgets.Scale;
|
||||||
|
import org.eclipse.jface.fieldassist.ControlDecoration;
|
||||||
|
import org.eclipse.swt.layout.FormLayout;
|
||||||
|
import org.eclipse.swt.layout.FillLayout;
|
||||||
|
|
||||||
|
public class ZoomingScrollbar extends Composite {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create the composite.
|
||||||
|
* @param parent
|
||||||
|
* @param style
|
||||||
|
*/
|
||||||
|
public ZoomingScrollbar(Composite parent, int style) {
|
||||||
|
super(parent, SWT.BORDER | SWT.NO_FOCUS);
|
||||||
|
GridLayout gridLayout = new GridLayout(3, false);
|
||||||
|
gridLayout.horizontalSpacing = 0;
|
||||||
|
gridLayout.verticalSpacing = 0;
|
||||||
|
gridLayout.marginWidth = 0;
|
||||||
|
gridLayout.marginHeight = 0;
|
||||||
|
setLayout(gridLayout);
|
||||||
|
|
||||||
|
Button scrlLeft = new Button(this, SWT.BORDER | SWT.FLAT | SWT.CENTER);
|
||||||
|
scrlLeft.setFont(SWTResourceManager.getFont("Sans", 5, SWT.NORMAL));
|
||||||
|
GridData gd_scrlLeft = new GridData(SWT.RIGHT, SWT.CENTER, false, false, 1, 1);
|
||||||
|
gd_scrlLeft.heightHint = 16;
|
||||||
|
gd_scrlLeft.widthHint = 16;
|
||||||
|
scrlLeft.setLayoutData(gd_scrlLeft);
|
||||||
|
|
||||||
|
Slider slider = new Slider(this, SWT.NONE);
|
||||||
|
slider.setBackground(SWTResourceManager.getColor(SWT.COLOR_WIDGET_BACKGROUND));
|
||||||
|
GridData gd_canvas = new GridData(SWT.FILL, SWT.FILL, true, false, 1, 1);
|
||||||
|
gd_canvas.heightHint = 16;
|
||||||
|
slider.setLayoutData(gd_canvas);
|
||||||
|
|
||||||
|
Button scrlRight = new Button(this, SWT.BORDER | SWT.FLAT | SWT.CENTER);
|
||||||
|
scrlRight.setAlignment(SWT.CENTER);
|
||||||
|
GridData gd_scrlRight = new GridData(SWT.LEFT, SWT.CENTER, false, false, 1, 1);
|
||||||
|
gd_scrlRight.heightHint = 16;
|
||||||
|
gd_scrlRight.widthHint = 16;
|
||||||
|
scrlRight.setLayoutData(gd_scrlRight);
|
||||||
|
|
||||||
|
SashForm sashForm = new SashForm(this, SWT.NONE);
|
||||||
|
sashForm.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true, 3, 1));
|
||||||
|
|
||||||
|
Composite composite = new Composite(sashForm, SWT.NONE);
|
||||||
|
composite.setBackground(SWTResourceManager.getColor(SWT.COLOR_MAGENTA));
|
||||||
|
composite.setLayout(null);
|
||||||
|
|
||||||
|
Composite wavformPane = new Composite(sashForm, SWT.BORDER | SWT.NO_FOCUS);
|
||||||
|
wavformPane.setBackground(SWTResourceManager.getColor(SWT.COLOR_BLUE));
|
||||||
|
GridLayout gl_wavformPane = new GridLayout(1, false);
|
||||||
|
gl_wavformPane.verticalSpacing = 0;
|
||||||
|
gl_wavformPane.marginWidth = 0;
|
||||||
|
gl_wavformPane.marginHeight = 0;
|
||||||
|
wavformPane.setLayout(gl_wavformPane);
|
||||||
|
|
||||||
|
Composite waveformCanvas = new Composite(wavformPane, SWT.NONE);
|
||||||
|
waveformCanvas.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true, 1, 1));
|
||||||
|
|
||||||
|
Composite timeSlider = new Composite(wavformPane, SWT.BORDER | SWT.NO_FOCUS);
|
||||||
|
GridLayout gl_timeSlider = new GridLayout(3, false);
|
||||||
|
gl_timeSlider.marginWidth = 0;
|
||||||
|
gl_timeSlider.verticalSpacing = 0;
|
||||||
|
gl_timeSlider.marginHeight = 0;
|
||||||
|
gl_timeSlider.horizontalSpacing = 0;
|
||||||
|
timeSlider.setLayout(gl_timeSlider);
|
||||||
|
GridData gd_timeSlider = new GridData(SWT.FILL, SWT.BOTTOM, false, false, 1, 1);
|
||||||
|
gd_timeSlider.heightHint = 16;
|
||||||
|
timeSlider.setLayoutData(gd_timeSlider);
|
||||||
|
|
||||||
|
Button buttonLeft = new Button(timeSlider, SWT.BORDER | SWT.FLAT | SWT.CENTER);
|
||||||
|
buttonLeft.setFont(SWTResourceManager.getFont("Sans", 5, SWT.NORMAL));
|
||||||
|
GridData gd_buttonLeft = new GridData(SWT.FILL, SWT.FILL, false, false, 1, 1);
|
||||||
|
gd_buttonLeft.widthHint = 10;
|
||||||
|
gd_buttonLeft.heightHint = 16;
|
||||||
|
buttonLeft.setLayoutData(gd_buttonLeft);
|
||||||
|
|
||||||
|
Slider slider2 = new Slider(timeSlider, SWT.NONE);
|
||||||
|
slider2.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, true, 1, 1));
|
||||||
|
|
||||||
|
Button buttonRight = new Button(timeSlider, SWT.FLAT | SWT.CENTER);
|
||||||
|
buttonRight.setFont(SWTResourceManager.getFont("Sans", 5, SWT.NORMAL));
|
||||||
|
GridData gd_buttonRight = new GridData(SWT.FILL, SWT.FILL, false, false, 1, 1);
|
||||||
|
gd_buttonRight.widthHint = 10;
|
||||||
|
gd_buttonRight.heightHint = 16;
|
||||||
|
buttonRight.setLayoutData(gd_buttonRight);
|
||||||
|
sashForm.setWeights(new int[] {1, 1});
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void checkSubclass() {
|
||||||
|
// Disable the check that prevents subclassing of SWT components
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,18 @@
|
||||||
|
package com.minres.scviewer.database.ui.swt.sb;
|
||||||
|
|
||||||
|
import org.eclipse.swt.widgets.Display;
|
||||||
|
|
||||||
|
public class ActionScheduler {
|
||||||
|
|
||||||
|
private final Display display;
|
||||||
|
private final Runnable action;
|
||||||
|
|
||||||
|
public ActionScheduler( Display display, Runnable action ) {
|
||||||
|
this.display = display;
|
||||||
|
this.action = action;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void schedule( int delay ) {
|
||||||
|
display.timerExec( delay, action );
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,45 @@
|
||||||
|
package com.minres.scviewer.database.ui.swt.sb;
|
||||||
|
|
||||||
|
import org.eclipse.swt.events.MouseEvent;
|
||||||
|
import org.eclipse.swt.graphics.Point;
|
||||||
|
import org.eclipse.swt.widgets.Control;
|
||||||
|
|
||||||
|
public class ButtonClick {
|
||||||
|
|
||||||
|
public static final int LEFT_BUTTON = 1;
|
||||||
|
|
||||||
|
private boolean armed;
|
||||||
|
|
||||||
|
public boolean isArmed() {
|
||||||
|
return armed;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void arm( MouseEvent event ) {
|
||||||
|
if( event.button == LEFT_BUTTON ) {
|
||||||
|
armed = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void disarm() {
|
||||||
|
armed = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void trigger( MouseEvent event, Runnable action ) {
|
||||||
|
try {
|
||||||
|
doTrigger( event, action );
|
||||||
|
} finally {
|
||||||
|
disarm();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void doTrigger( MouseEvent event, Runnable action ) {
|
||||||
|
if( armed && inRange( event ) ) {
|
||||||
|
action.run();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static boolean inRange( MouseEvent event ) {
|
||||||
|
Point size = ( ( Control )event.widget ).getSize();
|
||||||
|
return event.x >= 0 && event.x <= size.x && event.y >= 0 && event.y <= size.y;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,98 @@
|
||||||
|
package com.minres.scviewer.database.ui.swt.sb;
|
||||||
|
|
||||||
|
import org.eclipse.swt.SWT;
|
||||||
|
import org.eclipse.swt.events.ControlAdapter;
|
||||||
|
import org.eclipse.swt.events.ControlEvent;
|
||||||
|
import org.eclipse.swt.events.MouseEvent;
|
||||||
|
import org.eclipse.swt.events.MouseListener;
|
||||||
|
import org.eclipse.swt.events.MouseTrackListener;
|
||||||
|
import org.eclipse.swt.graphics.Color;
|
||||||
|
import org.eclipse.swt.widgets.Composite;
|
||||||
|
import org.eclipse.swt.widgets.Label;
|
||||||
|
|
||||||
|
|
||||||
|
class ClickControl extends ControlAdapter implements ViewComponent, MouseDownActionTimer.TimerAction, MouseListener, MouseTrackListener {
|
||||||
|
|
||||||
|
private final MouseDownActionTimer mouseDownActionTimer;
|
||||||
|
private final ClickAction clickAction;
|
||||||
|
private final ButtonClick buttonClick;
|
||||||
|
private final Label control;
|
||||||
|
private final ImageUpdate imageUpdate;
|
||||||
|
|
||||||
|
public interface ClickAction extends Runnable {
|
||||||
|
void setCoordinates( int x, int y );
|
||||||
|
}
|
||||||
|
|
||||||
|
ClickControl( Composite parent, ClickAction clickAction, int maxExtension ) {
|
||||||
|
this.control = new Label( parent, SWT.NONE );
|
||||||
|
this.imageUpdate = new ImageUpdate( control, maxExtension );
|
||||||
|
this.buttonClick = new ButtonClick();
|
||||||
|
this.mouseDownActionTimer = new MouseDownActionTimer( this, buttonClick, control.getDisplay() );
|
||||||
|
this.clickAction = clickAction;
|
||||||
|
this.control.addMouseTrackListener( this );
|
||||||
|
this.control.addMouseListener( this );
|
||||||
|
this.control.addControlListener( this );
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void controlResized( ControlEvent event ) {
|
||||||
|
imageUpdate.update();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Label getControl() {
|
||||||
|
return control;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void mouseDown( MouseEvent event ) {
|
||||||
|
buttonClick.arm( event );
|
||||||
|
clickAction.setCoordinates( event.x, event.y );
|
||||||
|
mouseDownActionTimer.activate();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void mouseUp( MouseEvent event ) {
|
||||||
|
buttonClick.trigger( event, clickAction );
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
|
clickAction.run();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isEnabled() {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void mouseExit( MouseEvent event ) {
|
||||||
|
buttonClick.disarm();
|
||||||
|
}
|
||||||
|
|
||||||
|
void setForeground( Color color ) {
|
||||||
|
imageUpdate.setForeground( color );
|
||||||
|
}
|
||||||
|
|
||||||
|
Color getForeground() {
|
||||||
|
return imageUpdate.getForeground();
|
||||||
|
}
|
||||||
|
|
||||||
|
void setBackground( Color color ) {
|
||||||
|
imageUpdate.setBackground( color );
|
||||||
|
}
|
||||||
|
|
||||||
|
Color getBackground() {
|
||||||
|
return imageUpdate.getBackground();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void mouseEnter( MouseEvent event ) {}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void mouseHover( MouseEvent event ) {}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void mouseDoubleClick( MouseEvent event ) {}
|
||||||
|
}
|
|
@ -0,0 +1,105 @@
|
||||||
|
package com.minres.scviewer.database.ui.swt.sb;
|
||||||
|
|
||||||
|
import static java.lang.Math.max;
|
||||||
|
|
||||||
|
import java.math.BigDecimal;
|
||||||
|
import java.math.RoundingMode;
|
||||||
|
|
||||||
|
class ComponentDistribution {
|
||||||
|
|
||||||
|
private static final int MIN_DRAG_LENGTH = 17;
|
||||||
|
|
||||||
|
final int upFastLength;
|
||||||
|
final int dragStart;
|
||||||
|
final int dragLength;
|
||||||
|
final int downFastStart;
|
||||||
|
final int downFastLength;
|
||||||
|
final int downStart;
|
||||||
|
final int buttonLen;
|
||||||
|
|
||||||
|
ComponentDistribution( int buttonLen, int len, int range, int pos, int thumb ) {
|
||||||
|
int slideLen = slideLen( buttonLen, len );
|
||||||
|
int relDragLen = relDragLen( slideLen, range, thumb );
|
||||||
|
int minDragLength = max( MIN_DRAG_LENGTH, buttonLen );
|
||||||
|
int interval = interval( range, relDragLen, minDragLength );
|
||||||
|
this.dragLength = dragLen( minDragLength, relDragLen );
|
||||||
|
this.upFastLength = upFastLen( minDragLength, interval, pos, slideLen, relDragLen, dragLength );
|
||||||
|
this.downStart = downStart( buttonLen, len );
|
||||||
|
this.downFastStart = downFastStart( buttonLen, upFastLength, dragLength );
|
||||||
|
this.dragStart = dragStart( buttonLen, upFastLength );
|
||||||
|
this.downFastLength = downFastLen( minDragLength, interval, pos, slideLen, relDragLen, dragLength, upFastLength );
|
||||||
|
this.buttonLen = buttonLen;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static int slideLen( int buttonLen, int len ) {
|
||||||
|
return len - buttonLen * 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static int relDragLen( int slideLen, int range, int thumb ) {
|
||||||
|
return divide( slideLen * thumb, range );
|
||||||
|
}
|
||||||
|
|
||||||
|
private static int interval( int range, int relDragLen, int minDragLength ) {
|
||||||
|
int result = range;
|
||||||
|
if( useMinDragLen( minDragLength, relDragLen ) ) {
|
||||||
|
result += minDragLength - relDragLen / 2;
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static int dragLen( int buttonLen, int relDragLen ) {
|
||||||
|
return max( relDragLen, buttonLen );
|
||||||
|
}
|
||||||
|
|
||||||
|
private static int upFastLen( int buttonLen, int range, int pos, int slideLen, int relDragLen, int dragLen ) {
|
||||||
|
int result = slideLen * pos / range;
|
||||||
|
if( useMinDragLen( buttonLen, relDragLen ) ) {
|
||||||
|
result -= divide( ( dragLen - relDragLen ) * pos, range );
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static int downStart( int buttonLen, int len ) {
|
||||||
|
return len - buttonLen;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static int downFastStart( int buttonLen, int upFastLength, int dragLength ) {
|
||||||
|
return buttonLen + upFastLength + dragLength;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static int dragStart( int buttonLen, int upFastLen ) {
|
||||||
|
return buttonLen + upFastLen;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static int downFastLen(
|
||||||
|
int buttonLen, int range, int pos, int slideLen, int relDragLen, int dragLen, int upFastLen )
|
||||||
|
{
|
||||||
|
int result = divide( slideLen * ( range - pos ), range ) - dragLen;
|
||||||
|
if( useMinDragLen( buttonLen, relDragLen ) ) {
|
||||||
|
result += divide( ( dragLen - relDragLen ) * pos, range );
|
||||||
|
}
|
||||||
|
return adjustDownFastLen( result, slideLen, dragLen, upFastLen );
|
||||||
|
}
|
||||||
|
|
||||||
|
private static boolean useMinDragLen( int buttonLen, int relDragLen ) {
|
||||||
|
return relDragLen < buttonLen;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int divide( int dividend, int divisor ) {
|
||||||
|
BigDecimal bigDividend = new BigDecimal( dividend );
|
||||||
|
BigDecimal bigDivisor = new BigDecimal( divisor );
|
||||||
|
return bigDividend .divide( bigDivisor, 0, RoundingMode.HALF_EVEN ) .intValue();
|
||||||
|
}
|
||||||
|
|
||||||
|
private static int adjustDownFastLen( int tentative, int slideLen, int dragLen, int upFastLen ) {
|
||||||
|
// TODO [fappel]: Without this there is a flickering of the downFast label of one pixel.
|
||||||
|
// Check whether this can be resolved by better rounding or whatsoever.
|
||||||
|
int result = tentative;
|
||||||
|
if( slideLen < upFastLen + dragLen + result ) {
|
||||||
|
result--;
|
||||||
|
} else if( slideLen > upFastLen + dragLen + result ) {
|
||||||
|
result++;
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,24 @@
|
||||||
|
package com.minres.scviewer.database.ui.swt.sb;
|
||||||
|
|
||||||
|
import org.eclipse.swt.SWT;
|
||||||
|
|
||||||
|
import com.minres.scviewer.database.ui.swt.sb.ClickControl.ClickAction;
|
||||||
|
|
||||||
|
class Decrementer implements ClickAction {
|
||||||
|
|
||||||
|
private final FlatScrollBar scrollBar;
|
||||||
|
|
||||||
|
Decrementer( FlatScrollBar scrollBar ) {
|
||||||
|
this.scrollBar = scrollBar;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
|
int selection = scrollBar.getSelection() - scrollBar.getIncrement();
|
||||||
|
scrollBar.setSelectionInternal( selection, SWT.ARROW_UP );
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setCoordinates( int x, int y ) {
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,203 @@
|
||||||
|
package com.minres.scviewer.database.ui.swt.sb;
|
||||||
|
|
||||||
|
import static com.minres.scviewer.database.ui.swt.sb.FlatScrollBar.BAR_BREADTH;
|
||||||
|
import static java.lang.Math.max;
|
||||||
|
|
||||||
|
import org.eclipse.swt.SWT;
|
||||||
|
import org.eclipse.swt.graphics.Point;
|
||||||
|
import org.eclipse.swt.graphics.Rectangle;
|
||||||
|
import org.eclipse.swt.widgets.Composite;
|
||||||
|
import org.eclipse.swt.widgets.Control;
|
||||||
|
|
||||||
|
enum Direction {
|
||||||
|
|
||||||
|
HORIZONTAL( SWT.HORIZONTAL ) {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void layout( FlatScrollBar scrollBar, int buttonLength ) {
|
||||||
|
ComponentDistribution distribution = calculateComponentDistribution( scrollBar, buttonLength );
|
||||||
|
Rectangle[] componentBounds = calculateComponentBounds( distribution, scrollBar );
|
||||||
|
applyComponentBounds( scrollBar, componentBounds );
|
||||||
|
}
|
||||||
|
|
||||||
|
private ComponentDistribution calculateComponentDistribution( FlatScrollBar scrollBar, int buttonLength ) {
|
||||||
|
return calculateComponentDistribution( scrollBar, buttonLength, getControlBounds( scrollBar ).width );
|
||||||
|
}
|
||||||
|
|
||||||
|
private Rectangle[] calculateComponentBounds( ComponentDistribution distribution, FlatScrollBar scrollBar ) {
|
||||||
|
int width = getControlBounds( scrollBar ).width;
|
||||||
|
int height = getControlBounds( scrollBar ).height - FlatScrollBar.BAR_BREADTH + 1;
|
||||||
|
int balance = getRoundingBalance( distribution, scrollBar );
|
||||||
|
return new Rectangle[] {
|
||||||
|
calcButtons( distribution, width, $( 0, CLEARANCE, distribution.buttonLen, height ) ),
|
||||||
|
$( distribution.buttonLen, CLEARANCE, distribution.upFastLength, height ),
|
||||||
|
calcDrag( distribution, $( distribution.dragStart, CLEARANCE, distribution.dragLength + balance, height ) ),
|
||||||
|
$( distribution.downFastStart, CLEARANCE, distribution.downFastLength - balance, height ),
|
||||||
|
calcButtons( distribution, width, $( distribution.downStart, CLEARANCE, distribution.buttonLen, height ) )
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
private Rectangle calcButtons( ComponentDistribution distribution, int length, Rectangle bounds ) {
|
||||||
|
Rectangle result = bounds;
|
||||||
|
if( length <= distribution.buttonLen* 2 ) {
|
||||||
|
int downStart = calcDownStartForSmallLength( bounds.x, length );
|
||||||
|
result = $( downStart, CLEARANCE, length / 2, bounds.height );
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void setDefaultSize( Control control ) {
|
||||||
|
Point size = control.getSize();
|
||||||
|
control.setSize( size.x, FlatScrollBar.BAR_BREADTH );
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected Point computeSize( Composite composite, int wHint, int hHint, boolean changed ) {
|
||||||
|
int x = wHint == SWT.DEFAULT ? composite.getParent().getClientArea().width : wHint;
|
||||||
|
return new Point( x, FlatScrollBar.BAR_BREADTH );
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void expand( Control control, int maxExpansion ) {
|
||||||
|
Rectangle bounds = control.getBounds();
|
||||||
|
int expand = expand( bounds.height, maxExpansion );
|
||||||
|
control.setBounds( bounds.x, bounds.y - expand, bounds.width, bounds.height + expand );
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
VERTICAL( SWT.VERTICAL ) {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void layout( FlatScrollBar scrollBar, int buttonLength ) {
|
||||||
|
ComponentDistribution calculation = calculateComponentDistribution( scrollBar, buttonLength );
|
||||||
|
applyComponentBounds( scrollBar, calculateComponentBounds( calculation, scrollBar ) );
|
||||||
|
}
|
||||||
|
|
||||||
|
private ComponentDistribution calculateComponentDistribution( FlatScrollBar scrollBar, int buttonLength ) {
|
||||||
|
return calculateComponentDistribution( scrollBar, buttonLength, getControlBounds( scrollBar ).height );
|
||||||
|
}
|
||||||
|
|
||||||
|
private Rectangle[] calculateComponentBounds( ComponentDistribution distribution, FlatScrollBar scrollBar ) {
|
||||||
|
int width = getControlBounds( scrollBar ).width - FlatScrollBar.BAR_BREADTH + 1;
|
||||||
|
int height = getControlBounds( scrollBar ).height;
|
||||||
|
int balance = getRoundingBalance( distribution, scrollBar );
|
||||||
|
return new Rectangle[] {
|
||||||
|
calculateButtons( distribution, height, $( CLEARANCE, 0, width, distribution.buttonLen ) ),
|
||||||
|
$( CLEARANCE, distribution.buttonLen, width, distribution.upFastLength ),
|
||||||
|
calcDrag( distribution, $( CLEARANCE, distribution.dragStart, width, distribution.dragLength + balance ) ),
|
||||||
|
$( CLEARANCE, distribution.downFastStart, width, distribution.downFastLength - balance ),
|
||||||
|
calculateButtons( distribution, height, $( CLEARANCE, distribution.downStart, width, distribution.buttonLen ) )
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
private Rectangle calculateButtons( ComponentDistribution distribution, int length, Rectangle bounds ) {
|
||||||
|
Rectangle result = bounds;
|
||||||
|
if( length <= distribution.buttonLen * 2 ) {
|
||||||
|
int downStart = calcDownStartForSmallLength( bounds.y, length );
|
||||||
|
result = $( CLEARANCE, downStart, bounds.width, length / 2 );
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void setDefaultSize( Control control ) {
|
||||||
|
Point size = control.getSize();
|
||||||
|
control.setSize( FlatScrollBar.BAR_BREADTH, size.y );
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected Point computeSize( Composite composite, int wHint, int hHint, boolean changed ) {
|
||||||
|
int y = hHint == SWT.DEFAULT ? composite.getParent().getClientArea().height : hHint;
|
||||||
|
return new Point( FlatScrollBar.BAR_BREADTH, y );
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void expand( Control control, int maxExpansion ) {
|
||||||
|
Rectangle bounds = control.getBounds();
|
||||||
|
int expand = expand( bounds.width, maxExpansion );
|
||||||
|
control.setBounds( bounds.x - expand, bounds.y, bounds.width + expand, bounds.height );
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
static final Rectangle EMPTY_RECTANGLE = $( 0, 0, 0, 0 );
|
||||||
|
static final int CLEARANCE = BAR_BREADTH - 2;
|
||||||
|
|
||||||
|
private final int value;
|
||||||
|
|
||||||
|
protected abstract void layout( FlatScrollBar scrollBar, int buttonLength );
|
||||||
|
protected abstract void setDefaultSize( Control control );
|
||||||
|
protected abstract Point computeSize( Composite comp, int wHint, int hHint, boolean changed );
|
||||||
|
protected abstract void expand( Control control, int maxExpansion );
|
||||||
|
|
||||||
|
Direction( int value ) {
|
||||||
|
this.value = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int value() {
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static ComponentDistribution calculateComponentDistribution(
|
||||||
|
FlatScrollBar scrollBar , int buttonLength , int length )
|
||||||
|
{
|
||||||
|
int range = scrollBar.getMaximum() - scrollBar.getMinimum();
|
||||||
|
int position = scrollBar.getSelection() - scrollBar.getMinimum();
|
||||||
|
int thumb = scrollBar.getThumb();
|
||||||
|
return new ComponentDistribution( buttonLength, length, range, position, thumb );
|
||||||
|
}
|
||||||
|
|
||||||
|
private static Rectangle getControlBounds( FlatScrollBar scrollBar ) {
|
||||||
|
return scrollBar.getClientArea();
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void applyComponentBounds( FlatScrollBar scrollBar, Rectangle[] bounds ) {
|
||||||
|
scrollBar.up.getControl().setBounds( bounds[ 0 ] );
|
||||||
|
scrollBar.upFast.getControl().setBounds( bounds[ 1 ] );
|
||||||
|
scrollBar.drag.getControl().setBounds( bounds[ 2 ] );
|
||||||
|
scrollBar.downFast.getControl().setBounds( bounds[ 3 ] );
|
||||||
|
scrollBar.down.getControl().setBounds( bounds[ 4 ] );
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO [fappel]: There is a 1 pixel rounding problem at the seam of drag/downFast with down.
|
||||||
|
// Seems to work but I would prefer a better solution if possible
|
||||||
|
private static int getRoundingBalance( ComponentDistribution calculation, FlatScrollBar scrollBar ) {
|
||||||
|
int result = 0;
|
||||||
|
int maximumSelection = scrollBar.getMaximum() - scrollBar.getThumb();
|
||||||
|
if( scrollBar.getSelection() == maximumSelection && 0 != calculation.downFastLength ) {
|
||||||
|
result = 1;
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static int expand( int toExpand, int maxExpansion ) {
|
||||||
|
return max( 0, FlatScrollBar.BAR_BREADTH + maxExpansion - max( FlatScrollBar.BAR_BREADTH, toExpand ) );
|
||||||
|
}
|
||||||
|
|
||||||
|
private static Rectangle calcDrag( ComponentDistribution distribution, Rectangle bounds ) {
|
||||||
|
Rectangle result = bounds;
|
||||||
|
if( isUndercutOfDragVisibility( distribution ) ) {
|
||||||
|
result = EMPTY_RECTANGLE;
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static boolean isUndercutOfDragVisibility( ComponentDistribution distribution ) {
|
||||||
|
return distribution.dragLength + distribution.buttonLen >= distribution.downStart;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static int calcDownStartForSmallLength( int position, int length ) {
|
||||||
|
int result = position;
|
||||||
|
if( isDownStartPosition( position ) ) {
|
||||||
|
result = length / 2;
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
private static boolean isDownStartPosition( int position ) {
|
||||||
|
return position > 0 || position < 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static Rectangle $( int x, int y, int width, int height ) {
|
||||||
|
return new Rectangle( x, y , width , height );
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,105 @@
|
||||||
|
package com.minres.scviewer.database.ui.swt.sb;
|
||||||
|
|
||||||
|
import org.eclipse.swt.SWT;
|
||||||
|
import org.eclipse.swt.events.ControlAdapter;
|
||||||
|
import org.eclipse.swt.events.ControlEvent;
|
||||||
|
import org.eclipse.swt.events.DragDetectEvent;
|
||||||
|
import org.eclipse.swt.events.DragDetectListener;
|
||||||
|
import org.eclipse.swt.events.MouseEvent;
|
||||||
|
import org.eclipse.swt.events.MouseListener;
|
||||||
|
import org.eclipse.swt.events.MouseMoveListener;
|
||||||
|
import org.eclipse.swt.graphics.Color;
|
||||||
|
import org.eclipse.swt.graphics.Point;
|
||||||
|
import org.eclipse.swt.widgets.Composite;
|
||||||
|
import org.eclipse.swt.widgets.Label;
|
||||||
|
|
||||||
|
|
||||||
|
class DragControl
|
||||||
|
extends ControlAdapter
|
||||||
|
implements ViewComponent, DragDetectListener, MouseListener, MouseMoveListener
|
||||||
|
{
|
||||||
|
|
||||||
|
private final DragDetector dragDetector;
|
||||||
|
private final ImageUpdate imageUpdate;
|
||||||
|
private final DragAction dragAction;
|
||||||
|
private final Label control;
|
||||||
|
|
||||||
|
private Point startingPosition;
|
||||||
|
|
||||||
|
public interface DragAction {
|
||||||
|
void start();
|
||||||
|
void run( int startX, int startY, int currentX, int currentY );
|
||||||
|
void end();
|
||||||
|
}
|
||||||
|
|
||||||
|
DragControl( Composite parent, DragAction dragAction, int maxExpansion ) {
|
||||||
|
this.control = new Label( parent, SWT.NONE );
|
||||||
|
this.imageUpdate = new ImageUpdate( control, maxExpansion );
|
||||||
|
this.dragDetector = new DragDetector( control, 0 );
|
||||||
|
this.dragAction = dragAction;
|
||||||
|
initializeControl();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Label getControl() {
|
||||||
|
return control;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void dragDetected( DragDetectEvent event ) {
|
||||||
|
if( startingPosition != null ) {
|
||||||
|
dragAction.run( startingPosition.x, startingPosition.y, event.x, event.y );
|
||||||
|
}
|
||||||
|
dragDetector.dragHandled();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void mouseDown( MouseEvent event ) {
|
||||||
|
startingPosition = new Point( event.x, event.y );
|
||||||
|
dragAction.start();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void mouseUp( MouseEvent event ) {
|
||||||
|
if( startingPosition != null ) {
|
||||||
|
dragAction.end();
|
||||||
|
}
|
||||||
|
startingPosition = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void mouseMove( MouseEvent event ) {
|
||||||
|
dragDetector.mouseMove( event );
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void controlResized( ControlEvent event ) {
|
||||||
|
imageUpdate.update();
|
||||||
|
}
|
||||||
|
|
||||||
|
void setForeground( Color color ) {
|
||||||
|
imageUpdate.setForeground( color );
|
||||||
|
}
|
||||||
|
|
||||||
|
Color getForeground() {
|
||||||
|
return imageUpdate.getForeground();
|
||||||
|
}
|
||||||
|
|
||||||
|
Color getBackground() {
|
||||||
|
return imageUpdate.getBackground();
|
||||||
|
}
|
||||||
|
|
||||||
|
void setBackground( Color color ) {
|
||||||
|
imageUpdate.setBackground( color );
|
||||||
|
}
|
||||||
|
|
||||||
|
private void initializeControl( ) {
|
||||||
|
control.addMouseListener( this );
|
||||||
|
control.addMouseMoveListener( this );
|
||||||
|
control.addControlListener( this );
|
||||||
|
control.addDragDetectListener( this );
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void mouseDoubleClick( MouseEvent event ) {}
|
||||||
|
}
|
|
@ -0,0 +1,60 @@
|
||||||
|
package com.minres.scviewer.database.ui.swt.sb;
|
||||||
|
|
||||||
|
import org.eclipse.swt.SWT;
|
||||||
|
import org.eclipse.swt.events.MouseEvent;
|
||||||
|
import org.eclipse.swt.widgets.Control;
|
||||||
|
import org.eclipse.swt.widgets.Event;
|
||||||
|
|
||||||
|
// TODO [fappel]: This is a workaround for a problem described here:
|
||||||
|
// http://stackoverflow.com/questions/3908290/mousedown-events-are-not-delivered-until-mouseup-when-a-drag-source-is-present
|
||||||
|
// This seems to be related to https://bugs.eclipse.org/bugs/show_bug.cgi?id=328396
|
||||||
|
// which is resolved. As it did not work on my setup I adapted the workaround of the last
|
||||||
|
// stackoverflow answer.
|
||||||
|
|
||||||
|
public class DragDetector {
|
||||||
|
|
||||||
|
int lastMouseX;
|
||||||
|
int lastMouseY;
|
||||||
|
boolean dragEventGenerated;
|
||||||
|
|
||||||
|
private final Control control;
|
||||||
|
private final int sensibility;
|
||||||
|
|
||||||
|
public DragDetector( Control control, int sensibility ) {
|
||||||
|
this.control = control;
|
||||||
|
this.sensibility = sensibility;
|
||||||
|
this.control.setDragDetect( false );
|
||||||
|
}
|
||||||
|
|
||||||
|
public void mouseMove( MouseEvent e ) {
|
||||||
|
if( ( e.stateMask & SWT.BUTTON1 ) > 0 ) {
|
||||||
|
int deltaX = lastMouseX - e.x;
|
||||||
|
int deltaY = lastMouseY - e.y;
|
||||||
|
int dragDistance = deltaX * deltaX + deltaY * deltaY;
|
||||||
|
if( !dragEventGenerated && dragDistance > sensibility ) {
|
||||||
|
dragEventGenerated = true;
|
||||||
|
Event event = createDragEvent( e );
|
||||||
|
control.notifyListeners( SWT.DragDetect, event );
|
||||||
|
}
|
||||||
|
lastMouseX = e.x;
|
||||||
|
lastMouseY = e.y;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void dragHandled() {
|
||||||
|
dragEventGenerated = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
private Event createDragEvent( MouseEvent e ) {
|
||||||
|
Event event = new Event();
|
||||||
|
event.type = SWT.DragDetect;
|
||||||
|
event.display = control.getDisplay();
|
||||||
|
event.widget = control;
|
||||||
|
event.button = e.button;
|
||||||
|
event.stateMask = e.stateMask;
|
||||||
|
event.time = e.time;
|
||||||
|
event.x = e.x;
|
||||||
|
event.y = e.y;
|
||||||
|
return event;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,59 @@
|
||||||
|
package com.minres.scviewer.database.ui.swt.sb;
|
||||||
|
|
||||||
|
import static com.minres.scviewer.database.ui.swt.sb.Direction.HORIZONTAL;
|
||||||
|
import static com.minres.scviewer.database.ui.swt.sb.ShiftData.calculateSelectionRange;
|
||||||
|
|
||||||
|
import org.eclipse.swt.SWT;
|
||||||
|
import org.eclipse.swt.graphics.Point;
|
||||||
|
|
||||||
|
import com.minres.scviewer.database.ui.swt.sb.DragControl.DragAction;
|
||||||
|
|
||||||
|
final class DragShifter implements DragAction {
|
||||||
|
|
||||||
|
private final FlatScrollBar scrollBar;
|
||||||
|
private final int buttonLength;
|
||||||
|
|
||||||
|
public DragShifter( FlatScrollBar scrollBar, int buttonLength ) {
|
||||||
|
this.scrollBar = scrollBar;
|
||||||
|
this.buttonLength = buttonLength;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void start() {
|
||||||
|
scrollBar.notifyListeners( SWT.DRAG );
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void run( int startX, int startY, int currentX, int currentY ) {
|
||||||
|
ShiftData shiftData = newShiftData( startX, startY, currentX, currentY );
|
||||||
|
if( shiftData.canShift() ) {
|
||||||
|
int selectionRange = calculateSelectionRange( scrollBar );
|
||||||
|
int selectionDelta = shiftData.calculateSelectionDelta( selectionRange );
|
||||||
|
int selection = scrollBar.getSelection() + selectionDelta;
|
||||||
|
scrollBar.setSelectionInternal( selection, SWT.DRAG );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void end() {
|
||||||
|
scrollBar.notifyListeners( SWT.NONE );
|
||||||
|
}
|
||||||
|
|
||||||
|
private ShiftData newShiftData( int startX, int startY, int currentX, int currentY ) {
|
||||||
|
ShiftData result;
|
||||||
|
if( scrollBar.direction == HORIZONTAL ) {
|
||||||
|
result = new ShiftData( buttonLength, getScrollBarSize().x, getDragSize().x, currentX - startX );
|
||||||
|
} else {
|
||||||
|
result = new ShiftData( buttonLength, getScrollBarSize().y, getDragSize().y, currentY - startY );
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
private Point getScrollBarSize() {
|
||||||
|
return scrollBar.getSize();
|
||||||
|
}
|
||||||
|
|
||||||
|
private Point getDragSize() {
|
||||||
|
return scrollBar.drag.getControl().getSize();
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,49 @@
|
||||||
|
package com.minres.scviewer.database.ui.swt.sb;
|
||||||
|
|
||||||
|
import org.eclipse.swt.SWT;
|
||||||
|
import org.eclipse.swt.graphics.Point;
|
||||||
|
import org.eclipse.swt.graphics.Rectangle;
|
||||||
|
import org.eclipse.swt.widgets.Display;
|
||||||
|
|
||||||
|
import com.minres.scviewer.database.ui.swt.sb.ClickControl.ClickAction;
|
||||||
|
|
||||||
|
class FastDecrementer implements ClickAction {
|
||||||
|
|
||||||
|
private final FlatScrollBar scrollBar;
|
||||||
|
|
||||||
|
private int x;
|
||||||
|
private int y;
|
||||||
|
|
||||||
|
FastDecrementer( FlatScrollBar scrollBar ) {
|
||||||
|
this.scrollBar = scrollBar;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
|
Rectangle drag = getDragBounds();
|
||||||
|
Point mouse = getMouseLocation();
|
||||||
|
if( mouse.x <= drag.x || mouse.y <= drag.y ) {
|
||||||
|
int selection = scrollBar.getSelection() - scrollBar.getPageIncrement();
|
||||||
|
scrollBar.setSelectionInternal( selection, SWT.PAGE_UP );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setCoordinates( int x, int y ) {
|
||||||
|
this.x = x;
|
||||||
|
this.y = y;
|
||||||
|
}
|
||||||
|
|
||||||
|
private Point getMouseLocation() {
|
||||||
|
return getDisplay().map( scrollBar.upFast.getControl(), null, x, y );
|
||||||
|
}
|
||||||
|
|
||||||
|
private Rectangle getDragBounds() {
|
||||||
|
Rectangle dragBounds = scrollBar.drag.getControl().getBounds();
|
||||||
|
return getDisplay().map( scrollBar, null, dragBounds );
|
||||||
|
}
|
||||||
|
|
||||||
|
private Display getDisplay() {
|
||||||
|
return scrollBar.getDisplay();
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,42 @@
|
||||||
|
package com.minres.scviewer.database.ui.swt.sb;
|
||||||
|
|
||||||
|
import org.eclipse.swt.SWT;
|
||||||
|
import org.eclipse.swt.graphics.Point;
|
||||||
|
import org.eclipse.swt.graphics.Rectangle;
|
||||||
|
import org.eclipse.swt.widgets.Display;
|
||||||
|
|
||||||
|
import com.minres.scviewer.database.ui.swt.sb.ClickControl.ClickAction;
|
||||||
|
|
||||||
|
class FastIncrementer implements ClickAction {
|
||||||
|
|
||||||
|
private final FlatScrollBar scrollBar;
|
||||||
|
|
||||||
|
private Point mouse;
|
||||||
|
|
||||||
|
FastIncrementer( FlatScrollBar scrollBar ) {
|
||||||
|
this.scrollBar = scrollBar;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
|
Rectangle drag = getDragBounds();
|
||||||
|
if( mouse.x > drag.x + drag.width || mouse.y > drag.y + drag.height ) {
|
||||||
|
int selection = scrollBar.getSelection() + scrollBar.getPageIncrement();
|
||||||
|
scrollBar.setSelectionInternal( selection, SWT.PAGE_DOWN );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setCoordinates( int x, int y ) {
|
||||||
|
mouse = getMouseLocation( x, y );
|
||||||
|
}
|
||||||
|
|
||||||
|
private Point getMouseLocation(int x, int y) {
|
||||||
|
return Display.getCurrent().map( scrollBar.downFast.getControl(), null, x, y );
|
||||||
|
}
|
||||||
|
|
||||||
|
private Rectangle getDragBounds() {
|
||||||
|
Rectangle dragBounds = scrollBar.drag.getControl().getBounds();
|
||||||
|
return Display.getCurrent().map( scrollBar, null, dragBounds );
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,295 @@
|
||||||
|
package com.minres.scviewer.database.ui.swt.sb;
|
||||||
|
|
||||||
|
import static com.minres.scviewer.database.ui.swt.sb.UntypedSelectionAdapter.lookup;
|
||||||
|
|
||||||
|
import java.util.Collection;
|
||||||
|
import java.util.HashSet;
|
||||||
|
|
||||||
|
import org.eclipse.swt.SWT;
|
||||||
|
import org.eclipse.swt.events.SelectionEvent;
|
||||||
|
import org.eclipse.swt.events.SelectionListener;
|
||||||
|
import org.eclipse.swt.graphics.Color;
|
||||||
|
import org.eclipse.swt.widgets.Composite;
|
||||||
|
import org.eclipse.swt.widgets.Display;
|
||||||
|
import org.eclipse.swt.widgets.Event;
|
||||||
|
import org.eclipse.swt.widgets.Layout;
|
||||||
|
import org.eclipse.swt.widgets.Listener;
|
||||||
|
|
||||||
|
public class FlatScrollBar extends Composite {
|
||||||
|
|
||||||
|
public static final int BAR_BREADTH = 6;
|
||||||
|
|
||||||
|
static final int DEFAULT_MINIMUM = 0;
|
||||||
|
static final int DEFAULT_MAXIMUM = 100;
|
||||||
|
static final int DEFAULT_INCREMENT = 1;
|
||||||
|
static final int DEFAULT_THUMB = 10;
|
||||||
|
static final int DEFAULT_PAGE_INCREMENT = DEFAULT_THUMB;
|
||||||
|
static final int DEFAULT_SELECTION = 0;
|
||||||
|
static final int DEFAULT_BUTTON_LENGTH = 0;
|
||||||
|
static final int DEFAULT_MAX_EXPANSION = Direction.CLEARANCE + 2;
|
||||||
|
|
||||||
|
final ClickControl up;
|
||||||
|
final ClickControl upFast;
|
||||||
|
final DragControl drag;
|
||||||
|
final ClickControl downFast;
|
||||||
|
final ClickControl down;
|
||||||
|
final Direction direction;
|
||||||
|
final MouseWheelShifter mouseWheelHandler;
|
||||||
|
final Collection<SelectionListener> listeners;
|
||||||
|
|
||||||
|
private int minimum;
|
||||||
|
private int maximum;
|
||||||
|
private int increment;
|
||||||
|
private int pageIncrement;
|
||||||
|
private int thumb;
|
||||||
|
private int selection;
|
||||||
|
private boolean onDrag;
|
||||||
|
private int buttonLength;
|
||||||
|
|
||||||
|
public FlatScrollBar( final Composite parent, int style ) {
|
||||||
|
this( parent, style, DEFAULT_BUTTON_LENGTH, DEFAULT_MAX_EXPANSION );
|
||||||
|
}
|
||||||
|
|
||||||
|
FlatScrollBar( Composite parent, int style, int buttonLength, int maxExpansion ) {
|
||||||
|
super( parent, SWT.NONE );
|
||||||
|
super.setLayout( new FlatScrollBarLayout( getDirection( style ) ) );
|
||||||
|
this.minimum = DEFAULT_MINIMUM;
|
||||||
|
this.maximum = DEFAULT_MAXIMUM;
|
||||||
|
this.increment = DEFAULT_INCREMENT;
|
||||||
|
this.pageIncrement = DEFAULT_PAGE_INCREMENT;
|
||||||
|
this.thumb = DEFAULT_THUMB;
|
||||||
|
this.selection = DEFAULT_SELECTION;
|
||||||
|
this.buttonLength = buttonLength;
|
||||||
|
this.direction = getDirection( style );
|
||||||
|
this.direction.setDefaultSize( this );
|
||||||
|
this.up = new ClickControl( this, new Decrementer( this ), maxExpansion );
|
||||||
|
this.upFast = new ClickControl( this, new FastDecrementer( this ), maxExpansion );
|
||||||
|
this.drag = new DragControl( this, new DragShifter( this, buttonLength ), maxExpansion );
|
||||||
|
this.downFast = new ClickControl( this, new FastIncrementer( this ), maxExpansion );
|
||||||
|
this.down = new ClickControl( this, new Incrementer( this ), maxExpansion );
|
||||||
|
this.mouseWheelHandler = new MouseWheelShifter( this, parent, buttonLength );
|
||||||
|
this.listeners = new HashSet<SelectionListener>();
|
||||||
|
addMouseTrackListener( new MouseTracker( this, maxExpansion ) );
|
||||||
|
addControlListener( new ResizeObserver( this ) );
|
||||||
|
setDefaultColorScheme();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setLayout( Layout layout ) {
|
||||||
|
throw new UnsupportedOperationException( FlatScrollBar.class.getName() + " does not allow to change layout." );
|
||||||
|
};
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getStyle() {
|
||||||
|
return direction != null ? super.getStyle() | direction.value() : super.getStyle();
|
||||||
|
};
|
||||||
|
|
||||||
|
Direction getDirection() {
|
||||||
|
return direction;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setMinimum( int minimum ) {
|
||||||
|
if( this.minimum != minimum && minimum >= 0 && minimum < maximum ) {
|
||||||
|
this.minimum = minimum;
|
||||||
|
adjustThumb();
|
||||||
|
adjustSelection();
|
||||||
|
layout();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getMinimum() {
|
||||||
|
return minimum;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setMaximum( int maximum ) {
|
||||||
|
if( this.maximum != maximum && maximum >= 0 && maximum > minimum ) {
|
||||||
|
this.maximum = maximum;
|
||||||
|
adjustThumb();
|
||||||
|
adjustSelection();
|
||||||
|
layout();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getMaximum() {
|
||||||
|
return maximum;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setThumb( int thumb ) {
|
||||||
|
if( this.thumb != thumb && thumb >= 1 ) {
|
||||||
|
this.thumb = thumb;
|
||||||
|
adjustThumb();
|
||||||
|
adjustSelection();
|
||||||
|
layout();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getThumb() {
|
||||||
|
return thumb;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setIncrement( int increment ) {
|
||||||
|
if( this.increment != increment ) {
|
||||||
|
this.increment = increment;
|
||||||
|
layout();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getIncrement() {
|
||||||
|
return increment;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setPageIncrement( int pageIncrement ) {
|
||||||
|
this.pageIncrement = pageIncrement;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getPageIncrement() {
|
||||||
|
return pageIncrement;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setSelection( int selection ) {
|
||||||
|
if( !onDrag ) {
|
||||||
|
updateSelection( selection );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getSelection() {
|
||||||
|
return selection;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void addSelectionListener( SelectionListener selectionListener ) {
|
||||||
|
listeners.add( selectionListener );
|
||||||
|
}
|
||||||
|
|
||||||
|
public void removeSelectionListener( SelectionListener selectionListener ) {
|
||||||
|
listeners.remove( selectionListener );
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void addListener( int eventType, final Listener listener ) {
|
||||||
|
if( eventType == SWT.Selection ) {
|
||||||
|
addSelectionListener( new UntypedSelectionAdapter( listener ) );
|
||||||
|
} else {
|
||||||
|
super.addListener( eventType, listener );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void removeListener( int eventType, Listener listener ) {
|
||||||
|
if( eventType == SWT.Selection ) {
|
||||||
|
removeSelectionListener( lookup( listeners, listener ) );
|
||||||
|
} else {
|
||||||
|
super.removeListener( eventType, listener );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void layout() {
|
||||||
|
direction.layout( this, buttonLength );
|
||||||
|
update();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setIncrementButtonLength( int length ) {
|
||||||
|
this.buttonLength = length;
|
||||||
|
layout();
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getIncrementButtonLength() {
|
||||||
|
return buttonLength;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setIncrementColor( Color color ) {
|
||||||
|
up.setForeground( color );
|
||||||
|
down.setForeground( color );
|
||||||
|
}
|
||||||
|
|
||||||
|
public Color getIncrementColor() {
|
||||||
|
return up.getForeground();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setPageIncrementColor( Color color ) {
|
||||||
|
upFast.setForeground( color );
|
||||||
|
downFast.setForeground( color );
|
||||||
|
}
|
||||||
|
|
||||||
|
public Color getPageIncrementColor() {
|
||||||
|
return upFast.getForeground();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setThumbColor( Color color ) {
|
||||||
|
drag.setForeground( color );
|
||||||
|
}
|
||||||
|
|
||||||
|
public Color getThumbColor() {
|
||||||
|
return drag.getForeground();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setBackground( Color color ) {
|
||||||
|
up.setBackground( color );
|
||||||
|
upFast.setBackground( color );
|
||||||
|
drag.setBackground( color );
|
||||||
|
downFast.setBackground( color );
|
||||||
|
down.setBackground( color );
|
||||||
|
super.setBackground( color );
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void setSelectionInternal( int selection, int detail ) {
|
||||||
|
int oldSelection = this.selection;
|
||||||
|
updateSelection( selection );
|
||||||
|
if( oldSelection != this.selection ) {
|
||||||
|
notifyListeners( detail );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void updateSelection( int selection ) {
|
||||||
|
if( this.selection != selection ) {
|
||||||
|
this.selection = selection;
|
||||||
|
adjustSelection();
|
||||||
|
layout();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void notifyListeners( int detail ) {
|
||||||
|
updateOnDrag( detail );
|
||||||
|
SelectionEvent selectionEvent = createEvent( detail );
|
||||||
|
for( SelectionListener listener : listeners ) {
|
||||||
|
listener.widgetSelected( selectionEvent );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void updateOnDrag( int detail ) {
|
||||||
|
onDrag = ( onDrag || ( SWT.DRAG & detail ) > 0 ) && ( SWT.NONE != detail );
|
||||||
|
}
|
||||||
|
|
||||||
|
private SelectionEvent createEvent( int detail ) {
|
||||||
|
Event event = new Event();
|
||||||
|
event.widget = this;
|
||||||
|
event.detail = detail;
|
||||||
|
return new SelectionEvent( event );
|
||||||
|
}
|
||||||
|
|
||||||
|
private void adjustThumb() {
|
||||||
|
if( thumb > maximum - minimum ) {
|
||||||
|
thumb = Math.min( maximum - minimum, thumb );
|
||||||
|
thumb = Math.max( 1, thumb );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void adjustSelection() {
|
||||||
|
selection = Math.min( selection, maximum - thumb );
|
||||||
|
selection = Math.max( selection, minimum );
|
||||||
|
}
|
||||||
|
|
||||||
|
private static Direction getDirection( int style ) {
|
||||||
|
return ( style & SWT.HORIZONTAL ) > 0 ? Direction.HORIZONTAL : Direction.VERTICAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void setDefaultColorScheme() {
|
||||||
|
up.setForeground( Display.getCurrent().getSystemColor( SWT.COLOR_WIDGET_NORMAL_SHADOW ) );
|
||||||
|
upFast.setForeground( Display.getCurrent().getSystemColor( SWT.COLOR_WIDGET_BACKGROUND ) );
|
||||||
|
drag.setForeground( Display.getCurrent().getSystemColor( SWT.COLOR_WIDGET_FOREGROUND ) );
|
||||||
|
downFast.setForeground( Display.getCurrent().getSystemColor( SWT.COLOR_WIDGET_BACKGROUND ) );
|
||||||
|
down.setForeground( Display.getCurrent().getSystemColor( SWT.COLOR_WIDGET_NORMAL_SHADOW ) );
|
||||||
|
setBackground( getBackground() );
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,23 @@
|
||||||
|
package com.minres.scviewer.database.ui.swt.sb;
|
||||||
|
|
||||||
|
import org.eclipse.swt.graphics.Point;
|
||||||
|
import org.eclipse.swt.widgets.Composite;
|
||||||
|
import org.eclipse.swt.widgets.Layout;
|
||||||
|
|
||||||
|
class FlatScrollBarLayout extends Layout {
|
||||||
|
|
||||||
|
private final Direction direction;
|
||||||
|
|
||||||
|
public FlatScrollBarLayout( Direction orientation ) {
|
||||||
|
this.direction = orientation;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void layout( Composite composite, boolean flushCache ) {
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected Point computeSize( Composite composite, int wHint, int hHint, boolean flushCache ) {
|
||||||
|
return direction.computeSize( composite, wHint, hHint, flushCache );
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,109 @@
|
||||||
|
package com.minres.scviewer.database.ui.swt.sb;
|
||||||
|
|
||||||
|
import static java.lang.Math.min;
|
||||||
|
|
||||||
|
import org.eclipse.swt.SWT;
|
||||||
|
import org.eclipse.swt.graphics.Color;
|
||||||
|
import org.eclipse.swt.graphics.GC;
|
||||||
|
import org.eclipse.swt.graphics.Image;
|
||||||
|
import org.eclipse.swt.widgets.Display;
|
||||||
|
|
||||||
|
class ImageDrawer {
|
||||||
|
|
||||||
|
static final String IMAGE_DRAWER_IS_DISPOSED = "ImageDrawer is disposed.";
|
||||||
|
|
||||||
|
private final int maxExpansion;
|
||||||
|
|
||||||
|
private Color background;
|
||||||
|
private Color foreground;
|
||||||
|
|
||||||
|
ImageDrawer( int expansion ) {
|
||||||
|
this( expansion, getSystemColor( SWT.COLOR_WIDGET_DARK_SHADOW ), getSystemColor( SWT.COLOR_LIST_BACKGROUND ) );
|
||||||
|
}
|
||||||
|
|
||||||
|
ImageDrawer( int expansion, Color background, Color foreground ) {
|
||||||
|
this.maxExpansion = expansion;
|
||||||
|
this.foreground = defensiveCopy( background );
|
||||||
|
this.background = defensiveCopy( foreground );
|
||||||
|
}
|
||||||
|
|
||||||
|
void setForeground( Color foreground ) {
|
||||||
|
checkDisposed();
|
||||||
|
if( foreground != null ) {
|
||||||
|
this.foreground = prepareColorAttribute( this.foreground, foreground );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Color getForeground() {
|
||||||
|
checkDisposed();
|
||||||
|
return foreground;
|
||||||
|
}
|
||||||
|
|
||||||
|
void setBackground( Color background ) {
|
||||||
|
checkDisposed();
|
||||||
|
if( background != null ) {
|
||||||
|
this.background = prepareColorAttribute( this.background, background );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Color getBackground() {
|
||||||
|
checkDisposed();
|
||||||
|
return background;
|
||||||
|
}
|
||||||
|
|
||||||
|
Image draw( int width, int height ) {
|
||||||
|
checkDisposed();
|
||||||
|
Image result = new Image( getDisplay(), width, height );
|
||||||
|
GC gc = new GC( result );
|
||||||
|
try {
|
||||||
|
draw( gc, width, height );
|
||||||
|
} finally {
|
||||||
|
gc.dispose();
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
boolean isDisposed() {
|
||||||
|
return background.isDisposed();
|
||||||
|
}
|
||||||
|
|
||||||
|
void dispose() {
|
||||||
|
if( !isDisposed() ) {
|
||||||
|
this.background.dispose();
|
||||||
|
this.foreground.dispose();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void draw( GC gc, int width, int height ) {
|
||||||
|
gc.setBackground( background );
|
||||||
|
gc.fillRectangle( 0, 0, width, height );
|
||||||
|
gc.setBackground( foreground );
|
||||||
|
gc.setAdvanced( true );
|
||||||
|
gc.setAntialias( SWT.ON );
|
||||||
|
int arc = min( width, height ) == 1 ? 1 : maxExpansion + 2;
|
||||||
|
gc.fillRoundRectangle( 0, 0, width, height, arc, arc );
|
||||||
|
}
|
||||||
|
|
||||||
|
private void checkDisposed() {
|
||||||
|
if( isDisposed() ) {
|
||||||
|
throw new IllegalStateException( IMAGE_DRAWER_IS_DISPOSED );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static Color getSystemColor( int colorCode ) {
|
||||||
|
return getDisplay().getSystemColor( colorCode );
|
||||||
|
}
|
||||||
|
|
||||||
|
private static Color prepareColorAttribute( Color oldColor, Color newColor ) {
|
||||||
|
oldColor.dispose();
|
||||||
|
return defensiveCopy( newColor );
|
||||||
|
}
|
||||||
|
|
||||||
|
private static Color defensiveCopy( Color background ) {
|
||||||
|
return new Color( getDisplay(), background.getRGB() );
|
||||||
|
}
|
||||||
|
|
||||||
|
private static Display getDisplay() {
|
||||||
|
return Display.getCurrent();
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,46 @@
|
||||||
|
package com.minres.scviewer.database.ui.swt.sb;
|
||||||
|
|
||||||
|
import org.eclipse.swt.SWT;
|
||||||
|
import org.eclipse.swt.graphics.Color;
|
||||||
|
import org.eclipse.swt.graphics.Point;
|
||||||
|
import org.eclipse.swt.widgets.Label;
|
||||||
|
|
||||||
|
class ImageUpdate {
|
||||||
|
|
||||||
|
private final ImageDrawer imageDrawer;
|
||||||
|
private final Label control;
|
||||||
|
|
||||||
|
ImageUpdate( Label control, int maxExpansion ) {
|
||||||
|
this.imageDrawer = new ImageDrawer( maxExpansion );
|
||||||
|
this.control = control;
|
||||||
|
this.control.addListener( SWT.Dispose, evt -> imageDrawer.dispose() );
|
||||||
|
}
|
||||||
|
|
||||||
|
void setForeground( Color color ) {
|
||||||
|
imageDrawer.setForeground( color );
|
||||||
|
}
|
||||||
|
|
||||||
|
Color getForeground() {
|
||||||
|
return imageDrawer.getForeground();
|
||||||
|
}
|
||||||
|
|
||||||
|
void setBackground( Color color ) {
|
||||||
|
imageDrawer.setBackground( color );
|
||||||
|
}
|
||||||
|
|
||||||
|
Color getBackground() {
|
||||||
|
return imageDrawer.getBackground();
|
||||||
|
}
|
||||||
|
|
||||||
|
void update() {
|
||||||
|
if( !control.isDisposed() ) {
|
||||||
|
if( control.getImage() != null ) {
|
||||||
|
control.getImage().dispose();
|
||||||
|
}
|
||||||
|
Point size = control.getSize();
|
||||||
|
if( size.x > 0 && size.y > 0 ) {
|
||||||
|
control.setImage( imageDrawer.draw( size.x, size.y ) );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,24 @@
|
||||||
|
package com.minres.scviewer.database.ui.swt.sb;
|
||||||
|
|
||||||
|
import org.eclipse.swt.SWT;
|
||||||
|
|
||||||
|
import com.minres.scviewer.database.ui.swt.sb.ClickControl.ClickAction;
|
||||||
|
|
||||||
|
class Incrementer implements ClickAction {
|
||||||
|
|
||||||
|
private final FlatScrollBar scrollBar;
|
||||||
|
|
||||||
|
Incrementer( FlatScrollBar scrollBar ) {
|
||||||
|
this.scrollBar = scrollBar;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
|
int selection = scrollBar.getSelection() + scrollBar.getIncrement();
|
||||||
|
scrollBar.setSelectionInternal( selection, SWT.ARROW_DOWN );
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setCoordinates( int x, int y ) {
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,37 @@
|
||||||
|
package com.minres.scviewer.database.ui.swt.sb;
|
||||||
|
|
||||||
|
import org.eclipse.swt.widgets.Display;
|
||||||
|
|
||||||
|
public class MouseDownActionTimer implements Runnable {
|
||||||
|
|
||||||
|
public static final int INITIAL_DELAY = 300;
|
||||||
|
public static final int FAST_DELAY = 50;
|
||||||
|
|
||||||
|
private final ActionScheduler scheduler;
|
||||||
|
private final TimerAction timerAction;
|
||||||
|
private final ButtonClick mouseClick;
|
||||||
|
|
||||||
|
public interface TimerAction extends Runnable {
|
||||||
|
boolean isEnabled();
|
||||||
|
}
|
||||||
|
|
||||||
|
public MouseDownActionTimer( TimerAction timerAction, ButtonClick mouseClick, Display display ) {
|
||||||
|
this.scheduler = new ActionScheduler( display, this );
|
||||||
|
this.timerAction = timerAction;
|
||||||
|
this.mouseClick = mouseClick;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void activate() {
|
||||||
|
if( timerAction.isEnabled() ) {
|
||||||
|
scheduler.schedule( INITIAL_DELAY );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
|
if( mouseClick.isArmed() && timerAction.isEnabled() ) {
|
||||||
|
timerAction.run();
|
||||||
|
scheduler.schedule( FAST_DELAY );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,66 @@
|
||||||
|
package com.minres.scviewer.database.ui.swt.sb;
|
||||||
|
|
||||||
|
import org.eclipse.swt.events.DisposeEvent;
|
||||||
|
import org.eclipse.swt.events.DisposeListener;
|
||||||
|
import org.eclipse.swt.events.MouseEvent;
|
||||||
|
import org.eclipse.swt.events.MouseTrackAdapter;
|
||||||
|
import org.eclipse.swt.graphics.Rectangle;
|
||||||
|
import org.eclipse.swt.widgets.Display;
|
||||||
|
|
||||||
|
class MouseTracker extends MouseTrackAdapter implements Runnable, DisposeListener {
|
||||||
|
|
||||||
|
static final int DELAY = 500;
|
||||||
|
|
||||||
|
private final FlatScrollBar scrollBar;
|
||||||
|
private final int maxExpansion;
|
||||||
|
|
||||||
|
private Rectangle expandedBounds;
|
||||||
|
private Rectangle originBounds;
|
||||||
|
private boolean mouseOver;
|
||||||
|
private boolean disposed;
|
||||||
|
|
||||||
|
MouseTracker( FlatScrollBar scrollBar, int maxExpansion ) {
|
||||||
|
this.scrollBar = scrollBar;
|
||||||
|
this.maxExpansion = maxExpansion;
|
||||||
|
this.scrollBar.addDisposeListener( this );
|
||||||
|
this.scrollBar.up.getControl().addMouseTrackListener( this );
|
||||||
|
this.scrollBar.upFast.getControl().addMouseTrackListener( this );
|
||||||
|
this.scrollBar.drag.getControl().addMouseTrackListener( this );
|
||||||
|
this.scrollBar.downFast.getControl().addMouseTrackListener( this );
|
||||||
|
this.scrollBar.down.getControl().addMouseTrackListener( this );
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void mouseEnter( MouseEvent event ) {
|
||||||
|
mouseOver = true;
|
||||||
|
if( !disposed && originBounds == null ) {
|
||||||
|
originBounds = scrollBar.getBounds();
|
||||||
|
scrollBar.getDirection().expand( scrollBar, maxExpansion );
|
||||||
|
expandedBounds = scrollBar.getBounds();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void mouseExit( MouseEvent event ) {
|
||||||
|
mouseOver = false;
|
||||||
|
if( !disposed ) {
|
||||||
|
Display.getCurrent().timerExec( DELAY, this );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
|
if( !disposed && !mouseOver ) {
|
||||||
|
if( scrollBar.getBounds().equals( expandedBounds ) ) {
|
||||||
|
scrollBar.setBounds( originBounds );
|
||||||
|
}
|
||||||
|
originBounds = null;
|
||||||
|
expandedBounds = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void widgetDisposed( DisposeEvent e ) {
|
||||||
|
disposed = true;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,69 @@
|
||||||
|
package com.minres.scviewer.database.ui.swt.sb;
|
||||||
|
|
||||||
|
import static com.minres.scviewer.database.ui.swt.sb.Direction.HORIZONTAL;
|
||||||
|
import static com.minres.scviewer.database.ui.swt.sb.ShiftData.calculateSelectionRange;
|
||||||
|
|
||||||
|
import org.eclipse.swt.SWT;
|
||||||
|
import org.eclipse.swt.events.DisposeEvent;
|
||||||
|
import org.eclipse.swt.events.DisposeListener;
|
||||||
|
import org.eclipse.swt.graphics.Point;
|
||||||
|
import org.eclipse.swt.widgets.Composite;
|
||||||
|
import org.eclipse.swt.widgets.Event;
|
||||||
|
import org.eclipse.swt.widgets.Listener;
|
||||||
|
|
||||||
|
public class MouseWheelShifter implements Listener, DisposeListener {
|
||||||
|
|
||||||
|
private final FlatScrollBar scrollBar;
|
||||||
|
private final Composite parent;
|
||||||
|
private final int buttonLength;
|
||||||
|
|
||||||
|
MouseWheelShifter( FlatScrollBar scrollBar, Composite parent, int buttonLength ) {
|
||||||
|
this.scrollBar = scrollBar;
|
||||||
|
this.parent = parent;
|
||||||
|
this.buttonLength = buttonLength;
|
||||||
|
parent.addListener( getListenerType(), this );
|
||||||
|
scrollBar.addDisposeListener( this );
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void handleEvent( Event event ) {
|
||||||
|
handleMouseWheelScroll( event );
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void widgetDisposed( DisposeEvent e ) {
|
||||||
|
parent.removeListener( getListenerType(), this );
|
||||||
|
}
|
||||||
|
|
||||||
|
private void handleMouseWheelScroll( Event event ) {
|
||||||
|
ShiftData shiftData = newShiftData( event.count );
|
||||||
|
if( shiftData.canShift() ) {
|
||||||
|
int selectionRange = calculateSelectionRange( scrollBar );
|
||||||
|
int selectionDelta = shiftData.calculateSelectionDelta( selectionRange );
|
||||||
|
int selection = scrollBar.getSelection() - selectionDelta;
|
||||||
|
scrollBar.setSelectionInternal( selection, scrollBar.direction.value() );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private ShiftData newShiftData( int delta ) {
|
||||||
|
ShiftData result;
|
||||||
|
if( scrollBar.direction == Direction.HORIZONTAL ) {
|
||||||
|
result = new ShiftData( buttonLength, getScrollBarSize().x, getDragSize().x, delta );
|
||||||
|
} else {
|
||||||
|
result = new ShiftData( buttonLength, getScrollBarSize().y, getDragSize().y, delta );
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
private Point getScrollBarSize() {
|
||||||
|
return scrollBar.getSize();
|
||||||
|
}
|
||||||
|
|
||||||
|
private Point getDragSize() {
|
||||||
|
return scrollBar.drag.getControl().getSize();
|
||||||
|
}
|
||||||
|
|
||||||
|
private int getListenerType() {
|
||||||
|
return scrollBar.direction == HORIZONTAL ? SWT.MouseHorizontalWheel: SWT.MouseVerticalWheel;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,19 @@
|
||||||
|
package com.minres.scviewer.database.ui.swt.sb;
|
||||||
|
|
||||||
|
import org.eclipse.swt.events.ControlAdapter;
|
||||||
|
import org.eclipse.swt.events.ControlEvent;
|
||||||
|
|
||||||
|
class ResizeObserver extends ControlAdapter {
|
||||||
|
|
||||||
|
private final FlatScrollBar flatScrollBar;
|
||||||
|
|
||||||
|
public ResizeObserver( FlatScrollBar flatScrollBar ) {
|
||||||
|
this.flatScrollBar = flatScrollBar;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void controlResized( ControlEvent event ) {
|
||||||
|
flatScrollBar.layout();
|
||||||
|
flatScrollBar.moveAbove( null );
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,32 @@
|
||||||
|
package com.minres.scviewer.database.ui.swt.sb;
|
||||||
|
|
||||||
|
import static com.minres.scviewer.database.ui.swt.sb.ComponentDistribution.divide;
|
||||||
|
|
||||||
|
class ShiftData {
|
||||||
|
|
||||||
|
private final int slidePixels;
|
||||||
|
private final int movedPixels;
|
||||||
|
private final int buttonLength;
|
||||||
|
|
||||||
|
ShiftData( int buttonLength, int scrollBarPixels, int dragPixels, int movedPixels ) {
|
||||||
|
this.buttonLength = buttonLength;
|
||||||
|
this.slidePixels = calculateSlidePixels( scrollBarPixels, dragPixels );
|
||||||
|
this.movedPixels = movedPixels;
|
||||||
|
}
|
||||||
|
|
||||||
|
boolean canShift( ) {
|
||||||
|
return slidePixels > 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int calculateSelectionDelta( int selectionRange ) {
|
||||||
|
return divide( movedPixels * selectionRange, slidePixels );
|
||||||
|
}
|
||||||
|
|
||||||
|
static int calculateSelectionRange( FlatScrollBar scrollBar ) {
|
||||||
|
return scrollBar.getMaximum() - scrollBar.getMinimum() - scrollBar.getThumb();
|
||||||
|
}
|
||||||
|
|
||||||
|
private int calculateSlidePixels( int scrollBarPixels, int dragPixels ) {
|
||||||
|
return scrollBarPixels - 2 * buttonLength - dragPixels;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,43 @@
|
||||||
|
package com.minres.scviewer.database.ui.swt.sb;
|
||||||
|
|
||||||
|
import java.util.Collection;
|
||||||
|
|
||||||
|
import org.eclipse.swt.events.SelectionAdapter;
|
||||||
|
import org.eclipse.swt.events.SelectionEvent;
|
||||||
|
import org.eclipse.swt.events.SelectionListener;
|
||||||
|
import org.eclipse.swt.widgets.Event;
|
||||||
|
import org.eclipse.swt.widgets.Listener;
|
||||||
|
|
||||||
|
class UntypedSelectionAdapter extends SelectionAdapter {
|
||||||
|
|
||||||
|
final Listener listener;
|
||||||
|
|
||||||
|
UntypedSelectionAdapter( Listener listener ) {
|
||||||
|
this.listener = listener;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void widgetSelected( SelectionEvent selectionEvent ) {
|
||||||
|
Event event = new Event();
|
||||||
|
event.widget = selectionEvent.widget;
|
||||||
|
event.detail = selectionEvent.detail;
|
||||||
|
listener.handleEvent( event );
|
||||||
|
}
|
||||||
|
|
||||||
|
static SelectionListener lookup( Collection<SelectionListener> listeners, Listener untypedListener ) {
|
||||||
|
for( SelectionListener listener : listeners ) {
|
||||||
|
if( isAdapterType( listener ) && matches( untypedListener, listener ) ) {
|
||||||
|
return listener;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static boolean isAdapterType( SelectionListener listener ) {
|
||||||
|
return listener instanceof UntypedSelectionAdapter;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static boolean matches( Listener untypedListener, SelectionListener listener ) {
|
||||||
|
return ( ( UntypedSelectionAdapter )listener ).listener == untypedListener;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,7 @@
|
||||||
|
package com.minres.scviewer.database.ui.swt.sb;
|
||||||
|
|
||||||
|
import org.eclipse.swt.widgets.Control;
|
||||||
|
|
||||||
|
public interface ViewComponent {
|
||||||
|
Control getControl();
|
||||||
|
}
|
|
@ -0,0 +1,438 @@
|
||||||
|
/*******************************************************************************
|
||||||
|
* Copyright (c) 2011 Google, Inc. 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:
|
||||||
|
* Google, Inc. - initial API and implementation
|
||||||
|
* Wim Jongman - 1.8 and higher compliance
|
||||||
|
*******************************************************************************/
|
||||||
|
package org.eclipse.wb.swt;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
|
import java.io.InputStream;
|
||||||
|
import java.lang.reflect.Constructor;
|
||||||
|
import java.lang.reflect.Method;
|
||||||
|
import java.net.MalformedURLException;
|
||||||
|
import java.net.URL;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.Iterator;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
import org.eclipse.core.runtime.Platform;
|
||||||
|
import org.eclipse.jface.resource.CompositeImageDescriptor;
|
||||||
|
import org.eclipse.jface.resource.ImageDescriptor;
|
||||||
|
import org.eclipse.swt.graphics.Image;
|
||||||
|
import org.eclipse.swt.graphics.ImageData;
|
||||||
|
import org.eclipse.swt.graphics.ImageDataProvider;
|
||||||
|
import org.eclipse.swt.graphics.Point;
|
||||||
|
import org.eclipse.swt.graphics.Rectangle;
|
||||||
|
import org.osgi.framework.Bundle;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Utility class for managing OS resources associated with SWT/JFace controls
|
||||||
|
* such as colors, fonts, images, etc.
|
||||||
|
*
|
||||||
|
* This class is created automatically when you fiddle around with images and
|
||||||
|
* colors in WB. You might want to prevent your application from using this
|
||||||
|
* class and provide your own more effective means of resource caching.
|
||||||
|
*
|
||||||
|
* Even though this class can be used to manage these resources, if they are
|
||||||
|
* here for the duration of the application and not used then you still have an
|
||||||
|
* effective resource leak.
|
||||||
|
*
|
||||||
|
* Application code must explicitly invoke the <code>dispose()</code> method to
|
||||||
|
* release the operating system resources managed by cached objects when those
|
||||||
|
* objects and OS resources are no longer needed.
|
||||||
|
*
|
||||||
|
* This class may be freely distributed as part of any application or plugin.
|
||||||
|
* <p>
|
||||||
|
*
|
||||||
|
* @author scheglov_ke
|
||||||
|
* @author Dan Rubel
|
||||||
|
* @author Wim Jongman
|
||||||
|
*/
|
||||||
|
public class ResourceManager extends SWTResourceManager {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The map where we store our images.
|
||||||
|
*/
|
||||||
|
private static Map<ImageDescriptor, Image> m_descriptorImageMap = new HashMap<ImageDescriptor, Image>();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns an {@link ImageDescriptor} stored in the file at the specified path
|
||||||
|
* relative to the specified class.
|
||||||
|
*
|
||||||
|
* @param clazz the {@link Class} relative to which to find the image
|
||||||
|
* descriptor.
|
||||||
|
* @param path the path to the image file.
|
||||||
|
* @return the {@link ImageDescriptor} stored in the file at the specified path.
|
||||||
|
*/
|
||||||
|
public static ImageDescriptor getImageDescriptor(Class<?> clazz, String path) {
|
||||||
|
return ImageDescriptor.createFromFile(clazz, path);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns an {@link ImageDescriptor} stored in the file at the specified path.
|
||||||
|
*
|
||||||
|
* @param path the path to the image file.
|
||||||
|
* @return the {@link ImageDescriptor} stored in the file at the specified path.
|
||||||
|
*/
|
||||||
|
public static ImageDescriptor getImageDescriptor(String path) {
|
||||||
|
try {
|
||||||
|
return ImageDescriptor.createFromURL(new File(path).toURI().toURL());
|
||||||
|
} catch (MalformedURLException e) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns an {@link Image} based on the specified {@link ImageDescriptor}.
|
||||||
|
*
|
||||||
|
* @param descriptor the {@link ImageDescriptor} for the {@link Image}.
|
||||||
|
* @return the {@link Image} based on the specified {@link ImageDescriptor}.
|
||||||
|
*/
|
||||||
|
public static Image getImage(ImageDescriptor descriptor) {
|
||||||
|
if (descriptor == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
Image image = m_descriptorImageMap.get(descriptor);
|
||||||
|
if (image == null) {
|
||||||
|
image = descriptor.createImage();
|
||||||
|
m_descriptorImageMap.put(descriptor, image);
|
||||||
|
}
|
||||||
|
return image;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Maps images to decorated images.
|
||||||
|
*/
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
|
private static Map<Image, Map<Image, Image>>[] m_decoratedImageMap = new Map[LAST_CORNER_KEY];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns an {@link Image} composed of a base image decorated by another image.
|
||||||
|
*
|
||||||
|
* @param baseImage the base {@link Image} that should be decorated.
|
||||||
|
* @param decorator the {@link Image} to decorate the base image.
|
||||||
|
* @return {@link Image} The resulting decorated image.
|
||||||
|
*/
|
||||||
|
public static Image decorateImage(Image baseImage, Image decorator) {
|
||||||
|
return decorateImage(baseImage, decorator, BOTTOM_RIGHT);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns an {@link Image} composed of a base image decorated by another image.
|
||||||
|
*
|
||||||
|
* @param baseImage
|
||||||
|
* the base {@link Image} that should be decorated.
|
||||||
|
* @param decorator
|
||||||
|
* the {@link Image} to decorate the base image.
|
||||||
|
* @param corner
|
||||||
|
* the corner to place decorator image.
|
||||||
|
* @return the resulting decorated {@link Image}.
|
||||||
|
*/
|
||||||
|
public static Image decorateImage(final Image baseImage, final Image decorator, final int corner) {
|
||||||
|
if (corner <= 0 || corner >= LAST_CORNER_KEY) {
|
||||||
|
throw new IllegalArgumentException("Wrong decorate corner");
|
||||||
|
}
|
||||||
|
Map<Image, Map<Image, Image>> cornerDecoratedImageMap = m_decoratedImageMap[corner];
|
||||||
|
if (cornerDecoratedImageMap == null) {
|
||||||
|
cornerDecoratedImageMap = new HashMap<Image, Map<Image, Image>>();
|
||||||
|
m_decoratedImageMap[corner] = cornerDecoratedImageMap;
|
||||||
|
}
|
||||||
|
Map<Image, Image> decoratedMap = cornerDecoratedImageMap.get(baseImage);
|
||||||
|
if (decoratedMap == null) {
|
||||||
|
decoratedMap = new HashMap<Image, Image>();
|
||||||
|
cornerDecoratedImageMap.put(baseImage, decoratedMap);
|
||||||
|
}
|
||||||
|
//
|
||||||
|
Image result = decoratedMap.get(decorator);
|
||||||
|
if (result == null) {
|
||||||
|
final Rectangle bib = baseImage.getBounds();
|
||||||
|
final Rectangle dib = decorator.getBounds();
|
||||||
|
final Point baseImageSize = new Point(bib.width, bib.height);
|
||||||
|
CompositeImageDescriptor compositImageDesc = new CompositeImageDescriptor() {
|
||||||
|
@Override
|
||||||
|
protected void drawCompositeImage(int width, int height) {
|
||||||
|
drawImage(createCachedImageDataProvider(baseImage), 0, 0);
|
||||||
|
if (corner == TOP_LEFT) {
|
||||||
|
drawImage(getUnzoomedImageDataProvider(decorator.getImageData()) , 0, 0);
|
||||||
|
} else if (corner == TOP_RIGHT) {
|
||||||
|
drawImage(getUnzoomedImageDataProvider(decorator.getImageData()), bib.width - dib.width, 0);
|
||||||
|
} else if (corner == BOTTOM_LEFT) {
|
||||||
|
drawImage(getUnzoomedImageDataProvider(decorator.getImageData()), 0, bib.height - dib.height);
|
||||||
|
} else if (corner == BOTTOM_RIGHT) {
|
||||||
|
drawImage(getUnzoomedImageDataProvider(decorator.getImageData()), bib.width - dib.width, bib.height - dib.height);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@Override
|
||||||
|
protected Point getSize() {
|
||||||
|
return baseImageSize;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
//
|
||||||
|
result = compositImageDesc.createImage();
|
||||||
|
decoratedMap.put(decorator, result);
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static ImageDataProvider getUnzoomedImageDataProvider(ImageData imageData) {
|
||||||
|
return zoom -> zoom == 100 ? imageData : null;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Dispose all of the cached images.
|
||||||
|
*/
|
||||||
|
public static void disposeImages() {
|
||||||
|
SWTResourceManager.disposeImages();
|
||||||
|
// dispose ImageDescriptor images
|
||||||
|
{
|
||||||
|
for (Iterator<Image> I = m_descriptorImageMap.values().iterator(); I.hasNext();) {
|
||||||
|
I.next().dispose();
|
||||||
|
}
|
||||||
|
m_descriptorImageMap.clear();
|
||||||
|
}
|
||||||
|
// dispose decorated images
|
||||||
|
for (int i = 0; i < m_decoratedImageMap.length; i++) {
|
||||||
|
Map<Image, Map<Image, Image>> cornerDecoratedImageMap = m_decoratedImageMap[i];
|
||||||
|
if (cornerDecoratedImageMap != null) {
|
||||||
|
for (Map<Image, Image> decoratedMap : cornerDecoratedImageMap.values()) {
|
||||||
|
for (Image image : decoratedMap.values()) {
|
||||||
|
image.dispose();
|
||||||
|
}
|
||||||
|
decoratedMap.clear();
|
||||||
|
}
|
||||||
|
cornerDecoratedImageMap.clear();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// dispose plugin images
|
||||||
|
{
|
||||||
|
for (Iterator<Image> I = m_URLImageMap.values().iterator(); I.hasNext();) {
|
||||||
|
I.next().dispose();
|
||||||
|
}
|
||||||
|
m_URLImageMap.clear();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////
|
||||||
|
//
|
||||||
|
// Plugin images support
|
||||||
|
//
|
||||||
|
////////////////////////////////////////////////////////////////////////////
|
||||||
|
/**
|
||||||
|
* Maps URL to images.
|
||||||
|
*/
|
||||||
|
private static Map<String, Image> m_URLImageMap = new HashMap<String, Image>();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Provider for plugin resources, used by WindowBuilder at design time.
|
||||||
|
*/
|
||||||
|
public interface PluginResourceProvider {
|
||||||
|
URL getEntry(String symbolicName, String path);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Instance of {@link PluginResourceProvider}, used by WindowBuilder at design
|
||||||
|
* time.
|
||||||
|
*/
|
||||||
|
private static PluginResourceProvider m_designTimePluginResourceProvider = null;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns an {@link Image} based on a plugin and file path.
|
||||||
|
*
|
||||||
|
* @param plugin the plugin {@link Object} containing the image
|
||||||
|
* @param name the path to the image within the plugin
|
||||||
|
* @return the {@link Image} stored in the file at the specified path
|
||||||
|
*
|
||||||
|
* @deprecated Use {@link #getPluginImage(String, String)} instead.
|
||||||
|
*/
|
||||||
|
@Deprecated
|
||||||
|
public static Image getPluginImage(Object plugin, String name) {
|
||||||
|
try {
|
||||||
|
URL url = getPluginImageURL(plugin, name);
|
||||||
|
if (url != null) {
|
||||||
|
return getPluginImageFromUrl(url);
|
||||||
|
}
|
||||||
|
} catch (Throwable e) {
|
||||||
|
// Ignore any exceptions
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns an {@link Image} based on a {@link Bundle} and resource entry path.
|
||||||
|
*
|
||||||
|
* @param symbolicName the symbolic name of the {@link Bundle}.
|
||||||
|
* @param path the path of the resource entry.
|
||||||
|
* @return the {@link Image} stored in the file at the specified path.
|
||||||
|
*/
|
||||||
|
public static Image getPluginImage(String symbolicName, String path) {
|
||||||
|
try {
|
||||||
|
URL url = getPluginImageURL(symbolicName, path);
|
||||||
|
if (url != null) {
|
||||||
|
return getPluginImageFromUrl(url);
|
||||||
|
}
|
||||||
|
} catch (Throwable e) {
|
||||||
|
// Ignore any exceptions
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns an {@link Image} based on given {@link URL}.
|
||||||
|
*/
|
||||||
|
private static Image getPluginImageFromUrl(URL url) {
|
||||||
|
try {
|
||||||
|
try {
|
||||||
|
String key = url.toExternalForm();
|
||||||
|
Image image = m_URLImageMap.get(key);
|
||||||
|
if (image == null) {
|
||||||
|
InputStream stream = url.openStream();
|
||||||
|
try {
|
||||||
|
image = getImage(stream);
|
||||||
|
m_URLImageMap.put(key, image);
|
||||||
|
} finally {
|
||||||
|
stream.close();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return image;
|
||||||
|
} catch (Throwable e) {
|
||||||
|
// Ignore any exceptions
|
||||||
|
}
|
||||||
|
} catch (Throwable e) {
|
||||||
|
// Ignore any exceptions
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns an {@link ImageDescriptor} based on a plugin and file path.
|
||||||
|
*
|
||||||
|
* @param plugin the plugin {@link Object} containing the image.
|
||||||
|
* @param name the path to th eimage within the plugin.
|
||||||
|
* @return the {@link ImageDescriptor} stored in the file at the specified path.
|
||||||
|
*
|
||||||
|
* @deprecated Use {@link #getPluginImageDescriptor(String, String)} instead.
|
||||||
|
*/
|
||||||
|
@Deprecated
|
||||||
|
public static ImageDescriptor getPluginImageDescriptor(Object plugin, String name) {
|
||||||
|
try {
|
||||||
|
try {
|
||||||
|
URL url = getPluginImageURL(plugin, name);
|
||||||
|
return ImageDescriptor.createFromURL(url);
|
||||||
|
} catch (Throwable e) {
|
||||||
|
// Ignore any exceptions
|
||||||
|
}
|
||||||
|
} catch (Throwable e) {
|
||||||
|
// Ignore any exceptions
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns an {@link ImageDescriptor} based on a {@link Bundle} and resource
|
||||||
|
* entry path.
|
||||||
|
*
|
||||||
|
* @param symbolicName the symbolic name of the {@link Bundle}.
|
||||||
|
* @param path the path of the resource entry.
|
||||||
|
* @return the {@link ImageDescriptor} based on a {@link Bundle} and resource
|
||||||
|
* entry path.
|
||||||
|
*/
|
||||||
|
public static ImageDescriptor getPluginImageDescriptor(String symbolicName, String path) {
|
||||||
|
try {
|
||||||
|
URL url = getPluginImageURL(symbolicName, path);
|
||||||
|
if (url != null) {
|
||||||
|
return ImageDescriptor.createFromURL(url);
|
||||||
|
}
|
||||||
|
} catch (Throwable e) {
|
||||||
|
// Ignore any exceptions
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns an {@link URL} based on a {@link Bundle} and resource entry path.
|
||||||
|
*/
|
||||||
|
private static URL getPluginImageURL(String symbolicName, String path) {
|
||||||
|
// try runtime plugins
|
||||||
|
{
|
||||||
|
Bundle bundle = Platform.getBundle(symbolicName);
|
||||||
|
if (bundle != null) {
|
||||||
|
return bundle.getEntry(path);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// try design time provider
|
||||||
|
if (m_designTimePluginResourceProvider != null) {
|
||||||
|
return m_designTimePluginResourceProvider.getEntry(symbolicName, path);
|
||||||
|
}
|
||||||
|
// no such resource
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns an {@link URL} based on a plugin and file path.
|
||||||
|
*
|
||||||
|
* @param plugin the plugin {@link Object} containing the file path.
|
||||||
|
* @param name the file path.
|
||||||
|
* @return the {@link URL} representing the file at the specified path.
|
||||||
|
* @throws Exception
|
||||||
|
*/
|
||||||
|
private static URL getPluginImageURL(Object plugin, String name) throws Exception {
|
||||||
|
// try to work with 'plugin' as with OSGI BundleContext
|
||||||
|
try {
|
||||||
|
Class<?> BundleClass = Class.forName("org.osgi.framework.Bundle"); //$NON-NLS-1$
|
||||||
|
Class<?> BundleContextClass = Class.forName("org.osgi.framework.BundleContext"); //$NON-NLS-1$
|
||||||
|
if (BundleContextClass.isAssignableFrom(plugin.getClass())) {
|
||||||
|
Method getBundleMethod = BundleContextClass.getMethod("getBundle", new Class[0]); //$NON-NLS-1$
|
||||||
|
Object bundle = getBundleMethod.invoke(plugin, new Object[0]);
|
||||||
|
//
|
||||||
|
Class<?> PathClass = Class.forName("org.eclipse.core.runtime.Path"); //$NON-NLS-1$
|
||||||
|
Constructor<?> pathConstructor = PathClass.getConstructor(new Class[] { String.class });
|
||||||
|
Object path = pathConstructor.newInstance(new Object[] { name });
|
||||||
|
//
|
||||||
|
Class<?> IPathClass = Class.forName("org.eclipse.core.runtime.IPath"); //$NON-NLS-1$
|
||||||
|
Class<?> PlatformClass = Class.forName("org.eclipse.core.runtime.Platform"); //$NON-NLS-1$
|
||||||
|
Method findMethod = PlatformClass.getMethod("find", new Class[] { BundleClass, IPathClass }); //$NON-NLS-1$
|
||||||
|
return (URL) findMethod.invoke(null, new Object[] { bundle, path });
|
||||||
|
}
|
||||||
|
} catch (Throwable e) {
|
||||||
|
// Ignore any exceptions
|
||||||
|
}
|
||||||
|
// else work with 'plugin' as with usual Eclipse plugin
|
||||||
|
{
|
||||||
|
Class<?> PluginClass = Class.forName("org.eclipse.core.runtime.Plugin"); //$NON-NLS-1$
|
||||||
|
if (PluginClass.isAssignableFrom(plugin.getClass())) {
|
||||||
|
//
|
||||||
|
Class<?> PathClass = Class.forName("org.eclipse.core.runtime.Path"); //$NON-NLS-1$
|
||||||
|
Constructor<?> pathConstructor = PathClass.getConstructor(new Class[] { String.class });
|
||||||
|
Object path = pathConstructor.newInstance(new Object[] { name });
|
||||||
|
//
|
||||||
|
Class<?> IPathClass = Class.forName("org.eclipse.core.runtime.IPath"); //$NON-NLS-1$
|
||||||
|
Method findMethod = PluginClass.getMethod("find", new Class[] { IPathClass }); //$NON-NLS-1$
|
||||||
|
return (URL) findMethod.invoke(plugin, new Object[] { path });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////
|
||||||
|
//
|
||||||
|
// General
|
||||||
|
//
|
||||||
|
////////////////////////////////////////////////////////////////////////////
|
||||||
|
/**
|
||||||
|
* Dispose of cached objects and their underlying OS resources. This should only
|
||||||
|
* be called when the cached objects are no longer needed (e.g. on application
|
||||||
|
* shutdown).
|
||||||
|
*/
|
||||||
|
public static void dispose() {
|
||||||
|
disposeColors();
|
||||||
|
disposeFonts();
|
||||||
|
disposeImages();
|
||||||
|
}
|
||||||
|
}
|
|
@ -29,17 +29,14 @@ import org.eclipse.swt.graphics.Rectangle;
|
||||||
import org.eclipse.swt.widgets.Display;
|
import org.eclipse.swt.widgets.Display;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Utility class for managing OS resources associated with SWT controls such as
|
* Utility class for managing OS resources associated with SWT controls such as colors, fonts, images, etc.
|
||||||
* colors, fonts, images, etc.
|
|
||||||
* <p>
|
* <p>
|
||||||
* !!! IMPORTANT !!! Application code must explicitly invoke the
|
* !!! IMPORTANT !!! Application code must explicitly invoke the <code>dispose()</code> method to release the
|
||||||
* <code>dispose()</code> method to release the operating system resources
|
* operating system resources managed by cached objects when those objects and OS resources are no longer
|
||||||
* managed by cached objects when those objects and OS resources are no longer
|
|
||||||
* needed (e.g. on application shutdown)
|
* needed (e.g. on application shutdown)
|
||||||
* <p>
|
* <p>
|
||||||
* This class may be freely distributed as part of any application or plugin.
|
* This class may be freely distributed as part of any application or plugin.
|
||||||
* <p>
|
* <p>
|
||||||
*
|
|
||||||
* @author scheglov_ke
|
* @author scheglov_ke
|
||||||
* @author Dan Rubel
|
* @author Dan Rubel
|
||||||
*/
|
*/
|
||||||
|
@ -49,54 +46,57 @@ public class SWTResourceManager {
|
||||||
// Color
|
// Color
|
||||||
//
|
//
|
||||||
////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////
|
||||||
private static Map<RGB, Color> colorMap = new HashMap<>();
|
private static Map<RGB, Color> m_colorMap = new HashMap<RGB, Color>();
|
||||||
|
|
||||||
private SWTResourceManager() {}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the system {@link Color} matching the specific ID.
|
* Returns the system {@link Color} matching the specific ID.
|
||||||
*
|
*
|
||||||
* @param systemColorID the ID value for the color
|
* @param systemColorID
|
||||||
|
* the ID value for the color
|
||||||
* @return the system {@link Color} matching the specific ID
|
* @return the system {@link Color} matching the specific ID
|
||||||
*/
|
*/
|
||||||
public static Color getColor(int systemColorID) {
|
public static Color getColor(int systemColorID) {
|
||||||
Display display = Display.getCurrent();
|
Display display = Display.getCurrent();
|
||||||
return display.getSystemColor(systemColorID);
|
return display.getSystemColor(systemColorID);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns a {@link Color} given its red, green and blue component values.
|
* Returns a {@link Color} given its red, green and blue component values.
|
||||||
*
|
*
|
||||||
* @param r the red component of the color
|
* @param r
|
||||||
* @param g the green component of the color
|
* the red component of the color
|
||||||
* @param b the blue component of the color
|
* @param g
|
||||||
* @return the {@link Color} matching the given red, green and blue component
|
* the green component of the color
|
||||||
* values
|
* @param b
|
||||||
|
* the blue component of the color
|
||||||
|
* @return the {@link Color} matching the given red, green and blue component values
|
||||||
*/
|
*/
|
||||||
public static Color getColor(int r, int g, int b) {
|
public static Color getColor(int r, int g, int b) {
|
||||||
return getColor(new RGB(r, g, b));
|
return getColor(new RGB(r, g, b));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns a {@link Color} given its RGB value.
|
* Returns a {@link Color} given its RGB value.
|
||||||
*
|
*
|
||||||
* @param rgb the {@link RGB} value of the color
|
* @param rgb
|
||||||
|
* the {@link RGB} value of the color
|
||||||
* @return the {@link Color} matching the RGB value
|
* @return the {@link Color} matching the RGB value
|
||||||
*/
|
*/
|
||||||
public static Color getColor(RGB rgb) {
|
public static Color getColor(RGB rgb) {
|
||||||
return colorMap.computeIfAbsent(rgb, k -> new Color(Display.getCurrent(), rgb));
|
Color color = m_colorMap.get(rgb);
|
||||||
|
if (color == null) {
|
||||||
|
Display display = Display.getCurrent();
|
||||||
|
color = new Color(display, rgb);
|
||||||
|
m_colorMap.put(rgb, color);
|
||||||
|
}
|
||||||
|
return color;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Dispose of all the cached {@link Color}'s.
|
* Dispose of all the cached {@link Color}'s.
|
||||||
*/
|
*/
|
||||||
public static void disposeColors() {
|
public static void disposeColors() {
|
||||||
for (Color color : colorMap.values()) {
|
for (Color color : m_colorMap.values()) {
|
||||||
color.dispose();
|
color.dispose();
|
||||||
}
|
}
|
||||||
colorMap.clear();
|
m_colorMap.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////
|
||||||
//
|
//
|
||||||
// Image
|
// Image
|
||||||
|
@ -105,12 +105,12 @@ public class SWTResourceManager {
|
||||||
/**
|
/**
|
||||||
* Maps image paths to images.
|
* Maps image paths to images.
|
||||||
*/
|
*/
|
||||||
private static Map<String, Image> imageMap = new HashMap<>();
|
private static Map<String, Image> m_imageMap = new HashMap<String, Image>();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns an {@link Image} encoded by the specified {@link InputStream}.
|
* Returns an {@link Image} encoded by the specified {@link InputStream}.
|
||||||
*
|
*
|
||||||
* @param stream the {@link InputStream} encoding the image data
|
* @param stream
|
||||||
|
* the {@link InputStream} encoding the image data
|
||||||
* @return the {@link Image} encoded by the specified input stream
|
* @return the {@link Image} encoded by the specified input stream
|
||||||
*/
|
*/
|
||||||
protected static Image getImage(InputStream stream) throws IOException {
|
protected static Image getImage(InputStream stream) throws IOException {
|
||||||
|
@ -125,55 +125,52 @@ public class SWTResourceManager {
|
||||||
stream.close();
|
stream.close();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns an {@link Image} stored in the file at the specified path.
|
* Returns an {@link Image} stored in the file at the specified path.
|
||||||
*
|
*
|
||||||
* @param path the path to the image file
|
* @param path
|
||||||
|
* the path to the image file
|
||||||
* @return the {@link Image} stored in the file at the specified path
|
* @return the {@link Image} stored in the file at the specified path
|
||||||
*/
|
*/
|
||||||
public static Image getImage(String path) {
|
public static Image getImage(String path) {
|
||||||
Image image = imageMap.get(path);
|
Image image = m_imageMap.get(path);
|
||||||
if (image == null) {
|
if (image == null) {
|
||||||
try {
|
try {
|
||||||
image = getImage(new FileInputStream(path));
|
image = getImage(new FileInputStream(path));
|
||||||
imageMap.put(path, image);
|
m_imageMap.put(path, image);
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
image = getMissingImage();
|
image = getMissingImage();
|
||||||
imageMap.put(path, image);
|
m_imageMap.put(path, image);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return image;
|
return image;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns an {@link Image} stored in the file at the specified path relative to
|
* Returns an {@link Image} stored in the file at the specified path relative to the specified class.
|
||||||
* the specified class.
|
|
||||||
*
|
*
|
||||||
* @param clazz the {@link Class} relative to which to find the image
|
* @param clazz
|
||||||
* @param path the path to the image file, if starts with <code>'/'</code>
|
* the {@link Class} relative to which to find the image
|
||||||
|
* @param path
|
||||||
|
* the path to the image file, if starts with <code>'/'</code>
|
||||||
* @return the {@link Image} stored in the file at the specified path
|
* @return the {@link Image} stored in the file at the specified path
|
||||||
*/
|
*/
|
||||||
public static Image getImage(Class<?> clazz, String path) {
|
public static Image getImage(Class<?> clazz, String path) {
|
||||||
String key = clazz.getName() + '|' + path;
|
String key = clazz.getName() + '|' + path;
|
||||||
Image image = imageMap.get(key);
|
Image image = m_imageMap.get(key);
|
||||||
if (image == null) {
|
if (image == null) {
|
||||||
try {
|
try {
|
||||||
image = getImage(clazz.getResourceAsStream(path));
|
image = getImage(clazz.getResourceAsStream(path));
|
||||||
imageMap.put(key, image);
|
m_imageMap.put(key, image);
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
image = getMissingImage();
|
image = getMissingImage();
|
||||||
imageMap.put(key, image);
|
m_imageMap.put(key, image);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return image;
|
return image;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static final int MISSING_IMAGE_SIZE = 10;
|
private static final int MISSING_IMAGE_SIZE = 10;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return the small {@link Image} that can be used as placeholder for missing
|
* @return the small {@link Image} that can be used as placeholder for missing image.
|
||||||
* image.
|
|
||||||
*/
|
*/
|
||||||
private static Image getMissingImage() {
|
private static Image getMissingImage() {
|
||||||
Image image = new Image(Display.getCurrent(), MISSING_IMAGE_SIZE, MISSING_IMAGE_SIZE);
|
Image image = new Image(Display.getCurrent(), MISSING_IMAGE_SIZE, MISSING_IMAGE_SIZE);
|
||||||
|
@ -185,7 +182,6 @@ public class SWTResourceManager {
|
||||||
//
|
//
|
||||||
return image;
|
return image;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Style constant for placing decorator image in top left corner of base image.
|
* Style constant for placing decorator image in top left corner of base image.
|
||||||
*/
|
*/
|
||||||
|
@ -195,13 +191,11 @@ public class SWTResourceManager {
|
||||||
*/
|
*/
|
||||||
public static final int TOP_RIGHT = 2;
|
public static final int TOP_RIGHT = 2;
|
||||||
/**
|
/**
|
||||||
* Style constant for placing decorator image in bottom left corner of base
|
* Style constant for placing decorator image in bottom left corner of base image.
|
||||||
* image.
|
|
||||||
*/
|
*/
|
||||||
public static final int BOTTOM_LEFT = 3;
|
public static final int BOTTOM_LEFT = 3;
|
||||||
/**
|
/**
|
||||||
* Style constant for placing decorator image in bottom right corner of base
|
* Style constant for placing decorator image in bottom right corner of base image.
|
||||||
* image.
|
|
||||||
*/
|
*/
|
||||||
public static final int BOTTOM_RIGHT = 4;
|
public static final int BOTTOM_RIGHT = 4;
|
||||||
/**
|
/**
|
||||||
|
@ -212,77 +206,83 @@ public class SWTResourceManager {
|
||||||
* Maps images to decorated images.
|
* Maps images to decorated images.
|
||||||
*/
|
*/
|
||||||
@SuppressWarnings("unchecked")
|
@SuppressWarnings("unchecked")
|
||||||
private static Map<Image, Map<Image, Image>>[] decoratedImageMap = new Map[LAST_CORNER_KEY];
|
private static Map<Image, Map<Image, Image>>[] m_decoratedImageMap = new Map[LAST_CORNER_KEY];
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns an {@link Image} composed of a base image decorated by another image.
|
* Returns an {@link Image} composed of a base image decorated by another image.
|
||||||
*
|
*
|
||||||
* @param baseImage the base {@link Image} that should be decorated
|
* @param baseImage
|
||||||
* @param decorator the {@link Image} to decorate the base image
|
* the base {@link Image} that should be decorated
|
||||||
|
* @param decorator
|
||||||
|
* the {@link Image} to decorate the base image
|
||||||
* @return {@link Image} The resulting decorated image
|
* @return {@link Image} The resulting decorated image
|
||||||
*/
|
*/
|
||||||
public static Image decorateImage(Image baseImage, Image decorator) {
|
public static Image decorateImage(Image baseImage, Image decorator) {
|
||||||
return decorateImage(baseImage, decorator, BOTTOM_RIGHT);
|
return decorateImage(baseImage, decorator, BOTTOM_RIGHT);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns an {@link Image} composed of a base image decorated by another image.
|
* Returns an {@link Image} composed of a base image decorated by another image.
|
||||||
*
|
*
|
||||||
* @param baseImage the base {@link Image} that should be decorated
|
* @param baseImage
|
||||||
* @param decorator the {@link Image} to decorate the base image
|
* the base {@link Image} that should be decorated
|
||||||
* @param corner the corner to place decorator image
|
* @param decorator
|
||||||
|
* the {@link Image} to decorate the base image
|
||||||
|
* @param corner
|
||||||
|
* the corner to place decorator image
|
||||||
* @return the resulting decorated {@link Image}
|
* @return the resulting decorated {@link Image}
|
||||||
*/
|
*/
|
||||||
public static Image decorateImage(final Image baseImage, final Image decorator, final int corner) {
|
public static Image decorateImage(final Image baseImage, final Image decorator, final int corner) {
|
||||||
if (corner <= 0 || corner >= LAST_CORNER_KEY) {
|
if (corner <= 0 || corner >= LAST_CORNER_KEY) {
|
||||||
throw new IllegalArgumentException("Wrong decorate corner");
|
throw new IllegalArgumentException("Wrong decorate corner");
|
||||||
}
|
}
|
||||||
Map<Image, Map<Image, Image>> cornerDecoratedImageMap = decoratedImageMap[corner];
|
Map<Image, Map<Image, Image>> cornerDecoratedImageMap = m_decoratedImageMap[corner];
|
||||||
if (cornerDecoratedImageMap == null) {
|
if (cornerDecoratedImageMap == null) {
|
||||||
cornerDecoratedImageMap = new HashMap<>();
|
cornerDecoratedImageMap = new HashMap<Image, Map<Image, Image>>();
|
||||||
decoratedImageMap[corner] = cornerDecoratedImageMap;
|
m_decoratedImageMap[corner] = cornerDecoratedImageMap;
|
||||||
}
|
}
|
||||||
Map<Image, Image> decoratedMap = cornerDecoratedImageMap.computeIfAbsent(baseImage,
|
Map<Image, Image> decoratedMap = cornerDecoratedImageMap.get(baseImage);
|
||||||
k -> new HashMap<Image, Image>());
|
if (decoratedMap == null) {
|
||||||
return decoratedMap.computeIfAbsent(decorator, k -> {
|
decoratedMap = new HashMap<Image, Image>();
|
||||||
|
cornerDecoratedImageMap.put(baseImage, decoratedMap);
|
||||||
|
}
|
||||||
|
//
|
||||||
|
Image result = decoratedMap.get(decorator);
|
||||||
|
if (result == null) {
|
||||||
Rectangle bib = baseImage.getBounds();
|
Rectangle bib = baseImage.getBounds();
|
||||||
Rectangle dib = decorator.getBounds();
|
Rectangle dib = decorator.getBounds();
|
||||||
Image result = new Image(Display.getCurrent(), bib.width, bib.height);
|
//
|
||||||
|
result = new Image(Display.getCurrent(), bib.width, bib.height);
|
||||||
|
//
|
||||||
GC gc = new GC(result);
|
GC gc = new GC(result);
|
||||||
gc.drawImage(baseImage, 0, 0);
|
gc.drawImage(baseImage, 0, 0);
|
||||||
switch (corner) {
|
if (corner == TOP_LEFT) {
|
||||||
case TOP_LEFT:
|
|
||||||
gc.drawImage(decorator, 0, 0);
|
gc.drawImage(decorator, 0, 0);
|
||||||
break;
|
} else if (corner == TOP_RIGHT) {
|
||||||
case TOP_RIGHT:
|
|
||||||
gc.drawImage(decorator, bib.width - dib.width, 0);
|
gc.drawImage(decorator, bib.width - dib.width, 0);
|
||||||
break;
|
} else if (corner == BOTTOM_LEFT) {
|
||||||
case BOTTOM_LEFT:
|
|
||||||
gc.drawImage(decorator, 0, bib.height - dib.height);
|
gc.drawImage(decorator, 0, bib.height - dib.height);
|
||||||
break;
|
} else if (corner == BOTTOM_RIGHT) {
|
||||||
case BOTTOM_RIGHT:
|
|
||||||
gc.drawImage(decorator, bib.width - dib.width, bib.height - dib.height);
|
gc.drawImage(decorator, bib.width - dib.width, bib.height - dib.height);
|
||||||
break;
|
|
||||||
default:
|
|
||||||
// do nothing
|
|
||||||
}
|
}
|
||||||
gc.dispose();
|
gc.dispose();
|
||||||
return result;
|
//
|
||||||
});
|
decoratedMap.put(decorator, result);
|
||||||
|
}
|
||||||
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Dispose all of the cached {@link Image}'s.
|
* Dispose all of the cached {@link Image}'s.
|
||||||
*/
|
*/
|
||||||
public static void disposeImages() {
|
public static void disposeImages() {
|
||||||
// dispose loaded images
|
// dispose loaded images
|
||||||
for (Image image : imageMap.values()) {
|
{
|
||||||
image.dispose();
|
for (Image image : m_imageMap.values()) {
|
||||||
|
image.dispose();
|
||||||
|
}
|
||||||
|
m_imageMap.clear();
|
||||||
}
|
}
|
||||||
imageMap.clear();
|
|
||||||
// dispose decorated images
|
// dispose decorated images
|
||||||
for (int i = 0; i < decoratedImageMap.length; i++) {
|
for (int i = 0; i < m_decoratedImageMap.length; i++) {
|
||||||
Map<Image, Map<Image, Image>> cornerDecoratedImageMap = decoratedImageMap[i];
|
Map<Image, Map<Image, Image>> cornerDecoratedImageMap = m_decoratedImageMap[i];
|
||||||
if (cornerDecoratedImageMap != null) {
|
if (cornerDecoratedImageMap != null) {
|
||||||
for (Map<Image, Image> decoratedMap : cornerDecoratedImageMap.values()) {
|
for (Map<Image, Image> decoratedMap : cornerDecoratedImageMap.values()) {
|
||||||
for (Image image : decoratedMap.values()) {
|
for (Image image : decoratedMap.values()) {
|
||||||
|
@ -294,7 +294,6 @@ public class SWTResourceManager {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////
|
||||||
//
|
//
|
||||||
// Font
|
// Font
|
||||||
|
@ -303,39 +302,45 @@ public class SWTResourceManager {
|
||||||
/**
|
/**
|
||||||
* Maps font names to fonts.
|
* Maps font names to fonts.
|
||||||
*/
|
*/
|
||||||
private static Map<String, Font> fontMap = new HashMap<>();
|
private static Map<String, Font> m_fontMap = new HashMap<String, Font>();
|
||||||
/**
|
/**
|
||||||
* Maps fonts to their bold versions.
|
* Maps fonts to their bold versions.
|
||||||
*/
|
*/
|
||||||
private static Map<Font, Font> fontToBoldFontMap = new HashMap<>();
|
private static Map<Font, Font> m_fontToBoldFontMap = new HashMap<Font, Font>();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns a {@link Font} based on its name, height and style.
|
* Returns a {@link Font} based on its name, height and style.
|
||||||
*
|
*
|
||||||
* @param name the name of the font
|
* @param name
|
||||||
* @param height the height of the font
|
* the name of the font
|
||||||
* @param style the style of the font
|
* @param height
|
||||||
|
* the height of the font
|
||||||
|
* @param style
|
||||||
|
* the style of the font
|
||||||
* @return {@link Font} The font matching the name, height and style
|
* @return {@link Font} The font matching the name, height and style
|
||||||
*/
|
*/
|
||||||
public static Font getFont(String name, int height, int style) {
|
public static Font getFont(String name, int height, int style) {
|
||||||
return getFont(name, height, style, false, false);
|
return getFont(name, height, style, false, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns a {@link Font} based on its name, height and style. Windows-specific
|
* Returns a {@link Font} based on its name, height and style. Windows-specific strikeout and underline
|
||||||
* strikeout and underline flags are also supported.
|
* flags are also supported.
|
||||||
*
|
*
|
||||||
* @param name the name of the font
|
* @param name
|
||||||
* @param size the size of the font
|
* the name of the font
|
||||||
* @param style the style of the font
|
* @param size
|
||||||
* @param strikeout the strikeout flag (warning: Windows only)
|
* the size of the font
|
||||||
* @param underline the underline flag (warning: Windows only)
|
* @param style
|
||||||
* @return {@link Font} The font matching the name, height, style, strikeout and
|
* the style of the font
|
||||||
* underline
|
* @param strikeout
|
||||||
|
* the strikeout flag (warning: Windows only)
|
||||||
|
* @param underline
|
||||||
|
* the underline flag (warning: Windows only)
|
||||||
|
* @return {@link Font} The font matching the name, height, style, strikeout and underline
|
||||||
*/
|
*/
|
||||||
public static Font getFont(String name, int size, int style, boolean strikeout, boolean underline) {
|
public static Font getFont(String name, int size, int style, boolean strikeout, boolean underline) {
|
||||||
String fontName = name + '|' + size + '|' + style + '|' + strikeout + '|' + underline;
|
String fontName = name + '|' + size + '|' + style + '|' + strikeout + '|' + underline;
|
||||||
return fontMap.computeIfAbsent(fontName, k -> {
|
Font font = m_fontMap.get(fontName);
|
||||||
|
if (font == null) {
|
||||||
FontData fontData = new FontData(name, size, style);
|
FontData fontData = new FontData(name, size, style);
|
||||||
if (strikeout || underline) {
|
if (strikeout || underline) {
|
||||||
try {
|
try {
|
||||||
|
@ -349,45 +354,47 @@ public class SWTResourceManager {
|
||||||
logFontClass.getField("lfUnderline").set(logFont, Byte.valueOf((byte) 1)); //$NON-NLS-1$
|
logFontClass.getField("lfUnderline").set(logFont, Byte.valueOf((byte) 1)); //$NON-NLS-1$
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} catch (Exception e) {
|
} catch (Throwable e) {
|
||||||
|
System.err.println("Unable to set underline or strikeout" + " (probably on a non-Windows platform). " + e); //$NON-NLS-1$ //$NON-NLS-2$
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return new Font(Display.getCurrent(), fontData);
|
font = new Font(Display.getCurrent(), fontData);
|
||||||
|
m_fontMap.put(fontName, font);
|
||||||
});
|
}
|
||||||
|
return font;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns a bold version of the given {@link Font}.
|
* Returns a bold version of the given {@link Font}.
|
||||||
*
|
*
|
||||||
* @param baseFont the {@link Font} for which a bold version is desired
|
* @param baseFont
|
||||||
|
* the {@link Font} for which a bold version is desired
|
||||||
* @return the bold version of the given {@link Font}
|
* @return the bold version of the given {@link Font}
|
||||||
*/
|
*/
|
||||||
public static Font getBoldFont(Font baseFont) {
|
public static Font getBoldFont(Font baseFont) {
|
||||||
return fontToBoldFontMap.computeIfAbsent(baseFont, k -> {
|
Font font = m_fontToBoldFontMap.get(baseFont);
|
||||||
FontData[] fontDatas = baseFont.getFontData();
|
if (font == null) {
|
||||||
|
FontData fontDatas[] = baseFont.getFontData();
|
||||||
FontData data = fontDatas[0];
|
FontData data = fontDatas[0];
|
||||||
return new Font(Display.getCurrent(), data.getName(), data.getHeight(), SWT.BOLD);
|
font = new Font(Display.getCurrent(), data.getName(), data.getHeight(), SWT.BOLD);
|
||||||
});
|
m_fontToBoldFontMap.put(baseFont, font);
|
||||||
|
}
|
||||||
|
return font;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Dispose all of the cached {@link Font}'s.
|
* Dispose all of the cached {@link Font}'s.
|
||||||
*/
|
*/
|
||||||
public static void disposeFonts() {
|
public static void disposeFonts() {
|
||||||
// clear fonts
|
// clear fonts
|
||||||
for (Font font : fontMap.values()) {
|
for (Font font : m_fontMap.values()) {
|
||||||
font.dispose();
|
font.dispose();
|
||||||
}
|
}
|
||||||
fontMap.clear();
|
m_fontMap.clear();
|
||||||
// clear bold fonts
|
// clear bold fonts
|
||||||
for (Font font : fontToBoldFontMap.values()) {
|
for (Font font : m_fontToBoldFontMap.values()) {
|
||||||
font.dispose();
|
font.dispose();
|
||||||
}
|
}
|
||||||
fontToBoldFontMap.clear();
|
m_fontToBoldFontMap.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////
|
||||||
//
|
//
|
||||||
// Cursor
|
// Cursor
|
||||||
|
@ -396,38 +403,40 @@ public class SWTResourceManager {
|
||||||
/**
|
/**
|
||||||
* Maps IDs to cursors.
|
* Maps IDs to cursors.
|
||||||
*/
|
*/
|
||||||
private static Map<Integer, Cursor> idToCursorMap = new HashMap<>();
|
private static Map<Integer, Cursor> m_idToCursorMap = new HashMap<Integer, Cursor>();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the system cursor matching the specific ID.
|
* Returns the system cursor matching the specific ID.
|
||||||
*
|
*
|
||||||
* @param id int The ID value for the cursor
|
* @param id
|
||||||
|
* int The ID value for the cursor
|
||||||
* @return Cursor The system cursor matching the specific ID
|
* @return Cursor The system cursor matching the specific ID
|
||||||
*/
|
*/
|
||||||
public static Cursor getCursor(int id) {
|
public static Cursor getCursor(int id) {
|
||||||
Integer key = Integer.valueOf(id);
|
Integer key = Integer.valueOf(id);
|
||||||
return idToCursorMap.computeIfAbsent(key, k -> new Cursor(Display.getDefault(), id));
|
Cursor cursor = m_idToCursorMap.get(key);
|
||||||
|
if (cursor == null) {
|
||||||
|
cursor = new Cursor(Display.getDefault(), id);
|
||||||
|
m_idToCursorMap.put(key, cursor);
|
||||||
|
}
|
||||||
|
return cursor;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Dispose all of the cached cursors.
|
* Dispose all of the cached cursors.
|
||||||
*/
|
*/
|
||||||
public static void disposeCursors() {
|
public static void disposeCursors() {
|
||||||
for (Cursor cursor : idToCursorMap.values()) {
|
for (Cursor cursor : m_idToCursorMap.values()) {
|
||||||
cursor.dispose();
|
cursor.dispose();
|
||||||
}
|
}
|
||||||
idToCursorMap.clear();
|
m_idToCursorMap.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////
|
||||||
//
|
//
|
||||||
// General
|
// General
|
||||||
//
|
//
|
||||||
////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////
|
||||||
/**
|
/**
|
||||||
* Dispose of cached objects and their underlying OS resources. This should only
|
* Dispose of cached objects and their underlying OS resources. This should only be called when the cached
|
||||||
* be called when the cached objects are no longer needed (e.g. on application
|
* objects are no longer needed (e.g. on application shutdown).
|
||||||
* shutdown).
|
|
||||||
*/
|
*/
|
||||||
public static void dispose() {
|
public static void dispose() {
|
||||||
disposeColors();
|
disposeColors();
|
||||||
|
|
|
@ -80,7 +80,6 @@
|
||||||
|
|
||||||
<repositories>
|
<repositories>
|
||||||
<repository location="http://https://minres.github.io/SCViewer/repository" enabled="true" />
|
<repository location="http://https://minres.github.io/SCViewer/repository" enabled="true" />
|
||||||
<repository location="http://https://minres.github.io/SCViewer/repository" enabled="true" />
|
|
||||||
</repositories>
|
</repositories>
|
||||||
|
|
||||||
<preferencesInfo>
|
<preferencesInfo>
|
||||||
|
|
Loading…
Reference in New Issue