/******************************************************************************* * Copyright (c) 2012 EclipseSource 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: * EclipseSource - initial API and implementation ******************************************************************************/ package com.eclipsesource.tabris.demos.entrypoints; import java.util.ArrayList; import java.util.List; import org.eclipse.rap.rwt.application.EntryPoint; import org.eclipse.swt.SWT; import org.eclipse.swt.events.PaintEvent; import org.eclipse.swt.events.PaintListener; import org.eclipse.swt.graphics.Color; import org.eclipse.swt.graphics.GC; import org.eclipse.swt.graphics.Image; import org.eclipse.swt.graphics.Point; import org.eclipse.swt.graphics.Rectangle; import org.eclipse.swt.layout.FillLayout; import org.eclipse.swt.layout.GridData; import org.eclipse.swt.layout.GridLayout; import org.eclipse.swt.widgets.Composite; import org.eclipse.swt.widgets.Display; import org.eclipse.swt.widgets.Event; import org.eclipse.swt.widgets.Listener; import org.eclipse.swt.widgets.Shell; import org.eclipse.swt.widgets.ToolBar; import org.eclipse.swt.widgets.ToolItem; import com.eclipsesource.tabris.widgets.ClientCanvas; import com.eclipsesource.tabris.widgets.ClientDrawListener; public class DrawDemo implements EntryPoint { private static final List<int[]> ERNIE = new ArrayList<int[]>(); /** * includes labels for already connected dots */ private static final boolean LABEL_ALL_DOTS = false; /** * ignore labels in the dot info */ private static final boolean RENUMBER_LABELS = true; /** * original Ernie! */ private static final boolean SHOW_BLUE_PRINT = false; private static final int[] HAIR = new int[]{ 22, 93 }; private static final int[] LEFT_EYE = new int[]{ 163, 168 }; private static final int[] RIGHT_EYE = new int[]{ 158, 162 }; private static final int[] NECK = new int[]{ 169, 178 }; private static final int[] MOUTH = new int[]{ 108, 118 }; private static final List<int[]> ALLREADY_DRAWN_SUBSETS = new ArrayList<int[]>(); static { ALLREADY_DRAWN_SUBSETS.add( HAIR ); ALLREADY_DRAWN_SUBSETS.add( LEFT_EYE ); ALLREADY_DRAWN_SUBSETS.add( RIGHT_EYE ); ALLREADY_DRAWN_SUBSETS.add( NECK ); ALLREADY_DRAWN_SUBSETS.add( MOUTH ); addToErnie( 0, 95, 125 ); addToErnie( 1, 81, 166 ); addToErnie( 2, 61, 194 ); addToErnie( 3, 55, 233 ); addToErnie( 4, 82, 286 ); addToErnie( 5, 108, 315 ); addToErnie( 6, 123, 332 ); addToErnie( 7, 139, 342 ); addToErnie( 8, 158, 354 ); addToErnie( 9, 184, 363 ); addToErnie( 10, 218, 372 ); addToErnie( 11, 249, 369 ); addToErnie( 12, 280, 361 ); addToErnie( 13, 310, 350 ); addToErnie( 14, 326, 333 ); addToErnie( 15, 342, 324 ); addToErnie( 16, 368, 298 ); addToErnie( 17, 381, 282 ); addToErnie( 18, 391, 267 ); addToErnie( 19, 401, 242 ); addToErnie( 20, 399, 221 ); addToErnie( 21, 387, 198 ); addToErnie( 22, 362, 150 ); addToErnie( 179, 362, 150 ); addToErnie( 23, 332, 135 ); addToErnie( 24, 305, 121 ); addToErnie( 25, 281, 116 ); addToErnie( 26, 258, 115 ); addToErnie( 27, 244, 121 ); addToErnie( 28, 221, 114 ); addToErnie( 29, 191, 113 ); addToErnie( 30, 163, 121 ); addToErnie( 31, 131, 127 ); addToErnie( 32, 95, 125 ); addToErnie( 33, 76, 109 ); addToErnie( 34, 96, 108 ); addToErnie( 35, 82, 94 ); addToErnie( 36, 79, 73 ); addToErnie( 37, 106, 85 ); addToErnie( 38, 99, 74 ); addToErnie( 39, 98, 66 ); addToErnie( 40, 110, 71 ); addToErnie( 41, 129, 71 ); addToErnie( 42, 123, 61 ); addToErnie( 43, 115, 56 ); addToErnie( 44, 132, 51 ); addToErnie( 45, 151, 50 ); addToErnie( 46, 141, 38 ); addToErnie( 47, 156, 38 ); addToErnie( 48, 174, 43 ); addToErnie( 49, 162, 30 ); addToErnie( 50, 149, 29 ); addToErnie( 51, 165, 22 ); addToErnie( 52, 185, 27 ); addToErnie( 53, 183, 14 ); addToErnie( 54, 186, 2 ); addToErnie( 55, 197, 13 ); addToErnie( 56, 211, 24 ); addToErnie( 57, 215, 15 ); addToErnie( 58, 209, 8 ); addToErnie( 59, 224, 11 ); addToErnie( 60, 233, 18 ); addToErnie( 61, 248, 16 ); addToErnie( 62, 266, 6 ); addToErnie( 63, 276, 1 ); addToErnie( 64, 275, 9 ); addToErnie( 65, 272, 20 ); addToErnie( 66, 294, 12 ); addToErnie( 67, 322, 8 ); addToErnie( 68, 307, 15 ); addToErnie( 69, 299, 26 ); addToErnie( 70, 315, 26 ); addToErnie( 71, 326, 26 ); addToErnie( 72, 311, 35 ); addToErnie( 73, 340, 35 ); addToErnie( 74, 331, 50 ); addToErnie( 75, 353, 50 ); addToErnie( 76, 368, 54 ); addToErnie( 77, 350, 58 ); addToErnie( 78, 379, 62 ); addToErnie( 79, 396, 70 ); addToErnie( 80, 378, 72 ); addToErnie( 81, 368, 81 ); addToErnie( 82, 388, 84 ); addToErnie( 83, 369, 93 ); addToErnie( 84, 383, 102 ); addToErnie( 85, 410, 101 ); addToErnie( 86, 394, 109 ); addToErnie( 87, 379, 113 ); addToErnie( 88, 394, 125 ); addToErnie( 89, 410, 122 ); addToErnie( 90, 405, 133 ); addToErnie( 91, 386, 133 ); addToErnie( 92, 395, 143 ); addToErnie( 93, 365, 155 ); addToErnie( 100, 58, 157 ); addToErnie( 101, 31, 170 ); addToErnie( 102, 22, 207 ); addToErnie( 103, 35, 227 ); addToErnie( 104, 407, 194 ); addToErnie( 105, 433, 211 ); addToErnie( 106, 436, 241 ); addToErnie( 107, 417, 267 ); addToErnie( 108, 74, 217 ); addToErnie( 109, 85, 229 ); addToErnie( 110, 102, 239 ); addToErnie( 111, 152, 255 ); addToErnie( 112, 178, 261 ); addToErnie( 113, 226, 269 ); addToErnie( 114, 276, 271 ); addToErnie( 115, 315, 268 ); addToErnie( 116, 352, 257 ); addToErnie( 117, 375, 250 ); addToErnie( 118, 387, 240 ); addToErnie( 119, 340, 278 ); addToErnie( 120, 317, 297 ); addToErnie( 121, 276, 322 ); addToErnie( 122, 230, 332 ); addToErnie( 123, 182, 323 ); addToErnie( 124, 154, 306 ); addToErnie( 125, 132, 285 ); addToErnie( 126, 112, 260 ); addToErnie( 127, 103, 244 ); addToErnie( 128, 178, 265 ); addToErnie( 129, 195, 287 ); addToErnie( 130, 228, 301 ); addToErnie( 131, 253, 295 ); addToErnie( 132, 270, 282 ); addToErnie( 133, 226, 281 ); addToErnie( 134, 188, 228 ); addToErnie( 135, 191, 201 ); addToErnie( 136, 209, 184 ); addToErnie( 137, 234, 180 ); addToErnie( 138, 257, 189 ); addToErnie( 139, 269, 217 ); addToErnie( 140, 258, 248 ); addToErnie( 141, 242, 259 ); addToErnie( 142, 170, 198 ); addToErnie( 143, 152, 186 ); addToErnie( 144, 152, 156 ); addToErnie( 145, 167, 144 ); addToErnie( 146, 191, 131 ); addToErnie( 147, 215, 136 ); addToErnie( 148, 225, 154 ); addToErnie( 149, 221, 176 ); addToErnie( 150, 243, 166 ); addToErnie( 151, 254, 148 ); addToErnie( 152, 271, 135 ); addToErnie( 153, 294, 138 ); addToErnie( 154, 317, 165 ); addToErnie( 155, 316, 191 ); addToErnie( 156, 300, 204 ); addToErnie( 157, 282, 207 ); addToErnie( 158, 273, 184 ); addToErnie( 159, 289, 181 ); addToErnie( 160, 295, 169 ); addToErnie( 161, 281, 158 ); addToErnie( 162, 265, 168 ); addToErnie( 163, 189, 181 ); addToErnie( 164, 176, 172 ); addToErnie( 165, 180, 155 ); addToErnie( 166, 195, 153 ); addToErnie( 167, 203, 167 ); addToErnie( 168, 202, 178 ); addToErnie( 169, 120, 346 ); addToErnie( 170, 131, 366 ); addToErnie( 171, 150, 380 ); addToErnie( 172, 182, 397 ); addToErnie( 173, 217, 404 ); addToErnie( 174, 249, 405 ); addToErnie( 175, 285, 396 ); addToErnie( 176, 309, 382 ); addToErnie( 177, 332, 363 ); addToErnie( 178, 344, 343 ); determineErnieDimensions(); } private static float scaleFactor = 1f; private static Point ernieDimensions; private static Point ernieMinima; private Image bgPatternImage; protected int currentColor = SWT.COLOR_DARK_RED; protected int currentLineWidth = 8; protected int alpha = 255; private ClientCanvas canvas; private ToolItem redoToolItem; private ToolItem undoToolItem; private ToolItem clearToolItem; @Override public int createUI() { final Display display = new Display(); if( SHOW_BLUE_PRINT ) { bgPatternImage = new Image( display, DrawDemo.class.getResourceAsStream( "/ernie.png" ) ); } final Shell shell = new Shell( display, SWT.NO_TRIM ); shell.setMaximized( true ); shell.setLayout( new FillLayout() ); Composite mainComp = new Composite( shell, SWT.NONE ); mainComp.setLayout( createGridLayout( 1, false ) ); createToolbar( mainComp ); createClientCanvas( display, mainComp ); shell.open(); fitErnieToCanvas(); return 0; } private static void determineErnieDimensions() { int minX = -1; int minY = -1; int maxX = 0; int maxY = 0; for( int[] dotInfo : ERNIE ) { int x = dotInfo[ 1 ]; int y = dotInfo[ 2 ]; if( x > maxX ) { maxX = x; } if( y > maxY ) { maxY = y; } if( minX == -1 || x < minX ) { minX = x; } if( minY == -1 || y < minY ) { minY = y; } } ernieDimensions = new Point( maxX - minX, maxY - minY ); ernieMinima = new Point( minX, minY ); } private static void addToErnie( int index, int x, int y ) { ERNIE.add( new int[]{ index, x, y } ); } private void createClientCanvas( final Display display, Composite mainComp ) { canvas = new ClientCanvas( mainComp, SWT.NONE ); canvas.setLayoutData( createFill() ); if( bgPatternImage != null ) { canvas.setBackgroundImage( bgPatternImage ); } else { canvas.setBackground( display.getSystemColor( SWT.COLOR_WHITE ) ); } canvas.addPaintListener( new PaintListener() { @Override public void paintControl( PaintEvent e ) { e.gc.setLineWidth( currentLineWidth ); e.gc.setLineCap( SWT.CAP_ROUND ); e.gc.setLineJoin( SWT.JOIN_ROUND ); e.gc.setForeground( display.getSystemColor( currentColor ) ); e.gc.setAlpha( alpha ); } } ); canvas.addClientDrawListener( new ClientDrawListener() { @Override public void receivedDrawing() { redoToolItem.setEnabled( canvas.hasRedo() ); undoToolItem.setEnabled( canvas.hasUndo() ); clearToolItem.setEnabled( canvas.hasUndo() ); } } ); canvas.redraw(); canvas.addPaintListener( new PaintListener() { @Override public void paintControl( PaintEvent event ) { GC gc = event.gc; Color oldForeground = gc.getForeground(); Color oldBackground = gc.getBackground(); gc.setForeground( event.display.getSystemColor( SWT.COLOR_BLACK ) ); gc.setBackground( event.display.getSystemColor( SWT.COLOR_BLACK ) ); drawErnie( gc ); gc.setForeground( oldForeground ); gc.setBackground( oldBackground ); } private void drawErnie( GC gc ) { int oldLineWidth = currentLineWidth; gc.setLineWidth( 8 ); gc.fillPolygon( transform( getHair( ERNIE ) ) ); gc.drawPolyline( transform( getNeck( ERNIE ) ) ); gc.fillPolygon( transform( getRightEye( ERNIE ) ) ); gc.fillPolygon( transform( getLeftEye( ERNIE ) ) ); gc.drawPolyline( transform( getMouth( ERNIE ) ) ); drawDots( gc, ERNIE ); gc.setLineWidth( oldLineWidth ); } private int[] getLeftEye( List<int[]> dotInfos ) { return getDotsAsPoly( dotInfos, LEFT_EYE[ 0 ], LEFT_EYE[ 1 ] ); } private int[] getRightEye( List<int[]> dotInfos ) { return getDotsAsPoly( dotInfos, RIGHT_EYE[ 0 ], RIGHT_EYE[ 1 ] ); } private int[] getNeck( List<int[]> dotInfos ) { return getDotsAsPoly( dotInfos, NECK[ 0 ], NECK[ 1 ] ); } private int[] getHair( List<int[]> dotInfos ) { return getDotsAsPoly( dotInfos, HAIR[ 0 ], HAIR[ 1 ] ); } private int[] getMouth( List<int[]> dotInfos ) { return getDotsAsPoly( dotInfos, MOUTH[ 0 ], MOUTH[ 1 ] ); } private boolean isAlreadyDrawn( int dotLable ) { for( int[] interval : ALLREADY_DRAWN_SUBSETS ) { if( dotLable >= interval[ 0 ] && dotLable <= interval[ 1 ] ) { return true; } } return false; } private int[] getDotsAsPoly( List<int[]> dotInfos, int startLable, int endLable ) { List<int[]> dotInfoSubset = getDots( dotInfos, startLable, endLable ); int[] coordSubset = new int[ dotInfoSubset.size() * 2 ]; int coordIndex = 0; for( int[] dotInfo : dotInfoSubset ) { coordSubset[ coordIndex ] = dotInfo[ 1 ]; coordSubset[ coordIndex + 1 ] = dotInfo[ 2 ]; coordIndex += 2; } return coordSubset; } private List<int[]> getDots( List<int[]> dotInfos, int startLable, int endLable ) { List<int[]> result = new ArrayList<int[]>(); int currentLable = startLable; for( int[] dotInfo : dotInfos ) { int dotLable = dotInfo[ 0 ]; if( dotLable == currentLable ) { result.add( dotInfo ); currentLable++; } if( currentLable > endLable ) { break; } } return result; } private void drawDots( GC gc, List<int[]> dotInfos ) { int dotLable = 0; for( int[] dotInfo : dotInfos ) { if( LABEL_ALL_DOTS || !isAlreadyDrawn( dotInfo[ 0 ] ) ) { if( RENUMBER_LABELS ) { dotLable++; } else { dotLable = dotInfo[ 0 ]; } drawDot( gc, dotLable, dotInfo[ 1 ], dotInfo[ 2 ] ); } } } private void drawDot( GC gc, int dotLabel, int x, int y ) { Point dot = transform( new Point( x, y ) ); int lableInterval = 1; if( dotLabel % lableInterval == 0 ) { Color oldBackground = gc.getBackground(); gc.setBackground( gc.getDevice().getSystemColor( SWT.COLOR_WHITE ) ); gc.drawString( Integer.toString( dotLabel ), dot.x + 5, dot.y + 5 ); gc.setBackground( oldBackground ); } gc.fillOval( dot.x, dot.y, 5, 5 ); } Point transform( Point coord ) { Point centerDelta = calculateCenterDelta(); Point inTopLeft = translate( coord, -ernieMinima.x, -ernieMinima.y ); Point scaledInTopLeft = scale( inTopLeft, scaleFactor ); translate( scaledInTopLeft, centerDelta.x, centerDelta.y ); return scaledInTopLeft; } Point scale( Point coord, float factor ) { coord.x = ( int )( coord.x * factor ); coord.y = ( int )( coord.y * factor ); return coord; } Point translate( Point coord, int deltaX, int deltaY ) { coord.x = coord.x + deltaX; coord.y = coord.y + deltaY; return coord; } int[] transform( int[] coords ) { Point centerDelta = calculateCenterDelta(); int[] inTopLeft = translate( coords, -ernieMinima.x, -ernieMinima.y ); int[] scaledInTopLeft = scale( inTopLeft, scaleFactor ); translate( scaledInTopLeft, centerDelta.x, centerDelta.y ); return scaledInTopLeft; } Point calculateCenterDelta() { int canvasCenterX = canvas.getBounds().width / 2; int canvasCenterY = canvas.getBounds().height / 2; int ernieCenterX = ( ( int )( ( ernieDimensions.x / 2 ) * scaleFactor ) ); int ernieCenterY = ( ( int )( ( ernieDimensions.y / 2 ) * scaleFactor ) ); Point result = new Point( canvasCenterX - ernieCenterX, canvasCenterY - ernieCenterY ); return result; } int[] scale( int[] coords, float factor ) { for( int i = 0; i < coords.length; i++ ) { coords[ i ] = ( int )( coords[ i ] * factor ); } return coords; } int[] translate( int[] coords, int deltaX, int deltaY ) { for( int i = 0; i < coords.length; i += 2 ) { coords[ i ] += deltaX; coords[ i + 1 ] += deltaY; } return coords; } } ); } private void fitErnieToCanvas() { Rectangle bounds = canvas.getBounds(); if( bounds.width >= bounds.height ) { scaleFactor = ( float )bounds.height / ernieDimensions.y; } else { scaleFactor = ( float )bounds.width / ernieDimensions.x; } canvas.redraw(); } private GridData createFill() { return new GridData( SWT.FILL, SWT.FILL, true, true ); } private GridData createFillHori() { return new GridData( SWT.FILL, SWT.TOP, true, false ); } private GridLayout createGridLayout( int cols, boolean equalWidth ) { GridLayout layout = new GridLayout( cols, equalWidth ); layout.marginHeight = 0; layout.marginWidth = 0; layout.verticalSpacing = 0; layout.horizontalSpacing = 0; return layout; } private void createToolbar( Composite parent ) { final ToolBar toolBar = new ToolBar( parent, SWT.HORIZONTAL ); toolBar.setLayoutData( createFillHori() ); ToolItem widthThinToolItem = new ToolItem( toolBar, SWT.PUSH ); widthThinToolItem.setImage( new Image( parent.getDisplay(), DrawDemo.class.getResourceAsStream( "/line-width-thin.png" ) ) ); widthThinToolItem.addListener( SWT.Selection, new Listener() { @Override public void handleEvent( Event event ) { currentLineWidth = 1; canvas.redraw(); } } ); ToolItem widthMediumToolItem = new ToolItem( toolBar, SWT.PUSH ); widthMediumToolItem.setImage( new Image( parent.getDisplay(), DrawDemo.class.getResourceAsStream( "/line-width-medium.png" ) ) ); widthMediumToolItem.addListener( SWT.Selection, new Listener() { @Override public void handleEvent( Event event ) { currentLineWidth = 8; canvas.redraw(); } } ); ToolItem widthThickToolItem = new ToolItem( toolBar, SWT.PUSH ); widthThickToolItem.setImage( new Image( parent.getDisplay(), DrawDemo.class.getResourceAsStream( "/line-width-thick.png" ) ) ); widthThickToolItem.addListener( SWT.Selection, new Listener() { @Override public void handleEvent( Event event ) { currentLineWidth = 16; canvas.redraw(); } } ); new ToolItem( toolBar, SWT.SEPARATOR ); final ToolItem opacityToolItem = new ToolItem( toolBar, SWT.PUSH ); opacityToolItem.setText( "Opaque" ); opacityToolItem.addListener( SWT.Selection, new Listener() { @Override public void handleEvent( Event event ) { if( alpha == 255 ) { alpha = 128; opacityToolItem.setText( "Transparent" ); } else { alpha = 255; opacityToolItem.setText( "Opaque" ); } canvas.redraw(); } } ); new ToolItem( toolBar, SWT.SEPARATOR ); ToolItem colorRedToolItem = new ToolItem( toolBar, SWT.PUSH ); colorRedToolItem.setText( "Red" ); colorRedToolItem.addListener( SWT.Selection, new Listener() { @Override public void handleEvent( Event event ) { currentColor = SWT.COLOR_DARK_RED; canvas.redraw(); } } ); ToolItem colorGreenToolItem = new ToolItem( toolBar, SWT.PUSH ); colorGreenToolItem.setText( "Green" ); colorGreenToolItem.addListener( SWT.Selection, new Listener() { @Override public void handleEvent( Event event ) { currentColor = SWT.COLOR_DARK_GREEN; canvas.redraw(); } } ); ToolItem colorBlueToolItem = new ToolItem( toolBar, SWT.PUSH ); colorBlueToolItem.setText( "Blue" ); colorBlueToolItem.addListener( SWT.Selection, new Listener() { @Override public void handleEvent( Event event ) { currentColor = SWT.COLOR_DARK_BLUE; canvas.redraw(); } } ); new ToolItem( toolBar, SWT.SEPARATOR ); undoToolItem = new ToolItem( toolBar, SWT.PUSH ); undoToolItem.setImage( new Image( parent.getDisplay(), DrawDemo.class.getResourceAsStream( "/undo.png" ) ) ); undoToolItem.setEnabled( false ); undoToolItem.addListener( SWT.Selection, new Listener() { @Override public void handleEvent( Event event ) { canvas.undo(); undoToolItem.setEnabled( canvas.hasUndo() ); clearToolItem.setEnabled( canvas.hasUndo() ); } } ); redoToolItem = new ToolItem( toolBar, SWT.PUSH ); redoToolItem.setImage( new Image( parent.getDisplay(), DrawDemo.class.getResourceAsStream( "/redo.png" ) ) ); redoToolItem.setEnabled( false ); redoToolItem.addListener( SWT.Selection, new Listener() { @Override public void handleEvent( Event event ) { canvas.redo(); redoToolItem.setEnabled( canvas.hasRedo() ); } } ); new ToolItem( toolBar, SWT.SEPARATOR ); clearToolItem = new ToolItem( toolBar, SWT.PUSH ); clearToolItem.setText( "Clear" ); clearToolItem.addListener( SWT.Selection, new Listener() { @Override public void handleEvent( Event event ) { canvas.clear(); } } ); } }