14 |
14 |
15 import scala.swing.{Panel, ScrollPane} |
15 import scala.swing.{Panel, ScrollPane} |
16 import scala.swing.event._ |
16 import scala.swing.event._ |
17 |
17 |
18 |
18 |
19 class Graph_Panel(vis: Visualizer, make_tooltip: (JComponent, Int, Int, XML.Body) => String) |
19 class Graph_Panel( |
|
20 val visualizer: Visualizer, |
|
21 make_tooltip: (JComponent, Int, Int, XML.Body) => String) |
20 extends ScrollPane |
22 extends ScrollPane |
21 { |
23 { |
22 private val panel = this |
24 panel => |
23 |
25 |
24 private var tooltip_content: XML.Body = Nil |
26 private var tooltip_content: XML.Body = Nil |
25 |
27 |
26 override lazy val peer: JScrollPane = new JScrollPane with SuperMixin { |
28 override lazy val peer: JScrollPane = new JScrollPane with SuperMixin { |
27 override def getToolTipText(event: java.awt.event.MouseEvent): String = |
29 override def getToolTipText(event: java.awt.event.MouseEvent): String = |
34 requestFocus() |
36 requestFocus() |
35 |
37 |
36 horizontalScrollBarPolicy = ScrollPane.BarPolicy.Always |
38 horizontalScrollBarPolicy = ScrollPane.BarPolicy.Always |
37 verticalScrollBarPolicy = ScrollPane.BarPolicy.Always |
39 verticalScrollBarPolicy = ScrollPane.BarPolicy.Always |
38 |
40 |
39 def visualizer = vis |
|
40 |
|
41 def fit_to_window() = { |
41 def fit_to_window() = { |
42 Transform.fit_to_window() |
42 Transform.fit_to_window() |
43 repaint() |
43 repaint() |
44 } |
44 } |
45 |
45 |
46 def apply_layout() = vis.Coordinates.layout() |
46 def apply_layout() = visualizer.Coordinates.layout() |
47 |
47 |
48 private val paint_panel = new Panel { |
48 private val paint_panel = new Panel { |
49 def set_preferred_size() { |
49 def set_preferred_size() { |
50 val (minX, minY, maxX, maxY) = vis.Coordinates.bounds() |
50 val (minX, minY, maxX, maxY) = visualizer.Coordinates.bounds() |
51 val s = Transform.scale |
51 val s = Transform.scale |
52 val (px, py) = Transform.padding |
52 val (px, py) = Transform.padding |
53 |
53 |
54 preferredSize = new Dimension((math.abs(maxX - minX + px) * s).toInt, |
54 preferredSize = new Dimension((math.abs(maxX - minX + px) * s).toInt, |
55 (math.abs(maxY - minY + py) * s).toInt) |
55 (math.abs(maxY - minY + py) * s).toInt) |
108 _scale = math.max(math.min(s, 10), 0.01) |
108 _scale = math.max(math.min(s, 10), 0.01) |
109 paint_panel.set_preferred_size() |
109 paint_panel.set_preferred_size() |
110 } |
110 } |
111 |
111 |
112 def apply() = { |
112 def apply() = { |
113 val (minX, minY, _, _) = vis.Coordinates.bounds() |
113 val (minX, minY, _, _) = visualizer.Coordinates.bounds() |
114 |
114 |
115 val at = AffineTransform.getScaleInstance(scale, scale) |
115 val at = AffineTransform.getScaleInstance(scale, scale) |
116 at.translate(-minX + padding._1 / 2, -minY + padding._2 / 2) |
116 at.translate(-minX + padding._1 / 2, -minY + padding._2 / 2) |
117 at |
117 at |
118 } |
118 } |
119 |
119 |
120 def fit_to_window() { |
120 def fit_to_window() { |
121 if (vis.model.visible_nodes().isEmpty) |
121 if (visualizer.model.visible_nodes().isEmpty) |
122 scale = 1 |
122 scale = 1 |
123 else { |
123 else { |
124 val (minX, minY, maxX, maxY) = vis.Coordinates.bounds() |
124 val (minX, minY, maxX, maxY) = visualizer.Coordinates.bounds() |
125 |
125 |
126 val (dx, dy) = (maxX - minX + padding._1, maxY - minY + padding._2) |
126 val (dx, dy) = (maxX - minX + padding._1, maxY - minY + padding._2) |
127 val (sx, sy) = (1d * size.width / dx, 1d * size.height / dy) |
127 val (sx, sy) = (1d * size.width / dx, 1d * size.height / dy) |
128 scale = math.min(sx, sy) |
128 scale = math.min(sx, sy) |
129 } |
129 } |
178 type Dummy = ((String, String), Int) |
178 type Dummy = ((String, String), Int) |
179 |
179 |
180 private var draginfo: (Point, Iterable[String], Iterable[Dummy]) = null |
180 private var draginfo: (Point, Iterable[String], Iterable[Dummy]) = null |
181 private val g = |
181 private val g = |
182 new BufferedImage(1, 1, BufferedImage.TYPE_INT_RGB).createGraphics |
182 new BufferedImage(1, 1, BufferedImage.TYPE_INT_RGB).createGraphics |
183 g.setFont(vis.Font()) |
183 g.setFont(visualizer.Font()) |
184 g.setRenderingHints(vis.rendering_hints) |
184 g.setRenderingHints(visualizer.rendering_hints) |
185 |
185 |
186 val react: PartialFunction[Event, Unit] = { |
186 val react: PartialFunction[Event, Unit] = { |
187 case MousePressed(_, p, _, _, _) => pressed(p) |
187 case MousePressed(_, p, _, _, _) => pressed(p) |
188 case MouseDragged(_, to, _) => { |
188 case MouseDragged(_, to, _) => { |
189 drag(draginfo, to) |
189 drag(draginfo, to) |
194 case e@MouseClicked(_, p, m, n, _) => click(p, m, n, e) |
194 case e@MouseClicked(_, p, m, n, _) => click(p, m, n, e) |
195 case MouseMoved(_, p, _) => moved(p) |
195 case MouseMoved(_, p, _) => moved(p) |
196 } |
196 } |
197 |
197 |
198 def node(at: Point2D): Option[String] = |
198 def node(at: Point2D): Option[String] = |
199 vis.model.visible_nodes().find({ |
199 visualizer.model.visible_nodes().find({ |
200 l => vis.Drawer.shape(g, Some(l)).contains(at) |
200 l => visualizer.Drawer.shape(g, Some(l)).contains(at) |
201 }) |
201 }) |
202 |
202 |
203 def dummy(at: Point2D): Option[Dummy] = |
203 def dummy(at: Point2D): Option[Dummy] = |
204 vis.model.visible_edges().map({ |
204 visualizer.model.visible_edges().map({ |
205 i => vis.Coordinates(i).zipWithIndex.map((i, _)) |
205 i => visualizer.Coordinates(i).zipWithIndex.map((i, _)) |
206 }).flatten.find({ |
206 }).flatten.find({ |
207 case (_, ((x, y), _)) => |
207 case (_, ((x, y), _)) => |
208 vis.Drawer.shape(g, None).contains(at.getX() - x, at.getY() - y) |
208 visualizer.Drawer.shape(g, None).contains(at.getX() - x, at.getY() - y) |
209 }) match { |
209 }) match { |
210 case None => None |
210 case None => None |
211 case Some((name, (_, index))) => Some((name, index)) |
211 case Some((name, (_, index))) => Some((name, index)) |
212 } |
212 } |
213 |
213 |
214 def moved(at: Point) { |
214 def moved(at: Point) { |
215 val c = Transform.pane_to_graph_coordinates(at) |
215 val c = Transform.pane_to_graph_coordinates(at) |
216 node(c) match { |
216 node(c) match { |
217 case Some(l) => panel.tooltip = ""; panel.tooltip_content = vis.Tooltip.content(l) |
217 case Some(l) => |
218 case None => panel.tooltip = null; panel.tooltip_content = Nil |
218 panel.tooltip = "" |
|
219 panel.tooltip_content = visualizer.Tooltip.content(l) |
|
220 case None => |
|
221 panel.tooltip = null |
|
222 panel.tooltip_content = Nil |
219 } |
223 } |
220 } |
224 } |
221 |
225 |
222 def pressed(at: Point) { |
226 def pressed(at: Point) { |
223 val c = Transform.pane_to_graph_coordinates(at) |
227 val c = Transform.pane_to_graph_coordinates(at) |
224 val l = node(c) match { |
228 val l = node(c) match { |
225 case Some(l) => if (vis.Selection(l)) |
229 case Some(l) => |
226 vis.Selection() |
230 if (visualizer.Selection(l)) visualizer.Selection() else List(l) |
227 else |
|
228 List(l) |
|
229 |
|
230 case None => Nil |
231 case None => Nil |
231 } |
232 } |
232 val d = l match { |
233 val d = l match { |
233 case Nil => dummy(c) match { |
234 case Nil => dummy(c) match { |
234 case Some(d) => List(d) |
235 case Some(d) => List(d) |
247 val c = Transform.pane_to_graph_coordinates(at) |
248 val c = Transform.pane_to_graph_coordinates(at) |
248 val p = node(c) |
249 val p = node(c) |
249 |
250 |
250 def left_click() { |
251 def left_click() { |
251 (p, m) match { |
252 (p, m) match { |
252 case (Some(l), Control) => vis.Selection.add(l) |
253 case (Some(l), Control) => visualizer.Selection.add(l) |
253 case (None, Control) => |
254 case (None, Control) => |
254 |
255 |
255 case (Some(l), Shift) => vis.Selection.add(l) |
256 case (Some(l), Shift) => visualizer.Selection.add(l) |
256 case (None, Shift) => |
257 case (None, Shift) => |
257 |
258 |
258 case (Some(l), _) => vis.Selection.set(List(l)) |
259 case (Some(l), _) => visualizer.Selection.set(List(l)) |
259 case (None, _) => vis.Selection.clear |
260 case (None, _) => visualizer.Selection.clear |
260 } |
261 } |
261 } |
262 } |
262 |
263 |
263 def right_click() { |
264 def right_click() { |
264 val menu = Popups(panel, p, vis.Selection()) |
265 val menu = Popups(panel, p, visualizer.Selection()) |
265 menu.show(panel.peer, at.x, at.y) |
266 menu.show(panel.peer, at.x, at.y) |
266 } |
267 } |
267 |
268 |
268 if (clicks < 2) { |
269 if (clicks < 2) { |
269 if (SwingUtilities.isRightMouseButton(e.peer)) right_click() |
270 if (SwingUtilities.isRightMouseButton(e.peer)) right_click() |
283 |
284 |
284 paint_panel.peer.scrollRectToVisible(r) |
285 paint_panel.peer.scrollRectToVisible(r) |
285 } |
286 } |
286 |
287 |
287 case (Nil, ds) => |
288 case (Nil, ds) => |
288 ds.foreach(d => vis.Coordinates.translate(d, (dx / s, dy / s))) |
289 ds.foreach(d => visualizer.Coordinates.translate(d, (dx / s, dy / s))) |
289 |
290 |
290 case (ls, _) => |
291 case (ls, _) => |
291 ls.foreach(l => vis.Coordinates.translate(l, (dx / s, dy / s))) |
292 ls.foreach(l => visualizer.Coordinates.translate(l, (dx / s, dy / s))) |
292 } |
293 } |
293 } |
294 } |
294 |
295 |
295 def wheel(rotation: Int, at: Point) { |
296 def wheel(rotation: Int, at: Point) { |
296 val at2 = Transform.pane_to_graph_coordinates(at) |
297 val at2 = Transform.pane_to_graph_coordinates(at) |