diff --git a/pom.xml b/pom.xml index 5c203e5..4c0763e 100644 --- a/pom.xml +++ b/pom.xml @@ -21,7 +21,7 @@ org.graphstream gs-ui-swing - 2.0 + 2.1.0-SNAPSHOT jar gs-ui-swing diff --git a/src-test/org/graphstream/ui/viewer_swing/test/Clicks.java b/src-test/org/graphstream/ui/viewer_swing/test/Clicks.java new file mode 100644 index 0000000..707f88c --- /dev/null +++ b/src-test/org/graphstream/ui/viewer_swing/test/Clicks.java @@ -0,0 +1,136 @@ +import org.graphstream.graph.Graph; +import org.graphstream.graph.Node; +import org.graphstream.graph.implementations.SingleGraph; +import org.graphstream.ui.swing_viewer.SwingViewer; +import org.graphstream.ui.swing_viewer.ViewPanel; +import org.graphstream.ui.view.Viewer; +import org.graphstream.ui.view.ViewerListener; +import org.graphstream.ui.view.ViewerPipe; + +import javax.swing.*; +import java.awt.*; + +public class Clicks { + + static Graph graph; + static JDialog mainFrame; + static JPanel mainPanel; + + static JTextArea codeArea; + + + public static void main(String args[]) { + System.setProperty("org.graphstream.ui", "swing"); + System.setProperty("sun.java2d.uiScale", "1.0"); + new Clicks(); + System.out.println("Doneee"); + + } + + + boolean loop; + public Clicks() { + loop = true; + mainFrame = new JDialog(); + JDialog frame = mainFrame; + mainPanel = new JPanel(){ + @Override + public Dimension getPreferredSize() { + return new Dimension(640, 480); + } + }; + mainPanel.setLayout(new BorderLayout()); + JPanel panel = mainPanel; + codeArea = new JTextArea(); + codeArea.setEditable(false); + + + + + + + frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE); + + panel.setBorder(BorderFactory.createLineBorder(Color.blue, 5)); + mainFrame.add(panel); + + graph = new SingleGraph("Clicks"); + graph.setAttribute("ui.stylesheet", + "node {\n" + + " fill-color: yellow;\n" + + " text-color: blue;\n" + + " text-size: 15;\n" + + " shape: box;\n" + +// " size: 50px;\n" + + " size-mode: fit;\n" + + "}\n" + + "sprite.basicBlock {\n" + + " shape: rounded-box;\n" + + " stroke-mode: plain;\n" + + " stroke-color: #000000;\n" + + " fill-color: green;\n" + + " size-mode: fit;\n" + + " text-alignment: center;\n" + + "}"); + + Node a = graph.addNode("A"); + a.setAttribute("ui.label", "Line1\nLine2\nLine3\nLine4\nLine5\nLine6\nLine7\nLine8\nLine9\nLine10\nLine11\nLine12\nLine13\nLine14\nLine15\nLine16\nLine17\nLine18\nLine19\nLine20\nLine21\nLine22\nLine23\nLine24\nLine25"); + graph.addNode("B"); + graph.addNode("C"); + graph.addEdge("AB", "A", "B"); + graph.addEdge("BC", "B", "C"); + graph.addEdge("CA", "C", "A"); + + Viewer viewer = new SwingViewer(graph, Viewer.ThreadingModel.GRAPH_IN_GUI_THREAD); + + + ViewPanel viewPanel = (ViewPanel) viewer.addDefaultView(false); + viewer.getDefaultView().enableMouseOptions(); + viewer.enableAutoLayout(); + + panel.add(viewPanel, BorderLayout.CENTER); +// panel.add(codeArea, BorderLayout.SOUTH); + frame.pack(); + frame.setLocationRelativeTo(null); + frame.setVisible(true); + frame.setModal(true); + + ViewerPipe fromViewer = viewer.newViewerPipe(); + fromViewer.addViewerListener(new MouseOptions()); + fromViewer.addSink(graph); + + while(loop) { + fromViewer.pump(); + if (!frame.isVisible()) { + break; + } + } + + } + + + + public class MouseOptions implements ViewerListener { + public void viewClosed(String id) { + + loop = false; + } + + public void buttonPushed(String id) { +// codeArea.setText((String) graph.getNode(id).getAttribute("ui.label")); +// codeArea.setEditable(false); + } + + public void buttonReleased(String id) { + System.out.println("Button released on node "+id); + } + + public void mouseOver(String id) { + System.out.println("Need the Mouse Options to be activated"); + } + + public void mouseLeft(String id) { + System.out.println("Need the Mouse Options to be activated"); + } + } +} diff --git a/src/org/graphstream/ui/swing/renderer/shape/swing/IconAndText.java b/src/org/graphstream/ui/swing/renderer/shape/swing/IconAndText.java index 57a880f..49837b2 100644 --- a/src/org/graphstream/ui/swing/renderer/shape/swing/IconAndText.java +++ b/src/org/graphstream/ui/swing/renderer/shape/swing/IconAndText.java @@ -1,9 +1,9 @@ /* * This file is part of GraphStream . - * + * * GraphStream is a library whose purpose is to handle static or dynamic * graph, create them from scratch, file or any source and display them. - * + * * This program is free software distributed under the terms of two licenses, the * CeCILL-C license that fits European law, and the GNU Lesser General Public * License. You can use, modify and/ or redistribute the software under the terms @@ -11,14 +11,14 @@ * URL or under the terms of the GNU LGPL as published by * the Free Software Foundation, either version 3 of the License, or (at your * option) any later version. - * + * * This program is distributed in the hope that it will be useful, but WITHOUT ANY * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A * PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . - * + * * The fact that you are presently reading this means that you have had * knowledge of the CeCILL-C and LGPL licenses and that you accept their terms. */ @@ -28,7 +28,7 @@ * @author Guilhelm Savin * @author Hicham Brahimi */ - + package org.graphstream.ui.swing.renderer.shape.swing; import java.awt.Color; @@ -40,6 +40,8 @@ import java.awt.geom.Rectangle2D; import java.awt.geom.RoundRectangle2D; import java.awt.image.BufferedImage; +import java.util.ArrayList; +import java.util.List; import org.graphstream.ui.graphicGraph.GraphicElement; import org.graphstream.ui.graphicGraph.stylesheet.Style; @@ -59,16 +61,16 @@ public abstract class IconAndText { /** Overall height of the icon and text with all space and padding included. */ //protected double height; /** Overall descent of the icon and text with all space and padding included. */ - protected double descent; + protected double descent; /** Overall ascent of the icon and text with all space and padding included. */ protected double ascent ; - + protected TextBox text; protected double offx; protected double offy; protected double padx; protected double pady; - + public IconAndText(TextBox text, double offx, double offy, double padx, double pady) { this.descent = text.getDescent() ; this.ascent = text.getAscent(); @@ -78,7 +80,7 @@ public IconAndText(TextBox text, double offx, double offy, double padx, double p this.padx = padx ; this.pady = pady ; } - + public static IconAndText apply(Style style, DefaultCamera2D camera, GraphicElement element) { BufferedImage icon = null ; TextBox text = TextBox.apply(camera, style); @@ -92,41 +94,40 @@ public static IconAndText apply(Style style, DefaultCamera2D camera, GraphicElem double offy = padx; if ( padd.size() > 1 ) offy = camera.getMetrics().lengthToPx(off, 1); - + if( style.getIconMode() != IconMode.NONE ) { String url = style.getIcon(); - + if( url.equals( "dynamic" ) ) { if( element.hasLabel( "ui.icon" ) ) url = element.getLabel( "ui.icon" ).toString(); - else + else url = null; } - + if( url != null ) { icon = ImageCache.loadImage(url); } } - - if (icon == null) { - return new IconAndTextOnlyText(text, offx, offy, padx, pady); - } - else { - switch (style.getIconMode()) { - case AT_LEFT: - return new IconAtLeftAndText( icon, text, offx, offy, padx, pady ); - case AT_RIGHT: - return new IconAtLeftAndText( icon, text, offx, offy, padx, pady ); - case ABOVE: - return new IconAtLeftAndText( icon, text, offx, offy, padx, pady ); - case UNDER: - return new IconAtLeftAndText( icon, text, offx, offy, padx, pady ); - default: - throw new RuntimeException("???"); - } - } - } - + + if (icon == null) { + return new IconAndTextOnlyText(text, offx, offy, padx, pady); + } else { + switch (style.getIconMode()) { + case AT_LEFT: + return new IconAtLeftAndText(icon, text, offx, offy, padx, pady); + case AT_RIGHT: + return new IconAtLeftAndText(icon, text, offx, offy, padx, pady); + case ABOVE: + return new IconAtLeftAndText(icon, text, offx, offy, padx, pady); + case UNDER: + return new IconAtLeftAndText(icon, text, offx, offy, padx, pady); + default: + throw new RuntimeException("???"); + } + } + } + public abstract void render(Backend backend, DefaultCamera2D camera, double xLeft, double yBottom) ; public abstract void setIcon(Backend backend, String url) ; public abstract void setText(Backend backend, String text); @@ -139,72 +140,73 @@ class IconAndTextOnlyText extends IconAndText { public IconAndTextOnlyText(TextBox text, double offx, double offy, double padx, double pady ) { super(text, offx, offy, padx, pady); } - + public double getWidth() { return text.getWidth()+padx*2; } - + public double getHeight() { - return text.getAscent()+text.getDescent()+pady*2 ; + return text.getAscent()+text.getDescent()+text.getHeight()+pady*2 ; } - + public void setText(Backend backend, String text) { this.text.setText(text, backend); } - + public String getText(Backend backend) { return this.text.getText(); } - + public void setIcon(Backend backend, String url) {} - + public void render(Backend backend, DefaultCamera2D camera, double xLeft, double yBottom) { - this.text.render(backend, offx+xLeft, offy+yBottom - descent); + this.text.render(backend, offx+xLeft, + offy+yBottom - this.getHeight() + this.text.getAscent()); } } class IconAtLeftAndText extends IconAndText { private BufferedImage icon ; - + public IconAtLeftAndText(BufferedImage icon, TextBox text, double offx, double offy, double padx, double pady ) { super(text, offx, offy, padx, pady); //this.width = text.getWidth() + icon.getWidth(null) + 5 + padx*2 ; //this.height = Math.max(icon.getHeight(null), text.ascent + text.descent) + pady*2; this.icon = icon ; } - - + + public void setText(Backend backend, String text) { this.text.setText(text, backend); } - + public String getText(Backend backend) { return this.text.getText(); } - + public void setIcon(Backend backend, String url) { ImageCache.loadImage(url); if (icon == null) { icon = ImageCache.dummyImage(); } } - + public void render(Backend backend, DefaultCamera2D camera, double xLeft, double yBottom) { Graphics2D g = backend.graphics2D(); g.drawImage(icon, new AffineTransform(1f, 0f, 0f, 1f, offx+xLeft, offy+(yBottom-(getHeight()/2))-(icon.getHeight()/2)+pady), null); double th = text.getAscent() + text.getDescent(); double dh = 0f ; - if(icon.getHeight() > th) + if(icon.getHeight() > th) dh = ((icon.getHeight() - th) / 2f) ; - + this.text.render(backend, offx+xLeft + icon.getWidth() + 5, offy+yBottom - dh - descent); } - + public double getWidth() { return text.getWidth() + icon.getWidth(null) + 5 + padx*2; } - - + + public double getHeight() { return Math.max(icon.getHeight(null), text.getAscent() + text.getDescent()) + pady*2; } @@ -214,53 +216,53 @@ public double getHeight() { abstract class TextBox { /** The text string. */ String textData; - + /** Renders the text at the given coordinates. */ public abstract void render(Backend backend, double xLeft, double yBottom); /** Set the text string to paint. */ public abstract void setText(String text, Backend backend); public abstract String getText(); - + public abstract double getWidth(); public abstract double getHeight(); public abstract double getDescent(); public abstract double getAscent(); - + /** * Factory companion object for text boxes. */ static FontRenderContext defaultFontRenderContext = new FontRenderContext(new AffineTransform(), true, true); - + public static TextBox apply(DefaultCamera2D camera, Style style) { String fontName = style.getTextFont(); TextStyle fontStyle = style.getTextStyle(); Value fontSize = style.getTextSize(); Color textColor = ColorManager.getTextColor(style, 0); Color bgColor = null; - boolean rounded = false; - + boolean rounded = false; + switch (style.getTextBackgroundMode()) { case NONE: break; - case PLAIN: - rounded = false; + case PLAIN: + rounded = false; bgColor = ColorManager.getTextBackgroundColor(style, 0); break; - case ROUNDEDBOX: - rounded = true; + case ROUNDEDBOX: + rounded = true; bgColor = ColorManager.getTextBackgroundColor(style, 0); break; default: break; } - + Values padding = style.getTextPadding(); double padx = camera.getMetrics().lengthToPx(padding, 0); double pady = padx ; if(padding.size() > 1) camera.getMetrics().lengthToPx(padding, 1); - + return TextBox.apply(fontName, fontStyle, (int)fontSize.value, textColor, bgColor, rounded, padx, pady); } - + public static TextBox apply(String fontName, TextStyle style, int fontSize, Color textColor, Color bgColor, boolean rounded, double padx, double pady) { return new SwingTextBox(FontCache.getFont( fontName, style, fontSize ), textColor, bgColor, rounded, padx, pady); @@ -268,17 +270,17 @@ public static TextBox apply(String fontName, TextStyle style, int fontSize, Colo } class SwingTextBox extends TextBox { - + Font font; Color textColor; Color bgColor; boolean rounded; double padx; double pady; - - TextLayout text ; + + List text; Rectangle2D bounds ; - + public SwingTextBox(Font font, Color textColor, Color bgColor, boolean rounded, double padx, double pady) { this.font = font ; this.textColor = textColor ; @@ -286,13 +288,13 @@ public SwingTextBox(Font font, Color textColor, Color bgColor, boolean rounded, this.rounded = rounded ; this.padx = padx ; this.pady = pady ; - + this.text = null ; this.textData = null ; this.bounds = new Rectangle2D.Double(0, 0, 0, 0); } - - + + /** Changes the text and compute its bounds. This method tries to avoid recomputing bounds * if the text does not really changed. */ public void setText(String text, Backend backend) { @@ -302,9 +304,25 @@ public void setText(String text, Backend backend) { // the identity transform, and as the FontRenderContext uses the current // transform, we use a predefined default font render context initialized // with an identity transform here. - this.textData = text ; - this.text = new TextLayout(text, font, TextBox.defaultFontRenderContext); - this.bounds = this.text.getBounds(); + this.text = new ArrayList<>(); + String[] textLines = text.split("\n"); + double maxWidth = 0; + double maxHeight = 0; + for (int i = 0; i < textLines.length; i++) { + if (textLines[i].length() == 0) { + this.text.add(new TextLayout("\b", font, TextBox.defaultFontRenderContext)); + } else { + this.text.add(new TextLayout(textLines[i], font, TextBox.defaultFontRenderContext)); + maxWidth = Math.max(this.text.get(i).getAdvance(), maxWidth); + } + maxHeight += this.text.get(i).getAscent() + + this.text.get(i).getDescent(); + } + this.bounds = new Rectangle2D.Double( + this.text.get(0).getBounds().getX(), + this.text.get(0).getBounds().getY(), + maxWidth, + maxHeight); } else { this.textData = null ; @@ -313,58 +331,62 @@ public void setText(String text, Backend backend) { } } } - + @Override public String getText() { return textData; } - + public double getWidth() { - if ( bounds != null ) + if ( bounds != null ) return bounds.getWidth() ; else return 0 ; } - + public double getHeight() { - if ( bounds != null ) + if ( bounds != null ) return bounds.getHeight() ; else return 0 ; } - + public double getDescent() { - if ( text != null ) - return text.getDescent() ; + if ( text != null ) + return text.get(0).getDescent() ; else return 0 ; } - + public double getAscent() { - if ( text != null ) - return text.getAscent() ; + if ( text != null ) + return text.get(0).getAscent() ; else return 0 ; } public void render(Backend backend, double xLeft, double yBottom) { - + if ( text != null ) { Graphics2D g = backend.graphics2D(); - + if (bgColor != null) { - double a = getAscent() ; + double a = getAscent(); double h = a + getDescent() ; - + g.setColor(bgColor); if(rounded) { - g.fill(new RoundRectangle2D.Double(xLeft-padx, yBottom-(a+pady), getWidth()+1+(padx+padx), h+(pady+pady), 6, 6)); + g.fill(new RoundRectangle2D.Double(xLeft-padx, yBottom-(a+pady), getWidth()+1+(padx+padx), h+(pady+pady), 6, 6)); } else { g.fill(new Rectangle2D.Double(xLeft-padx, yBottom-(a+pady), getWidth()+1+(padx+padx), h+(pady+pady))); } } g.setColor(textColor); - text.draw(g, (float)xLeft, (float)yBottom); + for (int i = 0; i < text.size(); i++) { + text.get(i).draw(g, (float) xLeft, + (float) yBottom + i * + (text.get(i).getAscent() + text.get(i).getDescent())); + } } } }