/* * 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.primitive; import com.ait.lienzo.client.core.shape.Group; import com.ait.lienzo.client.core.shape.IPrimitive; import com.ait.lienzo.client.core.shape.Rectangle; import com.ait.lienzo.client.core.shape.Text; import com.ait.lienzo.client.core.shape.Triangle; import com.ait.lienzo.client.core.types.BoundingBox; import com.ait.lienzo.client.core.types.Point2D; import com.google.gwt.user.client.Timer; public class PrimitiveTooltip extends PrimitivePopup { private static final double PADDING = 10d; private static final double TRIANGLE_SIZE = 10d; private static final double ALPHA = 1d; private static final String BG_COLOR = "#8c8c8c"; private static final String TEXT_FAMILY = "Verdana"; private static final String TEXT_COLOR = "#FFFFFF"; private static final double TEXT_SIZE = 12d; private static final double TEXT_WIDTH = 1d; private static final int HIDE_TIMEOUT = 3500; /** * This internal timer ensures that if any error on its usage occurs, * it will get removed from the canvas at some point. * Use the method <code>setHideTimeout</code> to change the default timeout value. */ private int hideTimeout = HIDE_TIMEOUT; private final Timer hideTimer = new Timer() { @Override public void run() { PrimitiveTooltip.this.hide(); } }; public enum Direction { NORTH, WEST; } public PrimitiveTooltip() { setzIndex(100); } public void setHideTimeout(final int hideTimeout) { this.hideTimeout = hideTimeout; } public PrimitiveTooltip show(final IPrimitive<?> _glyph, final String text, final double width, final double height, final double x, final double y, final Direction direction) { clearTimers(); final IPrimitive<?> glyph = null != _glyph ? (IPrimitive<?>) _glyph.copy() : null; final Text descText = new Text(text) .setFontSize(TEXT_SIZE) .setFontStyle("") .setFontFamily(TEXT_FAMILY) .setStrokeWidth(TEXT_WIDTH) .setStrokeColor(TEXT_COLOR) .setStrokeAlpha(1); final BoundingBox descTextBB = descText.getBoundingBox(); final double descTextBbW = descTextBB.getWidth(); final double descTextBbH = descTextBB.getHeight(); final double dw = (descTextBbW > width ? (descTextBbW + PADDING) : (width + PADDING)); final double dh = height + descTextBbH + PADDING; final IPrimitive<?> decorator = buildDecorator(dw, dh, direction); final double w = dw + (isWest(direction) ? TRIANGLE_SIZE * 2 : 0); final double h = dh + (isNorth(direction) ? TRIANGLE_SIZE * 2 : 0); ; final Group g = new Group(); g.add(decorator); if (null != glyph) { g.add(glyph); } g.add(descText); super.show(g, w, h, x, y); double _x = (w / 2) + (isWest(direction) ? PADDING / 2 : 0); double _y = PADDING / 2 + (isNorth(direction) ? TRIANGLE_SIZE : 0); if (null != glyph) { glyph.setX(_x - (width / 2)); glyph.setY(_y); _x += width; _y += height; } descText.setX(_x - (descTextBbW / 2)); descText.setY(_y + descTextBbH); // Ensure text is on top. descText.moveToTop(); canvasLayer.draw(); startTimers(); return this; } @Override public PrimitivePopup hide() { clearTimers(); return super.hide(); } @Override public PrimitivePopup remove() { clearTimers(); return super.remove(); } private IPrimitive<?> buildDecorator(final double width, final double height, final Direction direction) { final boolean isWest = isWest(direction); final boolean isNorth = isNorth(direction); final double h2 = height / 2; final double w2 = width / 2; final double s2 = TRIANGLE_SIZE / 2; final Point2D a = isWest ? new Point2D(0, h2) : new Point2D(10, 0); final Point2D b = isWest ? new Point2D(TRIANGLE_SIZE, h2 + s2) : new Point2D(10 + s2, TRIANGLE_SIZE); final Point2D c = isWest ? new Point2D(TRIANGLE_SIZE, h2 - s2) : new Point2D(10 - s2, TRIANGLE_SIZE); final Triangle triangle = new Triangle(a, b, c) .setFillColor(BG_COLOR) .setFillAlpha(ALPHA) .setStrokeWidth(0); final Rectangle rectangle = new Rectangle( width + (isWest ? TRIANGLE_SIZE : 0), height + (isNorth ? TRIANGLE_SIZE : 0)) .setX(isWest ? TRIANGLE_SIZE : 0) .setY(isWest ? 0 : TRIANGLE_SIZE) .setCornerRadius(10) .setFillColor(BG_COLOR) .setFillAlpha(ALPHA) .setStrokeAlpha(0) .setCornerRadius(5); final Group decorator = new Group(); decorator.add(rectangle); decorator.add(triangle); return decorator; } private boolean isWest(final Direction direction) { return Direction.WEST.equals(direction); } private boolean isNorth(final Direction direction) { return Direction.NORTH.equals(direction); } private void startTimers() { this.hideTimer.schedule(hideTimeout); } private void clearTimers() { if (null != this.hideTimer) { if (this.hideTimer.isRunning()) { this.hideTimer.cancel(); } } } }