add first elements
This commit is contained in:
		
										
											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.SelectionAdapter; | ||||
| import org.eclipse.swt.events.SelectionEvent; | ||||
| import org.eclipse.swt.graphics.Color; | ||||
| import org.eclipse.swt.graphics.GC; | ||||
| import org.eclipse.swt.graphics.Point; | ||||
| 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.GridData; | ||||
| import org.eclipse.swt.layout.GridLayout; | ||||
| import org.eclipse.swt.widgets.Button; | ||||
| import org.eclipse.swt.widgets.Canvas; | ||||
| import org.eclipse.swt.widgets.Composite; | ||||
| 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.Menu; | ||||
| import org.eclipse.swt.widgets.ScrollBar; | ||||
| import org.eclipse.swt.widgets.Slider; | ||||
| import org.eclipse.swt.widgets.Widget; | ||||
| 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.IWaveformZoom; | ||||
| import com.minres.scviewer.database.ui.TrackEntry; | ||||
| import com.minres.scviewer.database.ui.swt.sb.FlatScrollBar; | ||||
|  | ||||
| public class WaveformView implements IWaveformView { | ||||
|  | ||||
| @@ -330,8 +334,22 @@ public class WaveformView implements IWaveformView { | ||||
| 		rightSash.setBackground(SWTResourceManager.getColor(SWT.COLOR_GRAY)); | ||||
|  | ||||
| 		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 | ||||
| 		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; | ||||
|  | ||||
| /** | ||||
|  * Utility class for managing OS resources associated with SWT controls such as | ||||
|  * colors, fonts, images, etc. | ||||
|  * Utility class for managing OS resources associated with SWT controls such as colors, fonts, images, etc. | ||||
|  * <p> | ||||
|  * !!! IMPORTANT !!! 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 | ||||
|  * !!! IMPORTANT !!! 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 (e.g. on application shutdown) | ||||
|  * <p> | ||||
|  * This class may be freely distributed as part of any application or plugin. | ||||
|  * <p> | ||||
|  *  | ||||
|  * @author scheglov_ke | ||||
|  * @author Dan Rubel | ||||
|  */ | ||||
| @@ -49,54 +46,57 @@ public class SWTResourceManager { | ||||
| 	// Color | ||||
| 	// | ||||
| 	//////////////////////////////////////////////////////////////////////////// | ||||
| 	private static Map<RGB, Color> colorMap = new HashMap<>(); | ||||
|  | ||||
| 	private SWTResourceManager() {} | ||||
| 	 | ||||
| 	private static Map<RGB, Color> m_colorMap = new HashMap<RGB, Color>(); | ||||
| 	/** | ||||
| 	 * 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 | ||||
| 	 */ | ||||
| 	public static Color getColor(int systemColorID) { | ||||
| 		Display display = Display.getCurrent(); | ||||
| 		return display.getSystemColor(systemColorID); | ||||
| 	} | ||||
|  | ||||
| 	/** | ||||
| 	 * Returns a {@link Color} given its red, green and blue component values. | ||||
| 	 *  | ||||
| 	 * @param r the red component of the color | ||||
| 	 * @param g the green component of the color | ||||
| 	 * @param b the blue component of the color | ||||
| 	 * @return the {@link Color} matching the given red, green and blue component | ||||
| 	 *         values | ||||
| 	 * @param r | ||||
| 	 *            the red component of the color | ||||
| 	 * @param g | ||||
| 	 *            the green component of the color | ||||
| 	 * @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) { | ||||
| 		return getColor(new RGB(r, g, b)); | ||||
| 	} | ||||
|  | ||||
| 	/** | ||||
| 	 * 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 | ||||
| 	 */ | ||||
| 	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. | ||||
| 	 */ | ||||
| 	public static void disposeColors() { | ||||
| 		for (Color color : colorMap.values()) { | ||||
| 		for (Color color : m_colorMap.values()) { | ||||
| 			color.dispose(); | ||||
| 		} | ||||
| 		colorMap.clear(); | ||||
| 		m_colorMap.clear(); | ||||
| 	} | ||||
|  | ||||
| 	//////////////////////////////////////////////////////////////////////////// | ||||
| 	// | ||||
| 	// Image | ||||
| @@ -105,12 +105,12 @@ public class SWTResourceManager { | ||||
| 	/** | ||||
| 	 * 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}. | ||||
| 	 *  | ||||
| 	 * @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 | ||||
| 	 */ | ||||
| 	protected static Image getImage(InputStream stream) throws IOException { | ||||
| @@ -125,55 +125,52 @@ public class SWTResourceManager { | ||||
| 			stream.close(); | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	/** | ||||
| 	 * 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 | ||||
| 	 */ | ||||
| 	public static Image getImage(String path) { | ||||
| 		Image image = imageMap.get(path); | ||||
| 		Image image = m_imageMap.get(path); | ||||
| 		if (image == null) { | ||||
| 			try { | ||||
| 				image = getImage(new FileInputStream(path)); | ||||
| 				imageMap.put(path, image); | ||||
| 				m_imageMap.put(path, image); | ||||
| 			} catch (Exception e) { | ||||
| 				image = getMissingImage(); | ||||
| 				imageMap.put(path, image); | ||||
| 				m_imageMap.put(path, image); | ||||
| 			} | ||||
| 		} | ||||
| 		return image; | ||||
| 	} | ||||
|  | ||||
| 	/** | ||||
| 	 * Returns an {@link Image} stored in the file at the specified path relative to | ||||
| 	 * the specified class. | ||||
| 	 * Returns an {@link Image} 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 | ||||
| 	 * @param path  the path to the image file, if starts with <code>'/'</code> | ||||
| 	 * @param clazz | ||||
| 	 *            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 | ||||
| 	 */ | ||||
| 	public static Image getImage(Class<?> clazz, String path) { | ||||
| 		String key = clazz.getName() + '|' + path; | ||||
| 		Image image = imageMap.get(key); | ||||
| 		Image image = m_imageMap.get(key); | ||||
| 		if (image == null) { | ||||
| 			try { | ||||
| 				image = getImage(clazz.getResourceAsStream(path)); | ||||
| 				imageMap.put(key, image); | ||||
| 				m_imageMap.put(key, image); | ||||
| 			} catch (Exception e) { | ||||
| 				image = getMissingImage(); | ||||
| 				imageMap.put(key, image); | ||||
| 				m_imageMap.put(key, image); | ||||
| 			} | ||||
| 		} | ||||
| 		return image; | ||||
| 	} | ||||
|  | ||||
| 	private static final int MISSING_IMAGE_SIZE = 10; | ||||
|  | ||||
| 	/** | ||||
| 	 * @return the small {@link Image} that can be used as placeholder for missing | ||||
| 	 *         image. | ||||
| 	 * @return the small {@link Image} that can be used as placeholder for missing image. | ||||
| 	 */ | ||||
| 	private static Image getMissingImage() { | ||||
| 		Image image = new Image(Display.getCurrent(), MISSING_IMAGE_SIZE, MISSING_IMAGE_SIZE); | ||||
| @@ -185,7 +182,6 @@ public class SWTResourceManager { | ||||
| 		// | ||||
| 		return 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; | ||||
| 	/** | ||||
| 	 * Style constant for placing decorator image in bottom left corner of base | ||||
| 	 * image. | ||||
| 	 * Style constant for placing decorator image in bottom left corner of base image. | ||||
| 	 */ | ||||
| 	public static final int BOTTOM_LEFT = 3; | ||||
| 	/** | ||||
| 	 * Style constant for placing decorator image in bottom right corner of base | ||||
| 	 * image. | ||||
| 	 * Style constant for placing decorator image in bottom right corner of base image. | ||||
| 	 */ | ||||
| 	public static final int BOTTOM_RIGHT = 4; | ||||
| 	/** | ||||
| @@ -212,77 +206,83 @@ public class SWTResourceManager { | ||||
| 	 * Maps images to decorated images. | ||||
| 	 */ | ||||
| 	@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. | ||||
| 	 *  | ||||
| 	 * @param baseImage the base {@link Image} that should be decorated | ||||
| 	 * @param decorator the {@link Image} to decorate the base 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 | ||||
| 	 * @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 = decoratedImageMap[corner]; | ||||
| 		Map<Image, Map<Image, Image>> cornerDecoratedImageMap = m_decoratedImageMap[corner]; | ||||
| 		if (cornerDecoratedImageMap == null) { | ||||
| 			cornerDecoratedImageMap = new HashMap<>(); | ||||
| 			decoratedImageMap[corner] = cornerDecoratedImageMap; | ||||
| 			cornerDecoratedImageMap = new HashMap<Image, Map<Image, Image>>(); | ||||
| 			m_decoratedImageMap[corner] = cornerDecoratedImageMap; | ||||
| 		} | ||||
| 		Map<Image, Image> decoratedMap = cornerDecoratedImageMap.computeIfAbsent(baseImage, | ||||
| 				k -> new HashMap<Image, Image>()); | ||||
| 		return decoratedMap.computeIfAbsent(decorator, k -> { | ||||
| 		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) { | ||||
| 			Rectangle bib = baseImage.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.drawImage(baseImage, 0, 0); | ||||
| 			switch (corner) { | ||||
| 			case TOP_LEFT: | ||||
| 			if (corner == TOP_LEFT) { | ||||
| 				gc.drawImage(decorator, 0, 0); | ||||
| 				break; | ||||
| 			case TOP_RIGHT: | ||||
| 			} else if (corner == TOP_RIGHT) { | ||||
| 				gc.drawImage(decorator, bib.width - dib.width, 0); | ||||
| 				break; | ||||
| 			case BOTTOM_LEFT: | ||||
| 			} else if (corner == BOTTOM_LEFT) { | ||||
| 				gc.drawImage(decorator, 0, bib.height - dib.height); | ||||
| 				break; | ||||
| 			case BOTTOM_RIGHT: | ||||
| 			} else if (corner == BOTTOM_RIGHT) { | ||||
| 				gc.drawImage(decorator, bib.width - dib.width, bib.height - dib.height); | ||||
| 				break; | ||||
| 			default: | ||||
| 				// do nothing | ||||
| 			} | ||||
| 			gc.dispose(); | ||||
| 			return result; | ||||
| 		}); | ||||
| 			// | ||||
| 			decoratedMap.put(decorator, result); | ||||
| 		} | ||||
| 		return result; | ||||
| 	} | ||||
|  | ||||
| 	/** | ||||
| 	 * Dispose all of the cached {@link Image}'s. | ||||
| 	 */ | ||||
| 	public static void disposeImages() { | ||||
| 		// 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 | ||||
| 		for (int i = 0; i < decoratedImageMap.length; i++) { | ||||
| 			Map<Image, Map<Image, Image>> cornerDecoratedImageMap = decoratedImageMap[i]; | ||||
| 		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()) { | ||||
| @@ -294,7 +294,6 @@ public class SWTResourceManager { | ||||
| 			} | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	//////////////////////////////////////////////////////////////////////////// | ||||
| 	// | ||||
| 	// Font | ||||
| @@ -303,39 +302,45 @@ public class SWTResourceManager { | ||||
| 	/** | ||||
| 	 * 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. | ||||
| 	 */ | ||||
| 	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. | ||||
| 	 *  | ||||
| 	 * @param name   the name of the font | ||||
| 	 * @param height the height of the font | ||||
| 	 * @param style  the style of the font | ||||
| 	 * @param name | ||||
| 	 *            the name 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 | ||||
| 	 */ | ||||
| 	public static Font getFont(String name, int height, int style) { | ||||
| 		return getFont(name, height, style, false, false); | ||||
| 	} | ||||
|  | ||||
| 	/** | ||||
| 	 * Returns a {@link Font} based on its name, height and style. Windows-specific | ||||
| 	 * strikeout and underline flags are also supported. | ||||
| 	 * Returns a {@link Font} based on its name, height and style. Windows-specific strikeout and underline | ||||
| 	 * flags are also supported. | ||||
| 	 *  | ||||
| 	 * @param name      the name of the font | ||||
| 	 * @param size      the size of the font | ||||
| 	 * @param style     the style of the font | ||||
| 	 * @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 | ||||
| 	 * @param name | ||||
| 	 *            the name of the font | ||||
| 	 * @param size | ||||
| 	 *            the size of the font | ||||
| 	 * @param style | ||||
| 	 *            the style of the font | ||||
| 	 * @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) { | ||||
| 		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); | ||||
| 			if (strikeout || underline) { | ||||
| 				try { | ||||
| @@ -349,45 +354,47 @@ public class SWTResourceManager { | ||||
| 							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}. | ||||
| 	 *  | ||||
| 	 * @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} | ||||
| 	 */ | ||||
| 	public static Font getBoldFont(Font baseFont) { | ||||
| 		return fontToBoldFontMap.computeIfAbsent(baseFont, k -> { | ||||
| 			FontData[] fontDatas = baseFont.getFontData(); | ||||
| 		Font font = m_fontToBoldFontMap.get(baseFont); | ||||
| 		if (font == null) { | ||||
| 			FontData fontDatas[] = baseFont.getFontData(); | ||||
| 			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. | ||||
| 	 */ | ||||
| 	public static void disposeFonts() { | ||||
| 		// clear fonts | ||||
| 		for (Font font : fontMap.values()) { | ||||
| 		for (Font font : m_fontMap.values()) { | ||||
| 			font.dispose(); | ||||
| 		} | ||||
| 		fontMap.clear(); | ||||
| 		m_fontMap.clear(); | ||||
| 		// clear bold fonts | ||||
| 		for (Font font : fontToBoldFontMap.values()) { | ||||
| 		for (Font font : m_fontToBoldFontMap.values()) { | ||||
| 			font.dispose(); | ||||
| 		} | ||||
| 		fontToBoldFontMap.clear(); | ||||
| 		m_fontToBoldFontMap.clear(); | ||||
| 	} | ||||
|  | ||||
| 	//////////////////////////////////////////////////////////////////////////// | ||||
| 	// | ||||
| 	// Cursor | ||||
| @@ -396,38 +403,40 @@ public class SWTResourceManager { | ||||
| 	/** | ||||
| 	 * 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. | ||||
| 	 *  | ||||
| 	 * @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 | ||||
| 	 */ | ||||
| 	public static Cursor getCursor(int 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. | ||||
| 	 */ | ||||
| 	public static void disposeCursors() { | ||||
| 		for (Cursor cursor : idToCursorMap.values()) { | ||||
| 		for (Cursor cursor : m_idToCursorMap.values()) { | ||||
| 			cursor.dispose(); | ||||
| 		} | ||||
| 		idToCursorMap.clear(); | ||||
| 		m_idToCursorMap.clear(); | ||||
| 	} | ||||
|  | ||||
| 	//////////////////////////////////////////////////////////////////////////// | ||||
| 	// | ||||
| 	// 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). | ||||
| 	 * 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(); | ||||
|   | ||||
| @@ -80,7 +80,6 @@ | ||||
|  | ||||
|    <repositories> | ||||
|       <repository location="http://https://minres.github.io/SCViewer/repository" enabled="true" /> | ||||
|       <repository location="http://https://minres.github.io/SCViewer/repository" enabled="true" /> | ||||
|    </repositories> | ||||
|  | ||||
|    <preferencesInfo> | ||||
|   | ||||
		Reference in New Issue
	
	Block a user