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