You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
232 lines
10 KiB
232 lines
10 KiB
package com.fr.design.mainframe; |
|
|
|
import com.fr.design.designer.creator.XChartEditor; |
|
import com.fr.design.designer.creator.XCreator; |
|
import com.fr.design.designer.creator.XCreatorUtils; |
|
import com.fr.design.designer.creator.XElementCase; |
|
import com.fr.design.designer.creator.XLayoutContainer; |
|
import com.fr.design.designer.creator.XWParameterLayout; |
|
import com.fr.design.form.parameter.FormParaDesigner; |
|
import com.fr.design.form.util.FormDesignerUtils; |
|
import com.fr.design.utils.ComponentUtils; |
|
import com.fr.stable.Constants; |
|
import com.fr.stable.GraphDrawHelper; |
|
|
|
import java.awt.Color; |
|
import java.awt.Font; |
|
import java.awt.FontMetrics; |
|
import java.awt.Graphics; |
|
import java.awt.Graphics2D; |
|
import java.awt.Rectangle; |
|
import java.awt.event.MouseEvent; |
|
import java.awt.geom.RoundRectangle2D; |
|
|
|
public class FormSpacingLineDrawer { |
|
private static final Color LINE_COLOR = new Color(230, 82, 81); |
|
private static final Color TEXT_COLOR = new Color(255, 255, 255); |
|
private static final int TEXT_PADDING_HORIZONTAL = 8; |
|
private static final int TEXT_PADDING_VERTICAL = 2; |
|
private static final int MIN_SPACING = 10; |
|
private static final float TIP_FONT_SIZE = 10F; |
|
|
|
private FormDesigner designer; |
|
private XCreator hoverCreator = null; |
|
private XCreator selectedCreator = null; |
|
private Rectangle selectedRec; |
|
private Rectangle hoveredRec; |
|
private boolean isMouseMoveEvent = false; |
|
|
|
public FormSpacingLineDrawer(FormDesigner designer) { |
|
this.designer = designer; |
|
} |
|
|
|
public void updateMouseEvent(MouseEvent e, boolean isMouseMoveEvent) { |
|
selectedCreator = designer.getSelectionModel().getSelection().getSelectedCreator(); |
|
if (selectedCreator != null) { |
|
this.hoverCreator = getHoverComponentAt(e.getX(), e.getY()); |
|
} |
|
this.isMouseMoveEvent = isMouseMoveEvent; |
|
} |
|
|
|
public void draw(Graphics g) { |
|
if (!isMouseMoveEvent || selectedCreator == null || hoverCreator == null) { |
|
return; |
|
} |
|
|
|
if (!isDrawSpacingLine()) { |
|
return; |
|
} |
|
|
|
this.selectedRec = designer.getSelectionModel().getSelection().getRelativeBounds(); |
|
this.hoveredRec = ComponentUtils.getRelativeBounds(hoverCreator); |
|
|
|
drawHorizontalSpacingLine(g); |
|
drawVerticalSpacingLine(g); |
|
} |
|
|
|
private void drawHorizontalSpacingLine(Graphics g) { |
|
AbstractFormParallelLine[] lines = getNearestHorizontalSide(); |
|
drawSpacingLine(g, lines); |
|
} |
|
|
|
private void drawVerticalSpacingLine(Graphics g) { |
|
AbstractFormParallelLine[] lines = getNearestVerticalSide(); |
|
drawSpacingLine(g, lines); |
|
} |
|
|
|
private void drawSpacingLine(Graphics g, int startX, int startY, int endX, int endY) { |
|
Graphics2D g2d = (Graphics2D) g.create(); |
|
g2d.setColor(LINE_COLOR); |
|
GraphDrawHelper.drawLine(g2d, startX, startY, endX, endY, Constants.LINE_THIN); |
|
} |
|
|
|
private void drawSpacingLine(Graphics g, AbstractFormParallelLine[] nearestSides) { |
|
if (nearestSides.length != 2) { |
|
return; |
|
} |
|
int gap = nearestSides[0].getDistanceWithLine(nearestSides[1]); |
|
if (gap <= MIN_SPACING) { |
|
return; |
|
} |
|
|
|
int startX = (int) nearestSides[0].getStartPointOnVerticalCenterLine().getX() - designer.getHorizontalScaleValue(); |
|
int startY = (int) nearestSides[0].getStartPointOnVerticalCenterLine().getY() - designer.getVerticalScaleValue(); |
|
int endX = (int) nearestSides[0].getEndPointOnVerticalCenterLine(nearestSides[1].getParallelValue()).getX() - designer.getHorizontalScaleValue(); |
|
int endY = (int) nearestSides[0].getEndPointOnVerticalCenterLine(nearestSides[1].getParallelValue()).getY() - designer.getVerticalScaleValue(); |
|
|
|
drawSpacingLine(g, startX, startY, endX, endY); |
|
drawSpacingText(g, String.valueOf(gap), (startX + endX) / 2, (startY + endY) / 2); |
|
drawExtendedLine(g, nearestSides); |
|
} |
|
|
|
private void drawExtendedLine(Graphics g, int startX, int startY, int endX, int endY) { |
|
Graphics2D g2d = (Graphics2D) g.create(); |
|
g2d.setColor(LINE_COLOR); |
|
GraphDrawHelper.drawLine(g2d, startX, startY, endX, endY, Constants.LINE_DASH); |
|
} |
|
|
|
private void drawExtendedLine(Graphics g, AbstractFormParallelLine[] nearestSides) { |
|
if (isNeedExtendedLine(nearestSides)) { |
|
int startX = (int) nearestSides[1].getExtendedLineStartPoint(nearestSides[0]).getX() - designer.getHorizontalScaleValue(); |
|
int startY = (int) nearestSides[1].getExtendedLineStartPoint(nearestSides[0]).getY() - designer.getVerticalScaleValue(); |
|
int endX = (int) nearestSides[1].getExtendedLineEndPoint(nearestSides[0]).getX() - designer.getHorizontalScaleValue(); |
|
int endY = (int) nearestSides[1].getExtendedLineEndPoint(nearestSides[0]).getY() - designer.getVerticalScaleValue(); |
|
drawExtendedLine(g, startX, startY, endX, endY); |
|
} |
|
} |
|
|
|
private void drawSpacingText(Graphics g, String text, int x, int y) { |
|
Graphics2D g2d = (Graphics2D) g.create(); |
|
g2d.setColor(LINE_COLOR); |
|
Font newFont = g2d.getFont().deriveFont(TIP_FONT_SIZE).deriveFont(Font.BOLD); |
|
g2d.setFont(newFont); |
|
FontMetrics metrics = g2d.getFontMetrics(); |
|
int lineHeight = metrics.getAscent(); // 这里由于都是数字,要居中必须忽略掉leading和descent的高度 |
|
int lineWidth = metrics.stringWidth(text); |
|
|
|
int labelPaneX = x - lineWidth / 2 - TEXT_PADDING_HORIZONTAL; |
|
int labelPaneY = y - lineHeight / 2 - TEXT_PADDING_VERTICAL; |
|
int labelPaneWidth = lineWidth + 2 * TEXT_PADDING_HORIZONTAL; |
|
int labelPaneHeight = lineHeight + 2 * TEXT_PADDING_VERTICAL; |
|
int labelPaneArc = Math.min(labelPaneWidth, labelPaneHeight); |
|
GraphDrawHelper.fill(g2d, new RoundRectangle2D.Double(labelPaneX, labelPaneY, labelPaneWidth, labelPaneHeight, labelPaneArc, labelPaneArc)); |
|
|
|
g2d.setColor(TEXT_COLOR); |
|
int labelX = x - lineWidth / 2; |
|
int labelY = y + (lineHeight - 2) / 2; // 由于ascent里面包含了一小段空白,数字又没有大写的情况,相当于五线行第一行是空的,所以往上微调一点来居中 |
|
GraphDrawHelper.drawString(g2d, text, labelX, labelY); |
|
} |
|
|
|
private boolean isNeedExtendedLine(AbstractFormParallelLine[] nearestSides) { |
|
return nearestSides[0].isVerticalCenterLineBeforeTheParallelLine(nearestSides[1]) || nearestSides[0].isVerticalCenterLineBehindTheParallelLine(nearestSides[1]); |
|
} |
|
|
|
// 当前组件是否在参数面板里面 |
|
private boolean isComponentInBody(XCreator creator) { |
|
XLayoutContainer container = XCreatorUtils.getHotspotContainer(creator); |
|
return container != null && !container.acceptType(XWParameterLayout.class); |
|
} |
|
|
|
private boolean isSelectedComponentInBody() { |
|
return isComponentInBody(selectedCreator); |
|
} |
|
|
|
private boolean isHoveredComponentInBody() { |
|
return isComponentInBody(hoverCreator); |
|
} |
|
|
|
private boolean isBodyAbsoluteLayout() { |
|
return !(designer instanceof FormParaDesigner) && FormDesignerUtils.isBodyAbsolute(designer); |
|
} |
|
|
|
private boolean isInAbsoluteLayout() { |
|
return isBodyAbsoluteLayout() && hoverCreator.isParentAbsolute() && selectedCreator.isParentAbsolute(); |
|
} |
|
|
|
private boolean isDrawSpacingLine() { |
|
return isInAbsoluteLayout() && isSelectedComponentInBody() && isHoveredComponentInBody(); |
|
} |
|
|
|
private AbstractFormParallelLine[] getNearestHorizontalSide() { |
|
AbstractFormParallelLine[] selectedRecSides = new AbstractFormParallelLine[] { |
|
new FormHorizontalParallelLine(selectedRec.y, selectedRec.x, selectedRec.x + selectedRec.width), |
|
new FormHorizontalParallelLine(selectedRec.y + selectedRec.height, selectedRec.x, selectedRec.x + selectedRec.width) |
|
}; |
|
|
|
AbstractFormParallelLine[] hoveredCreatorSides = new AbstractFormParallelLine[] { |
|
new FormHorizontalParallelLine(hoveredRec.y, hoveredRec.x, hoveredRec.x + hoveredRec.width), |
|
new FormHorizontalParallelLine(hoveredRec.y + hoveredRec.height, hoveredRec.x, hoveredRec.x + hoveredRec.width) |
|
}; |
|
return getNearestSide(selectedRecSides, hoveredCreatorSides); |
|
} |
|
|
|
private AbstractFormParallelLine[] getNearestVerticalSide() { |
|
AbstractFormParallelLine[] selectedRecSides = new AbstractFormParallelLine[] { |
|
new FormVerticalParallelLine(selectedRec.x, selectedRec.y, selectedRec.y + selectedRec.height), |
|
new FormVerticalParallelLine(selectedRec.x + selectedRec.width, selectedRec.y, selectedRec.y + selectedRec.height) |
|
}; |
|
|
|
AbstractFormParallelLine[] hoveredCreatorSides = new AbstractFormParallelLine[] { |
|
new FormVerticalParallelLine(hoveredRec.x, hoveredRec.y, hoveredRec.y + hoveredRec.height), |
|
new FormVerticalParallelLine(hoveredRec.x + hoveredRec.width, hoveredRec.y, hoveredRec.y + hoveredRec.height) |
|
}; |
|
return getNearestSide(selectedRecSides, hoveredCreatorSides); |
|
} |
|
|
|
private AbstractFormParallelLine[] getNearestSide(AbstractFormParallelLine[] lines1, AbstractFormParallelLine[] lines2) { |
|
AbstractFormParallelLine[] nearestSides = new AbstractFormParallelLine[] {lines1[0], lines2[0]}; |
|
int minDistance = lines1[0].getDistanceWithLine(lines2[0]); |
|
for (int i = 0; i < lines1.length; i++) { |
|
for (int j = 0; j < lines2.length; j++) { |
|
int distance = lines1[i].getDistanceWithLine(lines2[j]); |
|
if (distance < minDistance) { |
|
minDistance = distance; |
|
nearestSides[0] = lines1[i]; |
|
nearestSides[1] = lines2[j]; |
|
} |
|
} |
|
} |
|
return nearestSides; |
|
} |
|
|
|
private XCreator getHoverComponentAt(int x, int y) { |
|
XCreator component = designer.getComponentAt(x, y); |
|
XLayoutContainer parent = XCreatorUtils.getHotspotContainer(component).getTopLayout(); |
|
if (parent != null) { |
|
if (!parent.isEditable()) { |
|
return parent; |
|
} else { |
|
if (parent == component) { |
|
return null; |
|
} |
|
|
|
if (component instanceof XChartEditor || component instanceof XElementCase) { |
|
return (XCreator) component.getParent(); |
|
} |
|
return component; |
|
} |
|
} else { |
|
return component; |
|
} |
|
} |
|
}
|
|
|