Skip to main content

Notice: this Wiki will be going read only early in 2024 and edits will no longer be possible. Please see: https://gitlab.eclipse.org/eclipsefdn/helpdesk/-/wikis/Wiki-shutdown-plan for the plan.

Jump to: navigation, search

Difference between revisions of "GEF/GEF4/SwtFX"

< GEF‎ | GEF4
m
(Redirect page to GEF/GEF4/FX, because GEF4 SwtFX component was merged into GEF4 FX)
 
(8 intermediate revisions by 2 users not shown)
Line 1: Line 1:
''Note to non-wiki readers: This documentation is generated from the Eclipse wiki - if you have corrections or additions it would be awesome if you added them in [http://wiki.eclipse.org/GEF/GEF4/SwtFx the original wiki page]''.
+
#REDIRECT [[GEF/GEF4/FX]]
 
+
== Introduction ==
+
 
+
The GEF4 SwtFX component provides abstractions for the combined rendering of lightweight (shape and canvas figures) and non-lightweight (SWT widgets) objects. The API is inspired by concepts of JavaFX, such as the event system (event bubbling and capturing). It is intended to replace the core of Draw2d.
+
 
+
The component is subdivided into different packages:
+
 
+
* '''org.eclipse.gef4.swtfx''', partially implemented<br />Contains classes and interfaces for the combined rendering of ligthweight scene graph nodes and heavyweight SWT widgets.
+
* '''org.eclipse.gef4.swtfx.events''', partially implemented<br />Contains the event system of the component. Implements event bubbling and capturing phases.
+
* '''org.eclipse.gef4.swtfx.gc''', implemented<br />Contains a GraphicsContext implementation similar to the JavaFX GraphicsContext2D using SWT under the hood. (Many lines of code from the old Graphics component found its way into this package.)
+
* '''org.eclipse.gef4.swtfx.layout''', partially implemented<br />Contains default layout managers and corresponding functionality.
+
* '''org.eclipse.gef4.swtfx.animation''', planned<br />Provides timeline animation and transition animation support.
+
 
+
== Key abstractions ==
+
 
+
* '''package: org.eclipse.gef4.swtfx'''
+
 
+
The SwtFX component provides a scene graph model which can be embedded into an SWT application. The scene graph model consists of leaf nodes and composite parent nodes (containing other parents/leaves). As you can see in the following diagram, the constellation reflects the standard composite design pattern:
+
 
+
[[Image:GEF4SwtFX-key-abstractions.jpg|Key abstractions]]
+
 
+
The INode, IFigure, and IParent interfaces are the key abstractions used within the GEF4 SwtFX component. The INode interface describes the general behavior inherent to all nodes. The other two interfaces refine and extend that behavior: Leaf nodes implement the IFigure interface and composite nodes implement the IParent interface.
+
 
+
Parent nodes and figure nodes take different responsibilities. The figure nodes are responsible for drawing themselves (during rendering phases). That's why their interface allows the manipulation of several drawing attributes. Parent nodes are responsible for laying out their children, i.e. they can take control of their children's positions and sizes. All nodes can perform hit testing, i.e. they can tell if a screen location is incident to their visual representation. Additionally, all nodes are possible event targets, so that they can react to keyboard, mouse, or other events.
+
 
+
[[Image:GEF4SwtFX-abstract-realizations.jpg|Abstract realizations]]
+
 
+
SwtFX provides abstract implementations of these interfaces which serve as the basis for all nodes. The majority of methods specified in the INode interface is implemented by AbstractNode. The AbstractFigure class implements getters and setters for drawing attributes. Besides it does ensure that the GraphicsContext used to draw the figure is restored to its initial state after drawing. The AbstractParent class implements layout and rendering propagation.
+
 
+
If you wish to implement a custom parent or figure node, all you have to do is extend the corresponding abstract realization and override the appropriate methods. You can take a look at the provided parent and figure nodes as a source of inspiration.
+
 
+
[[Image:GEF4SwtFX-concrete-implementations.jpg|Concrete implementations]]
+
 
+
The SwtFX component ships with two IFigure implementations and several IParent implementations. The provided figure nodes are called CanvasFigure and ShapeFigure. A CanvasFigure displays a rectangular area in which you can draw using a GraphicsContext. A ShapeFigure displays a geometric shape - an object of the GEF4 Geometry component - on the screen. The shape is filled and stroked by default. The provided parent nodes implement different layout procedures. HBox and VBox, for example, are laying out their children horizontally or vertically, respectively.
+
 
+
Moreover, there is one INode implementation which is neither a figure nor a parent. This is the ControlNode class. A ControlNode is used to embed SWT controls into the scene graph. The ControlNode class consists of glueing both systems together, i.e. redirecting events, manipulating SWT bounds, and computing a local transformation matrix for the ControlNode, so that the wrapped SWT control's bounds are always axis aligned (because SWT controls are not rotatable).
+
 
+
=== Scene ===
+
 
+
[[Image:GEF4SwtFX-Scene-class.png|left|Scene class diagram]]
+
 
+
As scene graph hierarchy and SWT widget hierarchy are not shared, a special SWT widget is used to embed a scene graph. This widget is provided by SwtFX and is called Scene. A Scene stores the root node of a scene graph (always an IParent) and propagates SWT events through that scene graph. A Scene does also schedule update, layout, and render phases.
+
 
+
As you can see in the class diagram, you need an SWT Composite and an IParent to construct a Scene. The Scene class itself extends the SWT Canvas class. Therefore, it is part of the SWT widget hierarchy and can contain other SWT controls. The Composite that is given to the Scene is the parent widget (SWT) of the Scene. Using SWT layout managers, you can make the Scene take all available space. The IParent that is given to the Scene is the root node of the scene graph to display.
+
 
+
The Scene is tightly coupled with the event system (because it has to redirect SWT events). That's why the current mouse target and focus target nodes are also managed by the Scene. Additionally, the Scene can serve as the SWT parent for SWT controls that you want to wrap in a ControlNode. Example:
+
 
+
<source lang="Java">
+
ControlNode<Button> button = new ControlNode<Button>(
+
    new Button(root.getScene(), SWT.PUSH)
+
//            ^^^^^^^^^^^^^^^
+
);
+
button.getControl().setText("refresh");
+
button.relocate(10, 10);
+
button.addEventHandler(
+
    ActionEvent.SELECTION,
+
    new IEventHandler<ActionEvent>() {
+
        @Override
+
        public void handle(ActionEvent event) {
+
            root.getScene().refreshVisuals();
+
        }
+
    }
+
);
+
</source>
+
 
+
<div style="clear: both"></div>
+
 
+
=== INode ===
+
 
+
The INode interface describes the general behavior inherent to all GEF4 scene graph nodes. This comprises several attributes resp. operations to query and manipulate those attributes. Arguably, the most important node attributes are its different bounds types. These different bounds types differ in the perspective of the beholder:
+
 
+
[[Image:GEF4SwtFX-bounds-diagram.png|Different bounds types]]
+
 
+
Each node has its own local coordinate system in which a bounds representation exists. The bounds representation in the local coordinate system of a node is called ''layout-bounds''. As the name indicates, these bounds are considered during layout calculations. Another important type of bounds are the ''bounds-in-local'', which take into account drawing attributes, such as clipping area and stroke. Every node manages a set of local transformation attributes to rotate, scale, and translate the node. After applying those transformations to the bounds-in-local, you receive the so called ''bounds-in-parent'', because such a bounds object is in the local coordinate system of the node's parent.
+
 
+
This is a list of all transformation attributes:
+
 
+
* ''translate-x'' and ''translate-y''<br />Translate the node by x and y coordinates.
+
* ''pivot-x'' and ''pivot-y''<br />Pivot point for scale and rotate operations.
+
* ''scale-x'' and ''scale-y''<br />Scale the node horizontally and vertically around its pivot point.
+
* ''rotate''<br />Rotate the node by a specified angle around its pivot point.
+
* ''transforms''<br />Dynamic list of transformation matrices which are applied on top of the other transformations.
+
 
+
Additionally, a node has ''layout-x'' and ''layout-y'' attributes which are set during layout and translate the node to its determined screen location. The translate-x and translate-y attributes, on the other hand, specify a translation which is not included in the layout calculations (per default).
+
 
+
Another important set of node attributes are the layout related attributes ''min-width'', ''min-height'', ''pref-width'', ''pref-height'', ''max-width'', and ''max-height''. They are evaluated by layout managers (i.e. parent nodes) to find out how much space has to be assigned, should be assigned, and can be assigned to a node, respectively. When a parent node takes control of positions and sizes of its children (i.e. layout), it may provide a mechanism to constraint those positions and sizes. For example, an HBox has more space available than is needed for its children, it may be constrained to distribute the exceeding space equally among them. In that case, the HBox will not resize any child above its maximum width.
+
 
+
Consequently, if you want a node to grow arbitrarily, you have to set its maximum size correctly:
+
 
+
<source lang="Java">
+
ShapeFigure box = new ShapeFigure(new Rectangle(0, 0, 100, 100));
+
box.setMaxWidth(Double.MAX_VALUE);
+
box.setMaxHeight(Double.MAX_VALUE);
+
hbox.add(box, new HBoxConstraints());
+
</source>
+
 
+
Other layout managers may wish to ignore the maximal, minimal, and preferred sizes. Laying out nodes can be separated from the scene graph and its abstractions using an IParent implementation that delegates layout calculations to a pure layout manager.
+
 
+
=== IFigure ===
+
 
+
The IFigure interface specifies the behavior of figure nodes in the scene graph. Figure nodes are leaf nodes, i.e. they do not have any children. Instead, they are used to display content. An IFigure is responsible for drawing itself during rendering phases. Similar to other frameworks, a GraphicsContext is used to perform all drawing operations. The two provided IFigure implementations serve different purposes:
+
 
+
* A ShapeFigure consists of a geometric object such as Rectangle, Ellipse, or Polygon (an IShape of the GEF4 Geometry component). During rendering, a ShapeFigure fills the interior of its associated IShape and traces its outline. Both operations are standard GraphicsContext operations called ''fill'' and ''stroke'', respectively. The colors/gradients/images used to fill resp. stroke an object are stored as attributes of the ShapeFigure.
+
* A CanvasFigure consists of a raster image to draw into using a GraphicsContext. A planned feature is to be able to apply image filters/effects to the final raster image.
+
 
+
=== IParent ===
+
 
+
The IParent interface specifies the behavior of parent nodes in the scene graph. Parent nodes are composite nodes, i.e. they can have children. Besides, a parent node is not responsible for displaying content, although it has the possibility to do so, which is discouraged. The only reason for parent nodes to be able to perform drawing operations, is that they have to pass a GraphicsContext through to their child figures. Possibly, this implementation detail may not be revealed in the future.
+
 
+
Other than that, a parent node takes the responsibility to perform layout calculations for their managed children. Each of the IParent implementations implements another layout procedure. In this regard, the Group is special, as it does not layout its children. The Group is only used to group scene graph nodes together in oder to be able to control some of their attributes simultanously.
+
 
+
== Event system ==
+
 
+
* '''package: org.eclipse.gef4.swtfx.event'''
+
 
+
In comparison to SWT, the event system exclusively uses typed event objects. The event types (and classes) are organized hierarchical, so that you can define event listeners for superordinate event types which will get called when any descendent event is fired. One event class may define and implement many event types. Event types are always defined as constants in an event class.
+
 
+
[[Image:GEF4SwtFX-event-hierarchy.jpg|Event hierarchy]]
+
 
+
<pre>EventType instances (incomplete):
+
 
+
Event.ANY
+
+- InputEvent.ANY
+
|  +- MouseEvent.ANY
+
|  |  +- MouseEvent.MOUSE_PRESSED
+
|  |  +- MouseEvent.MOUSE_RELEASED
+
|  |  +- MouseEvent.MOUSE_SCROLLED
+
|  |  +- MouseEvent.MOUSE_MOVED
+
|  |  +- MouseEvent.MOUSE_ENTERED_TARGET
+
|  |  |  +- MouseEvent.MOUSE_ENTERED
+
|  |  +- MouseEvent.MOUSE_EXITED_TARGET
+
|  |      +- MouseEvent.MOUSE_EXITED
+
|  +- KeyEvent.ANY
+
|      +- KeyEvent.KEY_PRESSED
+
|      +- KeyEvent.KEY_RELEASED
+
+- ActionEvent.ANY
+
    +- ActionEvent.SELECTION
+
    +- ActionEvent.RESIZE</pre>
+
 
+
If several event listeners can react to an occured event, the one with the most special event type will be called first. Assuming you would define an event listener for InputEvent.ANY and a listener for MouseEvent.ANY, the MouseEvent.ANY listener would be called before the InputEvent.ANY listener, when a mouse event occurs.
+
 
+
To be able to react to events, you have to implement the IEventTarget interface. An IEventTarget is responsible for building an EventDispatchChain. In general, all the parent nodes (up to the root) are prepended to the EventDispatchChain. INode extends the IEventTarget interface, therefore all nodes can be used as event targets.
+
 
+
Every INode manages an IEventDispatcher to add and remove event listeners to the node and to dispatch incoming events to the correct listeners. The IEventDispatcher differentiates between event handlers and event filters. Both are implementations of the IEventHandler interface, but they are executed during different phases of event propagation.
+
 
+
=== Event propagation ===
+
 
+
When an event is fired, 4 different steps are executed:
+
 
+
# Target Selection
+
#:Several rules exist to determine the event target (IEventTarget) for the fired event:
+
#:* For keyboard events, the current focus target will be the event target.
+
#:* For mouse events, the current mouse target will be the event target.
+
#:* If no node currently has keyboard or mouse focus, or the event is of another type, then the node under the mouse pointer will be the event target.
+
# Route Construction
+
#:The selected IEventTarget is utilized to get the IEventDispatchChain for further event processing. Basically, an event dispatch chain is just a list of IEventTargets. Usually, the list consists of all nodes from the root of the scene graph down to the selected event target.
+
# Event Capturing
+
#:The event object travels along the IEventDispatchChain. On its way, all registered ''event-filters'' can process, and eventually consume, the event. Event processing terminates, if an event is consumed.
+
# Event Bubbling
+
#:If the event reaches the selected IEventTarget, it will travel back the IEventDispatchChain to the root. On its way, all registered ''event-handlers'' can process, and eventually consume, the event.
+
 
+
== Layout Panes ==
+
 
+
* '''package: org.eclipse.gef4.swtfx.layout'''
+
 
+
Several layout managers are implemented per default:
+
 
+
* Pane<br />The Pane autosizes its children. TODO: more about autosize
+
* HBox<br />The HBox lays out its children horizontally.
+
* VBox<br />The VBox lays out its children vertically.
+
* BorderPane<br />The BorderPane divides its area into 5 sections -- left, right, top, bottom, and center -- each of them displays an individual node.
+
* AnchorPane<br />The AnchorPane lays out its children relative to its left, right, top, and bottom edges.
+
 
+
== GraphicsContext ==
+
 
+
* '''package: org.eclipse.gef4.swtfx.gc'''
+
 
+
The GraphicsContext is used to perform drawing operations on an image/the screen. For example, you can retrieve a GraphicsContext to draw into a CanvasFigure like so:
+
 
+
<source lang="Java">
+
CanvasNode canvas = new CanvasNode(400, 300);
+
GraphicsContext gc = canvas.getGraphicsContext();
+
gc.arc(100, 100, 40, 60, 10, 90);
+
gc.rect(10, 10, 20, 20);
+
gc.fill();
+
gc.cleanUp();
+
</source>
+
 
+
To a great extent, the GraphicsContext is the former GEF4 Graphics component. The Graphics documentation and examples will soon be transferred to SwtFX and this wiki.
+
 
+
== Animations ==
+
 
+
* '''package: org.eclipse.gef4.swtfx.animation'''
+
 
+
GEF4 SwtFX will support arbitrary animations and make it especially easy to define a small set of transition animations. At the time of writing, the following transitions are partially implemented:
+
 
+
* RotateTransition<br />Rotates a node over time.
+
* PathTransition<br />Moves a node along a path over time.
+
* ParallelTransition<br />Compound transition which executes several transitions at once.
+
 
+
The following example program demonstrates those transitions:
+
 
+
<source lang="java">
+
/*******************************************************************************
+
* Copyright (c) 2013 itemis AG 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:
+
*    Matthias Wienand (itemis AG) - initial API and implementation
+
*
+
*******************************************************************************/
+
package org.eclipse.gef4.swt.fx.examples;
+
 
+
import org.eclipse.gef4.geometry.planar.Point;
+
import org.eclipse.gef4.geometry.planar.Rectangle;
+
import org.eclipse.gef4.swtfx.Group;
+
import org.eclipse.gef4.swtfx.Scene;
+
import org.eclipse.gef4.swtfx.ShapeFigure;
+
import org.eclipse.gef4.swtfx.animation.ParallelTransition;
+
import org.eclipse.gef4.swtfx.animation.PathTransition;
+
import org.eclipse.gef4.swtfx.animation.RotateTransition;
+
import org.eclipse.swt.widgets.Shell;
+
 
+
public class ParallelTransitionExample extends Application {
+
public static void main(String[] args) {
+
new ParallelTransitionExample();
+
}
+
 
+
@Override
+
public Scene start(Shell shell) {
+
Group root = new Group();
+
root.setPrefWidth(400);
+
root.setPrefHeight(300);
+
 
+
ShapeFigure box = new ShapeFigure(new Rectangle(0, 0, 100, 50));
+
box.setPivot(new Point(50, 25));
+
 
+
root.addChildNodes(box);
+
Scene scene = new Scene(shell, root);
+
 
+
new ParallelTransition(new PathTransition(2500, new Rectangle(0, 0,
+
300, 250).toPath(), box), new RotateTransition(2500, box, 0,
+
720)).play();
+
 
+
return scene;
+
}
+
}
+
</source>
+
 
+
=== Interpolators ===
+
 
+
Per default, all transitions use linear interpolation to compute the attribute values at a specific time. But you can specify another IInterpolator implementation for your transitions. An IInterpolator is used to generate interpolation factors in range <tt>[0;1]</tt> which are used to interpolate attribute values between two states A and B during a transition. For convenience, the smoothstep function is provided by SwtFX as the IInterpolator.SMOOTH_STEP. The smoothstep interpolator will accelerate the animation at the start and slow it down at the end:
+
 
+
[[Image:GEF4SwtFX-smoothstep.png|smoothstep function]]
+

Latest revision as of 16:18, 11 August 2014

Redirect to:

Back to the top