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