diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..f175fdc
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,27 @@
+**/bin
+*.so
+**/native-image/*-*.json
+
+# Compiled class file
+*.class
+
+# Log file
+*.log
+
+# BlueJ files
+*.ctxt
+
+# Mobile Tools for Java (J2ME)
+.mtj.tmp/
+
+# Package Files #
+*.jar
+*.war
+*.nar
+*.ear
+*.zip
+*.tar.gz
+*.rar
+
+# virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml
+hs_err_pid*
diff --git a/draw2d/.classpath b/draw2d/.classpath
new file mode 100644
index 0000000..4328baf
--- /dev/null
+++ b/draw2d/.classpath
@@ -0,0 +1,16 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/draw2d/.project b/draw2d/.project
new file mode 100644
index 0000000..2482c9f
--- /dev/null
+++ b/draw2d/.project
@@ -0,0 +1,17 @@
+
+
+ demo.draw2d
+
+
+
+
+
+ org.eclipse.jdt.core.javabuilder
+
+
+
+
+
+ org.eclipse.jdt.core.javanature
+
+
diff --git a/draw2d/README.md b/draw2d/README.md
new file mode 100644
index 0000000..a18a330
--- /dev/null
+++ b/draw2d/README.md
@@ -0,0 +1,17 @@
+build source
+```
+./build.sh
+```
+run and generate configuration for native image
+```
+./run.sh -trace
+```
+build native image
+```
+./build.sh -native
+```
+launch
+```
+./draw2dapp
+```
+Blog: [Graalvm Native Image Demo - JFace and Draw2D](https://www.spket.com/blog/graalvm-native-image-demo-jface-and-draw2d/)
diff --git a/draw2d/build.sh b/draw2d/build.sh
new file mode 100755
index 0000000..62a825e
--- /dev/null
+++ b/draw2d/build.sh
@@ -0,0 +1,26 @@
+#! /bin/sh
+
+if [ -z "$GRAALVM_HOME" ]; then
+ GRAALVM_HOME=$HOME/tools/graalvm
+fi
+
+LIBS_3RD=../../third-party
+SWT_HOME=$LIBS_3RD/swt
+SKIJA_HOME=$LIBS_3RD/skija
+RCP_HOME=$LIBS_3RD/rcp
+GEF_HOME=$LIBS_3RD/gef
+CP=$SWT_HOME/swt.jar:$SKIJA_HOME/skija.jar:\
+$RCP_HOME/plugins/org.eclipse.jface_3.22.0.v20201106-0834.jar:\
+$RCP_HOME/plugins/org.eclipse.core.commands_3.9.800.v20201021-1339.jar:\
+$RCP_HOME/plugins/org.eclipse.equinox.common_3.14.0.v20201102-2053.jar:\
+$RCP_HOME/plugins/org.eclipse.ui.workbench_3.122.0.v20201122-1345.jar:\
+$GEF_HOME/plugins/org.eclipse.draw2d_3.10.100.201606061308.jar:\
+$GEF_HOME/plugins/org.eclipse.gef_3.11.0.201606061308.jar:\
+$GEF_HOME/plugins/org.eclipse.zest.core_1.5.300.201606061308.jar:\
+$GEF_HOME/plugins/org.eclipse.zest.layouts_1.1.300.201606061308.jar
+
+if [ "$1" = "-native" ]; then
+ $GRAALVM_HOME/bin/native-image -cp bin:res:$CP com.spket.demo.draw2d.Draw2DApp draw2dapp
+else
+ $GRAALVM_HOME/bin/javac -cp res:$CP -d bin -sourcepath src:gtk src/com/spket/demo/draw2d/Draw2DApp.java
+fi
diff --git a/draw2d/gtk/com/spket/demo/draw2d/FigureCanvasGL.java b/draw2d/gtk/com/spket/demo/draw2d/FigureCanvasGL.java
new file mode 100644
index 0000000..f07a021
--- /dev/null
+++ b/draw2d/gtk/com/spket/demo/draw2d/FigureCanvasGL.java
@@ -0,0 +1,301 @@
+package com.spket.demo.draw2d;
+
+import org.eclipse.draw2d.FigureCanvas;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.graphics.Rectangle;
+import org.eclipse.swt.internal.DPIUtil;
+import org.eclipse.swt.internal.gtk.GDK;
+import org.eclipse.swt.internal.gtk.GTK;
+import org.eclipse.swt.internal.gtk.GdkWindowAttr;
+import org.eclipse.swt.internal.gtk.OS;
+import org.eclipse.swt.internal.opengl.glx.GLX;
+import org.eclipse.swt.internal.opengl.glx.XVisualInfo;
+import org.eclipse.swt.opengl.GLData;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Listener;
+import org.jetbrains.skija.BackendRenderTarget;
+import org.jetbrains.skija.ColorSpace;
+import org.jetbrains.skija.DirectContext;
+import org.jetbrains.skija.FramebufferFormat;
+import org.jetbrains.skija.Surface;
+import org.jetbrains.skija.SurfaceColorFormat;
+import org.jetbrains.skija.SurfaceOrigin;
+
+public class FigureCanvasGL extends FigureCanvas {
+ private static int checkStyle(int style) {
+ style |= SWT.V_SCROLL | SWT.H_SCROLL;
+
+ return style;
+ }
+
+ private static GLData createDefaultData() {
+ GLData data = new GLData();
+ data.doubleBuffer = true;
+ data.stencilSize = 8;
+ return data;
+ }
+
+ long foreContext;
+ long backContext;
+
+ //long context;
+ long xWindow;
+ long glWindow;
+ XVisualInfo vinfo;
+ static final int MAX_ATTRIBUTES = 32;
+
+ private Surface surface;
+ private DirectContext context;
+ private BackendRenderTarget renderTarget;
+
+ public FigureCanvasGL(Composite parent) {
+ this(parent, SWT.NO_REDRAW_RESIZE | SWT.NO_BACKGROUND, createDefaultData());
+ }
+
+ public FigureCanvasGL(Composite parent, int style) {
+ this(parent, style, createDefaultData());
+ }
+
+ public FigureCanvasGL(Composite parent, int style, GLData data) {
+ super(checkStyle(style), parent, new LightweightSystemGL());
+
+ initGL(data, style);
+ }
+
+ protected void initGL(GLData data, int style) {
+ if (OS.IsWin32) SWT.error (SWT.ERROR_NOT_IMPLEMENTED);
+ if (data == null) SWT.error (SWT.ERROR_NULL_ARGUMENT);
+ int glxAttrib [] = new int [MAX_ATTRIBUTES];
+ int pos = 0;
+ glxAttrib [pos++] = GLX.GLX_RGBA;
+ if (data.doubleBuffer) glxAttrib [pos++] = GLX.GLX_DOUBLEBUFFER;
+ if (data.stereo) glxAttrib [pos++] = GLX.GLX_STEREO;
+ if (data.redSize > 0) {
+ glxAttrib [pos++] = GLX.GLX_RED_SIZE;
+ glxAttrib [pos++] = data.redSize;
+ }
+ if (data.greenSize > 0) {
+ glxAttrib [pos++] = GLX.GLX_GREEN_SIZE;
+ glxAttrib [pos++] = data.greenSize;
+ }
+ if (data.blueSize > 0) {
+ glxAttrib [pos++] = GLX.GLX_BLUE_SIZE;
+ glxAttrib [pos++] = data.blueSize;
+ }
+ if (data.alphaSize > 0) {
+ glxAttrib [pos++] = GLX.GLX_ALPHA_SIZE;
+ glxAttrib [pos++] = data.alphaSize;
+ }
+ if (data.depthSize > 0) {
+ glxAttrib [pos++] = GLX.GLX_DEPTH_SIZE;
+ glxAttrib [pos++] = data.depthSize;
+ }
+ if (data.stencilSize > 0) {
+ glxAttrib [pos++] = GLX.GLX_STENCIL_SIZE;
+ glxAttrib [pos++] = data.stencilSize;
+ }
+ if (data.accumRedSize > 0) {
+ glxAttrib [pos++] = GLX.GLX_ACCUM_RED_SIZE;
+ glxAttrib [pos++] = data.accumRedSize;
+ }
+ if (data.accumGreenSize > 0) {
+ glxAttrib [pos++] = GLX.GLX_ACCUM_GREEN_SIZE;
+ glxAttrib [pos++] = data.accumGreenSize;
+ }
+ if (data.accumBlueSize > 0) {
+ glxAttrib [pos++] = GLX.GLX_ACCUM_BLUE_SIZE;
+ glxAttrib [pos++] = data.accumBlueSize;
+ }
+ if (data.accumAlphaSize > 0) {
+ glxAttrib [pos++] = GLX.GLX_ACCUM_ALPHA_SIZE;
+ glxAttrib [pos++] = data.accumAlphaSize;
+ }
+ if (data.sampleBuffers > 0) {
+ glxAttrib [pos++] = GLX.GLX_SAMPLE_BUFFERS;
+ glxAttrib [pos++] = data.sampleBuffers;
+ }
+ if (data.samples > 0) {
+ glxAttrib [pos++] = GLX.GLX_SAMPLES;
+ glxAttrib [pos++] = data.samples;
+ }
+ glxAttrib [pos++] = 0;
+ GTK.gtk_widget_realize (handle);
+ long window = GTK.gtk_widget_get_window (handle);
+
+ long xDisplay = GDK.gdk_x11_display_get_xdisplay(GDK.gdk_window_get_display(window));
+ long infoPtr = GLX.glXChooseVisual (xDisplay, OS.XDefaultScreen (xDisplay), glxAttrib);
+ if (infoPtr == 0) {
+ dispose ();
+ SWT.error (SWT.ERROR_UNSUPPORTED_DEPTH);
+ }
+ vinfo = new XVisualInfo ();
+ GLX.memmove (vinfo, infoPtr, XVisualInfo.sizeof);
+ OS.XFree (infoPtr);
+ long screen = GDK.gdk_screen_get_default ();
+ long gdkvisual = GDK.gdk_x11_screen_lookup_visual (screen, vinfo.visualid);
+ long share = /* data.shareContext != null ? data.shareContext.context : */0;
+ foreContext = GLX.glXCreateContext (xDisplay, vinfo, share, true);
+ if (foreContext == 0) SWT.error (SWT.ERROR_NO_HANDLES);
+ GdkWindowAttr attrs = new GdkWindowAttr ();
+ attrs.width = 1;
+ attrs.height = 1;
+ attrs.event_mask = GDK.GDK_KEY_PRESS_MASK | GDK.GDK_KEY_RELEASE_MASK |
+ GDK.GDK_FOCUS_CHANGE_MASK | GDK.GDK_POINTER_MOTION_MASK |
+ GDK.GDK_BUTTON_PRESS_MASK | GDK.GDK_BUTTON_RELEASE_MASK |
+ GDK.GDK_ENTER_NOTIFY_MASK | GDK.GDK_LEAVE_NOTIFY_MASK |
+ GDK.GDK_EXPOSURE_MASK | GDK.GDK_POINTER_MOTION_HINT_MASK;
+ attrs.window_type = GDK.GDK_WINDOW_CHILD;
+ attrs.visual = gdkvisual;
+ glWindow = GDK.gdk_window_new (window, attrs, GDK.GDK_WA_VISUAL);
+ GDK.gdk_window_set_user_data (glWindow, handle);
+ if ((style & SWT.NO_BACKGROUND) != 0) {
+ //TODO: implement this on GTK3 as pixmaps are gone.
+ }
+
+ if (GTK.GTK4) {
+ // TODO: Enable when the GdkWindow to GdkSurface changes are in
+ //xWindow = GDK.gdk_x11_surface_get_xid(glWindow);
+ } else {
+ xWindow = GDK.gdk_x11_window_get_xid (glWindow);
+ }
+
+ GDK.gdk_window_show (glWindow);
+ //*
+ Listener listener = event -> {
+ switch (event.type) {
+ case SWT.Paint:
+ int [] viewport = new int [4];
+ GLX.glGetIntegerv (GLX.GL_VIEWPORT, viewport);
+ GLX.glViewport (viewport [0],viewport [1],viewport [2],viewport [3]);
+ break;
+ case SWT.Resize:
+ Rectangle clientArea = DPIUtil.autoScaleUp(getClientArea());
+ GDK.gdk_window_move (glWindow, clientArea.x, clientArea.y);
+ GDK.gdk_window_resize (glWindow, clientArea.width, clientArea.height);
+ break;
+ case SWT.Dispose:
+ onDispose();
+ break;
+ }
+ };
+
+ addListener (SWT.Resize, listener);
+ addListener (SWT.Paint, listener);
+ addListener (SWT.Dispose, listener);
+ //*/
+ }
+
+ public boolean setCurrent(boolean set) {
+ return setCurrent(SWT.FOREGROUND, set);
+ }
+
+ public boolean setCurrent(int pos, boolean set) {
+ long ctx = foreContext;
+ if (SWT.BACKGROUND == pos) {
+ //if (backContext == 0) ; //throw @error?
+ if (backContext != 0)
+ ctx = backContext;
+ }
+ return makeCurrent(ctx, set);
+ }
+
+ private void releaseContext() {
+ long window1 = GTK.gtk_widget_get_window(handle);
+ long xDisplay1 = gdk_x11_display_get_xdisplay(window1);
+ if (backContext != 0) {
+ GLX.glXDestroyContext(xDisplay1, backContext);
+ backContext = 0;
+ }
+ if (foreContext != 0) {
+ if (GLX.glXGetCurrentContext() == foreContext)
+ GLX.glXMakeCurrent(xDisplay1, 0, 0);
+ GLX.glXDestroyContext(xDisplay1, foreContext);
+ foreContext = 0;
+ }
+ }
+
+ public DirectContext getContext() {
+ if (context == null) {
+ setCurrent(SWT.FOREGROUND, true);
+ context = DirectContext.makeGL();
+ }
+ return context;
+ }
+
+ public Surface getSurface() {
+ checkWidget();
+ if (context == null) {
+ setCurrent(SWT.FOREGROUND, true);
+ context = DirectContext.makeGL();
+ }
+ if (surface == null) {
+ Rectangle rect = getClientArea();
+ renderTarget = BackendRenderTarget.makeGL(rect.width, rect.height, 0, 8, 0, FramebufferFormat.GR_GL_RGBA8);
+ surface = Surface.makeFromBackendRenderTarget(context, renderTarget, SurfaceOrigin.BOTTOM_LEFT, SurfaceColorFormat.RGBA_8888, ColorSpace.getDisplayP3());
+ }
+ return surface;
+ }
+
+ public void swapBuffers() {
+ checkWidget();
+ long window = GTK.gtk_widget_get_window(handle);
+ long xDisplay = gdk_x11_display_get_xdisplay(window);
+ GLX.glXSwapBuffers(xDisplay, xWindow);
+ }
+
+ protected boolean makeCurrent(long context, boolean set) {
+ boolean rc = false;
+ if (context != 0) {
+ //synchronized (this) {
+ long curContext = GLX.glXGetCurrentContext();
+ if (set) {
+ if (isDisposed()) SWT.error(SWT.ERROR_WIDGET_DISPOSED);
+ if (curContext == context) {
+ rc = true;
+ } else {
+ long window = GTK.gtk_widget_get_window(handle);
+ long xDisplay = gdk_x11_display_get_xdisplay(window);
+ GLX.glXMakeCurrent(xDisplay, xWindow, context);
+ }
+ } else if (curContext == context) {
+ long window = GTK.gtk_widget_get_window(handle);
+ long xDisplay = gdk_x11_display_get_xdisplay(window);
+ rc = GLX.glXMakeCurrent(xDisplay, 0, 0);
+ }
+ //}
+ }
+ return rc;
+ }
+
+ void releaseSurface() {
+ if (surface != null) {
+ surface.close();
+ surface = null;
+ }
+ if (renderTarget != null) {
+ renderTarget.close();
+ renderTarget = null;
+ }
+ }
+
+ private void releaseResource() {
+ if (context != null) {
+ context.close();
+ context = null;
+ }
+ }
+
+ protected void onResize() {
+ releaseSurface();
+ }
+
+ protected void onDispose() {
+ releaseResource();
+
+ releaseContext();
+ }
+
+ private long gdk_x11_display_get_xdisplay(long window) {
+ return GDK.gdk_x11_display_get_xdisplay(GDK.gdk_window_get_display(window));
+ }
+}
diff --git a/draw2d/res/META-INF/native-image/native-image.properties b/draw2d/res/META-INF/native-image/native-image.properties
new file mode 100644
index 0000000..cbc2ccf
--- /dev/null
+++ b/draw2d/res/META-INF/native-image/native-image.properties
@@ -0,0 +1 @@
+Args=--verbose --no-server --no-fallback --allow-incomplete-classpath --report-unsupported-elements-at-runtime -H:+JNIVerboseLookupErrors -H:+ReportExceptionStackTraces
diff --git a/draw2d/res/images/analytics-laptop-svgrepo-com.svg b/draw2d/res/images/analytics-laptop-svgrepo-com.svg
new file mode 100644
index 0000000..582abe0
--- /dev/null
+++ b/draw2d/res/images/analytics-laptop-svgrepo-com.svg
@@ -0,0 +1,63 @@
+
+
+
diff --git a/draw2d/res/images/folder-svgrepo-com.svg b/draw2d/res/images/folder-svgrepo-com.svg
new file mode 100644
index 0000000..00d2718
--- /dev/null
+++ b/draw2d/res/images/folder-svgrepo-com.svg
@@ -0,0 +1,39 @@
+
+
+
diff --git a/draw2d/res/images/gps-geolocalization-svgrepo-com.svg b/draw2d/res/images/gps-geolocalization-svgrepo-com.svg
new file mode 100644
index 0000000..607bb7c
--- /dev/null
+++ b/draw2d/res/images/gps-geolocalization-svgrepo-com.svg
@@ -0,0 +1,45 @@
+
+
+
diff --git a/draw2d/res/images/internet-shield-svgrepo-com.svg b/draw2d/res/images/internet-shield-svgrepo-com.svg
new file mode 100644
index 0000000..a9ac472
--- /dev/null
+++ b/draw2d/res/images/internet-shield-svgrepo-com.svg
@@ -0,0 +1,56 @@
+
+
+
diff --git a/draw2d/res/images/internet-svgrepo-com.svg b/draw2d/res/images/internet-svgrepo-com.svg
new file mode 100644
index 0000000..508ebe0
--- /dev/null
+++ b/draw2d/res/images/internet-svgrepo-com.svg
@@ -0,0 +1,54 @@
+
+
+
diff --git a/draw2d/res/images/ipad-svgrepo-com.svg b/draw2d/res/images/ipad-svgrepo-com.svg
new file mode 100644
index 0000000..5ddb2a5
--- /dev/null
+++ b/draw2d/res/images/ipad-svgrepo-com.svg
@@ -0,0 +1,58 @@
+
+
+
diff --git a/draw2d/res/images/search-svgrepo-com.svg b/draw2d/res/images/search-svgrepo-com.svg
new file mode 100644
index 0000000..d6af40c
--- /dev/null
+++ b/draw2d/res/images/search-svgrepo-com.svg
@@ -0,0 +1,43 @@
+
+
+
diff --git a/draw2d/res/images/settings-gear-svgrepo-com.svg b/draw2d/res/images/settings-gear-svgrepo-com.svg
new file mode 100644
index 0000000..0bf21b4
--- /dev/null
+++ b/draw2d/res/images/settings-gear-svgrepo-com.svg
@@ -0,0 +1,46 @@
+
+
+
diff --git a/draw2d/run.sh b/draw2d/run.sh
new file mode 100755
index 0000000..c104e57
--- /dev/null
+++ b/draw2d/run.sh
@@ -0,0 +1,33 @@
+#! /bin/sh
+
+if [ -z "$GRAALVM_HOME" ]; then
+ GRAALVM_HOME=$HOME/tools/graalvm
+fi
+
+LIBS_3RD=../../third-party
+SWT_HOME=$LIBS_3RD/swt
+SKIJA_HOME=$LIBS_3RD/skija
+RCP_HOME=$LIBS_3RD/rcp
+GEF_HOME=$LIBS_3RD/gef
+CP=$SWT_HOME/swt.jar:$SKIJA_HOME/skija.jar:\
+$RCP_HOME/plugins/org.eclipse.jface_3.22.0.v20201106-0834.jar:\
+$RCP_HOME/plugins/org.eclipse.core.commands_3.9.800.v20201021-1339.jar:\
+$RCP_HOME/plugins/org.eclipse.equinox.common_3.14.0.v20201102-2053.jar:\
+$RCP_HOME/plugins/org.eclipse.ui.workbench_3.122.0.v20201122-1345.jar:\
+$GEF_HOME/plugins/org.eclipse.draw2d_3.10.100.201606061308.jar:\
+$GEF_HOME/plugins/org.eclipse.gef_3.11.0.201606061308.jar:\
+$GEF_HOME/plugins/org.eclipse.zest.core_1.5.300.201606061308.jar:\
+$GEF_HOME/plugins/org.eclipse.zest.layouts_1.1.300.201606061308.jar
+
+for arg in "$@"; do
+ if [ "$arg" = "-trace" ]; then
+ rm -fr $HOME/.swt
+ JAVA_OPTS="$JAVA_OPTS -agentlib:native-image-agent=config-output-dir=res/META-INF/native-image"
+ elif [ "$arg" = "-debug" ]; then
+ JAVA_OPTS="$JAVA_OPTS -agentlib:jdwp=transport=dt_socket,server=y,suspend=y,address=8000"
+ else
+ JAVA_OPTS="$JAVA_OPTS $arg"
+ fi
+done
+
+$GRAALVM_HOME/bin/java $JAVA_OPTS -Djava.library.path=$SKIJA_HOME -cp bin:res:$CP com.spket.demo.draw2d.Draw2DApp
diff --git a/draw2d/src/com/spket/demo/draw2d/Draw2DApp.java b/draw2d/src/com/spket/demo/draw2d/Draw2DApp.java
new file mode 100644
index 0000000..41d0dbd
--- /dev/null
+++ b/draw2d/src/com/spket/demo/draw2d/Draw2DApp.java
@@ -0,0 +1,197 @@
+package com.spket.demo.draw2d;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.eclipse.draw2d.Animation;
+import org.eclipse.draw2d.FigureCanvas;
+import org.eclipse.draw2d.FreeformLayout;
+import org.eclipse.draw2d.IFigure;
+import org.eclipse.draw2d.LayoutAnimator;
+import org.eclipse.draw2d.geometry.Dimension;
+import org.eclipse.jface.action.MenuManager;
+import org.eclipse.jface.action.Separator;
+import org.eclipse.jface.window.ApplicationWindow;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.graphics.Point;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Control;
+import org.eclipse.swt.widgets.Shell;
+import org.eclipse.zest.core.widgets.internal.ZestRootLayer;
+import org.eclipse.zest.layouts.InvalidLayoutConfiguration;
+import org.eclipse.zest.layouts.LayoutAlgorithm;
+import org.eclipse.zest.layouts.LayoutEntity;
+import org.eclipse.zest.layouts.LayoutRelationship;
+import org.eclipse.zest.layouts.LayoutStyles;
+import org.eclipse.zest.layouts.algorithms.TreeLayoutAlgorithm;
+import org.jetbrains.skija.impl.Library;
+
+import com.spket.demo.draw2d.actions.ExitAction;
+import com.spket.demo.draw2d.actions.LayoutAction;
+import com.spket.demo.draw2d.actions.NewWizardAction;
+
+public class Draw2DApp extends ApplicationWindow {
+ public static void main(String[] args) {
+ loadLibrary();
+
+ Draw2DApp app = new Draw2DApp();
+
+ app.setBlockOnOpen(true);
+
+ app.open();
+ }
+
+ private static void loadLibrary() {
+ System.loadLibrary("skija");
+ System.setProperty("skija.staticLoad", String.valueOf(true));
+ Library._loaded = true;
+ Library._nAfterLoad();
+ }
+
+ private FigureCanvasGL canvas;
+ private LayoutAlgorithm layoutAlgorithm;
+ private LayoutEntity[] nodes;
+ private LayoutRelationship[] connections;
+ private boolean hasPendingLayoutRequest;
+
+ public Draw2DApp() {
+ super(null);
+
+ createMenu();
+ }
+
+ @Override
+ protected void configureShell(Shell shell) {
+ super.configureShell(shell);
+
+ shell.setText("Draw2D Demo");
+ }
+
+ @Override
+ protected Control createContents(Composite parent) {
+ canvas = new FigureCanvasGL(parent);
+ canvas.setScrollBarVisibility(FigureCanvas.NEVER);
+
+ Images.load();
+
+ canvas.getViewport().setContents(createContent());
+
+ canvas.addListener(SWT.Resize, e -> applyLayout());
+
+ return canvas;
+ }
+
+ @Override
+ protected Point getInitialSize() {
+ return new Point(800, 600);
+ }
+
+ protected void createMenu() {
+ addMenuBar();
+
+ MenuManager menu = getMenuBarManager();
+
+ MenuManager file = new MenuManager("&File");
+ createFileMenu(file);
+
+ menu.add(file);
+
+ MenuManager layout = new MenuManager("&Layout");
+ LayoutAction.fill(this, layout);
+
+ menu.add(layout);
+ }
+
+ protected void createFileMenu(MenuManager menu) {
+ menu.add(new NewWizardAction(this));
+
+ menu.add(new Separator());
+
+ menu.add(new ExitAction(this));
+ }
+
+
+ protected IFigure createContent() {
+ ZestRootLayer zestRootLayer = new ZestRootLayer();
+
+ zestRootLayer.setLayoutManager(new FreeformLayout());
+
+ zestRootLayer.addLayoutListener(LayoutAnimator.getDefault());
+
+ createNodes(zestRootLayer);
+
+ return zestRootLayer;
+ }
+
+ protected void createNodes(ZestRootLayer zest) {
+ SVGFigure analytics, internet, search, folder, gear, shield, gps, ipad;
+ List ents = new ArrayList<>();
+ List conns = new ArrayList<>();
+ ents.add(analytics = new SVGFigure(Images.getImage(Images.ANALYTICS_LAPTOP)));
+ ents.add(internet = new SVGFigure(Images.getImage(Images.INTERNET)));
+ ents.add(shield = new SVGFigure(Images.getImage(Images.INTERNET_SHIELD)));
+ ents.add(search = new SVGFigure(Images.getImage(Images.SEARCH)));
+ ents.add(folder = new SVGFigure(Images.getImage(Images.FOLDER)));
+ ents.add(gear = new SVGFigure(Images.getImage(Images.SETTINGS_GEAR)));
+ ents.add(gps = new SVGFigure(Images.getImage(Images.GPS)));
+ ents.add(ipad = new SVGFigure(Images.getImage(Images.IPAD)));
+
+ conns.add(new SVGRelationship(search, analytics));
+ conns.add(new SVGRelationship(search, folder));
+ conns.add(new SVGRelationship(search, internet));
+ conns.add(new SVGRelationship(internet, shield));
+ conns.add(new SVGRelationship(internet, gear));
+ conns.add(new SVGRelationship(gps, ipad));
+ //conns.add(new SVGRelationship(internet, shield));
+ conns.add(new SVGRelationship(search, gps));
+
+ ents.toArray(nodes = new LayoutEntity[ents.size()]);
+ conns.toArray(connections = new LayoutRelationship[conns.size()]);
+
+ for (IFigure c : conns)
+ zest.addConnection(c);
+ for (IFigure e : ents)
+ zest.addNode(e);
+ }
+
+ public void applyLayout() {
+ if (!hasPendingLayoutRequest) {
+ hasPendingLayoutRequest = true;
+
+ canvas.redraw();
+
+ canvas.getDisplay().asyncExec(() -> doLayout());
+ }
+ }
+
+ public void applyLayout(LayoutAlgorithm algorithm) {
+ if (layoutAlgorithm != algorithm) {
+ layoutAlgorithm = algorithm;
+
+ applyLayout();
+ }
+ }
+
+ protected void doLayout() {
+ hasPendingLayoutRequest = false;
+ if (canvas.isDisposed())
+ return;
+
+ int layoutStyle = LayoutStyles.NO_LAYOUT_NODE_RESIZING;
+ if (layoutAlgorithm == null) {
+ layoutAlgorithm = new TreeLayoutAlgorithm(layoutStyle);
+ } else {
+ layoutAlgorithm.setStyle(layoutAlgorithm.getStyle() | layoutStyle);
+ }
+ Dimension d = canvas.getViewport().getSize();
+
+ try {
+ Animation.markBegin();
+ layoutAlgorithm.applyLayout(nodes, connections, 0, 0, d.width, d.height, false, false);
+ Animation.run(500);
+ //canvas.getLightweightSystem().getUpdateManager().performUpdate();
+ } catch (InvalidLayoutConfiguration e) {
+ e.printStackTrace();
+ }
+ }
+}
diff --git a/draw2d/src/com/spket/demo/draw2d/ISkiaFigure.java b/draw2d/src/com/spket/demo/draw2d/ISkiaFigure.java
new file mode 100644
index 0000000..b439519
--- /dev/null
+++ b/draw2d/src/com/spket/demo/draw2d/ISkiaFigure.java
@@ -0,0 +1,20 @@
+package com.spket.demo.draw2d;
+
+import org.jetbrains.skija.Canvas;
+
+public interface ISkiaFigure {
+ default void paint(Canvas canvas) {
+ int sp = canvas.save();
+ try {
+ paintFigure(canvas);
+ paintClientArea(canvas);
+ paintBorder(canvas);
+ } finally {
+ canvas.restoreToCount(sp);
+ }
+ }
+
+ void paintBorder(Canvas canvas);
+ void paintFigure(Canvas canvas);
+ void paintClientArea(Canvas canvas);
+}
diff --git a/draw2d/src/com/spket/demo/draw2d/Images.java b/draw2d/src/com/spket/demo/draw2d/Images.java
new file mode 100644
index 0000000..8aab5c3
--- /dev/null
+++ b/draw2d/src/com/spket/demo/draw2d/Images.java
@@ -0,0 +1,67 @@
+package com.spket.demo.draw2d;
+
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.HashMap;
+import java.util.Map;
+
+import org.jetbrains.skija.Data;
+import org.jetbrains.skija.svg.DOM;
+
+public class Images {
+ public static final String ANALYTICS_LAPTOP = "analytics-laptop-svgrepo-com.svg";
+ public static final String FOLDER = "folder-svgrepo-com.svg";
+ public static final String GPS = "gps-geolocalization-svgrepo-com.svg";
+ public static final String INTERNET_SHIELD = "internet-shield-svgrepo-com.svg";
+ public static final String INTERNET = "internet-svgrepo-com.svg";
+ public static final String IPAD = "ipad-svgrepo-com.svg";
+ public static final String SEARCH = "search-svgrepo-com.svg";
+ public static final String SETTINGS_GEAR = "settings-gear-svgrepo-com.svg";
+ //public static final String STRATEGY = "strategy-svgrepo-com.svg";
+
+ private static Map images = new HashMap<>();
+
+ public static void load() {
+ try (ByteArrayOutputStream out = new ByteArrayOutputStream()) {
+ load(ANALYTICS_LAPTOP, out);
+ load(FOLDER, out);
+ load(GPS, out);
+ load(INTERNET_SHIELD, out);
+ load(INTERNET, out);
+ load(IPAD, out);
+ load(SEARCH, out);
+ load(SETTINGS_GEAR, out);
+ //load(STRATEGY, out);
+ } catch (IOException e) {
+ e.printStackTrace();
+ }
+
+ }
+
+ private static void load(String name, ByteArrayOutputStream out) throws IOException {
+ DOM dom = null;
+ try (InputStream in = Images.class.getResourceAsStream("/images/" + name)) {
+ out.reset();
+ in.transferTo(out);
+ try (Data data = Data.makeFromBytes(out.toByteArray())) {
+ dom = new DOM(data);
+ dom.setContainerSize(64, 64);
+ }
+ }
+
+ if (dom != null)
+ images.put(name, dom);
+ }
+
+ public static void dispose() {
+ for (DOM dom : images.values()) {
+ dom.close();
+ }
+ images.clear();
+ }
+
+ public static DOM getImage(String name) {
+ return images.get(name);
+ }
+}
diff --git a/draw2d/src/com/spket/demo/draw2d/LightweightSystemGL.java b/draw2d/src/com/spket/demo/draw2d/LightweightSystemGL.java
new file mode 100644
index 0000000..5072d69
--- /dev/null
+++ b/draw2d/src/com/spket/demo/draw2d/LightweightSystemGL.java
@@ -0,0 +1,130 @@
+package com.spket.demo.draw2d;
+
+import org.eclipse.draw2d.Graphics;
+import org.eclipse.draw2d.GraphicsSource;
+import org.eclipse.draw2d.LightweightSystem;
+import org.eclipse.draw2d.StackLayout;
+import org.eclipse.draw2d.geometry.Rectangle;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.graphics.GC;
+import org.jetbrains.skija.Canvas;
+import org.jetbrains.skija.ColorAlphaType;
+import org.jetbrains.skija.ImageInfo;
+import org.jetbrains.skija.Surface;
+
+public class LightweightSystemGL extends LightweightSystem implements GraphicsSource {
+ private class RootFigureGL extends RootFigure {
+ private Rectangle clip = new Rectangle();
+
+ @Override
+ public void paint(Graphics graphics) {
+ if (graphics instanceof SkiaGraphics) {
+ super.paint(graphics);
+ } else {
+ graphics.getClip(clip);
+
+ Graphics g = getGraphics(clip);
+
+ super.paint(g);
+
+ g.dispose();
+
+ flushGraphics(clip);
+ }
+ }
+ }
+
+ private FigureCanvasGL glCanvas;
+ private Surface surface;
+
+ @Override
+ public void setControl(org.eclipse.swt.widgets.Canvas c) {
+ if (c != glCanvas) {
+ if (c instanceof FigureCanvasGL) {
+ glCanvas = (FigureCanvasGL) c;
+ } else {
+ glCanvas = null;
+ }
+ super.setControl(c);
+ if (glCanvas != null)
+ getUpdateManager().setGraphicsSource(this);
+ }
+ }
+
+ @Override
+ public void paint(GC gc) {
+ super.paint(gc);
+
+ swapBuffer();
+ }
+
+ @Override
+ public Graphics getGraphics(Rectangle region) {
+ return new SkiaGraphics(getCanvas(), region);
+ }
+
+ @Override
+ public void flushGraphics(Rectangle region) {
+ surface.flush();
+
+ swapBuffer();
+ //glCanvas.redraw(region.x, region.y, region.width, region.height, false);
+ }
+
+ @Override
+ protected RootFigure createRootFigure() {
+ RootFigure f = new RootFigureGL();
+ f.addNotify();
+ f.setOpaque(true);
+ f.setLayoutManager(new StackLayout());
+ return f;
+ }
+
+ @Override
+ protected void addListeners() {
+ super.addListeners();
+ if (glCanvas != null) {
+ glCanvas.addListener(SWT.Dispose, e -> onDispose());
+ }
+ }
+
+ @Override
+ protected void controlResized() {
+ if (surface != null) {
+ surface.close();
+ surface = null;
+ }
+ glCanvas.releaseSurface();
+
+ super.controlResized();
+ }
+
+ protected void onDispose() {
+ if (surface != null && glCanvas != null && !glCanvas.isDisposed()) {
+ surface.close();
+ surface = null;
+ }
+ Images.dispose();
+ }
+
+ private void swapBuffer() {
+ Surface surf = glCanvas.getSurface();
+ Canvas canvas = surf.getCanvas();
+ if (surface != null) {
+ surface.draw(canvas, 0, 0, null);
+ } else {
+ canvas.clear(0xffffffff);
+ }
+ surf.flush();
+ glCanvas.swapBuffers();
+ }
+
+ private Canvas getCanvas() {
+ if (surface == null) {
+ org.eclipse.swt.graphics.Rectangle r = glCanvas.getClientArea();
+ ImageInfo info = ImageInfo.makeN32(r.width, r.height, ColorAlphaType.OPAQUE);
+ surface = Surface.makeRenderTarget(glCanvas.getContext(), false, info);
+ }
+ return surface.getCanvas();
+ }
+}
diff --git a/draw2d/src/com/spket/demo/draw2d/SVGFigure.java b/draw2d/src/com/spket/demo/draw2d/SVGFigure.java
new file mode 100644
index 0000000..5d9de59
--- /dev/null
+++ b/draw2d/src/com/spket/demo/draw2d/SVGFigure.java
@@ -0,0 +1,117 @@
+package com.spket.demo.draw2d;
+
+import org.eclipse.draw2d.Figure;
+import org.eclipse.draw2d.Graphics;
+import org.eclipse.draw2d.geometry.Dimension;
+import org.eclipse.draw2d.geometry.PrecisionDimension;
+import org.eclipse.draw2d.geometry.PrecisionRectangle;
+import org.eclipse.zest.layouts.LayoutEntity;
+import org.eclipse.zest.layouts.constraints.LayoutConstraint;
+import org.jetbrains.skija.Point;
+import org.jetbrains.skija.svg.DOM;
+
+public class SVGFigure extends Figure implements LayoutEntity {
+ private static final Dimension DEFAULT_SIZE = new PrecisionDimension(64, 64);
+
+ private DOM svg;
+ private Object layoutInfo;
+
+ public SVGFigure() {
+ }
+
+ public SVGFigure(DOM svg) {
+ this.svg = svg;
+ initSize();
+ }
+
+ protected void initSize() {
+ Dimension pSize = DEFAULT_SIZE;
+ //*
+ Point size = svg.getContainerSize();
+ if (size != null)
+ pSize = new PrecisionDimension(size.getX(), size.getY());
+
+ //*/
+ setPreferredSize(pSize);
+ setSize(pSize);
+ }
+
+ @Override
+ protected void paintFigure(Graphics graphics) {
+ if (svg != null) {
+ if (graphics instanceof SkiaGraphics) {
+ org.eclipse.draw2d.geometry.Rectangle b = getBounds();
+ ((SkiaGraphics) graphics).draw(svg, b.x, b.y);
+ }
+ }
+ }
+
+ @Override
+ public void setGraphData(Object o) {
+ if (svg != o) {
+ if (o instanceof DOM) {
+ svg = (DOM) o;
+ } else {
+ svg = null;
+ }
+ initSize();
+ }
+ }
+
+ @Override
+ public Object getGraphData() {
+ return svg;
+ }
+
+ @Override
+ public int compareTo(Object o) {
+ return 0;
+ }
+
+ @Override
+ public void setLocationInLayout(double x, double y) {
+ getParent().setConstraint(this, new PrecisionRectangle(x, y, bounds.preciseWidth(), bounds.preciseHeight()));
+ //setLocation(new PrecisionPoint(x, y));
+ }
+
+ @Override
+ public void setSizeInLayout(double width, double height) {
+ }
+
+ @Override
+ public double getXInLayout() {
+ return bounds.preciseX();
+ }
+
+ @Override
+ public double getYInLayout() {
+ return bounds.preciseY();
+ }
+
+ @Override
+ public double getWidthInLayout() {
+ return bounds.preciseWidth();
+ }
+
+ @Override
+ public double getHeightInLayout() {
+ return bounds.preciseHeight();
+ }
+
+ @Override
+ public Object getLayoutInformation() {
+ return layoutInfo;
+ }
+
+ @Override
+ public void setLayoutInformation(Object internalEntity) {
+ layoutInfo = internalEntity;
+ }
+
+ @Override
+ public void populateLayoutConstraint(LayoutConstraint constraint) {
+ // TODO Auto-generated method stub
+
+ }
+
+}
diff --git a/draw2d/src/com/spket/demo/draw2d/SVGRelationship.java b/draw2d/src/com/spket/demo/draw2d/SVGRelationship.java
new file mode 100644
index 0000000..3939fa1
--- /dev/null
+++ b/draw2d/src/com/spket/demo/draw2d/SVGRelationship.java
@@ -0,0 +1,59 @@
+package com.spket.demo.draw2d;
+
+import org.eclipse.draw2d.ChopboxAnchor;
+import org.eclipse.zest.core.widgets.internal.PolylineArcConnection;
+import org.eclipse.zest.layouts.LayoutBendPoint;
+import org.eclipse.zest.layouts.LayoutEntity;
+import org.eclipse.zest.layouts.LayoutRelationship;
+import org.eclipse.zest.layouts.constraints.LayoutConstraint;
+
+public class SVGRelationship extends PolylineArcConnection implements LayoutRelationship {
+ private Object layoutInfo;
+
+ public SVGRelationship(SVGFigure source, SVGFigure target) {
+ setSourceAnchor(new ChopboxAnchor(source));
+ setTargetAnchor(new ChopboxAnchor(target));
+ }
+
+ @Override
+ public Object getGraphData() {
+ return null;
+ }
+
+ @Override
+ public void setGraphData(Object o) {
+ }
+
+ @Override
+ public LayoutEntity getSourceInLayout() {
+ return (LayoutEntity) getSourceAnchor().getOwner();
+ }
+
+ @Override
+ public LayoutEntity getDestinationInLayout() {
+ return (LayoutEntity) getTargetAnchor().getOwner();
+ }
+
+ @Override
+ public Object getLayoutInformation() {
+ return layoutInfo;
+ }
+
+ @Override
+ public void setLayoutInformation(Object layoutInformation) {
+ layoutInfo = layoutInformation;
+ }
+
+ @Override
+ public void setBendPoints(LayoutBendPoint[] bendPoints) {
+ }
+
+ @Override
+ public void clearBendPoints() {
+ }
+
+ @Override
+ public void populateLayoutConstraint(LayoutConstraint constraint) {
+ }
+
+}
diff --git a/draw2d/src/com/spket/demo/draw2d/SkiaGraphics.java b/draw2d/src/com/spket/demo/draw2d/SkiaGraphics.java
new file mode 100644
index 0000000..eeff310
--- /dev/null
+++ b/draw2d/src/com/spket/demo/draw2d/SkiaGraphics.java
@@ -0,0 +1,551 @@
+package com.spket.demo.draw2d;
+
+import org.eclipse.draw2d.Graphics;
+import org.eclipse.draw2d.geometry.PointList;
+import org.eclipse.draw2d.geometry.Rectangle;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.graphics.Color;
+import org.eclipse.swt.graphics.Font;
+import org.eclipse.swt.graphics.FontMetrics;
+import org.eclipse.swt.graphics.Image;
+import org.eclipse.swt.graphics.LineAttributes;
+import org.eclipse.swt.graphics.Path;
+import org.eclipse.swt.graphics.Pattern;
+import org.eclipse.swt.graphics.TextLayout;
+import org.jetbrains.skija.Canvas;
+import org.jetbrains.skija.Paint;
+import org.jetbrains.skija.PaintMode;
+import org.jetbrains.skija.Rect;
+import org.jetbrains.skija.svg.DOM;
+
+public class SkiaGraphics extends Graphics {
+ private Canvas canvas;
+ private Paint cFill;
+ private Paint cStroke;
+
+ private org.jetbrains.skija.Path path;
+ private Rectangle clip;
+
+ private int savePoint;
+
+ public SkiaGraphics(Canvas canvas, Rectangle region) {
+ this.canvas = canvas;
+
+ savePoint = canvas.save();
+
+ clip = region;
+ cFill = new Paint();
+ cFill.setMode(PaintMode.FILL).setColor(0xffffffff);
+ cStroke = new Paint();
+ cStroke.setMode(PaintMode.STROKE);
+ path = new org.jetbrains.skija.Path();
+ }
+
+ public void draw(DOM dom, float x, float y) {
+ canvas.translate(x, y);
+ dom.render(canvas);
+ canvas.translate(-x, -y);
+ }
+
+ @Override
+ public void clipRect(Rectangle r) {
+ //TODO
+ canvas.clipRect(Rect.makeXYWH(r.x, r.y, r.width, r.height), false);
+ }
+
+ @Override
+ public void dispose() {
+ cFill.close();
+ cStroke.close();
+ path.close();
+
+ canvas.restoreToCount(savePoint);
+ }
+
+ @Override
+ public void drawArc(int x, int y, int w, int h, int offset, int length) {
+ // TODO Auto-generated method stub
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public void drawFocus(int x, int y, int w, int h) {
+ // TODO Auto-generated method stub
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public void drawImage(Image srcImage, int x, int y) {
+ // TODO Auto-generated method stub
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public void drawImage(Image srcImage, int x1, int y1, int w1, int h1, int x2, int y2, int w2, int h2) {
+ // TODO Auto-generated method stub
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public void drawLine(int x1, int y1, int x2, int y2) {
+ // TODO Auto-generated method stub
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public void drawOval(int x, int y, int w, int h) {
+ // TODO Auto-generated method stub
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public void drawPolygon(PointList points) {
+ // TODO Auto-generated method stub
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public void drawPolyline(PointList points) {
+ int[] ps = points.toIntArray();
+ float[] fps = new float[ps.length];
+
+ for (int i = 0; i < ps.length; i++)
+ fps[i] = ps[i];
+
+ path.addPoly(fps, false);
+
+ canvas.drawPath(path, cStroke);
+ }
+
+ @Override
+ public void drawRectangle(int x, int y, int width, int height) {
+ canvas.drawRect(Rect.makeXYWH(x, y, width, height), cStroke);
+ }
+
+ @Override
+ public void drawRoundRectangle(Rectangle r, int arcWidth, int arcHeight) {
+ // TODO Auto-generated method stub
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public void drawString(String s, int x, int y) {
+ // TODO Auto-generated method stub
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public void drawText(String s, int x, int y) {
+ // TODO Auto-generated method stub
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public void fillArc(int x, int y, int w, int h, int offset, int length) {
+ // TODO Auto-generated method stub
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public void fillGradient(int x, int y, int w, int h, boolean vertical) {
+ // TODO Auto-generated method stub
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public void fillOval(int x, int y, int w, int h) {
+ // TODO Auto-generated method stub
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public void fillPolygon(PointList points) {
+ // TODO Auto-generated method stub
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public void fillRectangle(int x, int y, int width, int height) {
+ canvas.drawRect(Rect.makeXYWH(x, y, width, height), cFill);
+ }
+
+ @Override
+ public void fillRoundRectangle(Rectangle r, int arcWidth, int arcHeight) {
+ // TODO Auto-generated method stub
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public void fillString(String s, int x, int y) {
+ // TODO Auto-generated method stub
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public void fillText(String s, int x, int y) {
+ // TODO Auto-generated method stub
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public Color getBackgroundColor() {
+ // TODO Auto-generated method stub
+ return null;
+ }
+
+ @Override
+ public Rectangle getClip(Rectangle rect) {
+ rect.setBounds(clip);
+
+ return rect;
+ }
+
+ @Override
+ public Font getFont() {
+ // TODO Auto-generated method stub
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public FontMetrics getFontMetrics() {
+ // TODO Auto-generated method stub
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public Color getForegroundColor() {
+ // TODO Auto-generated method stub
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public int getLineStyle() {
+ // TODO Auto-generated method stub
+ return 0;
+ }
+
+ @Override
+ public int getLineWidth() {
+ // TODO Auto-generated method stub
+ return 0;
+ }
+
+ @Override
+ public float getLineWidthFloat() {
+ // TODO Auto-generated method stub
+ return 0;
+ }
+
+ @Override
+ public boolean getXORMode() {
+ return false;
+ }
+
+ @Override
+ public void popState() {
+ canvas.restore();
+ }
+
+ @Override
+ public void pushState() {
+ canvas.save();
+ }
+
+ @Override
+ public void restoreState() {
+ canvas.restore();
+ canvas.save();
+ }
+
+ @Override
+ public void scale(double amount) {
+ float s = (float) amount;
+
+ canvas.scale(s, s);
+ }
+
+ @Override
+ public void setBackgroundColor(Color rgb) {
+ cFill.setARGB(rgb.getAlpha(), rgb.getRed(), rgb.getGreen(), rgb.getBlue());
+ }
+
+ @Override
+ public void setClip(Rectangle r) {
+ // TODO Auto-generated method stub
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public void setFont(Font f) {
+ // TODO Auto-generated method stub
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public void setForegroundColor(Color rgb) {
+ cStroke.setARGB(rgb.getAlpha(), rgb.getRed(), rgb.getGreen(), rgb.getBlue());
+ }
+
+ @Override
+ public void setLineStyle(int style) {
+ // TODO Auto-generated method stub
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public void setLineWidth(int width) {
+ // TODO Auto-generated method stub
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public void setLineWidthFloat(float width) {
+ // TODO Auto-generated method stub
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public void setLineMiterLimit(float miterLimit) {
+ // TODO Auto-generated method stub
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public void setXORMode(boolean b) {
+ // TODO Auto-generated method stub
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public void translate(int dx, int dy) {
+ canvas.translate(dx, dy);
+ }
+
+ @Override
+ public void clipPath(Path path) {
+ // TODO Auto-generated method stub
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public void drawPath(Path path) {
+ // TODO Auto-generated method stub
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public void drawPoint(int x, int y) {
+ canvas.drawPoint(x, y, cStroke);
+ }
+
+ @Override
+ public void drawPolygon(int[] points) {
+ // TODO Auto-generated method stub
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public void drawPolyline(int[] points) {
+ // TODO Auto-generated method stub
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public void drawText(String s, int x, int y, int style) {
+ // TODO Auto-generated method stub
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public void drawTextLayout(TextLayout layout, int x, int y, int selectionStart, int selectionEnd, Color selectionForeground, Color selectionBackground) {
+ // TODO Auto-generated method stub
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public void fillPath(Path path) {
+ // TODO Auto-generated method stub
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public void fillPolygon(int[] points) {
+ // TODO Auto-generated method stub
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public double getAbsoluteScale() {
+ // TODO Auto-generated method stub
+ return 1.0;
+ }
+
+ @Override
+ public boolean getAdvanced() {
+ // TODO Auto-generated method stub
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public int getAlpha() {
+ // TODO Auto-generated method stub
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public int getAntialias() {
+ return SWT.ON;
+ }
+
+ @Override
+ public int getFillRule() {
+ // TODO Auto-generated method stub
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public int getInterpolation() {
+ // TODO Auto-generated method stub
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public LineAttributes getLineAttributes() {
+ // TODO Auto-generated method stub
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public int getLineCap() {
+ // TODO Auto-generated method stub
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public int getLineJoin() {
+ // TODO Auto-generated method stub
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public float getLineMiterLimit() {
+ // TODO Auto-generated method stub
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public int getTextAntialias() {
+ // TODO Auto-generated method stub
+ return SWT.ON;
+ }
+
+ @Override
+ public void rotate(float degrees) {
+ canvas.rotate(degrees);
+ }
+
+ @Override
+ public void scale(float horizontal, float vertical) {
+ canvas.scale(horizontal, vertical);
+ }
+
+ @Override
+ public void setAlpha(int alpha) {
+ // TODO Auto-generated method stub
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public void setAdvanced(boolean advanced) {
+ // TODO Auto-generated method stub
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public void setAntialias(int value) {
+ // TODO Auto-generated method stub
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public void setBackgroundPattern(Pattern pattern) {
+ // TODO Auto-generated method stub
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public void setClip(Path path) {
+ // TODO Auto-generated method stub
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public void setFillRule(int rule) {
+ // TODO Auto-generated method stub
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public void setForegroundPattern(Pattern pattern) {
+ // TODO Auto-generated method stub
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public void setInterpolation(int interpolation) {
+ // TODO Auto-generated method stub
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public void setLineAttributes(LineAttributes attributes) {
+ // TODO Auto-generated method stub
+ //super.setLineAttributes(attributes);
+ }
+
+ @Override
+ public void setLineCap(int cap) {
+ // TODO Auto-generated method stub
+ //super.setLineCap(cap);
+ }
+
+ @Override
+ public void setLineDash(int[] dash) {
+ // TODO Auto-generated method stub
+ //super.setLineDash(dash);
+ }
+
+ @Override
+ public void setLineDash(float[] value) {
+ // TODO Auto-generated method stub
+ //super.setLineDash(value);
+ }
+
+ @Override
+ public void setLineDashOffset(float value) {
+ // TODO Auto-generated method stub
+ //super.setLineDashOffset(value);
+ }
+
+ @Override
+ public void setLineJoin(int join) {
+ // TODO Auto-generated method stub
+ //super.setLineJoin(join);
+ }
+
+ @Override
+ public void setTextAntialias(int value) {
+ // TODO Auto-generated method stub
+ //super.setTextAntialias(value);
+ }
+
+ @Override
+ public void shear(float horz, float vert) {
+ //canvas.
+ }
+
+ @Override
+ public void translate(float dx, float dy) {
+ canvas.translate(dx, dy);
+ }
+}
diff --git a/draw2d/src/com/spket/demo/draw2d/actions/ExitAction.java b/draw2d/src/com/spket/demo/draw2d/actions/ExitAction.java
new file mode 100644
index 0000000..01573be
--- /dev/null
+++ b/draw2d/src/com/spket/demo/draw2d/actions/ExitAction.java
@@ -0,0 +1,19 @@
+package com.spket.demo.draw2d.actions;
+
+import org.eclipse.jface.action.Action;
+import org.eclipse.jface.window.ApplicationWindow;
+
+public class ExitAction extends Action {
+ private ApplicationWindow window;
+
+ public ExitAction(ApplicationWindow window) {
+ super("&Exit");
+
+ this.window = window;
+ }
+
+ @Override
+ public void run() {
+ window.close();
+ }
+}
diff --git a/draw2d/src/com/spket/demo/draw2d/actions/LayoutAction.java b/draw2d/src/com/spket/demo/draw2d/actions/LayoutAction.java
new file mode 100644
index 0000000..e4f6059
--- /dev/null
+++ b/draw2d/src/com/spket/demo/draw2d/actions/LayoutAction.java
@@ -0,0 +1,53 @@
+package com.spket.demo.draw2d.actions;
+
+import org.eclipse.jface.action.Action;
+import org.eclipse.jface.action.IAction;
+import org.eclipse.jface.action.IContributionManager;
+import org.eclipse.zest.layouts.LayoutAlgorithm;
+import org.eclipse.zest.layouts.LayoutStyles;
+import org.eclipse.zest.layouts.algorithms.GridLayoutAlgorithm;
+import org.eclipse.zest.layouts.algorithms.HorizontalLayoutAlgorithm;
+import org.eclipse.zest.layouts.algorithms.HorizontalTreeLayoutAlgorithm;
+import org.eclipse.zest.layouts.algorithms.RadialLayoutAlgorithm;
+import org.eclipse.zest.layouts.algorithms.SpringLayoutAlgorithm;
+import org.eclipse.zest.layouts.algorithms.TreeLayoutAlgorithm;
+import org.eclipse.zest.layouts.algorithms.VerticalLayoutAlgorithm;
+
+import com.spket.demo.draw2d.Draw2DApp;
+
+public final class LayoutAction extends Action {
+ private static final String[] algorithmNames = { "Spring", "Tree - V", "Tree - H", "Radial", "Grid", "Horizontal", "Vertical" };
+ private static final LayoutAlgorithm[] algorithms = {
+ new SpringLayoutAlgorithm(LayoutStyles.NONE),
+ new TreeLayoutAlgorithm(LayoutStyles.NONE),
+ new HorizontalTreeLayoutAlgorithm(LayoutStyles.NONE),
+ new RadialLayoutAlgorithm(LayoutStyles.NONE),
+ new GridLayoutAlgorithm(LayoutStyles.NONE),
+ new HorizontalLayoutAlgorithm(LayoutStyles.NONE),
+ new VerticalLayoutAlgorithm(LayoutStyles.NONE)
+ };
+
+ public static void fill(Draw2DApp application, IContributionManager manager) {
+ for (int i = 0, length = algorithmNames.length; i < length; i++) {
+ LayoutAction action = new LayoutAction(application, algorithmNames[i], algorithms[i]);
+ if (i == 1)
+ action.setChecked(true);
+ manager.add(action);
+ }
+ }
+
+ private Draw2DApp application;
+ private LayoutAlgorithm algorithm;
+
+ private LayoutAction(Draw2DApp application, String name, LayoutAlgorithm algorithm) {
+ super(name, IAction.AS_RADIO_BUTTON);
+
+ this.application = application;
+ this.algorithm = algorithm;
+ }
+
+ @Override
+ public void run() {
+ application.applyLayout(algorithm);
+ }
+}
diff --git a/draw2d/src/com/spket/demo/draw2d/actions/NewWizardAction.java b/draw2d/src/com/spket/demo/draw2d/actions/NewWizardAction.java
new file mode 100644
index 0000000..9e5e68f
--- /dev/null
+++ b/draw2d/src/com/spket/demo/draw2d/actions/NewWizardAction.java
@@ -0,0 +1,22 @@
+package com.spket.demo.draw2d.actions;
+
+import org.eclipse.jface.action.Action;
+import org.eclipse.jface.window.IShellProvider;
+import org.eclipse.swt.widgets.Shell;
+
+public class NewWizardAction extends Action {
+ private IShellProvider shellProvider;
+
+ public NewWizardAction(IShellProvider shellProvider) {
+ super("&New...");
+ this.shellProvider = shellProvider;
+ }
+
+ @Override
+ public void run() {
+ Shell shell = shellProvider.getShell();
+ if (shell != null) {
+ //TODO
+ }
+ }
+}
diff --git a/draw2d/win32/com/spket/demo/draw2d/FigureCanvasGL.java b/draw2d/win32/com/spket/demo/draw2d/FigureCanvasGL.java
new file mode 100644
index 0000000..77acb93
--- /dev/null
+++ b/draw2d/win32/com/spket/demo/draw2d/FigureCanvasGL.java
@@ -0,0 +1,234 @@
+package com.spket.demo.draw2d;
+
+import org.eclipse.draw2d.FigureCanvas;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.graphics.Rectangle;
+import org.eclipse.swt.internal.opengl.win32.PIXELFORMATDESCRIPTOR;
+import org.eclipse.swt.internal.opengl.win32.WGL;
+import org.eclipse.swt.internal.win32.OS;
+import org.eclipse.swt.opengl.GLData;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Display;
+import org.jetbrains.skija.BackendRenderTarget;
+import org.jetbrains.skija.ColorSpace;
+import org.jetbrains.skija.DirectContext;
+import org.jetbrains.skija.FramebufferFormat;
+import org.jetbrains.skija.Surface;
+import org.jetbrains.skija.SurfaceColorFormat;
+import org.jetbrains.skija.SurfaceOrigin;
+
+public class FigureCanvasGL extends FigureCanvas {
+ private static final String USE_OWNDC_KEY = "org.eclipse.swt.internal.win32.useOwnDC"; //$NON-NLS-1$
+
+ private static int checkStyle(Composite parent, int style) {
+ parent.getDisplay().setData(USE_OWNDC_KEY, Boolean.TRUE);
+
+ style |= SWT.V_SCROLL | SWT.H_SCROLL;
+
+ return style;
+ }
+
+ private static GLData createDefaultData() {
+ GLData data = new GLData();
+ data.doubleBuffer = true;
+ data.stencilSize = 8;
+ return data;
+ }
+
+ int foreContext;
+ int backContext;
+
+ private Surface surface;
+ private DirectContext context;
+ private BackendRenderTarget renderTarget;
+
+ public FigureCanvasGL(Composite parent) {
+ this(parent, SWT.NO_REDRAW_RESIZE | SWT.NO_BACKGROUND, createDefaultData());
+ }
+
+ public FigureCanvasGL(Composite parent, int style) {
+ this(parent, style, createDefaultData());
+ }
+
+ public FigureCanvasGL(Composite parent, int style, GLData data) {
+ super(checkStyle(parent, style), parent, new LightweightSystemGL());
+
+ Display display = parent.getDisplay();
+
+ display.setData(USE_OWNDC_KEY, Boolean.FALSE);
+
+ initGL(parent.getDisplay(), data, (style & SWT.MULTI) != 0);
+
+ //getLightweightSystem().setUpdateManager(new DeferredUpdateManagerGL());
+
+ addListener(SWT.Dispose, e -> onDispose());
+ }
+
+ protected void initGL(Display display, GLData data, boolean createBackContext) {
+ display.setData(USE_OWNDC_KEY, Boolean.FALSE);
+ if (data == null)
+ SWT.error(SWT.ERROR_NULL_ARGUMENT);
+ PIXELFORMATDESCRIPTOR pfd = new PIXELFORMATDESCRIPTOR();
+ pfd.nSize = (short) PIXELFORMATDESCRIPTOR.sizeof;
+ pfd.nVersion = 1;
+ pfd.dwFlags = WGL.PFD_DRAW_TO_WINDOW | WGL.PFD_SUPPORT_OPENGL;
+ pfd.dwLayerMask = WGL.PFD_MAIN_PLANE;
+ pfd.iPixelType = (byte) WGL.PFD_TYPE_RGBA;
+ if (data.doubleBuffer) pfd.dwFlags |= WGL.PFD_DOUBLEBUFFER;
+ if (data.stereo) pfd.dwFlags |= WGL.PFD_STEREO;
+ pfd.cRedBits = (byte) data.redSize;
+ pfd.cGreenBits = (byte) data.greenSize;
+ pfd.cBlueBits = (byte) data.blueSize;
+ pfd.cAlphaBits = (byte) data.alphaSize;
+ pfd.cDepthBits = (byte) data.depthSize;
+ pfd.cStencilBits = (byte) data.stencilSize;
+ pfd.cAccumRedBits = (byte) data.accumRedSize;
+ pfd.cAccumGreenBits = (byte) data.accumGreenSize;
+ pfd.cAccumBlueBits = (byte) data.accumBlueSize;
+ pfd.cAccumAlphaBits = (byte) data.accumAlphaSize;
+ pfd.cAccumBits = (byte) (pfd.cAccumRedBits + pfd.cAccumGreenBits + pfd.cAccumBlueBits + pfd.cAccumAlphaBits);
+
+ int hDC = OS.GetDC(handle);
+ int pixelFormat = WGL.ChoosePixelFormat(hDC, pfd);
+ if (pixelFormat == 0 || !WGL.SetPixelFormat(hDC, pixelFormat, pfd)) {
+ OS.ReleaseDC(handle, hDC);
+ dispose();
+ SWT.error(SWT.ERROR_UNSUPPORTED_DEPTH);
+ }
+ foreContext = WGL.wglCreateContext(hDC);
+ if (foreContext == 0) {
+ OS.ReleaseDC(handle, hDC);
+ SWT.error(SWT.ERROR_NO_HANDLES);
+ } else if (createBackContext) {
+ backContext = WGL.wglCreateContext(hDC);
+ if (backContext != 0) {
+ boolean rc = WGL.wglShareLists(foreContext, backContext);
+ if (!rc ) {
+ WGL.wglDeleteContext(backContext);
+ backContext = 0;
+ }
+ }
+ }
+ OS.ReleaseDC(handle, hDC);
+ }
+
+ public boolean setCurrent(boolean set) {
+ return setCurrent(SWT.FOREGROUND, set);
+ }
+
+ public boolean setCurrent(int pos, boolean set) {
+ int ctx = foreContext;
+ if (SWT.BACKGROUND == pos) {
+ //if (backContext == 0) ; //throw @error?
+ if (backContext != 0)
+ ctx = backContext;
+ }
+ return makeCurrent(ctx, set);
+ }
+
+ public void releaseContext() {
+ if (backContext != 0) {
+ if (WGL.wglDeleteContext(backContext))
+ backContext = 0;
+ }
+ if (foreContext != 0) {
+ if (WGL.wglGetCurrentContext() == foreContext)
+ WGL.wglMakeCurrent(0, 0);
+ if (WGL.wglDeleteContext(foreContext))
+ foreContext = 0;
+ }
+ }
+
+ public DirectContext getContext() {
+ if (context == null) {
+ setCurrent(SWT.FOREGROUND, true);
+ context = DirectContext.makeGL();
+ }
+ return context;
+ }
+
+ public Surface getSurface() {
+ checkWidget();
+ if (context == null) {
+ setCurrent(SWT.FOREGROUND, true);
+ context = DirectContext.makeGL();
+ }
+ if (surface == null) {
+ Rectangle rect = getClientArea();
+ renderTarget = BackendRenderTarget.makeGL(rect.width, rect.height, 0, 8, 0, FramebufferFormat.GR_GL_RGBA8);
+ surface = Surface.makeFromBackendRenderTarget(context, renderTarget, SurfaceOrigin.BOTTOM_LEFT, SurfaceColorFormat.RGBA_8888, ColorSpace.getDisplayP3());
+ }
+ return surface;
+ }
+ /*
+ public Canvas getCanvas() {
+ checkWidget();
+ if (context == null) {
+ setCurrent(SWT.FOREGROUND, true);
+ context = DirectContext.makeGL();
+ }
+ if (surface == null) {
+ Rectangle rect = getClientArea();
+ renderTarget = BackendRenderTarget.makeGL(rect.width, rect.height, 0, 8, 0, FramebufferFormat.GR_GL_RGBA8);
+ surface = Surface.makeFromBackendRenderTarget(context, renderTarget, SurfaceOrigin.BOTTOM_LEFT, SurfaceColorFormat.RGBA_8888, ColorSpace.getDisplayP3());
+ }
+ return surface.getCanvas();
+ }
+ //*/
+ public void swapBuffers() {
+ checkWidget();
+ int hDC = OS.GetDC(handle);
+ WGL.SwapBuffers(hDC);
+ OS.ReleaseDC(handle, hDC);
+ }
+
+ protected boolean makeCurrent(int context, boolean set) {
+ boolean rc = false;
+ if (context != 0) {
+ //synchronized (this) {
+ int curContext = WGL.wglGetCurrentContext();
+ if (set) {
+ if (isDisposed()) SWT.error(SWT.ERROR_WIDGET_DISPOSED);
+ if (curContext == context) {
+ rc = true;
+ } else {
+ int hDC = OS.GetDC(handle);
+ rc = WGL.wglMakeCurrent(hDC, context);
+ OS.ReleaseDC(handle, hDC);
+ }
+ } else if (curContext == context) {
+ rc = WGL.wglMakeCurrent(0, 0);
+ }
+ //}
+ }
+ return rc;
+ }
+
+ void releaseSurface() {
+ if (surface != null) {
+ surface.close();
+ surface = null;
+ }
+ if (renderTarget != null) {
+ renderTarget.close();
+ renderTarget = null;
+ }
+ }
+
+ private void releaseResource() {
+ if (context != null) {
+ context.close();
+ context = null;
+ }
+ }
+
+ protected void onResize() {
+ releaseSurface();
+ }
+
+ protected void onDispose() {
+ releaseResource();
+
+ releaseContext();
+ }
+}