فهرست منبع

bessere Grafische darstellung der Annimation

Kolja Strohm 6 سال پیش
والد
کامیت
15af61e51d

+ 18 - 9
src/animation/AnimatedAlgorithm.java

@@ -17,6 +17,7 @@ public abstract class AnimatedAlgorithm extends Thread {
     private JFrame view;
     protected PseudoCodeNode root;
     protected PseudoCodeProcessor processor;
+    private boolean renderImage = false;
 
     public AnimatedAlgorithm( AnimationController controller, LayeredGraphNode graph, JFrame view )
     {
@@ -24,19 +25,27 @@ public abstract class AnimatedAlgorithm extends Thread {
         this.graph = graph;
         this.view = view;
         root = null;
+        renderImage = true;
     }
 
-    private void update()
+    private synchronized void update()
     {
-        SwingUtilities.invokeLater(new Runnable() {
-            public void run() {
-                view.repaint();
-                for( ComponentListener l : view.getComponentListeners() )
-                {
-                    l.componentResized( new ComponentEvent(view, 0) );
+        if( renderImage )
+        {
+            //renderImage = false;
+            SwingUtilities.invokeLater(new Runnable() {
+                public void run() {
+                    for( ComponentListener l : view.getComponentListeners() )
+                    {
+                        l.componentResized( new ComponentEvent(view, 0) );
+                        synchronized( AnimatedAlgorithm.this )
+                        {
+                            renderImage = true;
+                        }
+                    }
                 }
-            }
-        });
+            });
+        }
     }
 
     @Override

+ 2 - 2
src/bk/BKNodePlacement.java

@@ -148,8 +148,7 @@ public class BKNodePlacement extends AnimatedAlgorithm {
                 case BOTTOM_TOP_RIGHT:
                     state = State.LAYOUT4;
                     break;
-                case COMBINED:
-                    state = State.COMBINE;
+                case COMBINED: // this will never happen here
                     break;
                 }
                 for( LayeredGraphNode n : graph.getContainedNodes() )
@@ -175,6 +174,7 @@ public class BKNodePlacement extends AnimatedAlgorithm {
         PseudoCodeNode balancingStage = new PseudoCodeNode( "-- balancing --", vars, tree, new Comment() ) {
             @Override
             public String getDebugOutput( Memory m ) {
+                state = State.COMBINE;
                 if( !m.isSomewhereDefined( "graph", MemoryType.COMPLETE_STACK ) )
                     return "";
                 String info = "| Node | x BR | x BL | x UR | x UL | x CO |\n";

+ 1 - 1
src/bk/PlaceBlock.java

@@ -175,6 +175,6 @@ public class PlaceBlock{
         double max = 0;
         for( LayeredGraphNode n : graph.getContainedNodes() )
             max = Math.max( max, n.getWidth( layout ) );
-        return max + 5;
+        return max + 20;
     }
 }

+ 2 - 8
src/graph/LayeredEdge.java

@@ -189,14 +189,8 @@ public class LayeredEdge implements LayeredGraphEdge {
     {
         NodeView sourceView = ((LayeredNode)sources.get( 0 )).getView( layout );
         NodeView targetView = ((LayeredNode)targets.get( 0 )).getView( layout );
-        //if( bindPoints.get( 0 ) == null && sources.size() > 0 )
-        //{
-            setStartPoint( (int)sources.get( 0 ).getX( layout ) + sourceView.getScaledX( (int)sources.get( 0 ).getWidth( layout ) / 2 ), (int)sources.get( 0 ).getY( layout ) + sourceView.getPreferredSize().height - sourceView.getScaledY( 0 ), layout );
-        //}
-        //if( bindPoints.get( bindPoints.size() - 1 ) == null && targets.size() > 0 )
-        //{
-            setEndPoint( (int)targets.get( 0 ).getX( layout ) + targetView.getScaledX( (int)targets.get( 0 ).getWidth( layout ) / 2 ) , (int)targets.get( 0 ).getY( layout ) + targetView.getScaledY( 0 ), layout );
-        //}
+        setStartPoint( sourceView.getVirtualX() + sourceView.getVirtualWidth() / 2, sourceView.getVirtualY() + sourceView.getVirtualHeight(), layout );
+        setEndPoint( targetView.getVirtualX() + targetView.getVirtualWidth() / 2, targetView.getVirtualY(), layout );
         if( layout == LayoutType.TOP_BOTTOM_LEFT )
             return bindPoints[ 0 ];
         if( layout == LayoutType.TOP_BOTTOM_RIGHT )

+ 5 - 0
src/graph/LayeredGraphNode.java

@@ -24,6 +24,11 @@ public interface LayeredGraphNode {
    */
   public ElkNode getOriginalNode();
 
+
+  public void setMouseOver( boolean over );
+  
+  public boolean isMouseOver();
+  
   /**
    * set the shift of this node to the given value in the given layout
    * or in all layouts if the argument is null.

+ 14 - 7
src/graph/LayeredNode.java

@@ -48,7 +48,6 @@ public class LayeredNode implements LayeredGraphNode {
         public double y;
         public double w;
         public double h;
-        public Color color;
         public boolean selected;
         private NodeView view;
     }
@@ -56,6 +55,7 @@ public class LayeredNode implements LayeredGraphNode {
     private LayoutInfo[] layouts;
     private CombinedLayoutInfo combined;
     private String name;
+    private boolean mouseOver;
     
     // for subgraph in this node
     private ArrayList< LayeredGraphEdge > edges;
@@ -128,8 +128,16 @@ public class LayeredNode implements LayeredGraphNode {
 	        combined.w = original.getWidth();
 	        combined.h = original.getHeight();
         }
-        combined.color = null;
         combined.selected = false;
+        mouseOver = false;
+    }
+    
+    public void setMouseOver( boolean over ) {
+        mouseOver = over;
+    }
+    
+    public boolean isMouseOver() {
+        return mouseOver;
     }
     
     public void setView( NodeView view, LayoutType layout )
@@ -405,7 +413,6 @@ public class LayeredNode implements LayeredGraphNode {
             this.layouts[ 1 ].color = c;
             this.layouts[ 2 ].color = c;
             this.layouts[ 3 ].color = c;
-            combined.color = c;
         }
         if( layout == LayoutType.TOP_BOTTOM_LEFT )
             this.layouts[ 0 ].color = c;
@@ -415,8 +422,6 @@ public class LayeredNode implements LayeredGraphNode {
             this.layouts[ 2 ].color = c;
         if( layout == LayoutType.BOTTOM_TOP_RIGHT )
             this.layouts[ 3 ].color = c;
-        if( layout == LayoutType.COMBINED )
-            combined.color = c;
     }
     
     private int calcClassSize( LayeredGraphNode sink, LayoutType layout )
@@ -460,13 +465,15 @@ public class LayeredNode implements LayeredGraphNode {
         else if( layout == LayoutType.BOTTOM_TOP_RIGHT )
             return this.layouts[ 3 ].sink.getClassColor( layout );
         if( layout == LayoutType.COMBINED )
-            return combined.color;
+            return Color.LIGHT_GRAY;
         return null;
     }
     
     @Override
     public Color getColor( LayoutType layout )
     {
+        if( layout == null )
+            return this.layouts[ 0 ].color;
         if( layout == LayoutType.TOP_BOTTOM_LEFT && this.layouts[ 0 ].root == this && this.layouts[ 0 ].align == this )
             return Color.LIGHT_GRAY;
         if( layout == LayoutType.TOP_BOTTOM_LEFT && this.layouts[ 0 ].root != this )
@@ -492,7 +499,7 @@ public class LayeredNode implements LayeredGraphNode {
         if( layout == LayoutType.BOTTOM_TOP_RIGHT )
             return this.layouts[ 3 ].color;
         if( layout == LayoutType.COMBINED )
-            return combined.color;
+            return Color.LIGHT_GRAY;
         return null;
     }
     

+ 6 - 5
src/graph/InitializeNodePositions.java → src/lib/SimpleNodePlacement.java

@@ -1,9 +1,10 @@
-package graph;
+package lib;
 
 import java.awt.Color;
 import java.util.ArrayList;
 
 import bk.LayoutType;
+import graph.LayeredGraphNode;
 
 
 /**
@@ -12,7 +13,7 @@ import bk.LayoutType;
  * @author kolja
  *
  */
-public class InitializeNodePositions {
+public class SimpleNodePlacement {
     /**
      * the actual algorithm
      * @param graph the graph where the node positions are to be set.
@@ -24,7 +25,7 @@ public class InitializeNodePositions {
         for( LayeredGraphNode n : graph.getContainedNodes() )
         {
             n.setColor( Color.getHSBColor( hue, saturation, brightness ), null );
-            hue += 0.29f;
+            hue += 0.15f;
             placeNodes( n );
         }
         int curY = 0;
@@ -45,9 +46,9 @@ public class InitializeNodePositions {
             for (LayeredGraphNode node : layer) { // Gehe alle Knoten durch
                 node.setX( curX + maxWidth / 2 - node.getWidth( LayoutType.TOP_BOTTOM_LEFT ) / 2, false, null );
                 node.setY( curY + maxHeight / 2 - node.getHeight( LayoutType.TOP_BOTTOM_LEFT ) / 2, null ); // Position setzen
-                curX += maxWidth + 25;
+                curX += maxWidth + 20;
             }
-            curY += maxHeight + 25;
+            curY += maxHeight + 20;
         }
     }
 }

+ 3 - 3
src/main/Main.java

@@ -1,7 +1,7 @@
 package main;
-import graph.InitializeNodePositions;
 import graph.LayeredGraphNode;
 import graph.io.Reader;
+import lib.SimpleNodePlacement;
 import view.MainView;
 
 
@@ -17,9 +17,9 @@ public class Main {
      * @param args the command line arguments, currently not in use
      */
     public static void main(String[] args) {
-        Reader r = new Reader( "logo.json" );
+        Reader r = new Reader( "papergraph.json" );
         LayeredGraphNode graph = r.readInputGraph();
-        InitializeNodePositions.placeNodes( graph );
+        SimpleNodePlacement.placeNodes( graph );
         new MainView( graph );
     }
  

+ 9 - 0
src/view/AnnimatedView.java

@@ -0,0 +1,9 @@
+package view;
+
+public interface AnnimatedView {
+
+    public int getVirtualX();
+    public int getVirtualY();
+    public int getVirtualWidth();
+    public int getVirtualHeight();
+}

+ 51 - 50
src/view/EdgeView.java

@@ -2,7 +2,6 @@ package view;
 
 import java.awt.BasicStroke;
 import java.awt.Color;
-import java.awt.Dimension;
 import java.awt.Graphics;
 import java.awt.Graphics2D;
 import java.awt.Point;
@@ -18,7 +17,7 @@ import graph.LayeredGraphEdge;
  * @author kolja
  *
  */
-public class EdgeView extends JPanel {
+public class EdgeView extends JPanel implements AnnimatedView {
     private static final long serialVersionUID = 1L;
 
     private LayeredGraphEdge model;
@@ -30,73 +29,75 @@ public class EdgeView extends JPanel {
     }
     
     @Override
-    public Point getLocation()
-    {
-        ArrayList<Point> bps = model.getLinePoints( layout );
-        double minX = bps.get( 0 ).getX();
-        double minY = bps.get( 0 ).getY();
-        for( Point p : bps )
-        {
-            minX = Math.min( minX, p.getX() );
-            minY =  Math.min( minY, p.getY() );
-        }
-        minX -= 5;
-        minY -= 5;
-        return new Point( (int)minX, (int)minY );
-    }
-    
-    @Override
-    public int getWidth()
+    public void paint( Graphics g )
     {
-        ArrayList<Point> bps = model.getLinePoints( layout );
-        double max = bps.get( 0 ).getX();
-        for( Point p : bps )
-            max =  Math.max( max, p.getX() );
-        return (int)max + 10;
+        paintComponent( g );
     }
     
-    @Override
-    public int getHeight()
+    private int getScaledX( int x )
     {
-        ArrayList<Point> bps = model.getLinePoints( layout );
-        double max = bps.get( 0 ).getY();
-        for( Point p : bps )
-            max =  Math.max( max, p.getY() );
-        return (int)max + 10;
+        double scale = Math.min( getWidth() / (double)getVirtualWidth(), getHeight() / (double)getVirtualHeight());
+        x *= scale;
+        return x;
     }
     
-    @Override
-    public Dimension getPreferredSize()
+    private int getScaledY( int y )
     {
-        return new Dimension( getWidth(), getHeight() );
+        double scale = Math.min( getWidth() / (double)getVirtualWidth(), getHeight() / (double)getVirtualHeight());
+        y *= scale;
+        return y;
     }
-    
-    @Override
-    public void paint( Graphics g )
-    {
-        paintComponent( g );/*
-        for( Component c : getComponents() )
-            c.paint( g.create( 
-                    c.getX() + 10, 
-                    c.getY() + 10, 
-                    Math.min( getWidth() - 10, c.getWidth() + c.getX() + 10 ), 
-                    Math.min( getHeight() - 10, c.getHeight() + c.getY() + 10 ) ) );
-    */}
 
     @Override
     public void paintComponent( Graphics g )
     {
         ((Graphics2D)g).setStroke(new BasicStroke(1));
-        //System.out.println( "Clipping: x:" + g.getClip().getBounds().getX() + " y:" + g.getClip().getBounds().getY() + " w:" + g.getClip().getBounds().getWidth() + " h:" + g.getClip().getBounds().getHeight() );
         g.setColor( Color.LIGHT_GRAY );
         if( model.isConflicted( layout ) )
             g.setColor( Color.RED );
         ArrayList<Point> bps = model.getLinePoints( layout );
+        int x = getVirtualX();
+        int y = getVirtualY();
         for( int i = 1; i < bps.size(); i++ )
         {
-          //  System.out.println( "Draw a Line from (" + (int)bps.get( i - 1 ).getX() + "," + (int)bps.get( i - 1 ).getY() + ") to (" + (int)bps.get( i ).getX() + "," + (int)bps.get( i ).getY() + ")" );
-            g.drawLine( (int)bps.get( i - 1 ).getX() - getLocation().x, (int)bps.get( i - 1 ).getY() - getLocation().y, (int)bps.get( i ).getX() - getLocation().x, (int)bps.get( i ).getY() - getLocation().y );
+            g.drawLine( getScaledX((int)bps.get( i - 1 ).getX() - x), getScaledY((int)bps.get( i - 1 ).getY() - y), getScaledX((int)bps.get( i ).getX() - x), getScaledY((int)bps.get( i ).getY() - y ));
         }
-        ((Graphics2D)g).fill( RenderHelper.createArrowShape( new Point( bps.get( bps.size() - 2 ).x - getLocation().x, bps.get( bps.size() - 2 ).y - getLocation().y ), new Point( bps.get( bps.size() - 1 ).x - getLocation().x, bps.get( bps.size() - 1 ).y - getLocation().y ) ) );
+        ((Graphics2D)g).fill( RenderHelper.createArrowShape( new Point( getScaledX( bps.get( 0 ).x - x ), getScaledY( bps.get( 0 ).y - y ) ), new Point( getScaledX( bps.get( bps.size() - 1 ).x - x ), getScaledY( bps.get( bps.size() - 1 ).y - y ) ) ) );
+    }
+
+    @Override
+    public int getVirtualX() {
+        int min = Integer.MAX_VALUE;
+        ArrayList<Point> bps = model.getLinePoints( layout );
+        for( Point p : bps )
+            min = Math.min( min, (int)p.getX() - 5 );
+        return min;
+    }
+
+    @Override
+    public int getVirtualY() {
+        int min = Integer.MAX_VALUE;
+        ArrayList<Point> bps = model.getLinePoints( layout );
+        for( Point p : bps )
+            min = Math.min( min, (int)p.getY() - 5 );
+        return min;
+    }
+
+    @Override
+    public int getVirtualWidth() {
+        int max = Integer.MIN_VALUE;
+        ArrayList<Point> bps = model.getLinePoints( layout );
+        for( Point p : bps )
+            max = Math.max( max, (int)p.getX() + 5 );
+        return max - getVirtualX();
+    }
+
+    @Override
+    public int getVirtualHeight() {
+        int max = Integer.MIN_VALUE;
+        ArrayList<Point> bps = model.getLinePoints( layout );
+        for( Point p : bps )
+            max = Math.max( max, (int)p.getY() + 5 );
+        return max - getVirtualY();
     }
 }

+ 13 - 36
src/view/MainView.java

@@ -41,13 +41,14 @@ import animation.Action;
 import animation.AnimationController;
 import animation.PseudoCodeNode;
 import bk.BKNodePlacement;
+import bk.BKNodePlacement.State;
 import bk.LayoutType;
-import graph.InitializeNodePositions;
 import graph.LayeredGraphEdge;
 import graph.LayeredGraphNode;
 import graph.LayeredNode;
 import graph.io.Reader;
 import graph.io.Writer;
+import lib.SimpleNodePlacement;
 import lib.TextLayoutHelper;
 
 /**
@@ -162,6 +163,7 @@ public class MainView {
      */
     public MainView( LayeredGraphNode graph )
     {
+        graph.setColor( null, null );
         frameCounter++;
         this.graph = graph;
         controller = new AnimationController();
@@ -388,7 +390,7 @@ public class MainView {
                 {
                     Reader r = new Reader( chooser.getSelectedFile().getAbsolutePath() );
                     LayeredGraphNode graph = r.readInputGraph();
-                    InitializeNodePositions.placeNodes( graph );
+                    SimpleNodePlacement.placeNodes( graph );
                     new MainView( graph );
                 }
             }
@@ -570,47 +572,17 @@ public class MainView {
         pl.setLocation( 0, 0 );
         pl.setSize( frame.getSize() );
         NodeView topLeft = createNodeView( graph, LayoutType.TOP_BOTTOM_LEFT );
-        topLeft.addMouseMotionListener( new MouseAdapter() {
-            @Override
-            public void mouseMoved( MouseEvent e ) {
-                topLeft.setToolTipText( topLeft.updateTooltipText( e.getX(), e.getY() ) );
-            }
-        });
         NodeView topRight = createNodeView( graph, LayoutType.TOP_BOTTOM_RIGHT );
-        topRight.addMouseMotionListener( new MouseAdapter() {
-            @Override
-            public void mouseMoved( MouseEvent e ) {
-                topRight.setToolTipText( topRight.updateTooltipText( e.getX(), e.getY() ) );
-            }
-        });
         NodeView bottomLeft = createNodeView( graph, LayoutType.BOTTOM_TOP_LEFT );
-        bottomLeft.addMouseMotionListener( new MouseAdapter() {
-            @Override
-            public void mouseMoved( MouseEvent e ) {
-                bottomLeft.setToolTipText( bottomLeft.updateTooltipText( e.getX(), e.getY() ) );
-            }
-        });
         NodeView bottomRight = createNodeView( graph, LayoutType.BOTTOM_TOP_RIGHT );
-        bottomRight.addMouseMotionListener( new MouseAdapter() {
-            @Override
-            public void mouseMoved( MouseEvent e ) {
-                bottomRight.setToolTipText( bottomRight.updateTooltipText( e.getX(), e.getY() ) );
-            }
-        });
         pl.add( topLeft );
         pl.add( topRight );
         pl.add( bottomLeft );
         pl.add( bottomRight );
-        layne.add( pl, 1 );
         NodeView combined = createNodeView( graph, LayoutType.COMBINED );
-        combined.addMouseMotionListener( new MouseAdapter() {
-            @Override
-            public void mouseMoved( MouseEvent e ) {
-                combined.setToolTipText( combined.updateTooltipText( e.getX(), e.getY() ) );
-            }
-        });
         combined.setSize( 500, 500 );
         layne.add( combined, 0 );
+        layne.add( pl, 1 );
         
         JSplitPane spane = new JSplitPane( JSplitPane.HORIZONTAL_SPLIT );
         spane.setLeftComponent( layne );
@@ -659,20 +631,25 @@ public class MainView {
         frame.revalidate();
         frame.repaint();
 
+        State old = algorithm.getAlgorithmState();
+        
         frame.addComponentListener(new ComponentAdapter()
         {
             public void componentResized(ComponentEvent evt) {
                 menue.setSize( menue.getWidth(), layne.getHeight() );
                 spane2.setSize( menue.getWidth() - 20, menue.getHeight() - 120 );
-                if( graph.getColor( LayoutType.COMBINED ) == null )
+                if( graph.getColor( null ) == null )
                 {
                     grout.setHgap( 10 );
                     grout.setVgap( 10 );
+                    combined.setVisible( false );
                 }
                 else
                 {
                     grout.setHgap( layne.getWidth() / 3 );
                     grout.setVgap( layne.getHeight() / 3 );
+                    combined.setVisible( true );
+                    combined.doLayout();
                 }
                 combined.setSize( layne.getWidth() / 3, layne.getHeight() / 3 );
                 combined.setLocation( layne.getWidth() / 3, layne.getHeight() / 3 );
@@ -680,7 +657,7 @@ public class MainView {
                 debugText.setText( algorithm.getDebugString().trim() );
                 layne.remove( pl );
                 layne.add( pl, 1 );
-                if( optionsDialog != null && optionsDialog.getLayerDisplayOption() == 1 )
+                if( optionsDialog != null && optionsDialog.getLayerDisplayOption() == 1 && old != algorithm.getAlgorithmState() )
                 {
                     pl.remove( topLeft );
                     pl.remove( topRight );
@@ -781,7 +758,7 @@ public class MainView {
 
     private NodeView createNodeView( LayeredGraphNode gNode, LayoutType lt )
     {
-        NodeView graphView = new NodeView( gNode, lt );
+        NodeView graphView = new NodeView( gNode, lt, frame );
         ((LayeredNode)gNode).setView( graphView, lt );
         graphView.setLayout( null );
         graphView.setOpaque( true );

+ 156 - 82
src/view/NodeView.java

@@ -3,13 +3,17 @@ package view;
 import java.awt.BasicStroke;
 import java.awt.Color;
 import java.awt.Component;
-import java.awt.Dimension;
 import java.awt.Graphics;
 import java.awt.Graphics2D;
-import java.awt.Point;
+import java.awt.event.ComponentEvent;
+import java.awt.event.ComponentListener;
+import java.awt.event.MouseEvent;
+import java.awt.event.MouseListener;
 
 import javax.swing.BorderFactory;
+import javax.swing.JFrame;
 import javax.swing.JPanel;
+import javax.swing.SwingUtilities;
 import javax.swing.border.Border;
 
 import bk.LayoutType;
@@ -20,119 +24,142 @@ import graph.LayeredGraphNode;
  * @author kolja
  *
  */
-public class NodeView extends JPanel {
+public class NodeView extends JPanel implements AnnimatedView, MouseListener {
     private static final long serialVersionUID = 1L;
     private LayeredGraphNode model;
     private LayoutType layout;
+    private JFrame mainView;
 
-    public NodeView( LayeredGraphNode model, LayoutType lt ) {
+    public NodeView( LayeredGraphNode model, LayoutType lt, JFrame mv ) {
+        mainView = mv;
         this.model = model;
         layout = lt;
         setSize( (int)model.getWidth( layout ), (int)model.getHeight( layout ) );
+        addMouseListener( this );
     }
 
-    @Override
-    public Point getLocation()
-    {
-        return new Point( (int)model.getX( layout ), (int)model.getY( layout ) );
-    }
-    
-    @Override
-    public Dimension getPreferredSize()
+    private synchronized void update()
     {
-        return new Dimension( (int)model.getWidth( layout ), (int)model.getHeight( layout ) );
+        SwingUtilities.invokeLater(new Runnable() {
+            public void run() {
+                for( ComponentListener l : mainView.getComponentListeners() )
+                {
+                    l.componentResized( new ComponentEvent(mainView, 0) );
+                }
+            }
+        });
     }
     
     public int getScaledX( int x )
     {
-        double scale = Math.min( (double)super.getWidth() / (int)model.getWidth( layout ), (double)super.getHeight() / (int)model.getHeight( layout ));
+        double scale = Math.min( (getWidth()-50) / (double)getVirtualWidth(), (getHeight()-50) / (double)getVirtualHeight());
         x *= scale;
-        if( scale == (double)super.getHeight() / (int)model.getHeight( layout ) )
-            x += (super.getWidth() - (model.getWidth( layout ) * scale )) / 2;
         return x;
     }
     
     public int getScaledY( int y )
     {
-        double scale = Math.min( (double)super.getWidth() / (int)model.getWidth( layout ), (double)super.getHeight() / (int)model.getHeight( layout ));
+        double scale = Math.min( (getWidth()-50) / (double)getVirtualWidth(), (getHeight()-50) / (double)getVirtualHeight());
         y *= scale;
-        if( scale == (double)super.getWidth() / (int)model.getWidth( layout ) )
-            y += (super.getHeight() - (model.getHeight( layout ) * scale )) / 2;
         return y;
     }
     
-    public String updateTooltipText( int mx, int my ) {
-        int x = 0;
-        int y = 0;
-        double scaleW = Math.min( (double)super.getWidth() / (int)model.getWidth( layout ), (double)super.getHeight() / (int)model.getHeight( layout ));
-        double scaleH = scaleW;
-        int width = (int)(super.getWidth() / scaleW);
-        if( scaleW == (double)super.getWidth() / (int)model.getWidth( layout ) )
-            y += (super.getHeight() - (model.getHeight( layout ) * scaleH )) / scaleH / 2;
-        if( scaleH == (double)super.getHeight() / (int)model.getHeight( layout ) )
-            x += (super.getWidth() - (model.getWidth( layout ) * scaleW )) / scaleW / 2;
-        if( model.isDummyNode() )
+    public void updateTooltipText() {
+        if( layout != LayoutType.COMBINED )
         {
-            scaleW *= 1 / 4.0;
-            x += width / (3/4.0);
+            setToolTipText( "<html>Name: " + model.toString() + 
+                            "<br>Root: " + model.getRoot( layout ).toString() +
+                            "<br>Shink: " + model.getSink( layout ).toString() + 
+                            "<br>Shift: " + model.getShift( layout ) + "</html>" );
         }
-        double minX = Double.POSITIVE_INFINITY;
+        else
+            setToolTipText( "Name: " + model.toString() );
         for( Component c : getComponents() )
         {
-            minX = Math.min( c.getLocation().x, minX);
+            if( !(c instanceof NodeView) )
+                continue;
+            ((NodeView)c).updateTooltipText();
         }
+    }
+    
+    public int getXOffset()
+    {
+        int x = 0;
+        double scale = Math.min( (getWidth()-50) / (double)getVirtualWidth(), (getHeight()-50) / (double)getVirtualHeight());
+        x += (getWidth()-50) / 2 - (getVirtualWidth() * scale ) / 2 + 25;
+        return x;
+    }
+    
+    public int getYOffset()
+    {
+        int y = 0;
+        double scale = Math.min( (getWidth()-50) / (double)getVirtualWidth(), (getHeight()-50) / (double)getVirtualHeight());
+        y += (getHeight()-50) / 2 - (getVirtualHeight() * scale ) / 2 + 25;
+        return y;
+    }
+    
+    @Override
+    public void doLayout() {
+        double minX = Double.POSITIVE_INFINITY;
         for( Component c : getComponents() )
         {
-            int nx = (int)(mx / scaleW) - (c.getLocation().x + 25 - (int)minX + x);
-            int ny = (int)(my / scaleH) - (c.getLocation().y + 25 + y);
-            int width1 = Math.min( (int)model.getWidth( layout ) - 25, c.getPreferredSize().width + 25 );
-            int height1 = Math.min( (int)model.getHeight( layout ) - 25, c.getPreferredSize().height + 25 );
-            if( nx < width1 && ny < height1 && nx > 0 && ny > 0 && c instanceof NodeView )
-                return ((NodeView)c).updateTooltipText( nx, ny );
+            if( !(c instanceof AnnimatedView) )
+                continue;
+            minX = Math.min( ((AnnimatedView)c).getVirtualX(), minX);
         }
-        if( layout != LayoutType.COMBINED )
+        int x = 0;
+        int y = 0;
+        double scale = Math.min( (getWidth()-50) / (double)getVirtualWidth(), (getHeight()-50) / (double)getVirtualHeight());
+        y += (getHeight()-50) / 2 - (getVirtualHeight() * scale ) / 2 + 25;
+        x += (getWidth()-50) / 2 - (getVirtualWidth() * scale ) / 2 + 25;
+        for( Component c : getComponents() )
         {
-            return "<html>Name: " + model.toString() + 
-                    "<br>Root: " + model.getRoot( layout ).toString() +
-                    "<br>Shink: " + model.getSink( layout ).toString() + 
-                    "<br>Shift: " + model.getShift( layout ) + "</html>";
+            if( !(c instanceof AnnimatedView) )
+                continue;
+            AnnimatedView view = (AnnimatedView)c;
+            c.setLocation( getScaledX( view.getVirtualX() - (int)minX ) + x, getScaledY( view.getVirtualY() ) + y);
+            c.setSize( getScaledX( view.getVirtualWidth() ), getScaledY( view.getVirtualHeight() ) );
+            c.doLayout();
         }
-        return "Name: " + model.toString(); 
     }
     
     @Override
     public void paint( Graphics g )
     {
-        if( layout == LayoutType.COMBINED && model.getColor( layout ) == null )
+        if( layout == LayoutType.COMBINED && model.getColor( null ) == null )
             return;
-        double scale = Math.min( (double)super.getWidth() / (int)model.getWidth( layout ), (double)super.getHeight() / (int)model.getHeight( layout ));
-        ((Graphics2D)g).scale( scale, scale );
-        int x = 0;
-        int y = 0;
-        int width = (int)(super.getWidth() / scale);
-        int height = (int)(super.getHeight() / scale);
-        if( scale == (double)super.getWidth() / (int)model.getWidth( layout ) )
-        	y += (super.getHeight() - (model.getHeight( layout ) * scale )) / scale / 2;
-        if( scale == (double)super.getHeight() / (int)model.getHeight( layout ) )
-        	x += (super.getWidth() - (model.getWidth( layout ) * scale )) / scale / 2;
-        if( model.isDummyNode() )
-        {
-            ((Graphics2D)g).scale( 1 / 4.0, 1 );
-            x += width / (3/4.0);
-        }
-        paintComponent( g.create( x, y, width, height ) );
+        updateTooltipText();
+        paintComponent( g );
         double minX = Double.POSITIVE_INFINITY;
         for( Component c : getComponents() )
         {
-            minX = Math.min( c.getLocation().x, minX);
+            if( !(c instanceof AnnimatedView) )
+                continue;
+            minX = Math.min( ((AnnimatedView)c).getVirtualX(), minX);
         }
+        int x = 0;
+        double scale = Math.min( (getWidth()-50) / (double)getVirtualWidth(), (getHeight()-50) / (double)getVirtualHeight());
+        x += (getWidth()-50) / 2 - (getVirtualWidth() * scale ) / 2 + 25;
         for( Component c : getComponents() )
         {
-            c.paint( g.create( 
-                    c.getLocation().x + 25 - (int)minX + x, 
-                    c.getLocation().y + 25 + y, 
-                    Math.min( (int)model.getWidth( layout ) - 25, c.getPreferredSize().width + Math.abs(c.getLocation().x) + 25 ), 
-                    Math.min( (int)model.getHeight( layout ) - 25, c.getPreferredSize().height + Math.abs(c.getLocation().y) + 25 ) ) );
+            if( c instanceof NodeView )
+            {
+                if( layout != LayoutType.COMBINED )
+                {
+                    NodeView v = (NodeView)c;
+                    v.renderClass( g.create( getScaledX( v.getPlainVirtualX() - (int)minX - 12 ) + x, c.getY() - getScaledY(12), getScaledX( v.getPlainVirtualWidth() + 22 ), c.getHeight() + getScaledY(22) ) );
+                }                
+            }
+            c.paint( g.create( c.getX(), c.getY(), c.getWidth(), c.getHeight() ) );
+        }
+    }
+    
+    public void renderClass( Graphics g ) {
+        g.setColor( model.getRoot( layout ).getClassColor( layout ) );
+        if( model.getContainedNodes().size() == 0 && model.getRoot( layout ).getClassColor( layout ) != Color.LIGHT_GRAY )
+        {
+            g.setColor( new Color( (g.getColor().getRed() + 500) / 3, (g.getColor().getGreen() + 500) / 3, (g.getColor().getBlue() + 500) / 3 ) );
+            g.fillRect( 0, 0, g.getClipBounds().width, g.getClipBounds().height );
         }
     }
 
@@ -145,9 +172,9 @@ public class NodeView extends JPanel {
         if( model.getContainedNodes().size() == 0 )
         {
             if( model.getRoot( layout ) == model )
-                g2.fillOval( 0, 0, (int)model.getWidth( layout )-1, (int)model.getHeight( layout )-1 );
+                g2.fillOval( 0, 0, getWidth(), getHeight() );
             else
-                g2.fillRect( 0, 0, (int)model.getWidth( layout )-1, (int)model.getHeight( layout )-1 );
+                g2.fillRect( 0, 0, getWidth(), getHeight() );
         }
         boolean selected = model.isSelected( layout );
         if( selected )
@@ -155,21 +182,68 @@ public class NodeView extends JPanel {
             g.setColor( Color.BLACK );
             if( model.getContainedNodes().size() > 0 )
                 g.setColor( Color.GRAY );
-            g.fillRect( 0, 0, (int)model.getWidth( layout )-1, (int)model.getHeight( layout )-1 );
+            g.fillRect( 0, 0, getWidth(), getHeight() );
         }
         Border linebor = BorderFactory.createLineBorder(model.getColor( layout ), 5);
         if( model.getRoot( layout ) != model || model.getContainedNodes().size() != 0  )
-            linebor.paintBorder( this, g2, 0, 0, (int)model.getWidth( layout )-1, (int)model.getHeight( layout )-1 );
-        if( layout != LayoutType.COMBINED )
+            linebor.paintBorder( this, g2, 0, 0, getWidth(), getHeight() );
+        if( model.isMouseOver() && model.getContainedNodes().size() == 0 )
         {
-            g.setColor( model.getRoot( layout ).getClassColor( layout ) );
-            if( model.getContainedNodes().size() == 0 )
-            {
-                if( selected )
-                    g.fillOval( (int)model.getWidth( layout ) / 2 - (int)model.getWidth( layout ) / 5, (int)model.getHeight( layout ) / 2 - (int)model.getHeight( layout ) / 5, (int)model.getWidth( layout ) / 5 * 2, (int)model.getHeight( layout ) / 5 * 2 );
-                else
-                    g.fillOval( (int)model.getWidth( layout ) / 2 - (int)model.getWidth( layout ) / 3, (int)model.getHeight( layout ) / 2 - (int)model.getHeight( layout ) / 3, (int)model.getWidth( layout ) / 3 * 2, (int)model.getHeight( layout ) / 3 * 2 );
-            }
+            g.setColor( Color.WHITE );
+            g.fillOval( getWidth() / 4, getHeight() / 4, getWidth() / 2, getHeight() / 2 );
         }
     }
+
+    public int getPlainVirtualX() {
+        return (int)model.getX( layout );
+    }
+
+    @Override
+    public int getVirtualX() {
+        if( model.isDummyNode() )
+            return (int)(model.getX( layout ) + getVirtualWidth() / (3/4.0) );
+        return (int)model.getX( layout );
+    }
+
+    @Override
+    public int getVirtualY() {
+        return (int)model.getY( layout );
+    }
+
+    @Override
+    public int getVirtualWidth() {
+        if( model.isDummyNode() )
+            return (int)(model.getWidth( layout ) / 3);
+        return (int)model.getWidth( layout );
+    }
+
+    public int getPlainVirtualWidth() {
+        return (int)model.getWidth( layout );
+    }
+
+    @Override
+    public int getVirtualHeight() {
+        return (int)model.getHeight( layout );
+    }
+
+    @Override
+    public void mouseClicked(MouseEvent e) {}
+
+    @Override
+    public void mousePressed(MouseEvent e) {}
+
+    @Override
+    public void mouseReleased(MouseEvent e) {}
+
+    @Override
+    public void mouseEntered(MouseEvent e) {
+        model.setMouseOver( true );
+        update();
+    }
+
+    @Override
+    public void mouseExited(MouseEvent e) {
+        model.setMouseOver( false );
+        update();
+    }
 }

+ 2 - 2
src/view/RandomGraphDialog.java

@@ -16,9 +16,9 @@ import javax.swing.JLabel;
 import javax.swing.JOptionPane;
 import javax.swing.JTextField;
 
-import graph.InitializeNodePositions;
 import graph.LayeredGraphNode;
 import graph.RandomGraphGenerator;
+import lib.SimpleNodePlacement;
 import lib.SweepCrossingMinimizer;
 
 public class RandomGraphDialog extends JDialog {
@@ -308,7 +308,7 @@ public class RandomGraphDialog extends JDialog {
                         SweepCrossingMinimizer cminzer = new SweepCrossingMinimizer();
                         for( int i = 0; i < 10; i++ )
                           cminzer.minimizeCrossings( graph );
-                        InitializeNodePositions.placeNodes( graph );
+                        SimpleNodePlacement.placeNodes( graph );
                         new MainView( graph );
                         setVisible( false );
                     } catch( Exception e1 )