src/Tools/Graphview/src/graph_panel.scala
changeset 49731 9759181e861d
parent 49730 e0d98ff3c0db
child 49732 ad362eec19c3
equal deleted inserted replaced
49730:e0d98ff3c0db 49731:9759181e861d
    14 
    14 
    15 import scala.swing.{Panel, ScrollPane}
    15 import scala.swing.{Panel, ScrollPane}
    16 import scala.swing.event._
    16 import scala.swing.event._
    17 
    17 
    18 
    18 
    19 class Graph_Panel(vis: Visualizer, make_tooltip: (JComponent, Int, Int, XML.Body) => String)
    19 class Graph_Panel(
       
    20     val visualizer: Visualizer,
       
    21     make_tooltip: (JComponent, Int, Int, XML.Body) => String)
    20   extends ScrollPane
    22   extends ScrollPane
    21 {
    23 {
    22   private val panel = this
    24   panel =>
    23 
    25 
    24   private var tooltip_content: XML.Body = Nil
    26   private var tooltip_content: XML.Body = Nil
    25 
    27 
    26   override lazy val peer: JScrollPane = new JScrollPane with SuperMixin {
    28   override lazy val peer: JScrollPane = new JScrollPane with SuperMixin {
    27     override def getToolTipText(event: java.awt.event.MouseEvent): String =
    29     override def getToolTipText(event: java.awt.event.MouseEvent): String =
    34   requestFocus()
    36   requestFocus()
    35   
    37   
    36   horizontalScrollBarPolicy = ScrollPane.BarPolicy.Always
    38   horizontalScrollBarPolicy = ScrollPane.BarPolicy.Always
    37   verticalScrollBarPolicy = ScrollPane.BarPolicy.Always
    39   verticalScrollBarPolicy = ScrollPane.BarPolicy.Always
    38 
    40 
    39   def visualizer = vis
       
    40   
       
    41   def fit_to_window() = {
    41   def fit_to_window() = {
    42     Transform.fit_to_window()
    42     Transform.fit_to_window()
    43     repaint()
    43     repaint()
    44   }
    44   }
    45   
    45   
    46   def apply_layout() = vis.Coordinates.layout()  
    46   def apply_layout() = visualizer.Coordinates.layout()  
    47 
    47 
    48   private val paint_panel = new Panel {    
    48   private val paint_panel = new Panel {    
    49     def set_preferred_size() {
    49     def set_preferred_size() {
    50         val (minX, minY, maxX, maxY) = vis.Coordinates.bounds()
    50         val (minX, minY, maxX, maxY) = visualizer.Coordinates.bounds()
    51         val s = Transform.scale
    51         val s = Transform.scale
    52         val (px, py) = Transform.padding
    52         val (px, py) = Transform.padding
    53 
    53 
    54         preferredSize = new Dimension((math.abs(maxX - minX + px) * s).toInt,
    54         preferredSize = new Dimension((math.abs(maxX - minX + px) * s).toInt,
    55                                       (math.abs(maxY - minY + py) * s).toInt)
    55                                       (math.abs(maxY - minY + py) * s).toInt)
    60     override def paint(g: Graphics2D) {
    60     override def paint(g: Graphics2D) {
    61       set_preferred_size()
    61       set_preferred_size()
    62       super.paintComponent(g)
    62       super.paintComponent(g)
    63       g.transform(Transform())
    63       g.transform(Transform())
    64       
    64       
    65       vis.Drawer.paint_all_visible(g, true)
    65       visualizer.Drawer.paint_all_visible(g, true)
    66     }
    66     }
    67   }
    67   }
    68   contents = paint_panel
    68   contents = paint_panel
    69   
    69   
    70   listenTo(keys)
    70   listenTo(keys)
    91           case _ => repaint()
    91           case _ => repaint()
    92         }
    92         }
    93       }
    93       }
    94     }
    94     }
    95   }
    95   }
    96   vis.model.Colors.events += r
    96   visualizer.model.Colors.events += r
    97   vis.model.Mutators.events += r
    97   visualizer.model.Mutators.events += r
    98   
    98   
    99   apply_layout()
    99   apply_layout()
   100   fit_to_window()
   100   fit_to_window()
   101   
   101   
   102   protected object Transform {
   102   protected object Transform {
   108                   _scale = math.max(math.min(s, 10), 0.01)
   108                   _scale = math.max(math.min(s, 10), 0.01)
   109                   paint_panel.set_preferred_size()
   109                   paint_panel.set_preferred_size()
   110                 }
   110                 }
   111                 
   111                 
   112     def apply() = {
   112     def apply() = {
   113       val (minX, minY, _, _) = vis.Coordinates.bounds()
   113       val (minX, minY, _, _) = visualizer.Coordinates.bounds()
   114       
   114       
   115       val at = AffineTransform.getScaleInstance(scale, scale)
   115       val at = AffineTransform.getScaleInstance(scale, scale)
   116       at.translate(-minX + padding._1 / 2, -minY + padding._2 / 2)
   116       at.translate(-minX + padding._1 / 2, -minY + padding._2 / 2)
   117       at
   117       at
   118     }
   118     }
   119     
   119     
   120     def fit_to_window() {
   120     def fit_to_window() {
   121       if (vis.model.visible_nodes().isEmpty)
   121       if (visualizer.model.visible_nodes().isEmpty)
   122         scale = 1
   122         scale = 1
   123       else {
   123       else {
   124         val (minX, minY, maxX, maxY) = vis.Coordinates.bounds()
   124         val (minX, minY, maxX, maxY) = visualizer.Coordinates.bounds()
   125 
   125 
   126         val (dx, dy) = (maxX - minX + padding._1, maxY - minY + padding._2)
   126         val (dx, dy) = (maxX - minX + padding._1, maxY - minY + padding._2)
   127         val (sx, sy) = (1d * size.width / dx, 1d * size.height / dy)
   127         val (sx, sy) = (1d * size.width / dx, 1d * size.height / dy)
   128         scale = math.min(sx, sy)
   128         scale = math.min(sx, sy)
   129       }
   129       }
   158         case ('0', _) => {
   158         case ('0', _) => {
   159           Transform.fit_to_window()
   159           Transform.fit_to_window()
   160         }
   160         }
   161         
   161         
   162         case('1', _) => {
   162         case('1', _) => {
   163             vis.Coordinates.layout()
   163             visualizer.Coordinates.layout()
   164         }
   164         }
   165 
   165 
   166         case('2', _) => {
   166         case('2', _) => {
   167             Transform.fit_to_window()
   167             Transform.fit_to_window()
   168         }          
   168         }          
   178       type Dummy = ((String, String), Int)
   178       type Dummy = ((String, String), Int)
   179       
   179       
   180       private var draginfo: (Point, Iterable[String], Iterable[Dummy]) = null
   180       private var draginfo: (Point, Iterable[String], Iterable[Dummy]) = null
   181       private val g =
   181       private val g =
   182         new BufferedImage(1, 1, BufferedImage.TYPE_INT_RGB).createGraphics
   182         new BufferedImage(1, 1, BufferedImage.TYPE_INT_RGB).createGraphics
   183       g.setFont(vis.Font())
   183       g.setFont(visualizer.Font())
   184       g.setRenderingHints(vis.rendering_hints)
   184       g.setRenderingHints(visualizer.rendering_hints)
   185 
   185 
   186       val react: PartialFunction[Event, Unit] = {   
   186       val react: PartialFunction[Event, Unit] = {   
   187         case MousePressed(_, p, _, _, _) => pressed(p)
   187         case MousePressed(_, p, _, _, _) => pressed(p)
   188         case MouseDragged(_, to, _) => {
   188         case MouseDragged(_, to, _) => {
   189             drag(draginfo, to)
   189             drag(draginfo, to)
   194         case e@MouseClicked(_, p, m, n, _) => click(p, m, n, e)
   194         case e@MouseClicked(_, p, m, n, _) => click(p, m, n, e)
   195         case MouseMoved(_, p, _) => moved(p)
   195         case MouseMoved(_, p, _) => moved(p)
   196       }
   196       }
   197       
   197       
   198       def node(at: Point2D): Option[String] = 
   198       def node(at: Point2D): Option[String] = 
   199         vis.model.visible_nodes().find({
   199         visualizer.model.visible_nodes().find({
   200             l => vis.Drawer.shape(g, Some(l)).contains(at)
   200             l => visualizer.Drawer.shape(g, Some(l)).contains(at)
   201           })
   201           })
   202       
   202       
   203       def dummy(at: Point2D): Option[Dummy] =
   203       def dummy(at: Point2D): Option[Dummy] =
   204         vis.model.visible_edges().map({
   204         visualizer.model.visible_edges().map({
   205             i => vis.Coordinates(i).zipWithIndex.map((i, _))
   205             i => visualizer.Coordinates(i).zipWithIndex.map((i, _))
   206           }).flatten.find({
   206           }).flatten.find({
   207             case (_, ((x, y), _)) => 
   207             case (_, ((x, y), _)) => 
   208               vis.Drawer.shape(g, None).contains(at.getX() - x, at.getY() - y)
   208               visualizer.Drawer.shape(g, None).contains(at.getX() - x, at.getY() - y)
   209           }) match {
   209           }) match {
   210             case None => None
   210             case None => None
   211             case Some((name, (_, index))) => Some((name, index))
   211             case Some((name, (_, index))) => Some((name, index))
   212           }
   212           }
   213       
   213       
   214       def moved(at: Point) {
   214       def moved(at: Point) {
   215         val c = Transform.pane_to_graph_coordinates(at)
   215         val c = Transform.pane_to_graph_coordinates(at)
   216         node(c) match {
   216         node(c) match {
   217           case Some(l) => panel.tooltip = ""; panel.tooltip_content = vis.Tooltip.content(l)
   217           case Some(l) =>
   218           case None => panel.tooltip = null; panel.tooltip_content = Nil
   218             panel.tooltip = ""
       
   219             panel.tooltip_content = visualizer.Tooltip.content(l)
       
   220           case None =>
       
   221             panel.tooltip = null
       
   222             panel.tooltip_content = Nil
   219         }
   223         }
   220       }
   224       }
   221       
   225       
   222       def pressed(at: Point) {
   226       def pressed(at: Point) {
   223         val c = Transform.pane_to_graph_coordinates(at)
   227         val c = Transform.pane_to_graph_coordinates(at)
   224         val l = node(c) match {
   228         val l = node(c) match {
   225           case Some(l) => if (vis.Selection(l))
   229           case Some(l) =>
   226                             vis.Selection()
   230             if (visualizer.Selection(l)) visualizer.Selection() else List(l)
   227                           else
       
   228                             List(l)
       
   229           
       
   230           case None => Nil
   231           case None => Nil
   231         }
   232         }
   232         val d = l match {
   233         val d = l match {
   233           case Nil => dummy(c) match {
   234           case Nil => dummy(c) match {
   234               case Some(d) => List(d)
   235               case Some(d) => List(d)
   247         val c = Transform.pane_to_graph_coordinates(at)
   248         val c = Transform.pane_to_graph_coordinates(at)
   248         val p = node(c)
   249         val p = node(c)
   249         
   250         
   250         def left_click() {
   251         def left_click() {
   251           (p, m) match {
   252           (p, m) match {
   252             case (Some(l), Control) => vis.Selection.add(l)
   253             case (Some(l), Control) => visualizer.Selection.add(l)
   253             case (None, Control) =>
   254             case (None, Control) =>
   254 
   255 
   255             case (Some(l), Shift) => vis.Selection.add(l)
   256             case (Some(l), Shift) => visualizer.Selection.add(l)
   256             case (None, Shift) =>
   257             case (None, Shift) =>
   257 
   258 
   258             case (Some(l), _) => vis.Selection.set(List(l))
   259             case (Some(l), _) => visualizer.Selection.set(List(l))
   259             case (None, _) => vis.Selection.clear
   260             case (None, _) => visualizer.Selection.clear
   260           }          
   261           }          
   261         }
   262         }
   262         
   263         
   263         def right_click() {
   264         def right_click() {
   264           val menu = Popups(panel, p, vis.Selection())
   265           val menu = Popups(panel, p, visualizer.Selection())
   265           menu.show(panel.peer, at.x, at.y)
   266           menu.show(panel.peer, at.x, at.y)
   266         }
   267         }
   267         
   268         
   268         if (clicks < 2) {
   269         if (clicks < 2) {
   269           if (SwingUtilities.isRightMouseButton(e.peer)) right_click()
   270           if (SwingUtilities.isRightMouseButton(e.peer)) right_click()
   283 
   284 
   284             paint_panel.peer.scrollRectToVisible(r)
   285             paint_panel.peer.scrollRectToVisible(r)
   285           }
   286           }
   286             
   287             
   287           case (Nil, ds) =>
   288           case (Nil, ds) =>
   288             ds.foreach(d => vis.Coordinates.translate(d, (dx / s, dy / s)))
   289             ds.foreach(d => visualizer.Coordinates.translate(d, (dx / s, dy / s)))
   289                      
   290                      
   290           case (ls, _) =>
   291           case (ls, _) =>
   291             ls.foreach(l => vis.Coordinates.translate(l, (dx / s, dy / s)))
   292             ls.foreach(l => visualizer.Coordinates.translate(l, (dx / s, dy / s)))
   292         }
   293         }
   293       }
   294       }
   294 
   295 
   295       def wheel(rotation: Int, at: Point) {
   296       def wheel(rotation: Int, at: Point) {
   296         val at2 = Transform.pane_to_graph_coordinates(at)
   297         val at2 = Transform.pane_to_graph_coordinates(at)