/*
* Copyright 2000-2016 JetBrains s.r.o.
*
* 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 com.intellij.ui;
import com.intellij.icons.AllIcons.Ide.Notification.Shadow;
import com.intellij.openapi.ui.popup.Balloon;
import com.intellij.openapi.util.IconLoader;
import com.intellij.util.ui.JBInsets;
import com.intellij.util.ui.UIUtil;
import org.jetbrains.annotations.NotNull;
import javax.swing.*;
import java.awt.*;
import java.awt.geom.Rectangle2D;
import java.awt.geom.RoundRectangle2D;
/**
* @author Alexander Lobas
*/
public class NotificationBalloonShadowBorderProvider implements BalloonImpl.ShadowBorderProvider {
private static final Insets INSETS = new JBInsets(4, 6, 8, 6);
private final Color myFillColor;
private final Color myBorderColor;
public NotificationBalloonShadowBorderProvider(@NotNull Color fillColor, @NotNull Color borderColor) {
myFillColor = fillColor;
myBorderColor = borderColor;
}
@NotNull
@Override
public Insets getInsets() {
return INSETS;
}
@Override
public void paintShadow(@NotNull JComponent component, @NotNull Graphics g) {
int width = component.getWidth();
int height = component.getHeight();
int topLeftWidth = Shadow.Top_left.getIconWidth();
int topLeftHeight = Shadow.Top_left.getIconHeight();
int topRightWidth = Shadow.Top_right.getIconWidth();
int topRightHeight = Shadow.Top_right.getIconHeight();
int bottomLeftWidth = Shadow.Bottom_left.getIconWidth();
int bottomLeftHeight = Shadow.Bottom_left.getIconHeight();
int bottomRightWidth = Shadow.Bottom_right.getIconWidth();
int bottomRightHeight = Shadow.Bottom_right.getIconHeight();
int topWidth = Shadow.Top.getIconWidth();
int bottomWidth = Shadow.Bottom.getIconWidth();
int bottomHeight = Shadow.Bottom.getIconHeight();
int leftHeight = Shadow.Left.getIconHeight();
int rightWidth = Shadow.Right.getIconWidth();
int rightHeight = Shadow.Right.getIconHeight();
drawLine(component, g, Shadow.Top, width, topLeftWidth, topRightWidth, topWidth, 0, true);
drawLine(component, g, Shadow.Bottom, width, bottomLeftWidth, bottomRightWidth, bottomWidth, height - bottomHeight, true);
drawLine(component, g, Shadow.Left, height, topLeftHeight, bottomLeftHeight, leftHeight, 0, false);
drawLine(component, g, Shadow.Right, height, topRightHeight, bottomRightHeight, rightHeight, width - rightWidth, false);
Shadow.Top_left.paintIcon(component, g, 0, 0);
Shadow.Top_right.paintIcon(component, g, width - topRightWidth, 0);
Shadow.Bottom_right.paintIcon(component, g, width - bottomRightWidth, height - bottomRightHeight);
Shadow.Bottom_left.paintIcon(component, g, 0, height - bottomLeftHeight);
}
private static void drawLine(@NotNull JComponent component,
@NotNull Graphics g,
@NotNull Icon icon,
int fullLength,
int start,
int end,
int step,
int start2,
boolean horizontal) {
int length = fullLength - start - end;
int count = length / step;
int calcLength = step * count;
int lastValue = start + calcLength;
if (horizontal) {
for (int i = start; i < lastValue; i += step) {
icon.paintIcon(component, g, i, start2);
}
}
else {
for (int i = start; i < lastValue; i += step) {
icon.paintIcon(component, g, start2, i);
}
}
if (calcLength < length) {
ImageIcon imageIcon = (ImageIcon)IconLoader.getIconSnapshot(icon);
if (horizontal) {
UIUtil.drawImage(g, imageIcon.getImage(), lastValue, start2, length - calcLength, imageIcon.getIconHeight(), component);
}
else {
UIUtil.drawImage(g, imageIcon.getImage(), start2, lastValue, imageIcon.getIconWidth(), length - calcLength, component);
}
}
}
@Override
public void paintBorder(@NotNull Rectangle bounds, @NotNull Graphics2D g) {
g.setColor(myFillColor);
g.fill(new Rectangle2D.Double(bounds.x, bounds.y, bounds.width, bounds.height));
g.setColor(myBorderColor);
g.draw(new RoundRectangle2D.Double(bounds.x + 0.5, bounds.y + 0.5, bounds.width - 1, bounds.height - 1, 3, 3));
}
@Override
public void paintPointingShape(@NotNull Rectangle bounds,
@NotNull Point pointTarget,
@NotNull Balloon.Position position,
@NotNull Graphics2D g) {
int x, y, length;
if (position == Balloon.Position.above) {
length = INSETS.bottom;
x = pointTarget.x;
y = bounds.y + bounds.height + length;
}
else if (position == Balloon.Position.below) {
length = INSETS.top;
x = pointTarget.x;
y = bounds.y - length;
}
else if (position == Balloon.Position.atRight) {
length = INSETS.left;
x = bounds.x - length;
y = pointTarget.y;
}
else {
length = INSETS.right;
x = bounds.x + bounds.width + length;
y = pointTarget.y;
}
Polygon p = new Polygon();
p.addPoint(x, y);
length += 2;
if (position == Balloon.Position.above) {
p.addPoint(x - length, y - length);
p.addPoint(x + length, y - length);
}
else if (position == Balloon.Position.below) {
p.addPoint(x - length, y + length);
p.addPoint(x + length, y + length);
}
else if (position == Balloon.Position.atRight) {
p.addPoint(x + length, y - length);
p.addPoint(x + length, y + length);
}
else {
p.addPoint(x - length, y - length);
p.addPoint(x - length, y + length);
}
g.setColor(myFillColor);
g.fillPolygon(p);
g.setColor(myBorderColor);
length -= 2;
if (position == Balloon.Position.above) {
g.drawLine(x, y, x - length, y - length);
g.drawLine(x, y, x + length, y - length);
}
else if (position == Balloon.Position.below) {
g.drawLine(x, y, x - length, y + length);
g.drawLine(x, y, x + length, y + length);
}
else if (position == Balloon.Position.atRight) {
g.drawLine(x, y, x + length, y - length);
g.drawLine(x, y, x + length, y + length);
}
else {
g.drawLine(x, y, x - length, y - length);
g.drawLine(x, y, x - length, y + length);
}
}
}