src/Tools/Graphview/graph_panel.scala
author wenzelm
Sun, 25 Jan 2015 17:48:14 +0100
changeset 59441 ab2c3597f1d3
parent 59411 99d009ede619
child 59443 5b552b4f63a5
permissions -rw-r--r--
separate module Graph_File;
Ignore whitespace changes - Everywhere: Within whitespace: At end of lines:
59202
711c2446dc9d clarified source location;
wenzelm
parents: 57044
diff changeset
     1
/*  Title:      Tools/Graphview/graph_panel.scala
49557
61988f9df94d added Graphview tool, based on Isabelle/Scala and Swing/Graphics2D;
Markus Kaiser <markus.kaiser@in.tum.de>
parents:
diff changeset
     2
    Author:     Markus Kaiser, TU Muenchen
59240
e411afcfaa29 tuned headers;
wenzelm
parents: 59239
diff changeset
     3
    Author:     Makarius
49557
61988f9df94d added Graphview tool, based on Isabelle/Scala and Swing/Graphics2D;
Markus Kaiser <markus.kaiser@in.tum.de>
parents:
diff changeset
     4
61988f9df94d added Graphview tool, based on Isabelle/Scala and Swing/Graphics2D;
Markus Kaiser <markus.kaiser@in.tum.de>
parents:
diff changeset
     5
Graphview Java2D drawing panel.
61988f9df94d added Graphview tool, based on Isabelle/Scala and Swing/Graphics2D;
Markus Kaiser <markus.kaiser@in.tum.de>
parents:
diff changeset
     6
*/
61988f9df94d added Graphview tool, based on Isabelle/Scala and Swing/Graphics2D;
Markus Kaiser <markus.kaiser@in.tum.de>
parents:
diff changeset
     7
61988f9df94d added Graphview tool, based on Isabelle/Scala and Swing/Graphics2D;
Markus Kaiser <markus.kaiser@in.tum.de>
parents:
diff changeset
     8
package isabelle.graphview
61988f9df94d added Graphview tool, based on Isabelle/Scala and Swing/Graphics2D;
Markus Kaiser <markus.kaiser@in.tum.de>
parents:
diff changeset
     9
55618
995162143ef4 tuned imports;
wenzelm
parents: 51616
diff changeset
    10
49558
af7b652180d5 minimal component and build setup for graphview;
wenzelm
parents: 49557
diff changeset
    11
import isabelle._
49557
61988f9df94d added Graphview tool, based on Isabelle/Scala and Swing/Graphics2D;
Markus Kaiser <markus.kaiser@in.tum.de>
parents:
diff changeset
    12
59441
ab2c3597f1d3 separate module Graph_File;
wenzelm
parents: 59411
diff changeset
    13
import java.awt.{Dimension, Graphics2D, Point, Rectangle}
49557
61988f9df94d added Graphview tool, based on Isabelle/Scala and Swing/Graphics2D;
Markus Kaiser <markus.kaiser@in.tum.de>
parents:
diff changeset
    14
import java.awt.geom.{AffineTransform, Point2D}
59408
63cb603b5114 more symmetric layout of main panel;
wenzelm
parents: 59403
diff changeset
    15
import javax.imageio.ImageIO
59225
d0edf67253d3 tuned imports;
wenzelm
parents: 59219
diff changeset
    16
import javax.swing.{JScrollPane, JComponent, SwingUtilities}
59408
63cb603b5114 more symmetric layout of main panel;
wenzelm
parents: 59403
diff changeset
    17
import javax.swing.border.EmptyBorder
49729
f53a8f73b40f more basic tooltips;
wenzelm
parents: 49569
diff changeset
    18
59408
63cb603b5114 more symmetric layout of main panel;
wenzelm
parents: 59403
diff changeset
    19
import scala.swing.{BorderPanel, Button, CheckBox, Action, FileChooser, Panel, ScrollPane}
59253
9448f4fc95e0 apply_layout: proper repaint;
wenzelm
parents: 59250
diff changeset
    20
import scala.swing.event.{Event, Key, MousePressed, MouseDragged, MouseClicked, MouseEvent}
49557
61988f9df94d added Graphview tool, based on Isabelle/Scala and Swing/Graphics2D;
Markus Kaiser <markus.kaiser@in.tum.de>
parents:
diff changeset
    21
61988f9df94d added Graphview tool, based on Isabelle/Scala and Swing/Graphics2D;
Markus Kaiser <markus.kaiser@in.tum.de>
parents:
diff changeset
    22
59408
63cb603b5114 more symmetric layout of main panel;
wenzelm
parents: 59403
diff changeset
    23
class Graph_Panel(val visualizer: Visualizer) extends BorderPanel
49729
f53a8f73b40f more basic tooltips;
wenzelm
parents: 49569
diff changeset
    24
{
59408
63cb603b5114 more symmetric layout of main panel;
wenzelm
parents: 59403
diff changeset
    25
  graph_panel =>
63cb603b5114 more symmetric layout of main panel;
wenzelm
parents: 59403
diff changeset
    26
49729
f53a8f73b40f more basic tooltips;
wenzelm
parents: 49569
diff changeset
    27
59398
ea163bf8ad22 misc tuning;
wenzelm
parents: 59397
diff changeset
    28
59408
63cb603b5114 more symmetric layout of main panel;
wenzelm
parents: 59403
diff changeset
    29
  /** graph **/
59398
ea163bf8ad22 misc tuning;
wenzelm
parents: 59397
diff changeset
    30
59408
63cb603b5114 more symmetric layout of main panel;
wenzelm
parents: 59403
diff changeset
    31
  /* painter */
59243
21ef04bd4e17 recovered tooltip from 6e77ddb1e3fb: non-null default is required as prerequisite;
wenzelm
parents: 59241
diff changeset
    32
59408
63cb603b5114 more symmetric layout of main panel;
wenzelm
parents: 59403
diff changeset
    33
  private val painter = new Panel
63cb603b5114 more symmetric layout of main panel;
wenzelm
parents: 59403
diff changeset
    34
  {
63cb603b5114 more symmetric layout of main panel;
wenzelm
parents: 59403
diff changeset
    35
    override def paint(gfx: Graphics2D)
63cb603b5114 more symmetric layout of main panel;
wenzelm
parents: 59403
diff changeset
    36
    {
63cb603b5114 more symmetric layout of main panel;
wenzelm
parents: 59403
diff changeset
    37
      super.paintComponent(gfx)
63cb603b5114 more symmetric layout of main panel;
wenzelm
parents: 59403
diff changeset
    38
63cb603b5114 more symmetric layout of main panel;
wenzelm
parents: 59403
diff changeset
    39
      gfx.setColor(visualizer.background_color)
63cb603b5114 more symmetric layout of main panel;
wenzelm
parents: 59403
diff changeset
    40
      gfx.fillRect(0, 0, peer.getWidth, peer.getHeight)
63cb603b5114 more symmetric layout of main panel;
wenzelm
parents: 59403
diff changeset
    41
63cb603b5114 more symmetric layout of main panel;
wenzelm
parents: 59403
diff changeset
    42
      gfx.transform(Transform())
63cb603b5114 more symmetric layout of main panel;
wenzelm
parents: 59403
diff changeset
    43
      visualizer.paint_all_visible(gfx)
63cb603b5114 more symmetric layout of main panel;
wenzelm
parents: 59403
diff changeset
    44
    }
49729
f53a8f73b40f more basic tooltips;
wenzelm
parents: 49569
diff changeset
    45
  }
f53a8f73b40f more basic tooltips;
wenzelm
parents: 49569
diff changeset
    46
59408
63cb603b5114 more symmetric layout of main panel;
wenzelm
parents: 59403
diff changeset
    47
  def set_preferred_size()
63cb603b5114 more symmetric layout of main panel;
wenzelm
parents: 59403
diff changeset
    48
  {
63cb603b5114 more symmetric layout of main panel;
wenzelm
parents: 59403
diff changeset
    49
    val box = visualizer.bounding_box()
63cb603b5114 more symmetric layout of main panel;
wenzelm
parents: 59403
diff changeset
    50
    val s = Transform.scale_discrete
63cb603b5114 more symmetric layout of main panel;
wenzelm
parents: 59403
diff changeset
    51
    painter.preferredSize = new Dimension((box.width * s).ceil.toInt, (box.height * s).ceil.toInt)
63cb603b5114 more symmetric layout of main panel;
wenzelm
parents: 59403
diff changeset
    52
    painter.revalidate()
63cb603b5114 more symmetric layout of main panel;
wenzelm
parents: 59403
diff changeset
    53
  }
59398
ea163bf8ad22 misc tuning;
wenzelm
parents: 59397
diff changeset
    54
59408
63cb603b5114 more symmetric layout of main panel;
wenzelm
parents: 59403
diff changeset
    55
  def refresh()
63cb603b5114 more symmetric layout of main panel;
wenzelm
parents: 59403
diff changeset
    56
  {
63cb603b5114 more symmetric layout of main panel;
wenzelm
parents: 59403
diff changeset
    57
    if (painter != null) {
63cb603b5114 more symmetric layout of main panel;
wenzelm
parents: 59403
diff changeset
    58
      set_preferred_size()
63cb603b5114 more symmetric layout of main panel;
wenzelm
parents: 59403
diff changeset
    59
      painter.repaint()
63cb603b5114 more symmetric layout of main panel;
wenzelm
parents: 59403
diff changeset
    60
    }
63cb603b5114 more symmetric layout of main panel;
wenzelm
parents: 59403
diff changeset
    61
  }
59237
ac135eff1ffb clarified mouse wheel: conventional scrolling, not scaling;
wenzelm
parents: 59234
diff changeset
    62
59398
ea163bf8ad22 misc tuning;
wenzelm
parents: 59397
diff changeset
    63
  def scroll_to_node(node: Graph_Display.Node)
49735
30e2f3f1c623 more precise repaint and revalidate -- the latter is important to keep in sync with content update;
wenzelm
parents: 49733
diff changeset
    64
  {
59398
ea163bf8ad22 misc tuning;
wenzelm
parents: 59397
diff changeset
    65
    val gap = visualizer.metrics.gap
ea163bf8ad22 misc tuning;
wenzelm
parents: 59397
diff changeset
    66
    val info = visualizer.layout.get_node(node)
ea163bf8ad22 misc tuning;
wenzelm
parents: 59397
diff changeset
    67
ea163bf8ad22 misc tuning;
wenzelm
parents: 59397
diff changeset
    68
    val t = Transform()
ea163bf8ad22 misc tuning;
wenzelm
parents: 59397
diff changeset
    69
    val p =
ea163bf8ad22 misc tuning;
wenzelm
parents: 59397
diff changeset
    70
      t.transform(new Point2D.Double(info.x - info.width2 - gap, info.y - info.height2 - gap), null)
ea163bf8ad22 misc tuning;
wenzelm
parents: 59397
diff changeset
    71
    val q =
ea163bf8ad22 misc tuning;
wenzelm
parents: 59397
diff changeset
    72
      t.transform(new Point2D.Double(info.x + info.width2 + gap, info.y + info.height2 + gap), null)
ea163bf8ad22 misc tuning;
wenzelm
parents: 59397
diff changeset
    73
59408
63cb603b5114 more symmetric layout of main panel;
wenzelm
parents: 59403
diff changeset
    74
    painter.peer.scrollRectToVisible(
59398
ea163bf8ad22 misc tuning;
wenzelm
parents: 59397
diff changeset
    75
      new Rectangle(p.getX.toInt, p.getY.toInt,
ea163bf8ad22 misc tuning;
wenzelm
parents: 59397
diff changeset
    76
        (q.getX - p.getX).ceil.toInt, (q.getY - p.getY).ceil.toInt))
49735
30e2f3f1c623 more precise repaint and revalidate -- the latter is important to keep in sync with content update;
wenzelm
parents: 49733
diff changeset
    77
  }
30e2f3f1c623 more precise repaint and revalidate -- the latter is important to keep in sync with content update;
wenzelm
parents: 49733
diff changeset
    78
50470
wenzelm
parents: 50469
diff changeset
    79
59408
63cb603b5114 more symmetric layout of main panel;
wenzelm
parents: 59403
diff changeset
    80
  /* scrollable graph pane */
63cb603b5114 more symmetric layout of main panel;
wenzelm
parents: 59403
diff changeset
    81
63cb603b5114 more symmetric layout of main panel;
wenzelm
parents: 59403
diff changeset
    82
  private val graph_pane: ScrollPane = new ScrollPane(painter) {
63cb603b5114 more symmetric layout of main panel;
wenzelm
parents: 59403
diff changeset
    83
    tooltip = ""
50478
ccfdd1f6cf10 added explicit zoom box;
wenzelm
parents: 50477
diff changeset
    84
59408
63cb603b5114 more symmetric layout of main panel;
wenzelm
parents: 59403
diff changeset
    85
    override lazy val peer: JScrollPane = new JScrollPane with SuperMixin {
63cb603b5114 more symmetric layout of main panel;
wenzelm
parents: 59403
diff changeset
    86
      override def getToolTipText(event: java.awt.event.MouseEvent): String =
63cb603b5114 more symmetric layout of main panel;
wenzelm
parents: 59403
diff changeset
    87
        visualizer.find_node(Transform.pane_to_graph_coordinates(event.getPoint)) match {
63cb603b5114 more symmetric layout of main panel;
wenzelm
parents: 59403
diff changeset
    88
          case Some(node) =>
63cb603b5114 more symmetric layout of main panel;
wenzelm
parents: 59403
diff changeset
    89
            visualizer.model.full_graph.get_node(node) match {
63cb603b5114 more symmetric layout of main panel;
wenzelm
parents: 59403
diff changeset
    90
              case Nil => null
63cb603b5114 more symmetric layout of main panel;
wenzelm
parents: 59403
diff changeset
    91
              case content =>
63cb603b5114 more symmetric layout of main panel;
wenzelm
parents: 59403
diff changeset
    92
                visualizer.make_tooltip(graph_pane.peer, event.getX, event.getY, content)
63cb603b5114 more symmetric layout of main panel;
wenzelm
parents: 59403
diff changeset
    93
            }
63cb603b5114 more symmetric layout of main panel;
wenzelm
parents: 59403
diff changeset
    94
          case None => null
63cb603b5114 more symmetric layout of main panel;
wenzelm
parents: 59403
diff changeset
    95
        }
59218
eadd82d440b0 tuned whitespace;
wenzelm
parents: 59202
diff changeset
    96
    }
50470
wenzelm
parents: 50469
diff changeset
    97
59408
63cb603b5114 more symmetric layout of main panel;
wenzelm
parents: 59403
diff changeset
    98
    horizontalScrollBarPolicy = ScrollPane.BarPolicy.Always
63cb603b5114 more symmetric layout of main panel;
wenzelm
parents: 59403
diff changeset
    99
    verticalScrollBarPolicy = ScrollPane.BarPolicy.Always
63cb603b5114 more symmetric layout of main panel;
wenzelm
parents: 59403
diff changeset
   100
63cb603b5114 more symmetric layout of main panel;
wenzelm
parents: 59403
diff changeset
   101
    listenTo(mouse.moves)
63cb603b5114 more symmetric layout of main panel;
wenzelm
parents: 59403
diff changeset
   102
    listenTo(mouse.clicks)
63cb603b5114 more symmetric layout of main panel;
wenzelm
parents: 59403
diff changeset
   103
    reactions +=
59218
eadd82d440b0 tuned whitespace;
wenzelm
parents: 59202
diff changeset
   104
    {
59408
63cb603b5114 more symmetric layout of main panel;
wenzelm
parents: 59403
diff changeset
   105
      case MousePressed(_, p, _, _, _) =>
63cb603b5114 more symmetric layout of main panel;
wenzelm
parents: 59403
diff changeset
   106
        Mouse_Interaction.pressed(p)
63cb603b5114 more symmetric layout of main panel;
wenzelm
parents: 59403
diff changeset
   107
        painter.repaint()
63cb603b5114 more symmetric layout of main panel;
wenzelm
parents: 59403
diff changeset
   108
      case MouseDragged(_, to, _) =>
63cb603b5114 more symmetric layout of main panel;
wenzelm
parents: 59403
diff changeset
   109
        Mouse_Interaction.dragged(to)
63cb603b5114 more symmetric layout of main panel;
wenzelm
parents: 59403
diff changeset
   110
        painter.repaint()
63cb603b5114 more symmetric layout of main panel;
wenzelm
parents: 59403
diff changeset
   111
      case e @ MouseClicked(_, p, m, n, _) =>
63cb603b5114 more symmetric layout of main panel;
wenzelm
parents: 59403
diff changeset
   112
        Mouse_Interaction.clicked(p, m, n, SwingUtilities.isRightMouseButton(e.peer))
63cb603b5114 more symmetric layout of main panel;
wenzelm
parents: 59403
diff changeset
   113
        painter.repaint()
63cb603b5114 more symmetric layout of main panel;
wenzelm
parents: 59403
diff changeset
   114
    }
50470
wenzelm
parents: 50469
diff changeset
   115
59408
63cb603b5114 more symmetric layout of main panel;
wenzelm
parents: 59403
diff changeset
   116
    contents = painter
49557
61988f9df94d added Graphview tool, based on Isabelle/Scala and Swing/Graphics2D;
Markus Kaiser <markus.kaiser@in.tum.de>
parents:
diff changeset
   117
  }
59408
63cb603b5114 more symmetric layout of main panel;
wenzelm
parents: 59403
diff changeset
   118
  graph_pane.peer.getVerticalScrollBar.setUnitIncrement(10)
50470
wenzelm
parents: 50469
diff changeset
   119
59408
63cb603b5114 more symmetric layout of main panel;
wenzelm
parents: 59403
diff changeset
   120
63cb603b5114 more symmetric layout of main panel;
wenzelm
parents: 59403
diff changeset
   121
  /* transform */
49733
38a68e6593be prefer synchronous Mutator_Event.Bus on Swing_Thread;
wenzelm
parents: 49732
diff changeset
   122
59398
ea163bf8ad22 misc tuning;
wenzelm
parents: 59397
diff changeset
   123
  def rescale(s: Double)
ea163bf8ad22 misc tuning;
wenzelm
parents: 59397
diff changeset
   124
  {
ea163bf8ad22 misc tuning;
wenzelm
parents: 59397
diff changeset
   125
    Transform.scale = s
ea163bf8ad22 misc tuning;
wenzelm
parents: 59397
diff changeset
   126
    if (zoom != null) zoom.set_item((Transform.scale_discrete * 100).floor.toInt)
ea163bf8ad22 misc tuning;
wenzelm
parents: 59397
diff changeset
   127
    refresh()
ea163bf8ad22 misc tuning;
wenzelm
parents: 59397
diff changeset
   128
  }
50470
wenzelm
parents: 50469
diff changeset
   129
59399
wenzelm
parents: 59398
diff changeset
   130
  def fit_to_window()
wenzelm
parents: 59398
diff changeset
   131
  {
wenzelm
parents: 59398
diff changeset
   132
    Transform.fit_to_window()
wenzelm
parents: 59398
diff changeset
   133
    refresh()
wenzelm
parents: 59398
diff changeset
   134
  }
wenzelm
parents: 59398
diff changeset
   135
50469
wenzelm
parents: 50468
diff changeset
   136
  private object Transform
wenzelm
parents: 50468
diff changeset
   137
  {
50474
6ee044e2d1a7 initial layout coordinates more like old browser;
wenzelm
parents: 50470
diff changeset
   138
    private var _scale: Double = 1.0
50477
ffa18243a4e3 some attempts at more discrete scale factor;
wenzelm
parents: 50476
diff changeset
   139
    def scale: Double = _scale
ffa18243a4e3 some attempts at more discrete scale factor;
wenzelm
parents: 50476
diff changeset
   140
    def scale_=(s: Double)
50468
7a2a4b84c5ee tuned min/max;
wenzelm
parents: 50465
diff changeset
   141
    {
59241
541b95e94dc7 clarified bounding box, similar to old graph browser;
wenzelm
parents: 59240
diff changeset
   142
      _scale = (s min 10.0) max 0.1
50468
7a2a4b84c5ee tuned min/max;
wenzelm
parents: 50465
diff changeset
   143
    }
59255
db265648139c clarified fit_to_window: floor scale within window bounds;
wenzelm
parents: 59253
diff changeset
   144
50477
ffa18243a4e3 some attempts at more discrete scale factor;
wenzelm
parents: 50476
diff changeset
   145
    def scale_discrete: Double =
59286
ac74eedb910a GUI.imitate_font: more explicit result size, e.g. relevant for caching;
wenzelm
parents: 59262
diff changeset
   146
    {
59290
569a8109eeb2 separate module Metrics;
wenzelm
parents: 59287
diff changeset
   147
      val font_height = GUI.line_metrics(visualizer.metrics.font).getHeight.toInt
59286
ac74eedb910a GUI.imitate_font: more explicit result size, e.g. relevant for caching;
wenzelm
parents: 59262
diff changeset
   148
      (scale * font_height).floor / font_height
ac74eedb910a GUI.imitate_font: more explicit result size, e.g. relevant for caching;
wenzelm
parents: 59262
diff changeset
   149
    }
50470
wenzelm
parents: 50469
diff changeset
   150
59218
eadd82d440b0 tuned whitespace;
wenzelm
parents: 59202
diff changeset
   151
    def apply() =
eadd82d440b0 tuned whitespace;
wenzelm
parents: 59202
diff changeset
   152
    {
59302
4d985afc0565 explict layout graph structure, with dummies and coordinates;
wenzelm
parents: 59294
diff changeset
   153
      val box = visualizer.bounding_box()
59397
fc909f7e7ce5 proper scrolling wrt. transform;
wenzelm
parents: 59392
diff changeset
   154
      val t = AffineTransform.getScaleInstance(scale_discrete, scale_discrete)
fc909f7e7ce5 proper scrolling wrt. transform;
wenzelm
parents: 59392
diff changeset
   155
      t.translate(- box.x, - box.y)
fc909f7e7ce5 proper scrolling wrt. transform;
wenzelm
parents: 59392
diff changeset
   156
      t
49557
61988f9df94d added Graphview tool, based on Isabelle/Scala and Swing/Graphics2D;
Markus Kaiser <markus.kaiser@in.tum.de>
parents:
diff changeset
   157
    }
50470
wenzelm
parents: 50469
diff changeset
   158
59218
eadd82d440b0 tuned whitespace;
wenzelm
parents: 59202
diff changeset
   159
    def fit_to_window()
eadd82d440b0 tuned whitespace;
wenzelm
parents: 59202
diff changeset
   160
    {
59290
569a8109eeb2 separate module Metrics;
wenzelm
parents: 59287
diff changeset
   161
      if (visualizer.visible_graph.is_empty)
50491
0faaa279faee improved coupling of zoom_box and scale;
wenzelm
parents: 50478
diff changeset
   162
        rescale(1.0)
49557
61988f9df94d added Graphview tool, based on Isabelle/Scala and Swing/Graphics2D;
Markus Kaiser <markus.kaiser@in.tum.de>
parents:
diff changeset
   163
      else {
59302
4d985afc0565 explict layout graph structure, with dummies and coordinates;
wenzelm
parents: 59294
diff changeset
   164
        val box = visualizer.bounding_box()
59241
541b95e94dc7 clarified bounding box, similar to old graph browser;
wenzelm
parents: 59240
diff changeset
   165
        rescale((size.width / box.width) min (size.height / box.height))
49557
61988f9df94d added Graphview tool, based on Isabelle/Scala and Swing/Graphics2D;
Markus Kaiser <markus.kaiser@in.tum.de>
parents:
diff changeset
   166
      }
61988f9df94d added Graphview tool, based on Isabelle/Scala and Swing/Graphics2D;
Markus Kaiser <markus.kaiser@in.tum.de>
parents:
diff changeset
   167
    }
50470
wenzelm
parents: 50469
diff changeset
   168
59218
eadd82d440b0 tuned whitespace;
wenzelm
parents: 59202
diff changeset
   169
    def pane_to_graph_coordinates(at: Point2D): Point2D =
eadd82d440b0 tuned whitespace;
wenzelm
parents: 59202
diff changeset
   170
    {
50477
ffa18243a4e3 some attempts at more discrete scale factor;
wenzelm
parents: 50476
diff changeset
   171
      val s = Transform.scale_discrete
59408
63cb603b5114 more symmetric layout of main panel;
wenzelm
parents: 59403
diff changeset
   172
      val p = Transform().inverseTransform(graph_pane.peer.getViewport.getViewPosition, null)
50470
wenzelm
parents: 50469
diff changeset
   173
49557
61988f9df94d added Graphview tool, based on Isabelle/Scala and Swing/Graphics2D;
Markus Kaiser <markus.kaiser@in.tum.de>
parents:
diff changeset
   174
      p.setLocation(p.getX + at.getX / s, p.getY + at.getY / s)
61988f9df94d added Graphview tool, based on Isabelle/Scala and Swing/Graphics2D;
Markus Kaiser <markus.kaiser@in.tum.de>
parents:
diff changeset
   175
      p
61988f9df94d added Graphview tool, based on Isabelle/Scala and Swing/Graphics2D;
Markus Kaiser <markus.kaiser@in.tum.de>
parents:
diff changeset
   176
    }
61988f9df94d added Graphview tool, based on Isabelle/Scala and Swing/Graphics2D;
Markus Kaiser <markus.kaiser@in.tum.de>
parents:
diff changeset
   177
  }
50470
wenzelm
parents: 50469
diff changeset
   178
59398
ea163bf8ad22 misc tuning;
wenzelm
parents: 59397
diff changeset
   179
ea163bf8ad22 misc tuning;
wenzelm
parents: 59397
diff changeset
   180
  /* interaction */
49557
61988f9df94d added Graphview tool, based on Isabelle/Scala and Swing/Graphics2D;
Markus Kaiser <markus.kaiser@in.tum.de>
parents:
diff changeset
   181
59408
63cb603b5114 more symmetric layout of main panel;
wenzelm
parents: 59403
diff changeset
   182
  visualizer.model.Colors.events += { case _ => painter.repaint() }
63cb603b5114 more symmetric layout of main panel;
wenzelm
parents: 59403
diff changeset
   183
  visualizer.model.Mutators.events += { case _ => painter.repaint() }
59398
ea163bf8ad22 misc tuning;
wenzelm
parents: 59397
diff changeset
   184
ea163bf8ad22 misc tuning;
wenzelm
parents: 59397
diff changeset
   185
  private object Mouse_Interaction
ea163bf8ad22 misc tuning;
wenzelm
parents: 59397
diff changeset
   186
  {
ea163bf8ad22 misc tuning;
wenzelm
parents: 59397
diff changeset
   187
    private var draginfo: (Point, List[Graph_Display.Node], List[Layout.Dummy]) =
ea163bf8ad22 misc tuning;
wenzelm
parents: 59397
diff changeset
   188
      (new Point(0, 0), Nil, Nil)
59253
9448f4fc95e0 apply_layout: proper repaint;
wenzelm
parents: 59250
diff changeset
   189
9448f4fc95e0 apply_layout: proper repaint;
wenzelm
parents: 59250
diff changeset
   190
    def pressed(at: Point)
59218
eadd82d440b0 tuned whitespace;
wenzelm
parents: 59202
diff changeset
   191
    {
59253
9448f4fc95e0 apply_layout: proper repaint;
wenzelm
parents: 59250
diff changeset
   192
      val c = Transform.pane_to_graph_coordinates(at)
9448f4fc95e0 apply_layout: proper repaint;
wenzelm
parents: 59250
diff changeset
   193
      val l =
59305
b5e33012180e tuned signature;
wenzelm
parents: 59303
diff changeset
   194
        visualizer.find_node(c) match {
59253
9448f4fc95e0 apply_layout: proper repaint;
wenzelm
parents: 59250
diff changeset
   195
          case Some(node) =>
9448f4fc95e0 apply_layout: proper repaint;
wenzelm
parents: 59250
diff changeset
   196
            if (visualizer.Selection.contains(node)) visualizer.Selection.get()
9448f4fc95e0 apply_layout: proper repaint;
wenzelm
parents: 59250
diff changeset
   197
            else List(node)
9448f4fc95e0 apply_layout: proper repaint;
wenzelm
parents: 59250
diff changeset
   198
          case None => Nil
9448f4fc95e0 apply_layout: proper repaint;
wenzelm
parents: 59250
diff changeset
   199
        }
9448f4fc95e0 apply_layout: proper repaint;
wenzelm
parents: 59250
diff changeset
   200
      val d =
9448f4fc95e0 apply_layout: proper repaint;
wenzelm
parents: 59250
diff changeset
   201
        l match {
59305
b5e33012180e tuned signature;
wenzelm
parents: 59303
diff changeset
   202
          case Nil => visualizer.find_dummy(c).toList
59253
9448f4fc95e0 apply_layout: proper repaint;
wenzelm
parents: 59250
diff changeset
   203
          case _ => Nil
9448f4fc95e0 apply_layout: proper repaint;
wenzelm
parents: 59250
diff changeset
   204
        }
9448f4fc95e0 apply_layout: proper repaint;
wenzelm
parents: 59250
diff changeset
   205
      draginfo = (at, l, d)
9448f4fc95e0 apply_layout: proper repaint;
wenzelm
parents: 59250
diff changeset
   206
    }
50470
wenzelm
parents: 50469
diff changeset
   207
59398
ea163bf8ad22 misc tuning;
wenzelm
parents: 59397
diff changeset
   208
    def dragged(to: Point)
59253
9448f4fc95e0 apply_layout: proper repaint;
wenzelm
parents: 59250
diff changeset
   209
    {
59398
ea163bf8ad22 misc tuning;
wenzelm
parents: 59397
diff changeset
   210
      val (from, p, d) = draginfo
49557
61988f9df94d added Graphview tool, based on Isabelle/Scala and Swing/Graphics2D;
Markus Kaiser <markus.kaiser@in.tum.de>
parents:
diff changeset
   211
59253
9448f4fc95e0 apply_layout: proper repaint;
wenzelm
parents: 59250
diff changeset
   212
      val s = Transform.scale_discrete
59398
ea163bf8ad22 misc tuning;
wenzelm
parents: 59397
diff changeset
   213
      val dx = to.x - from.x
ea163bf8ad22 misc tuning;
wenzelm
parents: 59397
diff changeset
   214
      val dy = to.y - from.y
ea163bf8ad22 misc tuning;
wenzelm
parents: 59397
diff changeset
   215
59253
9448f4fc95e0 apply_layout: proper repaint;
wenzelm
parents: 59250
diff changeset
   216
      (p, d) match {
9448f4fc95e0 apply_layout: proper repaint;
wenzelm
parents: 59250
diff changeset
   217
        case (Nil, Nil) =>
59408
63cb603b5114 more symmetric layout of main panel;
wenzelm
parents: 59403
diff changeset
   218
          val r = graph_pane.peer.getViewport.getViewRect
59302
4d985afc0565 explict layout graph structure, with dummies and coordinates;
wenzelm
parents: 59294
diff changeset
   219
          r.translate(- dx, - dy)
59408
63cb603b5114 more symmetric layout of main panel;
wenzelm
parents: 59403
diff changeset
   220
          painter.peer.scrollRectToVisible(r)
50470
wenzelm
parents: 50469
diff changeset
   221
59253
9448f4fc95e0 apply_layout: proper repaint;
wenzelm
parents: 59250
diff changeset
   222
        case (Nil, ds) =>
59302
4d985afc0565 explict layout graph structure, with dummies and coordinates;
wenzelm
parents: 59294
diff changeset
   223
          ds.foreach(d => visualizer.translate_vertex(d, dx / s, dy / s))
59253
9448f4fc95e0 apply_layout: proper repaint;
wenzelm
parents: 59250
diff changeset
   224
9448f4fc95e0 apply_layout: proper repaint;
wenzelm
parents: 59250
diff changeset
   225
        case (ls, _) =>
59302
4d985afc0565 explict layout graph structure, with dummies and coordinates;
wenzelm
parents: 59294
diff changeset
   226
          ls.foreach(l => visualizer.translate_vertex(Layout.Node(l), dx / s, dy / s))
49557
61988f9df94d added Graphview tool, based on Isabelle/Scala and Swing/Graphics2D;
Markus Kaiser <markus.kaiser@in.tum.de>
parents:
diff changeset
   227
      }
59398
ea163bf8ad22 misc tuning;
wenzelm
parents: 59397
diff changeset
   228
ea163bf8ad22 misc tuning;
wenzelm
parents: 59397
diff changeset
   229
      draginfo = (to, p, d)
ea163bf8ad22 misc tuning;
wenzelm
parents: 59397
diff changeset
   230
    }
ea163bf8ad22 misc tuning;
wenzelm
parents: 59397
diff changeset
   231
ea163bf8ad22 misc tuning;
wenzelm
parents: 59397
diff changeset
   232
    def clicked(at: Point, m: Key.Modifiers, clicks: Int, right_click: Boolean)
ea163bf8ad22 misc tuning;
wenzelm
parents: 59397
diff changeset
   233
    {
ea163bf8ad22 misc tuning;
wenzelm
parents: 59397
diff changeset
   234
      val c = Transform.pane_to_graph_coordinates(at)
ea163bf8ad22 misc tuning;
wenzelm
parents: 59397
diff changeset
   235
ea163bf8ad22 misc tuning;
wenzelm
parents: 59397
diff changeset
   236
      if (clicks < 2) {
ea163bf8ad22 misc tuning;
wenzelm
parents: 59397
diff changeset
   237
        if (right_click) {
59403
db65d45b6740 suppress some controls that don't work yet;
wenzelm
parents: 59399
diff changeset
   238
          // FIXME
db65d45b6740 suppress some controls that don't work yet;
wenzelm
parents: 59399
diff changeset
   239
          if (false) {
59408
63cb603b5114 more symmetric layout of main panel;
wenzelm
parents: 59403
diff changeset
   240
            val menu = Popups(graph_panel, visualizer.find_node(c), visualizer.Selection.get())
63cb603b5114 more symmetric layout of main panel;
wenzelm
parents: 59403
diff changeset
   241
            menu.show(graph_pane.peer, at.x, at.y)
59403
db65d45b6740 suppress some controls that don't work yet;
wenzelm
parents: 59399
diff changeset
   242
          }
59398
ea163bf8ad22 misc tuning;
wenzelm
parents: 59397
diff changeset
   243
        }
ea163bf8ad22 misc tuning;
wenzelm
parents: 59397
diff changeset
   244
        else {
ea163bf8ad22 misc tuning;
wenzelm
parents: 59397
diff changeset
   245
          (visualizer.find_node(c), m) match {
ea163bf8ad22 misc tuning;
wenzelm
parents: 59397
diff changeset
   246
            case (Some(node), Key.Modifier.Control) => visualizer.Selection.add(node)
ea163bf8ad22 misc tuning;
wenzelm
parents: 59397
diff changeset
   247
            case (None, Key.Modifier.Control) =>
ea163bf8ad22 misc tuning;
wenzelm
parents: 59397
diff changeset
   248
ea163bf8ad22 misc tuning;
wenzelm
parents: 59397
diff changeset
   249
            case (Some(node), Key.Modifier.Shift) => visualizer.Selection.add(node)
ea163bf8ad22 misc tuning;
wenzelm
parents: 59397
diff changeset
   250
            case (None, Key.Modifier.Shift) =>
ea163bf8ad22 misc tuning;
wenzelm
parents: 59397
diff changeset
   251
ea163bf8ad22 misc tuning;
wenzelm
parents: 59397
diff changeset
   252
            case (Some(node), _) =>
ea163bf8ad22 misc tuning;
wenzelm
parents: 59397
diff changeset
   253
              visualizer.Selection.clear()
ea163bf8ad22 misc tuning;
wenzelm
parents: 59397
diff changeset
   254
              visualizer.Selection.add(node)
ea163bf8ad22 misc tuning;
wenzelm
parents: 59397
diff changeset
   255
            case (None, _) =>
ea163bf8ad22 misc tuning;
wenzelm
parents: 59397
diff changeset
   256
              visualizer.Selection.clear()
ea163bf8ad22 misc tuning;
wenzelm
parents: 59397
diff changeset
   257
          }
ea163bf8ad22 misc tuning;
wenzelm
parents: 59397
diff changeset
   258
        }
ea163bf8ad22 misc tuning;
wenzelm
parents: 59397
diff changeset
   259
      }
49557
61988f9df94d added Graphview tool, based on Isabelle/Scala and Swing/Graphics2D;
Markus Kaiser <markus.kaiser@in.tum.de>
parents:
diff changeset
   260
    }
61988f9df94d added Graphview tool, based on Isabelle/Scala and Swing/Graphics2D;
Markus Kaiser <markus.kaiser@in.tum.de>
parents:
diff changeset
   261
  }
59408
63cb603b5114 more symmetric layout of main panel;
wenzelm
parents: 59403
diff changeset
   262
63cb603b5114 more symmetric layout of main panel;
wenzelm
parents: 59403
diff changeset
   263
63cb603b5114 more symmetric layout of main panel;
wenzelm
parents: 59403
diff changeset
   264
63cb603b5114 more symmetric layout of main panel;
wenzelm
parents: 59403
diff changeset
   265
  /** controls **/
63cb603b5114 more symmetric layout of main panel;
wenzelm
parents: 59403
diff changeset
   266
63cb603b5114 more symmetric layout of main panel;
wenzelm
parents: 59403
diff changeset
   267
  private val mutator_dialog =
63cb603b5114 more symmetric layout of main panel;
wenzelm
parents: 59403
diff changeset
   268
    new Mutator_Dialog(visualizer, visualizer.model.Mutators, "Filters", "Hide", false)
63cb603b5114 more symmetric layout of main panel;
wenzelm
parents: 59403
diff changeset
   269
  private val color_dialog =
63cb603b5114 more symmetric layout of main panel;
wenzelm
parents: 59403
diff changeset
   270
    new Mutator_Dialog(visualizer, visualizer.model.Colors, "Colorations")
63cb603b5114 more symmetric layout of main panel;
wenzelm
parents: 59403
diff changeset
   271
63cb603b5114 more symmetric layout of main panel;
wenzelm
parents: 59403
diff changeset
   272
  private val chooser = new FileChooser {
63cb603b5114 more symmetric layout of main panel;
wenzelm
parents: 59403
diff changeset
   273
    fileSelectionMode = FileChooser.SelectionMode.FilesOnly
63cb603b5114 more symmetric layout of main panel;
wenzelm
parents: 59403
diff changeset
   274
    title = "Save image (.png or .pdf)"
63cb603b5114 more symmetric layout of main panel;
wenzelm
parents: 59403
diff changeset
   275
  }
63cb603b5114 more symmetric layout of main panel;
wenzelm
parents: 59403
diff changeset
   276
59409
wenzelm
parents: 59408
diff changeset
   277
  private val show_content = new CheckBox() {
wenzelm
parents: 59408
diff changeset
   278
    selected = visualizer.show_content
wenzelm
parents: 59408
diff changeset
   279
    action = Action("Show content") {
wenzelm
parents: 59408
diff changeset
   280
      visualizer.show_content = selected
wenzelm
parents: 59408
diff changeset
   281
      visualizer.update_layout()
wenzelm
parents: 59408
diff changeset
   282
      refresh()
wenzelm
parents: 59408
diff changeset
   283
    }
wenzelm
parents: 59408
diff changeset
   284
    tooltip = "Show full node content within graph layout"
wenzelm
parents: 59408
diff changeset
   285
  }
wenzelm
parents: 59408
diff changeset
   286
wenzelm
parents: 59408
diff changeset
   287
  private val show_arrow_heads = new CheckBox() {
wenzelm
parents: 59408
diff changeset
   288
    selected = visualizer.show_arrow_heads
wenzelm
parents: 59408
diff changeset
   289
    action = Action("Show arrow heads") {
wenzelm
parents: 59408
diff changeset
   290
      visualizer.show_arrow_heads = selected
wenzelm
parents: 59408
diff changeset
   291
      painter.repaint()
wenzelm
parents: 59408
diff changeset
   292
    }
wenzelm
parents: 59408
diff changeset
   293
    tooltip = "Draw edges with explicit arrow heads"
wenzelm
parents: 59408
diff changeset
   294
  }
wenzelm
parents: 59408
diff changeset
   295
wenzelm
parents: 59408
diff changeset
   296
  private val show_dummies = new CheckBox() {
wenzelm
parents: 59408
diff changeset
   297
    selected = visualizer.show_dummies
wenzelm
parents: 59408
diff changeset
   298
    action = Action("Show dummies") {
wenzelm
parents: 59408
diff changeset
   299
      visualizer.show_dummies = selected
wenzelm
parents: 59408
diff changeset
   300
      painter.repaint()
wenzelm
parents: 59408
diff changeset
   301
    }
wenzelm
parents: 59408
diff changeset
   302
    tooltip = "Draw dummy nodes within graph layout, for easier mouse dragging"
wenzelm
parents: 59408
diff changeset
   303
  }
wenzelm
parents: 59408
diff changeset
   304
wenzelm
parents: 59408
diff changeset
   305
  private val save_image = new Button {
wenzelm
parents: 59408
diff changeset
   306
    action = Action("Save image") {
wenzelm
parents: 59408
diff changeset
   307
      chooser.showSaveDialog(this) match {
59441
ab2c3597f1d3 separate module Graph_File;
wenzelm
parents: 59411
diff changeset
   308
        case FileChooser.Result.Approve =>
ab2c3597f1d3 separate module Graph_File;
wenzelm
parents: 59411
diff changeset
   309
          try { Graph_File.write(visualizer, chooser.selectedFile) }
ab2c3597f1d3 separate module Graph_File;
wenzelm
parents: 59411
diff changeset
   310
          catch {
ab2c3597f1d3 separate module Graph_File;
wenzelm
parents: 59411
diff changeset
   311
            case ERROR(msg) => GUI.error_dialog(this.peer, "Error", GUI.scrollable_text(msg))
ab2c3597f1d3 separate module Graph_File;
wenzelm
parents: 59411
diff changeset
   312
          }
59409
wenzelm
parents: 59408
diff changeset
   313
        case _ =>
wenzelm
parents: 59408
diff changeset
   314
      }
wenzelm
parents: 59408
diff changeset
   315
    }
wenzelm
parents: 59408
diff changeset
   316
    tooltip = "Save current graph layout as PNG or PDF"
wenzelm
parents: 59408
diff changeset
   317
  }
wenzelm
parents: 59408
diff changeset
   318
wenzelm
parents: 59408
diff changeset
   319
  private val zoom = new GUI.Zoom_Box { def changed = rescale(0.01 * factor) }
wenzelm
parents: 59408
diff changeset
   320
wenzelm
parents: 59408
diff changeset
   321
  private val fit_window = new Button {
wenzelm
parents: 59408
diff changeset
   322
    action = Action("Fit to window") { fit_to_window() }
wenzelm
parents: 59408
diff changeset
   323
    tooltip = "Zoom to fit window width and height"
wenzelm
parents: 59408
diff changeset
   324
  }
wenzelm
parents: 59408
diff changeset
   325
wenzelm
parents: 59408
diff changeset
   326
  private val update_layout = new Button {
wenzelm
parents: 59408
diff changeset
   327
    action = Action("Update layout") {
wenzelm
parents: 59408
diff changeset
   328
      visualizer.update_layout()
wenzelm
parents: 59408
diff changeset
   329
      refresh()
wenzelm
parents: 59408
diff changeset
   330
    }
wenzelm
parents: 59408
diff changeset
   331
    tooltip = "Regenerate graph layout according to built-in algorithm"
wenzelm
parents: 59408
diff changeset
   332
  }
wenzelm
parents: 59408
diff changeset
   333
wenzelm
parents: 59408
diff changeset
   334
  private val colorations = new Button { action = Action("Colorations") { color_dialog.open } }
wenzelm
parents: 59408
diff changeset
   335
  private val filters = new Button { action = Action("Filters") { mutator_dialog.open } }
wenzelm
parents: 59408
diff changeset
   336
59408
63cb603b5114 more symmetric layout of main panel;
wenzelm
parents: 59403
diff changeset
   337
  private val controls =
59409
wenzelm
parents: 59408
diff changeset
   338
    new Wrap_Panel(Wrap_Panel.Alignment.Right)(show_content, show_arrow_heads, show_dummies,
59411
99d009ede619 suppress inactive controls (again);
wenzelm
parents: 59409
diff changeset
   339
      save_image, zoom, fit_window, update_layout) // FIXME colorations, filters
59408
63cb603b5114 more symmetric layout of main panel;
wenzelm
parents: 59403
diff changeset
   340
63cb603b5114 more symmetric layout of main panel;
wenzelm
parents: 59403
diff changeset
   341
63cb603b5114 more symmetric layout of main panel;
wenzelm
parents: 59403
diff changeset
   342
63cb603b5114 more symmetric layout of main panel;
wenzelm
parents: 59403
diff changeset
   343
  /** main layout **/
63cb603b5114 more symmetric layout of main panel;
wenzelm
parents: 59403
diff changeset
   344
63cb603b5114 more symmetric layout of main panel;
wenzelm
parents: 59403
diff changeset
   345
  layout(graph_pane) = BorderPanel.Position.Center
63cb603b5114 more symmetric layout of main panel;
wenzelm
parents: 59403
diff changeset
   346
  layout(controls) = BorderPanel.Position.North
63cb603b5114 more symmetric layout of main panel;
wenzelm
parents: 59403
diff changeset
   347
63cb603b5114 more symmetric layout of main panel;
wenzelm
parents: 59403
diff changeset
   348
  rescale(1.0)
49557
61988f9df94d added Graphview tool, based on Isabelle/Scala and Swing/Graphics2D;
Markus Kaiser <markus.kaiser@in.tum.de>
parents:
diff changeset
   349
}