diff --git a/designer-base/src/main/java/com/fr/design/mainframe/guide/tip/BubbleTip.java b/designer-base/src/main/java/com/fr/design/mainframe/guide/tip/BubbleTip.java index d3d1c040d..13e5dc28f 100644 --- a/designer-base/src/main/java/com/fr/design/mainframe/guide/tip/BubbleTip.java +++ b/designer-base/src/main/java/com/fr/design/mainframe/guide/tip/BubbleTip.java @@ -2,8 +2,6 @@ package com.fr.design.mainframe.guide.tip; import com.fr.design.dialog.FineJOptionPane; import com.fr.design.i18n.Toolkit; -import com.fr.design.mainframe.DesignerContext; -import com.fr.design.mainframe.DesignerFrame; import com.fr.design.mainframe.guide.base.Guide; import com.fr.design.mainframe.guide.base.GuideManager; import com.fr.design.mainframe.guide.ui.bubble.Bubble; @@ -16,9 +14,11 @@ import java.awt.event.ActionEvent; import java.awt.event.ActionListener; public class BubbleTip implements GuideTip { + private static final int GAP = 5; private BubbleWithClose bubbleBox; private Point anchor; + /** * * @param title 标题 @@ -70,12 +70,12 @@ public class BubbleTip implements GuideTip { int bubbleW = bubbleBox.getPreferredSize().width; int bubbleH = bubbleBox.getPreferredSize().height; if (bubbleBox.isTailHorizontal()) { - int x = bubbleBox.isTailLeft() ? anchor.x : anchor.x - bubbleW; + int x = bubbleBox.isTailLeft() ? anchor.x + GAP : anchor.x - bubbleW - GAP; int y = anchor.y - (int) (bubbleH * bubbleBox.getTailStart()); bubbleBox.setBounds(x, y, bubbleW, bubbleH); } else if (bubbleBox.isTailVertical()) { int x = anchor.x - (int) (bubbleW * bubbleBox.getTailStart()); - int y = bubbleBox.isTailTop() ? anchor.y : anchor.y - bubbleH; + int y = bubbleBox.isTailTop() ? anchor.y + GAP : anchor.y - bubbleH - GAP; bubbleBox.setBounds(x, y, bubbleW, bubbleH); } } diff --git a/designer-base/src/main/java/com/fr/design/mainframe/guide/ui/bubble/BubbleWithClose.java b/designer-base/src/main/java/com/fr/design/mainframe/guide/ui/bubble/BubbleWithClose.java index ba8f3da05..904185ccb 100644 --- a/designer-base/src/main/java/com/fr/design/mainframe/guide/ui/bubble/BubbleWithClose.java +++ b/designer-base/src/main/java/com/fr/design/mainframe/guide/ui/bubble/BubbleWithClose.java @@ -9,6 +9,7 @@ import com.fr.stable.StringUtils; import javax.swing.Icon; import javax.swing.JTextPane; +import javax.swing.text.MutableAttributeSet; import javax.swing.text.SimpleAttributeSet; import javax.swing.text.StyleConstants; import javax.swing.text.StyledDocument; @@ -18,7 +19,6 @@ import java.awt.Container; import java.awt.Dimension; import java.awt.Font; import java.awt.FontMetrics; -import java.awt.Graphics2D; import java.awt.Insets; import java.awt.LayoutManager; import java.awt.Rectangle; @@ -32,13 +32,21 @@ import java.text.AttributedCharacterIterator; import java.text.AttributedString; public class BubbleWithClose extends Bubble { - private static final Font FONT = new Font(Font.SANS_SERIF, Font.PLAIN, 14); + private static final Font TITLE_FONT = new Font(Font.SANS_SERIF, Font.PLAIN, 14); + private static final Font CONTENT_FONT = new Font(Font.SANS_SERIF, Font.PLAIN, 12); + private static final int TITLE_LINE_HEIGHT = 22; + private static final int CONTENT_LINE_HEIGHT = 18; + private static final Icon ICON = IOUtils.readIcon("/com/fr/design/mainframe/guide/close.png"); - private static final int HEADER_HEIGHT = 24; - private static final Color HEADER_COLOR = new Color(245, 245, 246); private static final Color TITLE_COLOR = new Color(51, 51, 52); private static final Color CONTENT_COLOR = new Color(51,51,52,128); - private static final Insets DEFAULT_INSET = new Insets(10, 15, 10, 15); + private static final Color HIGHLIGHT_COLOR = new Color(65, 155, 249); + private static final Insets DEFAULT_INSET = new Insets(15, 15, 15, 15); + private static final int MIN_WIDTH = 140; + private static final int MAX_WIDTH = 275; + private static final int ICON_GAP = 10; + private static final int ICON_SIZE = 10; + private static final int TEXT_GAP = 5; private String title; @@ -46,6 +54,8 @@ public class BubbleWithClose extends Bubble { private UITextPane titleTextArea; private UITextPane contentTextArea; private UIButton closeButton; + private Dimension titleSize; + private Dimension contentSize; public BubbleWithClose(String title, String content) { this(title, content, TailDirection.LEFT, 0.5f); @@ -87,23 +97,17 @@ public class BubbleWithClose extends Bubble { @Override public void componentResized(ComponentEvent e) { Rectangle rectBounds = getRectBounds(); - Dimension buttonSize = closeButton.getPreferredSize(); - - closeButton.setBounds(getWidth() - 10 - buttonSize.width, rectBounds.y + (HEADER_HEIGHT - buttonSize.height) / 2, buttonSize.width, buttonSize.height); - Dimension titleSize = new Dimension(0,0); - Dimension contentSize = new Dimension(0, 0); + closeButton.setBounds(rectBounds.x + rectBounds.width - DEFAULT_INSET.right - ICON_SIZE, rectBounds.y + 21, ICON_SIZE, ICON_SIZE); if (titleTextArea != null) { - titleSize = calTextSize(titleTextArea, getTextAreaMaxWidth()); - int x = rectBounds.x + (rectBounds.width - getHorizontalInsets() - titleSize.width) / 2 + DEFAULT_INSET.left; - int y = rectBounds.y + HEADER_HEIGHT + DEFAULT_INSET.top; + int x = rectBounds.x + DEFAULT_INSET.left; + int y = rectBounds.y + DEFAULT_INSET.top; titleTextArea.setBounds(x, y, titleSize.width, titleSize.height); } if (contentTextArea != null) { - contentSize = calTextSize(contentTextArea, getTextAreaMaxWidth()); - int x = rectBounds.x + (rectBounds.width - getHorizontalInsets() - contentSize.width) / 2 + DEFAULT_INSET.left; - int y = rectBounds.y = HEADER_HEIGHT + DEFAULT_INSET.top + (titleSize.height == 0 ? 0 : titleSize.height + 10); + int x = rectBounds.x + DEFAULT_INSET.left; + int y = rectBounds.y + DEFAULT_INSET.top + (titleSize.height == 0 ? 0 : titleSize.height + getTextGap()); contentTextArea.setBounds(x,y, contentSize.width, contentSize.height); } setSize(getPreferredSize().width, getPreferredSize().height); @@ -116,7 +120,7 @@ public class BubbleWithClose extends Bubble { closeButton = new UIButton(); closeButton.setIcon(ICON); closeButton.set4ToolbarButton(); - closeButton.setPreferredSize(new Dimension(12, 12)); + closeButton.setPreferredSize(new Dimension(ICON_SIZE, ICON_SIZE)); closeButton.setRolloverEnabled(false); closeButton.setPressedPainted(false); this.add(closeButton); @@ -138,44 +142,83 @@ public class BubbleWithClose extends Bubble { private void createTitleTextArea() { if (StringUtils.isNotEmpty(title)) { - titleTextArea = createTextArea(title, FONT, TITLE_COLOR); + titleTextArea = createTextArea(title, TITLE_FONT, TITLE_LINE_HEIGHT, TITLE_COLOR); this.add(titleTextArea); } - + titleSize = calTextSize(titleTextArea, TITLE_LINE_HEIGHT, getTextAreaWidth(MAX_WIDTH), getTextAreaWidth(MIN_WIDTH)); } private void createContentTextArea() { if (StringUtils.isNotEmpty(content)) { - contentTextArea = createTextArea(content, FONT, CONTENT_COLOR); + contentTextArea = createTextArea(content, CONTENT_FONT, CONTENT_LINE_HEIGHT, CONTENT_COLOR); this.add(contentTextArea); } + contentSize = calTextSize(contentTextArea, CONTENT_LINE_HEIGHT, getTextAreaWidth(MAX_WIDTH), getTextAreaWidth(MIN_WIDTH)); } - private UITextPane createTextArea(String str, Font font, Color foreground) { + private UITextPane createTextArea(String str, Font font, int lineHeight, Color foreground) { + int lineSpace = lineHeight - font.getSize(); UITextPane textArea= new UITextPane(){ @Override public Insets getInsets() { - return new Insets(0, 0, 0, 0); + return new Insets(lineSpace / 2 - 1, 0, lineSpace / 2, 0); } }; + changeLineSpacing(textArea, (float) lineSpace / 2 / lineHeight, true); textArea.setText(str); - textArea.setEnabled(false); + textArea.setEditable(false); + textArea.setForeground(foreground); textArea.setDisabledTextColor(foreground); textArea.setBorder(null); textArea.setFont(font); textArea.setOpaque(false); - textArea.setForeground(foreground); - StyledDocument doc = textArea.getStyledDocument(); - SimpleAttributeSet center = new SimpleAttributeSet(); - StyleConstants.setAlignment(center, StyleConstants.ALIGN_CENTER); - doc.setParagraphAttributes(0, doc.getLength(), center, false); + highlightText(textArea); return textArea; } + private void changeLineSpacing(JTextPane pane, float factor, boolean replace) { + pane.selectAll(); + MutableAttributeSet set = new SimpleAttributeSet(pane.getParagraphAttributes()); + StyleConstants.setLineSpacing(set, factor); + pane.setParagraphAttributes(set, replace); + } + + private void highlightText(JTextPane textArea) { + SimpleAttributeSet sas = new SimpleAttributeSet(); + StyleConstants.setForeground(sas, HIGHLIGHT_COLOR); + StyledDocument doc = textArea.getStyledDocument(); + String text = textArea.getText(); + int startPos = -1; + for (int i = 0; i < text.length(); i ++) { + char ch = text.charAt(i); + if (ch == '【') { + startPos = i; + } + if (ch == '】') { + if (startPos > 0) { + try { + doc.setCharacterAttributes(startPos, (i - startPos + 1), sas, false); + startPos = -1; + } catch (Exception e) { + } + } + } + } + + } + + @Override + protected int getDefaultWidth() { + return Math.max(titleSize.width, contentSize.width) + getHorizontalInsets() + ICON_GAP + ICON_SIZE + (isTailHorizontal() ? TAIL_HEIGHT : 0) ; + } + + @Override protected int getDefaultHeight() { - Dimension titleSize = calTextSize(titleTextArea, getDefaultTextAreaMaxWidth()); - Dimension contentSize = calTextSize(contentTextArea, getDefaultTextAreaMaxWidth()); - return (isTailVertical() ? TAIL_HEIGHT : 0) + HEADER_HEIGHT + titleSize.height + (titleSize.height == 0 ? 0 : 5) + contentSize.height + getVerticalInsets(); + return titleSize.height + contentSize.height + getTextGap() + getVerticalInsets() + (isTailVertical() ? TAIL_HEIGHT : 0); + } + + private int getTextGap() { + return (titleSize.height != 0 && contentSize.height != 0) ? TEXT_GAP : 0; } private LayoutManager getLayoutManager() { @@ -206,18 +249,6 @@ public class BubbleWithClose extends Bubble { }; } - @Override - protected void paintBubbleBg(Graphics2D g2) { - super.paintBubbleBg(g2); - paintHeaderBg(g2); - } - - private void paintHeaderBg(Graphics2D g2) { - g2.setColor(HEADER_COLOR); - Rectangle bounds = getRectBounds(); - g2.fillRoundRect(bounds.x, bounds.y, bounds.width, HEADER_HEIGHT, 10, 10); - } - private int countLines(JTextPane textArea, int max_width) { AttributedString text = new AttributedString(textArea.getText()); text.addAttribute(TextAttribute.FONT, textArea.getFont()); @@ -234,28 +265,26 @@ public class BubbleWithClose extends Bubble { return lines; } - private Dimension calTextSize(JTextPane textArea, int maxWidth) { + private Dimension calTextSize(JTextPane textArea, int lineHeight, int maxWidth, int minWidth) { if (textArea == null) { - return new Dimension(0, 0); + return new Dimension(minWidth, 0); } FontMetrics fontMetrics = GraphHelper.getFontMetrics(textArea.getFont()); int line = countLines(textArea, maxWidth); int width = maxWidth; if (line == 1) { - width = fontMetrics.stringWidth(textArea.getText()); + width = Math.max(fontMetrics.stringWidth(textArea.getText()), minWidth); } - int height = fontMetrics.getHeight() * line; + int height = lineHeight * line; return new Dimension(width, height); } - private int getTextAreaMaxWidth() { - return getWidth() - (isTailHorizontal() ? TAIL_HEIGHT : 0) -getHorizontalInsets(); - } - private int getDefaultTextAreaMaxWidth() { - return BUBBLE_WIDTH - getHorizontalInsets(); + private int getTextAreaWidth(int bubbleWidth) { + return bubbleWidth - getHorizontalInsets() - ICON_SIZE - ICON_GAP; } + private int getHorizontalInsets() { return DEFAULT_INSET.left + DEFAULT_INSET.right; } diff --git a/designer-realize/src/main/java/com/fr/design/mainframe/guide/creator/layout/UseLayoutAndComponentGuide.java b/designer-realize/src/main/java/com/fr/design/mainframe/guide/creator/layout/UseLayoutAndComponentGuide.java index 54fc5577b..6d67f3b93 100644 --- a/designer-realize/src/main/java/com/fr/design/mainframe/guide/creator/layout/UseLayoutAndComponentGuide.java +++ b/designer-realize/src/main/java/com/fr/design/mainframe/guide/creator/layout/UseLayoutAndComponentGuide.java @@ -105,7 +105,7 @@ public class UseLayoutAndComponentGuide { ClickScene.ClickType.LEFT ); - scene.addBubbleTip(Toolkit.i18nText("Fine-Design_Guide_Scene_F001001_Tip_New_Form") + "测试文本测试文本测试文本测试文本测试文本", GuideTip.Direction.BOTTOM); + scene.addBubbleTip(Toolkit.i18nText("Fine-Design_Guide_Scene_F001001_Tip_New_Form"), GuideTip.Direction.RIGHT); scene.showScene(); return true; }