| author | wenzelm |
| Tue, 06 Jan 2015 23:23:26 +0100 | |
| changeset 59310 | 7cdabe4cec33 |
| parent 59305 | b5e33012180e |
| child 59313 | d7f4f46e9a59 |
| permissions | -rw-r--r-- |
| 59202 | 1 |
/* Title: Tools/Graphview/visualizer.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 | 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 |
|
| 50475 | 5 |
Graph visualization parameters and interface state. |
|
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 |
|
| 50464 | 10 |
|
|
49565
ea4308b7ef0f
ML support for generic graph display, with browser and graphview backends (via print modes);
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 |
|
| 59290 | 13 |
import java.awt.{Font, Color, Shape, Graphics2D}
|
| 59305 | 14 |
import java.awt.geom.{Point2D, Rectangle2D}
|
| 49729 | 15 |
import javax.swing.JComponent |
|
49557
61988f9df94d
added Graphview tool, based on Isabelle/Scala and Swing/Graphics2D;
Markus Kaiser <markus.kaiser@in.tum.de>
parents:
diff
changeset
|
16 |
|
|
61988f9df94d
added Graphview tool, based on Isabelle/Scala and Swing/Graphics2D;
Markus Kaiser <markus.kaiser@in.tum.de>
parents:
diff
changeset
|
17 |
|
|
59286
ac74eedb910a
GUI.imitate_font: more explicit result size, e.g. relevant for caching;
wenzelm
parents:
59265
diff
changeset
|
18 |
class Visualizer(options: => Options, val model: Model) |
| 50465 | 19 |
{
|
|
50472
bad1a1ca61e1
separate instance of class Parameters for each Main_Panel -- avoid global program state;
wenzelm
parents:
50471
diff
changeset
|
20 |
visualizer => |
|
bad1a1ca61e1
separate instance of class Parameters for each Main_Panel -- avoid global program state;
wenzelm
parents:
50471
diff
changeset
|
21 |
|
|
59302
4d985afc0565
explict layout graph structure, with dummies and coordinates;
wenzelm
parents:
59294
diff
changeset
|
22 |
|
|
4d985afc0565
explict layout graph structure, with dummies and coordinates;
wenzelm
parents:
59294
diff
changeset
|
23 |
/* layout state */ |
|
4d985afc0565
explict layout graph structure, with dummies and coordinates;
wenzelm
parents:
59294
diff
changeset
|
24 |
|
| 59290 | 25 |
// owned by GUI thread |
| 59303 | 26 |
private var _layout: Layout = Layout.empty |
27 |
def layout: Layout = _layout |
|
| 59290 | 28 |
|
29 |
def metrics: Metrics = layout.metrics |
|
|
59302
4d985afc0565
explict layout graph structure, with dummies and coordinates;
wenzelm
parents:
59294
diff
changeset
|
30 |
def visible_graph: Graph_Display.Graph = layout.input_graph |
|
4d985afc0565
explict layout graph structure, with dummies and coordinates;
wenzelm
parents:
59294
diff
changeset
|
31 |
|
| 59303 | 32 |
def translate_vertex(v: Layout.Vertex, dx: Double, dy: Double): Unit = |
33 |
_layout = _layout.translate_vertex(v, dx, dy) |
|
|
59302
4d985afc0565
explict layout graph structure, with dummies and coordinates;
wenzelm
parents:
59294
diff
changeset
|
34 |
|
| 59305 | 35 |
def find_node(at: Point2D): Option[Graph_Display.Node] = |
36 |
layout.output_graph.iterator.collectFirst({
|
|
37 |
case (Layout.Node(node), _) if Shapes.Node.shape(visualizer, node).contains(at) => node |
|
38 |
}) |
|
39 |
||
40 |
def find_dummy(at: Point2D): Option[Layout.Dummy] = |
|
41 |
layout.output_graph.iterator.collectFirst({
|
|
42 |
case (dummy: Layout.Dummy, (d, _)) if Shapes.Dummy.shape(visualizer, d).contains(at) => dummy |
|
43 |
}) |
|
44 |
||
|
59302
4d985afc0565
explict layout graph structure, with dummies and coordinates;
wenzelm
parents:
59294
diff
changeset
|
45 |
def bounding_box(): Rectangle2D.Double = |
|
4d985afc0565
explict layout graph structure, with dummies and coordinates;
wenzelm
parents:
59294
diff
changeset
|
46 |
{
|
|
4d985afc0565
explict layout graph structure, with dummies and coordinates;
wenzelm
parents:
59294
diff
changeset
|
47 |
var x0 = 0.0 |
|
4d985afc0565
explict layout graph structure, with dummies and coordinates;
wenzelm
parents:
59294
diff
changeset
|
48 |
var y0 = 0.0 |
|
4d985afc0565
explict layout graph structure, with dummies and coordinates;
wenzelm
parents:
59294
diff
changeset
|
49 |
var x1 = 0.0 |
|
4d985afc0565
explict layout graph structure, with dummies and coordinates;
wenzelm
parents:
59294
diff
changeset
|
50 |
var y1 = 0.0 |
|
4d985afc0565
explict layout graph structure, with dummies and coordinates;
wenzelm
parents:
59294
diff
changeset
|
51 |
((for (node <- visible_graph.keys_iterator) yield Shapes.Node.shape(visualizer, node)) ++ |
|
4d985afc0565
explict layout graph structure, with dummies and coordinates;
wenzelm
parents:
59294
diff
changeset
|
52 |
(for (d <- layout.dummies_iterator) yield Shapes.Dummy.shape(visualizer, d))). |
|
4d985afc0565
explict layout graph structure, with dummies and coordinates;
wenzelm
parents:
59294
diff
changeset
|
53 |
foreach(rect => {
|
|
4d985afc0565
explict layout graph structure, with dummies and coordinates;
wenzelm
parents:
59294
diff
changeset
|
54 |
x0 = x0 min rect.getMinX |
|
4d985afc0565
explict layout graph structure, with dummies and coordinates;
wenzelm
parents:
59294
diff
changeset
|
55 |
y0 = y0 min rect.getMinY |
|
4d985afc0565
explict layout graph structure, with dummies and coordinates;
wenzelm
parents:
59294
diff
changeset
|
56 |
x1 = x1 max rect.getMaxX |
|
4d985afc0565
explict layout graph structure, with dummies and coordinates;
wenzelm
parents:
59294
diff
changeset
|
57 |
y1 = y1 max rect.getMaxY |
|
4d985afc0565
explict layout graph structure, with dummies and coordinates;
wenzelm
parents:
59294
diff
changeset
|
58 |
}) |
|
4d985afc0565
explict layout graph structure, with dummies and coordinates;
wenzelm
parents:
59294
diff
changeset
|
59 |
val gap = metrics.gap |
|
4d985afc0565
explict layout graph structure, with dummies and coordinates;
wenzelm
parents:
59294
diff
changeset
|
60 |
x0 = (x0 - gap).floor |
|
4d985afc0565
explict layout graph structure, with dummies and coordinates;
wenzelm
parents:
59294
diff
changeset
|
61 |
y0 = (y0 - gap).floor |
|
4d985afc0565
explict layout graph structure, with dummies and coordinates;
wenzelm
parents:
59294
diff
changeset
|
62 |
x1 = (x1 + gap).ceil |
|
4d985afc0565
explict layout graph structure, with dummies and coordinates;
wenzelm
parents:
59294
diff
changeset
|
63 |
y1 = (y1 + gap).ceil |
|
4d985afc0565
explict layout graph structure, with dummies and coordinates;
wenzelm
parents:
59294
diff
changeset
|
64 |
new Rectangle2D.Double(x0, y0, x1 - x0, y1 - y0) |
|
4d985afc0565
explict layout graph structure, with dummies and coordinates;
wenzelm
parents:
59294
diff
changeset
|
65 |
} |
|
4d985afc0565
explict layout graph structure, with dummies and coordinates;
wenzelm
parents:
59294
diff
changeset
|
66 |
|
|
4d985afc0565
explict layout graph structure, with dummies and coordinates;
wenzelm
parents:
59294
diff
changeset
|
67 |
def update_layout() |
|
4d985afc0565
explict layout graph structure, with dummies and coordinates;
wenzelm
parents:
59294
diff
changeset
|
68 |
{
|
|
4d985afc0565
explict layout graph structure, with dummies and coordinates;
wenzelm
parents:
59294
diff
changeset
|
69 |
val metrics = Metrics(make_font()) |
|
4d985afc0565
explict layout graph structure, with dummies and coordinates;
wenzelm
parents:
59294
diff
changeset
|
70 |
val visible_graph = model.make_visible_graph() |
|
4d985afc0565
explict layout graph structure, with dummies and coordinates;
wenzelm
parents:
59294
diff
changeset
|
71 |
|
|
4d985afc0565
explict layout graph structure, with dummies and coordinates;
wenzelm
parents:
59294
diff
changeset
|
72 |
// FIXME avoid expensive operation on GUI thread |
| 59303 | 73 |
_layout = Layout.make(metrics, visible_graph) |
|
59302
4d985afc0565
explict layout graph structure, with dummies and coordinates;
wenzelm
parents:
59294
diff
changeset
|
74 |
} |
| 59290 | 75 |
|
|
50476
1cb983bccb5b
more official graphics context with font metrics;
wenzelm
parents:
50475
diff
changeset
|
76 |
|
| 59233 | 77 |
/* tooltips */ |
78 |
||
79 |
def make_tooltip(parent: JComponent, x: Int, y: Int, body: XML.Body): String = null |
|
80 |
||
81 |
||
|
59228
56b34fc7a015
more dynamic visualizer -- re-use Isabelle/jEdit options;
wenzelm
parents:
59220
diff
changeset
|
82 |
/* main colors */ |
|
56b34fc7a015
more dynamic visualizer -- re-use Isabelle/jEdit options;
wenzelm
parents:
59220
diff
changeset
|
83 |
|
|
56b34fc7a015
more dynamic visualizer -- re-use Isabelle/jEdit options;
wenzelm
parents:
59220
diff
changeset
|
84 |
def foreground_color: Color = Color.BLACK |
|
56b34fc7a015
more dynamic visualizer -- re-use Isabelle/jEdit options;
wenzelm
parents:
59220
diff
changeset
|
85 |
def background_color: Color = Color.WHITE |
|
56b34fc7a015
more dynamic visualizer -- re-use Isabelle/jEdit options;
wenzelm
parents:
59220
diff
changeset
|
86 |
def selection_color: Color = Color.GREEN |
|
56b34fc7a015
more dynamic visualizer -- re-use Isabelle/jEdit options;
wenzelm
parents:
59220
diff
changeset
|
87 |
def error_color: Color = Color.RED |
| 59251 | 88 |
def dummy_color: Color = Color.GRAY |
|
59228
56b34fc7a015
more dynamic visualizer -- re-use Isabelle/jEdit options;
wenzelm
parents:
59220
diff
changeset
|
89 |
|
|
56b34fc7a015
more dynamic visualizer -- re-use Isabelle/jEdit options;
wenzelm
parents:
59220
diff
changeset
|
90 |
|
| 50475 | 91 |
/* font rendering information */ |
92 |
||
| 59290 | 93 |
def make_font(): Font = |
|
59286
ac74eedb910a
GUI.imitate_font: more explicit result size, e.g. relevant for caching;
wenzelm
parents:
59265
diff
changeset
|
94 |
{
|
|
ac74eedb910a
GUI.imitate_font: more explicit result size, e.g. relevant for caching;
wenzelm
parents:
59265
diff
changeset
|
95 |
val family = options.string("graphview_font_family")
|
|
ac74eedb910a
GUI.imitate_font: more explicit result size, e.g. relevant for caching;
wenzelm
parents:
59265
diff
changeset
|
96 |
val size = options.int("graphview_font_size")
|
|
ac74eedb910a
GUI.imitate_font: more explicit result size, e.g. relevant for caching;
wenzelm
parents:
59265
diff
changeset
|
97 |
new Font(family, Font.PLAIN, size) |
|
ac74eedb910a
GUI.imitate_font: more explicit result size, e.g. relevant for caching;
wenzelm
parents:
59265
diff
changeset
|
98 |
} |
| 50475 | 99 |
|
100 |
||
101 |
/* rendering parameters */ |
|
102 |
||
| 59294 | 103 |
// owned by GUI thread |
| 50475 | 104 |
var arrow_heads = false |
| 59294 | 105 |
var show_dummies = false |
| 50475 | 106 |
|
107 |
object Colors |
|
108 |
{
|
|
109 |
private val filter_colors = List( |
|
| 59220 | 110 |
new Color(0xD9, 0xF2, 0xE2), // blue |
111 |
new Color(0xFF, 0xE7, 0xD8), // orange |
|
112 |
new Color(0xFF, 0xFF, 0xE5), // yellow |
|
113 |
new Color(0xDE, 0xCE, 0xFF), // lilac |
|
114 |
new Color(0xCC, 0xEB, 0xFF), // turquoise |
|
115 |
new Color(0xFF, 0xE5, 0xE5), // red |
|
116 |
new Color(0xE5, 0xE5, 0xD9) // green |
|
| 50475 | 117 |
) |
118 |
||
119 |
private var curr : Int = -1 |
|
| 59220 | 120 |
def next(): Color = |
| 50475 | 121 |
{
|
122 |
curr = (curr + 1) % filter_colors.length |
|
123 |
filter_colors(curr) |
|
124 |
} |
|
125 |
} |
|
126 |
||
| 59294 | 127 |
def paint_all_visible(gfx: Graphics2D) |
128 |
{
|
|
129 |
gfx.setRenderingHints(Metrics.rendering_hints) |
|
130 |
for (edge <- visible_graph.edges_iterator) |
|
131 |
Shapes.Cardinal_Spline_Edge.paint(gfx, visualizer, edge) |
|
132 |
for (node <- visible_graph.keys_iterator) |
|
133 |
Shapes.Node.paint(gfx, visualizer, node) |
|
134 |
} |
|
|
50472
bad1a1ca61e1
separate instance of class Parameters for each Main_Panel -- avoid global program state;
wenzelm
parents:
50471
diff
changeset
|
135 |
|
| 50465 | 136 |
object Selection |
137 |
{
|
|
|
59245
be4180f3c236
more formal Graph_Display.Node (with ordering) and Graph_Display.Edge;
wenzelm
parents:
59242
diff
changeset
|
138 |
// owned by GUI thread |
|
be4180f3c236
more formal Graph_Display.Node (with ordering) and Graph_Display.Edge;
wenzelm
parents:
59242
diff
changeset
|
139 |
private var state: List[Graph_Display.Node] = Nil |
| 50465 | 140 |
|
|
59245
be4180f3c236
more formal Graph_Display.Node (with ordering) and Graph_Display.Edge;
wenzelm
parents:
59242
diff
changeset
|
141 |
def get(): List[Graph_Display.Node] = GUI_Thread.require { state }
|
|
be4180f3c236
more formal Graph_Display.Node (with ordering) and Graph_Display.Edge;
wenzelm
parents:
59242
diff
changeset
|
142 |
def contains(node: Graph_Display.Node): Boolean = get().contains(node) |
| 50465 | 143 |
|
|
59245
be4180f3c236
more formal Graph_Display.Node (with ordering) and Graph_Display.Edge;
wenzelm
parents:
59242
diff
changeset
|
144 |
def add(node: Graph_Display.Node): Unit = GUI_Thread.require { state = node :: state }
|
|
be4180f3c236
more formal Graph_Display.Node (with ordering) and Graph_Display.Edge;
wenzelm
parents:
59242
diff
changeset
|
145 |
def clear(): Unit = GUI_Thread.require { state = Nil }
|
|
49557
61988f9df94d
added Graphview tool, based on Isabelle/Scala and Swing/Graphics2D;
Markus Kaiser <markus.kaiser@in.tum.de>
parents:
diff
changeset
|
146 |
} |
| 50465 | 147 |
|
| 59220 | 148 |
sealed case class Node_Color(border: Color, background: Color, foreground: Color) |
| 50464 | 149 |
|
|
59245
be4180f3c236
more formal Graph_Display.Node (with ordering) and Graph_Display.Edge;
wenzelm
parents:
59242
diff
changeset
|
150 |
def node_color(node: Graph_Display.Node): Node_Color = |
| 59251 | 151 |
if (Selection.contains(node)) |
|
59245
be4180f3c236
more formal Graph_Display.Node (with ordering) and Graph_Display.Edge;
wenzelm
parents:
59242
diff
changeset
|
152 |
Node_Color(foreground_color, selection_color, foreground_color) |
|
be4180f3c236
more formal Graph_Display.Node (with ordering) and Graph_Display.Edge;
wenzelm
parents:
59242
diff
changeset
|
153 |
else |
|
be4180f3c236
more formal Graph_Display.Node (with ordering) and Graph_Display.Edge;
wenzelm
parents:
59242
diff
changeset
|
154 |
Node_Color(foreground_color, model.colors.getOrElse(node, background_color), foreground_color) |
| 59220 | 155 |
|
|
59245
be4180f3c236
more formal Graph_Display.Node (with ordering) and Graph_Display.Edge;
wenzelm
parents:
59242
diff
changeset
|
156 |
def edge_color(edge: Graph_Display.Edge): Color = foreground_color |
|
49557
61988f9df94d
added Graphview tool, based on Isabelle/Scala and Swing/Graphics2D;
Markus Kaiser <markus.kaiser@in.tum.de>
parents:
diff
changeset
|
157 |
} |