Adding is done via mouse right-click. A palette is opened (with one item only) that will be added when pressed.
Removed of nodes can be done in two ways. Either hover over the node, a handle tool with red cross is shown. Or select the node and press DEL key.
For the source of this tutorial step see github - gef4.mvc.tutorial7.
Note: parts of this tutorial are copied from other examples or from forum postings.
For the source of this tutorial step see github - gef4.mvc.tutorial7.
Note: parts of this tutorial are copied from other examples or from forum postings.
Creating a palette on right-click
The new palette to add items, shall show up, when clicked on the canvas. For this, we bind a policy to the root part adapter map.
adapterMapBinder
.addBinding(
AdapterKey.get(FXClickDragTool.CLICK_TOOL_POLICY_KEY,
"FXCreationMenuOnClick"))
.to(FXCreationMenuOnClickPolicy.class);
Then we need to test if the click is really on this canvas. And it is needed to store the coordinates in 2 ways
1. in screen coordinates, to position the palette as popup.
2. in the canvas coordinates, which might be even different in scaling, if the viewer is currently zoomed.
FXCreationMenuOnClickPolicy extends AbstractFXOnClickPolicy. The click() method looks like this:
@Override
public
void
click(MouseEvent e)
{
//
open menu on right click
if
(MouseButton.SECONDARY.equals(e.getButton()))
{
initialMousePositionInScreen
= new
Point2D(e.getScreenX(),
e.getScreenY());
//
use the viewer to transform into local coordinates
//
this works even if the viewer is scrolled and/or zoomed.
InfiniteCanvas
infiniteCanvas
= getViewer().getCanvas();
initialMousePositionInScene
=
infiniteCanvas.getContentGroup().screenToLocal(initialMousePositionInScreen);
//
only open if the even was on the visible canvas
if(
infiniteCanvas.getBoundsInLocal().contains(initialMousePositionInScene)
){
openMenu(e);
}
}
}
As palette, a Java FX popup is used. The image is set as graphics into a button instance in the popup. So we automatically have some hover behavior from the button.
The popup is set to have a border line and a shadow, to look like a context menu.
Adding a new TextNode
The action now is again done via an operation, so it can be undone.
GEF4 provides a ready to use policy for this, the CreationPolicy.
CreationPolicy<Node>
creationPolicy
= root.getAdapter(CreationPolicy.class);
creationPolicy.init();
creationPolicy.create(
textNode,
contentPartModel,
HashMultimap.create());
The textNode is the newly create object for the model. The contentPartModel is the ModelPart instance, that shall add the textNode.
The CreatePolicy delegates the work to the ModelPart#doAddContentChild(), which must be overridden, otherwise the base class implementation will throw an exception.
Deleting via short cut
Deletion of parts is just a matter of registering the TextNodePart:
adapterMapBinder.addBinding(AdapterKey.get(FXTypeTool.TOOL_POLICY_KEY))
.to(FXDeleteSelectedOnTypePolicy.class);
It delegates the model changes to the parents part doAddContentChild() and doRemoveContentChild().
Delete with the handle tool
This implementation is completely taken from the Logo example.
This deletion is implemented as an icon getting visible when hovering over the TextNodePart.
HoverHandleRootPart is a parent for optionally more than one such handle action. Now we have only one action, the deletion, but there may be more to add. So HoverHandleRootPart manages the position at the upper left corner of the TextNodePart, and adds child handle parts in a VBox vertically downwards.
HandlePartFactory creates the handle parts. It is registered in the overriden bindIHandlePartFactory() of the GuiceModule. When requested to give the handle parts for TextNodePart, it constructs the HoverHandleRootPart with one child, the DeleteHoverHandlePart.
The DeleteHoverHandlePart gets a policy DeleteOnClickPolicy attached, that implements the action to be done. In this case, it delegates to the DeletionPolicy, which is part of GEF4.