author | wenzelm |
Mon, 05 Jan 2015 22:41:09 +0100 | |
changeset 59292 | fef652c88263 |
parent 59291 | 506660c6792f |
child 59294 | 126293918a37 |
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} |
59241
541b95e94dc7
clarified bounding box, similar to old graph browser;
wenzelm
parents:
59240
diff
changeset
|
14 |
import java.awt.geom.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 |
|
59290 | 22 |
// owned by GUI thread |
23 |
private var layout: Layout = Layout.empty |
|
24 |
||
25 |
def metrics: Metrics = layout.metrics |
|
26 |
def visible_graph: Graph_Display.Graph = layout.visible_graph |
|
27 |
||
50476
1cb983bccb5b
more official graphics context with font metrics;
wenzelm
parents:
50475
diff
changeset
|
28 |
|
59233 | 29 |
/* tooltips */ |
30 |
||
31 |
def make_tooltip(parent: JComponent, x: Int, y: Int, body: XML.Body): String = null |
|
32 |
||
33 |
||
59228
56b34fc7a015
more dynamic visualizer -- re-use Isabelle/jEdit options;
wenzelm
parents:
59220
diff
changeset
|
34 |
/* main colors */ |
56b34fc7a015
more dynamic visualizer -- re-use Isabelle/jEdit options;
wenzelm
parents:
59220
diff
changeset
|
35 |
|
56b34fc7a015
more dynamic visualizer -- re-use Isabelle/jEdit options;
wenzelm
parents:
59220
diff
changeset
|
36 |
def foreground_color: Color = Color.BLACK |
56b34fc7a015
more dynamic visualizer -- re-use Isabelle/jEdit options;
wenzelm
parents:
59220
diff
changeset
|
37 |
def background_color: Color = Color.WHITE |
56b34fc7a015
more dynamic visualizer -- re-use Isabelle/jEdit options;
wenzelm
parents:
59220
diff
changeset
|
38 |
def selection_color: Color = Color.GREEN |
56b34fc7a015
more dynamic visualizer -- re-use Isabelle/jEdit options;
wenzelm
parents:
59220
diff
changeset
|
39 |
def error_color: Color = Color.RED |
59251 | 40 |
def dummy_color: Color = Color.GRAY |
59228
56b34fc7a015
more dynamic visualizer -- re-use Isabelle/jEdit options;
wenzelm
parents:
59220
diff
changeset
|
41 |
|
56b34fc7a015
more dynamic visualizer -- re-use Isabelle/jEdit options;
wenzelm
parents:
59220
diff
changeset
|
42 |
|
50475 | 43 |
/* font rendering information */ |
44 |
||
59290 | 45 |
def make_font(): Font = |
59286
ac74eedb910a
GUI.imitate_font: more explicit result size, e.g. relevant for caching;
wenzelm
parents:
59265
diff
changeset
|
46 |
{ |
ac74eedb910a
GUI.imitate_font: more explicit result size, e.g. relevant for caching;
wenzelm
parents:
59265
diff
changeset
|
47 |
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
|
48 |
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
|
49 |
new Font(family, Font.PLAIN, size) |
ac74eedb910a
GUI.imitate_font: more explicit result size, e.g. relevant for caching;
wenzelm
parents:
59265
diff
changeset
|
50 |
} |
50475 | 51 |
|
52 |
||
53 |
/* rendering parameters */ |
|
54 |
||
55 |
var arrow_heads = false |
|
56 |
||
57 |
object Colors |
|
58 |
{ |
|
59 |
private val filter_colors = List( |
|
59220 | 60 |
new Color(0xD9, 0xF2, 0xE2), // blue |
61 |
new Color(0xFF, 0xE7, 0xD8), // orange |
|
62 |
new Color(0xFF, 0xFF, 0xE5), // yellow |
|
63 |
new Color(0xDE, 0xCE, 0xFF), // lilac |
|
64 |
new Color(0xCC, 0xEB, 0xFF), // turquoise |
|
65 |
new Color(0xFF, 0xE5, 0xE5), // red |
|
66 |
new Color(0xE5, 0xE5, 0xD9) // green |
|
50475 | 67 |
) |
68 |
||
69 |
private var curr : Int = -1 |
|
59220 | 70 |
def next(): Color = |
50475 | 71 |
{ |
72 |
curr = (curr + 1) % filter_colors.length |
|
73 |
filter_colors(curr) |
|
74 |
} |
|
75 |
} |
|
76 |
||
50472
bad1a1ca61e1
separate instance of class Parameters for each Main_Panel -- avoid global program state;
wenzelm
parents:
50471
diff
changeset
|
77 |
|
50465 | 78 |
object Coordinates |
79 |
{ |
|
59262 | 80 |
def get_node(node: Graph_Display.Node): Layout.Point = layout.get_node(node) |
81 |
def get_dummies(edge: Graph_Display.Edge): List[Layout.Point] = layout.get_dummies(edge) |
|
50465 | 82 |
|
59262 | 83 |
def translate_node(node: Graph_Display.Node, dx: Double, dy: Double) |
50465 | 84 |
{ |
59262 | 85 |
layout = layout.map_node(node, p => Layout.Point(p.x + dx, p.y + dy)) |
49557
61988f9df94d
added Graphview tool, based on Isabelle/Scala and Swing/Graphics2D;
Markus Kaiser <markus.kaiser@in.tum.de>
parents:
diff
changeset
|
86 |
} |
50465 | 87 |
|
59262 | 88 |
def translate_dummy(d: (Graph_Display.Edge, Int), dx: Double, dy: Double) |
50465 | 89 |
{ |
59262 | 90 |
val (edge, index) = d |
91 |
layout = layout.map_dummies(edge, |
|
92 |
ds => { |
|
93 |
val p = ds(index) |
|
94 |
(ds.zipWithIndex :\ List.empty[Layout.Point]) { |
|
95 |
case ((t, i), n) => if (index == i) Layout.Point(p.x + dx, p.y + dy) :: n else t :: n |
|
96 |
} |
|
97 |
}) |
|
50465 | 98 |
} |
99 |
||
50470 | 100 |
def update_layout() |
50465 | 101 |
{ |
59290 | 102 |
val metrics = Metrics(make_font()) |
103 |
val visible_graph = model.make_visible_graph() |
|
104 |
||
59252 | 105 |
// FIXME avoid expensive operation on GUI thread |
59290 | 106 |
layout = Layout.make(metrics, visible_graph) |
49557
61988f9df94d
added Graphview tool, based on Isabelle/Scala and Swing/Graphics2D;
Markus Kaiser <markus.kaiser@in.tum.de>
parents:
diff
changeset
|
107 |
} |
50465 | 108 |
|
59241
541b95e94dc7
clarified bounding box, similar to old graph browser;
wenzelm
parents:
59240
diff
changeset
|
109 |
def bounding_box(): Rectangle2D.Double = |
541b95e94dc7
clarified bounding box, similar to old graph browser;
wenzelm
parents:
59240
diff
changeset
|
110 |
{ |
541b95e94dc7
clarified bounding box, similar to old graph browser;
wenzelm
parents:
59240
diff
changeset
|
111 |
var x0 = 0.0 |
541b95e94dc7
clarified bounding box, similar to old graph browser;
wenzelm
parents:
59240
diff
changeset
|
112 |
var y0 = 0.0 |
541b95e94dc7
clarified bounding box, similar to old graph browser;
wenzelm
parents:
59240
diff
changeset
|
113 |
var x1 = 0.0 |
541b95e94dc7
clarified bounding box, similar to old graph browser;
wenzelm
parents:
59240
diff
changeset
|
114 |
var y1 = 0.0 |
59292 | 115 |
((for (node <- visible_graph.keys_iterator) yield Shapes.Node.shape(visualizer, node)) ++ |
116 |
(for (d <- layout.dummies_iterator) yield Shapes.Dummy.shape(visualizer, d))). |
|
117 |
foreach(rect => { |
|
118 |
x0 = x0 min rect.getMinX |
|
119 |
y0 = y0 min rect.getMinY |
|
120 |
x1 = x1 max rect.getMaxX |
|
121 |
y1 = y1 max rect.getMaxY |
|
122 |
}) |
|
59290 | 123 |
val gap = metrics.gap |
124 |
x0 = (x0 - gap).floor |
|
125 |
y0 = (y0 - gap).floor |
|
126 |
x1 = (x1 + gap).ceil |
|
127 |
y1 = (y1 + gap).ceil |
|
59241
541b95e94dc7
clarified bounding box, similar to old graph browser;
wenzelm
parents:
59240
diff
changeset
|
128 |
new Rectangle2D.Double(x0, y0, x1 - x0, y1 - y0) |
541b95e94dc7
clarified bounding box, similar to old graph browser;
wenzelm
parents:
59240
diff
changeset
|
129 |
} |
49557
61988f9df94d
added Graphview tool, based on Isabelle/Scala and Swing/Graphics2D;
Markus Kaiser <markus.kaiser@in.tum.de>
parents:
diff
changeset
|
130 |
} |
50465 | 131 |
|
50464 | 132 |
object Drawer |
133 |
{ |
|
59250 | 134 |
def apply(gfx: Graphics2D, node: Graph_Display.Node): Unit = |
59258 | 135 |
if (!node.is_dummy) Shapes.Node.paint(gfx, visualizer, node) |
50465 | 136 |
|
59250 | 137 |
def apply(gfx: Graphics2D, edge: Graph_Display.Edge, head: Boolean, dummies: Boolean): Unit = |
138 |
Shapes.Cardinal_Spline_Edge.paint(gfx, visualizer, edge, head, dummies) |
|
50465 | 139 |
|
59250 | 140 |
def paint_all_visible(gfx: Graphics2D, dummies: Boolean) |
50464 | 141 |
{ |
59290 | 142 |
gfx.setRenderingHints(Metrics.rendering_hints) |
59259
399506ee38a5
clarified static full_graph vs. dynamic visible_graph;
wenzelm
parents:
59258
diff
changeset
|
143 |
visible_graph.edges_iterator.foreach(apply(gfx, _, arrow_heads, dummies)) |
399506ee38a5
clarified static full_graph vs. dynamic visible_graph;
wenzelm
parents:
59258
diff
changeset
|
144 |
visible_graph.keys_iterator.foreach(apply(gfx, _)) |
49557
61988f9df94d
added Graphview tool, based on Isabelle/Scala and Swing/Graphics2D;
Markus Kaiser <markus.kaiser@in.tum.de>
parents:
diff
changeset
|
145 |
} |
61988f9df94d
added Graphview tool, based on Isabelle/Scala and Swing/Graphics2D;
Markus Kaiser <markus.kaiser@in.tum.de>
parents:
diff
changeset
|
146 |
} |
50465 | 147 |
|
148 |
object Selection |
|
149 |
{ |
|
59245
be4180f3c236
more formal Graph_Display.Node (with ordering) and Graph_Display.Edge;
wenzelm
parents:
59242
diff
changeset
|
150 |
// owned by GUI thread |
be4180f3c236
more formal Graph_Display.Node (with ordering) and Graph_Display.Edge;
wenzelm
parents:
59242
diff
changeset
|
151 |
private var state: List[Graph_Display.Node] = Nil |
50465 | 152 |
|
59245
be4180f3c236
more formal Graph_Display.Node (with ordering) and Graph_Display.Edge;
wenzelm
parents:
59242
diff
changeset
|
153 |
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
|
154 |
def contains(node: Graph_Display.Node): Boolean = get().contains(node) |
50465 | 155 |
|
59245
be4180f3c236
more formal Graph_Display.Node (with ordering) and Graph_Display.Edge;
wenzelm
parents:
59242
diff
changeset
|
156 |
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
|
157 |
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
|
158 |
} |
50465 | 159 |
|
59220 | 160 |
sealed case class Node_Color(border: Color, background: Color, foreground: Color) |
50464 | 161 |
|
59245
be4180f3c236
more formal Graph_Display.Node (with ordering) and Graph_Display.Edge;
wenzelm
parents:
59242
diff
changeset
|
162 |
def node_color(node: Graph_Display.Node): Node_Color = |
59251 | 163 |
if (Selection.contains(node)) |
59245
be4180f3c236
more formal Graph_Display.Node (with ordering) and Graph_Display.Edge;
wenzelm
parents:
59242
diff
changeset
|
164 |
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
|
165 |
else |
be4180f3c236
more formal Graph_Display.Node (with ordering) and Graph_Display.Edge;
wenzelm
parents:
59242
diff
changeset
|
166 |
Node_Color(foreground_color, model.colors.getOrElse(node, background_color), foreground_color) |
59220 | 167 |
|
59245
be4180f3c236
more formal Graph_Display.Node (with ordering) and Graph_Display.Edge;
wenzelm
parents:
59242
diff
changeset
|
168 |
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
|
169 |
} |