From 6503b22db772a28021bb1141289ea6051b124681 Mon Sep 17 00:00:00 2001 From: Shyam Mehta Date: Thu, 21 Jul 2022 15:08:37 -0400 Subject: [PATCH 1/6] Add rudimentary support for multiline labels --- .../ui/viewer_swing/test/Clicks.java | 207 ++++++++++++++++++ .../ui/viewer_swing/test/TestManySprite.java | 59 ++--- .../ui/swing/renderer/JComponentRenderer.java | 164 +++++++------- .../renderer/shape/swing/IconAndText.java | 159 ++++++++------ 4 files changed, 407 insertions(+), 182 deletions(-) create mode 100644 src-test/org/graphstream/ui/viewer_swing/test/Clicks.java 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..7855ff7 --- /dev/null +++ b/src-test/org/graphstream/ui/viewer_swing/test/Clicks.java @@ -0,0 +1,207 @@ +package org.openrewrite.java.controlflow; + +import org.graphstream.graph.Graph; +import org.graphstream.graph.Node; +import org.graphstream.graph.implementations.SingleGraph; +import org.graphstream.ui.spriteManager.Sprite; +import org.graphstream.ui.spriteManager.SpriteManager; +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.*; + +import static java.awt.Dialog.ModalityType.DOCUMENT_MODAL; + +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); + + // We do as usual to display a graph. This + // connect the graph outputs to the viewer. + // The viewer is a sink of the graph. + graph = new SingleGraph("Clicks"); + graph.setAttribute("ui.stylesheet", + "node {\n" + + " fill-color: #f0f0f0;\n" + + " text-color: blue;\n" + + " text-size: 15;\n" + + " shape: box;\n" + + " size: 50px;\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", "ABC\n EFG"); + graph.addNode("B"); + graph.addNode("C"); + graph.addEdge("AB", "A", "B"); + graph.addEdge("BC", "B", "C"); + graph.addEdge("CA", "C", "A"); +// graph.display(); + +// SpriteManager spriteManager = new SpriteManager(graph); +// +// Sprite sprite = spriteManager.addSprite("sprite"); + +// sprite.attachToNode("A"); +// String bb = "A\nB\nC\nD\nE"; +// sprite.setAttribute("ui.label", bb.toString()); +// sprite.setPosition(0,0,0); +// sprite.setAttribute("ui.class", "basicBlock"); + +// Sprite sprite1 = spriteManager.addSprite("sprite"); +// sprite1.attachToNode("A"); +// String bb = "A\nB\nC"; +// sprite1.setAttribute("ui.label", "EDG"); +// sprite1.setPosition(1,1,0); +// sprite1.setAttribute("ui.class", "basicBlock"); + + 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); +// Viewer viewer = graph.display(); +// viewer.getDefaultView().enableMouseOptions(); +// +// // The default action when closing the view is to quit +// // the program. +// viewer.setCloseFramePolicy(Viewer.CloseFramePolicy.CLOSE_VIEWER); + + // We connect back the viewer to the graph, + // the graph becomes a sink for the viewer. + // We also install us as a viewer listener to + // intercept the graphic events. + ViewerPipe fromViewer = viewer.newViewerPipe(); + fromViewer.addViewerListener(new MouseOptions()); + fromViewer.addSink(graph); + + // Then we need a loop to do our work and to wait for events. + // In this loop we will need to call the + // pump() method before each use of the graph to copy back events + // that have already occurred in the viewer thread inside + // our thread. + +// fromViewer.pump(); + + while(loop) { + fromViewer.pump(); // or fromViewer.blockingPump(); in the nightly builds + if (!frame.isVisible()) { +// frame.dispose(); + break; + } + // here your simulation code. + + // You do not necessarily need to use a loop, this is only an example. + // as long as you call pump() before using the graph. pump() is non + // blocking. If you only use the loop to look at event, use blockingPump() + // to avoid 100% CPU usage. The blockingPump() method is only available from + // the nightly builds. + } + + } + +// 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"); +// } + + 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-test/org/graphstream/ui/viewer_swing/test/TestManySprite.java b/src-test/org/graphstream/ui/viewer_swing/test/TestManySprite.java index 2464c13..2f465a2 100644 --- a/src-test/org/graphstream/ui/viewer_swing/test/TestManySprite.java +++ b/src-test/org/graphstream/ui/viewer_swing/test/TestManySprite.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.viewer_swing.test; import org.graphstream.algorithm.generator.DorogovtsevMendesGenerator; @@ -47,10 +47,11 @@ public class TestManySprite implements ViewerListener { public static void main(String[] args) { System.setProperty("org.graphstream.ui", "org.graphstream.ui.swing.util.Display"); + System.setProperty("sun.java2d.uiScale", "1.0"); (new TestManySprite()).run(); } - + /** The application runs while this is true. */ boolean loop = true; @@ -62,7 +63,7 @@ public static void main(String[] args) { int NODE_COUNT = 1000; int SPRITE_COUNT = 500; - + private void run() { graph = new MultiGraph( "TestSprites" ); Viewer viewer = graph.display( true ); @@ -99,7 +100,7 @@ private void run() { System.out.println( "bye bye" ); System.exit(0); } - + protected void sleep( long ms ) { try { @@ -114,12 +115,12 @@ protected void sleep( long ms ) { public void buttonPushed( String id ) {} public void buttonReleased( String id ) {} - + private void moveSprites() { - sprites.forEach( s -> ((TestSprite)s).move() ); + sprites.forEach( s -> ((TestSprite)s).move() ); } - + private void addSprites() { sprites = new SpriteManager( graph ); @@ -136,13 +137,13 @@ private void addSprites() { private Edge randomEdge(Graph graph) { int min = 0 ; int max = (int) graph.edges().count(); - + int rand = (int) (min + (Math.random() * (max - min))); - + return graph.getEdge(rand); } - - private String styleSheet = + + private String styleSheet = "graph {"+ "fill-mode: plain;"+ "fill-color: white, gray;"+ @@ -171,7 +172,7 @@ private Edge randomEdge(Graph graph) { "fill-color: red;"+ "stroke-mode: none;"+ "}"; - + public void mouseOver(String id){} public void mouseLeft(String id){} @@ -186,11 +187,11 @@ public Sprite newSprite(String identifier, SpriteManager manager, Values positio class TestSprite extends Sprite { double dir = 0.01f; - + public TestSprite( String identifier, SpriteManager manager ) { super( identifier, manager ); } - + public void move() { double p = getX(); @@ -204,21 +205,21 @@ public void move() { public void chooseNextEdge() { Edge edge = (Edge) getAttachment(); - Node node = edge.getSourceNode(); + Node node = edge.getSourceNode(); if( dir > 0 ) node = edge.getTargetNode() ; - - + + Edge next = randomEdge( node ); double pos = 0; - if( node == next.getSourceNode() ) { - dir = 0.01f; + if( node == next.getSourceNode() ) { + dir = 0.01f; pos = 0; } - else { - dir = -0.01f; - pos = 1; + else { + dir = -0.01f; + pos = 1; } attachToEdge( next.getId() ); @@ -228,9 +229,9 @@ public void chooseNextEdge() { private Edge randomEdge(Node node) { int min = 0 ; int max = (int) node.edges().count(); - + int rand = (int) (min + (Math.random() * (max - min))); - + return node.getEdge(rand); } } diff --git a/src/org/graphstream/ui/swing/renderer/JComponentRenderer.java b/src/org/graphstream/ui/swing/renderer/JComponentRenderer.java index 0266519..3c37a1f 100644 --- a/src/org/graphstream/ui/swing/renderer/JComponentRenderer.java +++ b/src/org/graphstream/ui/swing/renderer/JComponentRenderer.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; import java.awt.Font; @@ -66,27 +66,27 @@ import org.graphstream.ui.view.util.GraphMetrics; public class JComponentRenderer extends StyleRenderer { - + private SwingGraphRenderer mainRenderer; private StyleGroup styleGroup; - + /** The size of components. */ protected Values size = null; - + /** The size in PX of components. */ protected int width = 0; - + /** The size in PX of components. */ protected int height = 0; - + /** Association between Swing components and graph elements. */ protected HashMap compToElement = new HashMap<>(); /** The potential shadow. */ protected SquareShape shadow = null; - + protected Object antialiasSetting = null; - + public JComponentRenderer(StyleGroup styleGroup, SwingGraphRenderer mainRenderer) { super(styleGroup); this.styleGroup = styleGroup ; @@ -103,12 +103,12 @@ public void setupRenderingPass(Backend bck, DefaultCamera2D camera, boolean forS height = width ; if(size.size() > 1) height = (int)metrics.lengthToPx(size, 1) ; - + if(group.getShadowMode() != StyleConstants.ShadowMode.NONE) shadow = new SquareShape(); - else + else shadow = null; - + antialiasSetting = g.getRenderingHint( RenderingHints.KEY_ANTIALIASING ); g.setRenderingHint( RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_OFF ); } @@ -119,7 +119,7 @@ public void pushStyle(Backend bck, DefaultCamera2D camera, boolean forShadow) { shadow.configureForGroup(bck, group, camera); // shadow.configure(bck, group, camera, null) // shadow.size(group, camera) - } + } } @Override @@ -132,12 +132,12 @@ public void renderElement(Backend bck, DefaultCamera2D camera, GraphicElement el ce.setVisible(true); ce.updatePosition(camera); ce.updateLabel(); - + if(ce.init == false) checkStyle(camera, ce, true); else if(group.hasEventElements()) checkStyle(camera, ce, ! hadEvents); // hadEvents allows to know if we just - else checkStyle(camera, ce, hadEvents); // changed the style due to an event + else checkStyle(camera, ce, hadEvents); // changed the style due to an event } // and therefore must change the style. @Override @@ -148,7 +148,7 @@ public void renderShadow(Backend bck, DefaultCamera2D camera, GraphicElement ele // if( element.isInstanceOf[GraphicSprite] ) { // camera.getSpritePosition( element.asInstanceOf[GraphicSprite], pos, StyleConstants.Units.GU ) // } -// +// //// shadow.setupContents( g, camera, element, null ) // shadow.positionAndFit( g, camera, null, element, pos.x, pos.y ) shadow.configureForElement(bck, element, null, camera); @@ -158,21 +158,21 @@ public void renderShadow(Backend bck, DefaultCamera2D camera, GraphicElement ele @Override public void elementInvisible(Backend bck, DefaultCamera2D camera, GraphicElement element) { - getOrEquipWithJComponent(element).setVisible(false); + getOrEquipWithJComponent(element).setVisible(false); } @Override public void endRenderingPass(Backend bck, DefaultCamera2D camera, boolean forShadow) { bck.graphics2D().setRenderingHint(RenderingHints.KEY_ANTIALIASING, antialiasSetting); } - + public void unequipElement(GraphicElement element) { if ( compToElement.get((JComponent)element.getComponent()) instanceof ComponentElement) { ComponentElement e = (ComponentElement)compToElement.get((JComponent)element.getComponent()) ; e.detach(); } } - + /** * Get the pair (swing component, graph element) corresponding to the given element. If the * element is not yet associated with a Swing component, the binding is done. @@ -195,7 +195,7 @@ protected ComponentElement getOrEquipWithJComponent(GraphicElement element) { default: throw new RuntimeException("WTF ?!?"); } - + if( ce != null ) { compToElement.put(ce.jComponent, ce); } @@ -203,10 +203,10 @@ protected ComponentElement getOrEquipWithJComponent(GraphicElement element) { else { ce = compToElement.get(component); } - + return ce; } - + public void checkStyle(DefaultCamera2D camera, ComponentElement ce, boolean force) { if(force) { ce.checkIcon(camera); @@ -216,24 +216,24 @@ public void checkStyle(DefaultCamera2D camera, ComponentElement ce, boolean forc ce.setTextFont(); } } - - + + // Nested classes - + /** * Represents the link between a JComponent and a GraphicElement. - * + * * Each of these component elements receive the action events of their button/text-field (for panel * the user is free to do whatever he wants). They are in charge of adding and removing the * component in the rendering surface, etc. - * + * * These elements also allow to push and remove the style to Swing components. We try to do this * only when the style potentially changed, not at each redraw. */ - abstract class ComponentElement extends JPanel + abstract class ComponentElement extends JPanel { protected GraphicElement element ; - + /** Set to true if the element is not yet initialised with its style. */ protected boolean init = false; @@ -245,11 +245,11 @@ abstract class ComponentElement extends JPanel // Construction public ComponentElement(GraphicElement element) { this.element = element ; - + setLayout(null); // No layout in this panel, we set the component bounds ourselves. mainRenderer.renderingSurface().add(this); } - + /** Set of reset the fill mode and colour for the Swing component. */ public void setFill() { // setBackground( group.getFillColor( 0 ) ) @@ -257,34 +257,34 @@ public void setFill() { // if( group.getFillMode == StyleConstants.FillMode.PLAIN ) // jComponent.setBackground( group.getFillColor( 0 ) ) } - + /** Set or reset the text alignment for the Swing component. */ public abstract void setTextAlignment(); - + /** Set or reset the text font size, style and colour for the Swing component. */ public abstract void setTextFont(); - + /** Set or reset the label of the component. */ public abstract void updateLabel(); - + public void setBounds(int x, int y, int width, int height, DefaultCamera2D camera) { setBounds(x, y, width, height); - + int borderWidth = 0; - + if(group.getStrokeMode() != StyleConstants.StrokeMode.NONE && group.getStrokeWidth().value > 0) borderWidth = (int)camera.getMetrics().lengthToPx(group.getStrokeWidth()); jComponent.setBounds(borderWidth, borderWidth, width-(borderWidth*2), height-(borderWidth*2)); } - + /** * Detach the Swing component from the graph element, remove the Swing component from its * Swing container and remove any listeners on the Swing component. The ComponentElement * is not usable after this. */ public void detach() { mainRenderer.renderingSurface().remove(this); } - + // Custom painting @Override public void paint(Graphics g) { @@ -292,7 +292,7 @@ public void paint(Graphics g) { paintBorder(g); paintChildren(g); } - + /** * Check the swing component follows the graph element position. * @param camera The transformation from GU to PX. @@ -312,24 +312,24 @@ else if ( element instanceof GraphicSprite){ // Command -- Utility, positioning private void positionNodeComponent(GraphicNode node, DefaultCamera2D camera) { Point3 pos = camera.transformGuToPx(node.getX(), node.getY(), 0); - + setBounds((int)(pos.x-(width/2)), (int)(pos.y-(height/2)), width, height, camera); } - + private void positionSpriteComponent(GraphicSprite sprite, DefaultCamera2D camera) { Point3 pos = camera.getSpritePosition( sprite, new Point3(), StyleConstants.Units.PX); - + setBounds((int)(pos.x-(width/2)), (int)(pos.y-(height/2)), width, height, camera); } - + // Command -- Utility, applying CSS style to Swing components public void checkBorder( DefaultCamera2D camera, boolean force ) { if(force) { if(group.getStrokeMode() != StyleConstants.StrokeMode.NONE && group.getStrokeWidth().value > 0) setBorder(createBorder(camera)); - else + else setBorder(null); - } + } else { updateBorder(camera); } @@ -339,7 +339,7 @@ private void updateBorder(DefaultCamera2D camera) {} private Border createBorder(DefaultCamera2D camera) { int width = (int)camera.getMetrics().lengthToPx( group.getStrokeWidth() ); - + switch (group.getStrokeMode()) { case PLAIN: return BorderFactory.createLineBorder( ColorManager.getStrokeColor( group, 0 ), width ); case DOTS: throw new RuntimeException( "TODO create dots and dashes borders for component to respect stroke-mode." ); @@ -347,42 +347,42 @@ private Border createBorder(DefaultCamera2D camera) { default: return null ; } } - + public abstract void checkIcon(DefaultCamera2D camera) ; } - + class TextFieldComponentElement extends ComponentElement implements ActionListener { private JTextField comp ; - + public TextFieldComponentElement(GraphicElement element, JTextField comp) { super(element); this.comp = comp ; this.element = element ; - + element.setComponent( comp ); comp.addActionListener( this ); add( comp ); this.jComponent = comp ; } - + @Override public void detach() { super.detach(); comp.removeActionListener( this ); remove( comp ); element.setComponent( null ); - + //component = null //element = null } - + @Override public void actionPerformed(ActionEvent e) { element.label = ((JTextField)comp).getText(); element.setAttribute( "ui.label", element.label ); element.setAttribute( "ui.clicked" ); } - + @Override public void setTextAlignment() { switch (group.getTextAlignment()) { @@ -398,54 +398,54 @@ public void setTextAlignment() { default: break; } } - + @Override public void setTextFont() { Font font = FontCache.getDefaultFont( group.getTextStyle(), (int)group.getTextSize().value ); if( ! group.getTextFont().equals( "default" ) ) font = FontCache.getFont( group.getTextFont(), group.getTextStyle(), (int)group.getTextSize().value ); - + comp.setFont( font ); comp.setForeground( ColorManager.getTextColor( group, 0 ) ); } - + @Override public void updateLabel() { if( ! comp.hasFocus() ) comp.setText( element.getLabel() ); } - + @Override public void checkIcon(DefaultCamera2D camera) {} } - + class ButtonComponentElement extends ComponentElement implements ActionListener { - + private JButton comp ; - + public ButtonComponentElement(GraphicElement element, JButton comp) { super(element); this.comp = comp ; this.element = element ; - + element.setComponent( comp ); comp.addActionListener( this ); add( comp ); this.jComponent = comp ; } - + @Override public void detach() { super.detach(); - + comp.removeActionListener( this ); remove(comp); element.setComponent( null ); - + // component = null; // element = null; } - + @Override public void actionPerformed(ActionEvent e) { element.label = comp.getText(); @@ -453,7 +453,7 @@ public void actionPerformed(ActionEvent e) { element.setAttribute( "ui.clicked" ); element.myGraph().setAttribute( "ui.clicked", element.getId() ); } - + @Override public void setTextAlignment() { switch (group.getTextAlignment()) { @@ -469,37 +469,37 @@ public void setTextAlignment() { default: break; } } - + @Override public void setTextFont() { Font font = FontCache.getDefaultFont( group.getTextStyle(), (int)group.getTextSize().value ); if( ! group.getTextFont().equals( "default" ) ) font = FontCache.getFont( group.getTextFont(), group.getTextStyle(), (int)group.getTextSize().value ); - + comp.setFont( font ); comp.setForeground( ColorManager.getTextColor( group, 0 ) ); } - + @Override public void updateLabel() { String label = element.getLabel(); - + if( label != null ) - comp.setText( label ); + comp.setText( label ); } - + @Override public void checkIcon(DefaultCamera2D camera) { if( group.getIconMode() != StyleConstants.IconMode.NONE ) { String url = group.getIcon(); BufferedImage image = ImageCache.loadImage( url ); - + if( image != null ) { comp.setIcon( new ImageIcon( image ) ); - + switch (group.getIconMode()) { case AT_LEFT: - comp.setHorizontalTextPosition( SwingConstants.RIGHT ); + comp.setHorizontalTextPosition( SwingConstants.RIGHT ); comp.setVerticalTextPosition( SwingConstants.CENTER ); break; case AT_RIGHT: @@ -518,7 +518,7 @@ public void checkIcon(DefaultCamera2D camera) { throw new RuntimeException( "unknown image mode "+group.getIconMode() ); } } - } + } } } } 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..c8df133 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,22 +94,22 @@ 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); } @@ -126,7 +128,7 @@ public static IconAndText apply(Style style, DefaultCamera2D camera, GraphicElem } } } - + 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,25 +141,25 @@ 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 ; } - + 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); } @@ -165,46 +167,46 @@ public void render(Backend backend, DefaultCamera2D camera, double xLeft, double 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) { @@ -303,8 +305,18 @@ public void setText(String text, Backend backend) { // 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(); + //split text into lines + String [] textLines = text.split("\n"); + //set max width to greatest integer value + double maxWidth = 0; + double maxHeight = 0; + for (int i = 0; i < textLines.length; i++) { + this.text.add(new TextLayout(textLines[i], font, TextBox.defaultFontRenderContext)); + maxWidth = Math.max(this.text.get(i).getBounds().getWidth(), maxWidth); + maxWidth = Math.max(this.text.get(i).getBounds().getHeight(), maxHeight); + } + this.bounds = this.text.get(0).getBounds(); } else { this.textData = null ; @@ -313,58 +325,63 @@ 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 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, xLeft, yBottom - getAscent()); +// yBottom -= getAscent() + getDescent(); + text.get(i).draw(g, (float)xLeft, (float) ((float)yBottom+i*getAscent())); + } +// text.get(0).draw(g, (float)xLeft, (float)yBottom); } } } From 30ddee1f2c5394996f693c63bbf1bf78e3c132e0 Mon Sep 17 00:00:00 2001 From: Shyam Mehta Date: Thu, 21 Jul 2022 16:05:56 -0400 Subject: [PATCH 2/6] Better formatting --- pom.xml | 56 +++++++++---------- .../ui/viewer_swing/test/Clicks.java | 4 +- .../renderer/shape/swing/IconAndText.java | 2 +- 3 files changed, 30 insertions(+), 32 deletions(-) diff --git a/pom.xml b/pom.xml index 5c203e5..28692f5 100644 --- a/pom.xml +++ b/pom.xml @@ -1,24 +1,24 @@ - 4.0.0 - + org.graphstream gs-ui-swing 2.0 @@ -26,16 +26,16 @@ gs-ui-swing Swing interface for GraphStream - + http://graphstream-project.org - + scm:git:git://github.com/graphstream/gs-ui-swing.git scm:git:git://github.com/graphstream/gs-ui-swing.git https://github.com/graphstream/gs-ui-swing - + github @@ -45,7 +45,7 @@ UTF-8 - + hbrahimi @@ -74,7 +74,7 @@ http://www.cecill.info/licences/Licence_CeCILL-C_V1-en.html - + 4.0.0 - + org.graphstream gs-ui-swing - 2.0 + 2.1.0-SNAPSHOT jar gs-ui-swing Swing interface for GraphStream - + http://graphstream-project.org - + scm:git:git://github.com/graphstream/gs-ui-swing.git scm:git:git://github.com/graphstream/gs-ui-swing.git https://github.com/graphstream/gs-ui-swing - + github @@ -45,7 +45,7 @@ UTF-8 - + hbrahimi @@ -74,7 +74,7 @@ http://www.cecill.info/licences/Licence_CeCILL-C_V1-en.html - +