/* * Copyright 2016 Red Hat, Inc. and/or its affiliates. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.kie.workbench.common.stunner.lienzo.toolbox; import java.util.logging.Level; import java.util.logging.Logger; import com.ait.lienzo.client.core.shape.IDrawable; import com.ait.lienzo.client.core.shape.IPrimitive; import com.ait.lienzo.client.core.shape.Layer; import com.ait.lienzo.client.core.shape.MultiPath; import com.ait.lienzo.client.core.shape.wires.WiresManager; import com.ait.lienzo.client.core.shape.wires.WiresShape; import com.ait.lienzo.client.core.shape.wires.WiresUtils; import com.ait.lienzo.client.core.types.Point2D; import com.ait.tooling.nativetools.client.event.HandlerRegistrationManager; import com.google.gwt.user.client.Timer; import org.kie.workbench.common.stunner.lienzo.toolbox.event.ToolboxButtonEvent; import org.kie.workbench.common.stunner.lienzo.toolbox.event.ToolboxButtonEventHandler; import org.kie.workbench.common.stunner.lienzo.util.LienzoPaths; public class ToolboxButton { private static Logger LOGGER = Logger.getLogger(ToolboxButton.class.getName()); private static final int CLICK_HANDLER_TIMER_DURATION = 100; private static final double STROKE0 = 0; private static final double STROKE1 = 0.8; private static final String DECORATOR_STROKE_COLOR = "#0000FF"; private final WiresShape primitive; private final Layer layer; private final HandlerRegistrationManager handlerRegistrationManager = new HandlerRegistrationManager(); private ToolboxButtonEventHandler clickHandler; private ToolboxButtonEventHandler mouseDownHandler; private ToolboxButtonEventHandler mouseEnterHandler; private ToolboxButtonEventHandler mouseExitHandler; private Timer clickHandlerTimer; private MultiPath decorator; public ToolboxButton(final Layer layer, final IPrimitive<?> shape, final int padding, final int iconSize, final ToolboxButtonEventHandler clickHandler, final ToolboxButtonEventHandler mouseDownHandler, final ToolboxButtonEventHandler mouseEnterHandler, final ToolboxButtonEventHandler mouseExitHandler) { this.layer = layer; this.clickHandler = clickHandler; this.mouseDownHandler = mouseDownHandler; this.mouseEnterHandler = mouseEnterHandler; this.mouseExitHandler = mouseExitHandler; this.primitive = build(shape, iconSize, padding); this.clickHandlerTimer = null; } public WiresShape getShape() { return primitive; } public MultiPath getDecorator() { return decorator; } public void remove() { clearClickHandlerTimer(); handlerRegistrationManager.removeHandler(); decorator.removeFromParent(); primitive.removeFromParent(); layer.batch(); } private WiresShape build(final IPrimitive<?> shape, final int padding, final int iconSize) { final WiresManager manager = WiresManager.get(layer); // Create the wires shape multipath that will be used as decorator. final int size = iconSize * 2; final float pad = padding / 2; decorator = LienzoPaths.rectangle(size + pad, size + pad, 0) .setX(-pad / 2) .setY(-pad / 2) .setStrokeWidth(1) .setStrokeAlpha(STROKE0) .setStrokeColor(DECORATOR_STROKE_COLOR) .setDraggable(false) .setFillBoundsForSelection(true); // Create and register the wires shape. final WiresShape wiresShape = new WiresShape(decorator).setDraggable(false).setResizable(false); manager.register(wiresShape, false); // Add the primitive shape as child. wiresShape.addChild(shape.setDraggable(false)); decorator.moveToTop(); registerShapeHandlers(wiresShape, decorator); return wiresShape; } private void registerShapeHandlers(final WiresShape wiresShape, final IDrawable<?> shape) { // Add mouse enter event handlers for the wiresshape's multipath. handlerRegistrationManager.register( shape.addNodeMouseEnterHandler(event -> onButtonMouseEnter(shape, getLocation(wiresShape), wiresShape.getGroup().getAbsoluteLocation(), event.getHumanInputEvent().getClientX(), event.getHumanInputEvent().getClientY()) )); // Add mouse exit event handlers for the wiresshape's multipath. handlerRegistrationManager.register( shape.addNodeMouseExitHandler(event -> onButtonMouseExit(shape, getLocation(wiresShape), wiresShape.getGroup().getAbsoluteLocation(), event.getHumanInputEvent().getClientX(), event.getHumanInputEvent().getClientY()) )); if (null != clickHandler) { // Add mouse click event handlers for the primitive shape. handlerRegistrationManager.register( shape.addNodeMouseClickHandler(event -> ToolboxButton.this.onButtonMouseClick(shape, getLocation(wiresShape), wiresShape.getGroup().getAbsoluteLocation(), event.getHumanInputEvent().getClientX(), event.getHumanInputEvent().getClientY()) )); } if (null != mouseDownHandler) { // Add mouse down event handlers for the primitive shape. handlerRegistrationManager.register( shape.addNodeMouseDownHandler(event -> ToolboxButton.this.onButtonMouseDown(shape, getLocation(wiresShape), wiresShape.getGroup().getAbsoluteLocation(), event.getHumanInputEvent().getClientX(), event.getHumanInputEvent().getClientY()) )); } } private Point2D getLocation(final WiresShape shape) { return WiresUtils.getLocation(shape.getGroup()); } private void onButtonMouseEnter(final IDrawable<?> shape, final Point2D location, final Point2D abs, final int clientX, final int clientY) { LOGGER.log(Level.FINE, "Entering into toolbox button..."); showDecorator(); if (null != mouseEnterHandler) { mouseEnterHandler.fire(buildEvent(location, abs, clientX, clientY)); } layer.batch(); } private void onButtonMouseExit(final IDrawable<?> shape, final Point2D location, final Point2D abs, final int clientX, final int clientY) { LOGGER.log(Level.FINE, "Exiting from toolbox button..."); hideDecorator(); if (null != mouseExitHandler) { mouseExitHandler.fire(buildEvent(location, abs, clientX, clientY)); } layer.batch(); } private void onButtonMouseClick(final IDrawable<?> shape, final Point2D location, final Point2D abs, final int clientX, final int clientY) { LOGGER.log(Level.FINE, "Clicking on toolbox button..."); hideDecorator(); ToolboxButton.this.clearClickHandlerTimer(); clickHandler.fire( buildEvent(location, abs, clientX, clientY)); layer.batch(); } private void onButtonMouseDown(final IDrawable<?> shape, final Point2D location, final Point2D abs, final int clientX, final int clientY) { if (null == ToolboxButton.this.clickHandlerTimer) { ToolboxButton.this.clickHandlerTimer = new Timer() { @Override public void run() { LOGGER.log(Level.FINE, "Mouse down on toolbox button..."); hideDecorator(); layer.batch(); mouseDownHandler.fire( buildEvent(location, abs, clientX, clientY)); ToolboxButton.this.clickHandlerTimer = null; } }; ToolboxButton.this.clickHandlerTimer.schedule(CLICK_HANDLER_TIMER_DURATION); } } private void showDecorator() { decorator.setStrokeAlpha(STROKE1); } private void hideDecorator() { decorator.setStrokeAlpha(STROKE0); } private ToolboxButtonEvent buildEvent(final Point2D location, final Point2D abs, final int clientX, final int clientY) { return new ToolboxButtonEvent() { @Override public int getX() { return (int) location.getX(); } @Override public int getY() { return (int) location.getY(); } @Override public int getAbsoluteX() { return (int) abs.getX(); } @Override public int getAbsoluteY() { return (int) abs.getY(); } @Override public int getClientX() { return clientX; } @Override public int getClientY() { return clientY; } }; } private void clearClickHandlerTimer() { if (null != this.clickHandlerTimer) { if (this.clickHandlerTimer.isRunning()) { this.clickHandlerTimer.cancel(); } this.clickHandlerTimer = null; } } }