blob: c7ee066ffb8d1e3ad9f386eaea61af7764abe219 [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2021 Johannes Kepler University Linz
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0.
*
* SPDX-License-Identifier: EPL-2.0
*
* Contributors:
* Alois Zoitl - initial API and implementation and/or initial documentation
*******************************************************************************/
package org.eclipse.fordiac.ide.gef.figures;
import org.eclipse.core.runtime.Assert;
import org.eclipse.draw2d.AbstractBackground;
import org.eclipse.draw2d.ColorConstants;
import org.eclipse.draw2d.Graphics;
import org.eclipse.draw2d.IFigure;
import org.eclipse.draw2d.geometry.Insets;
import org.eclipse.draw2d.geometry.Rectangle;
import org.eclipse.fordiac.ide.gef.preferences.DiagramPreferences;
class FBShapeShadowBorder extends AbstractBackground {
private static final int SHADOW_ALPHA = 25;
private static final int SHADOW_SIZE = 6;
protected static final Insets SHADOW_INSETS = new Insets(2, 2, SHADOW_SIZE, SHADOW_SIZE * 2 / 3);
@Override
public Insets getInsets(final IFigure figure) {
return SHADOW_INSETS;
}
@Override
public boolean isOpaque() {
return true;
}
@Override
public void paintBackground(final IFigure figure, final Graphics graphics, final Insets insets) {
Assert.isTrue(figure instanceof FBShape);
final FBShape fbShape = (FBShape) figure;
graphics.pushState();
graphics.setBackgroundColor(ColorConstants.black);
final Rectangle topShadowRect = fbShape.getTop().getBounds().getExpanded(2, 2);
final Rectangle middleShadowRect = fbShape.getMiddle().getBounds().getExpanded(2, 0);
final Rectangle bottomShadowRect = fbShape.getBottom().getBounds().getExpanded(2, 2);
final Rectangle clipRect = topShadowRect.getCopy();
clipRect.union(middleShadowRect);
clipRect.union(bottomShadowRect);
clipRect.width += SHADOW_SIZE;
clipRect.height += SHADOW_SIZE;
graphics.setClip(clipRect);
drawShadowHalo(graphics, topShadowRect, middleShadowRect, bottomShadowRect);
drawDropShadow(graphics, topShadowRect, middleShadowRect, bottomShadowRect);
graphics.popState();
}
private static void drawShadowHalo(final Graphics graphics, final Rectangle topShadowRect,
final Rectangle middleShadowRect, final Rectangle bottomShadowRect) {
graphics.setAlpha(SHADOW_ALPHA);
drawShadowFigure(graphics, topShadowRect, middleShadowRect, bottomShadowRect);
topShadowRect.shrink(1, 1);
middleShadowRect.shrink(1, 0);
bottomShadowRect.shrink(1, 1);
graphics.setAlpha(2 * SHADOW_ALPHA);
drawShadowFigure(graphics, topShadowRect, middleShadowRect, bottomShadowRect);
}
private static void drawDropShadow(final Graphics graphics, final Rectangle topShadowRect,
final Rectangle middleShadowRect, final Rectangle bottomShadowRect) {
graphics.setAlpha(SHADOW_ALPHA);
final double horInc = 0.8; // emulate a roughly 30° shadow angle
double horI = 0;
for (int i = 0; i < SHADOW_SIZE; i++) {
horI += horInc;
topShadowRect.translate((int) horI, 1);
middleShadowRect.translate((int) horI, 1);
bottomShadowRect.translate((int) horI, 1);
drawShadowFigure(graphics, topShadowRect, middleShadowRect, bottomShadowRect);
if (horI > 1.0) {
horI -= 1.0;
}
}
}
private static void drawShadowFigure(final Graphics graphics, final Rectangle topShadowRect,
final Rectangle middleShadowRect, final Rectangle bottomShadowRect) {
graphics.fillRoundRectangle(topShadowRect, DiagramPreferences.CORNER_DIM, DiagramPreferences.CORNER_DIM);
graphics.fillRectangle(middleShadowRect);
graphics.fillRoundRectangle(bottomShadowRect, DiagramPreferences.CORNER_DIM, DiagramPreferences.CORNER_DIM);
}
}