13 import java.awt.{BasicStroke, Graphics2D, Shape} |
13 import java.awt.{BasicStroke, Graphics2D, Shape} |
14 import java.awt.geom.{AffineTransform, GeneralPath, Path2D, Rectangle2D, |
14 import java.awt.geom.{AffineTransform, GeneralPath, Path2D, Rectangle2D, |
15 RoundRectangle2D, PathIterator} |
15 RoundRectangle2D, PathIterator} |
16 |
16 |
17 |
17 |
18 object Shapes |
18 object Shapes { |
19 { |
|
20 private val default_stroke = |
19 private val default_stroke = |
21 new BasicStroke(1, BasicStroke.CAP_BUTT, BasicStroke.JOIN_ROUND) |
20 new BasicStroke(1, BasicStroke.CAP_BUTT, BasicStroke.JOIN_ROUND) |
22 |
21 |
23 def shape(info: Layout.Info): Rectangle2D.Double = |
22 def shape(info: Layout.Info): Rectangle2D.Double = |
24 new Rectangle2D.Double(info.x - info.width2, info.y - info.height2, info.width, info.height) |
23 new Rectangle2D.Double(info.x - info.width2, info.y - info.height2, info.width, info.height) |
25 |
24 |
26 def highlight_node(gfx: Graphics2D, graphview: Graphview, node: Graph_Display.Node): Unit = |
25 def highlight_node(gfx: Graphics2D, graphview: Graphview, node: Graph_Display.Node): Unit = { |
27 { |
|
28 val metrics = graphview.metrics |
26 val metrics = graphview.metrics |
29 val extra = metrics.char_width |
27 val extra = metrics.char_width |
30 val info = graphview.layout.get_node(node) |
28 val info = graphview.layout.get_node(node) |
31 |
29 |
32 gfx.setColor(graphview.highlight_color) |
30 gfx.setColor(graphview.highlight_color) |
35 info.y - info.height2 - extra, |
33 info.y - info.height2 - extra, |
36 info.width + 2 * extra, |
34 info.width + 2 * extra, |
37 info.height + 2 * extra)) |
35 info.height + 2 * extra)) |
38 } |
36 } |
39 |
37 |
40 def paint_node(gfx: Graphics2D, graphview: Graphview, node: Graph_Display.Node): Unit = |
38 def paint_node(gfx: Graphics2D, graphview: Graphview, node: Graph_Display.Node): Unit = { |
41 { |
|
42 val metrics = graphview.metrics |
39 val metrics = graphview.metrics |
43 val info = graphview.layout.get_node(node) |
40 val info = graphview.layout.get_node(node) |
44 val c = graphview.node_color(node) |
41 val c = graphview.node_color(node) |
45 val s = shape(info) |
42 val s = shape(info) |
46 |
43 |
64 gfx.drawString(Word.bidi_override(line), x, y) |
61 gfx.drawString(Word.bidi_override(line), x, y) |
65 y += metrics.height.ceil.toInt |
62 y += metrics.height.ceil.toInt |
66 } |
63 } |
67 } |
64 } |
68 |
65 |
69 def paint_dummy(gfx: Graphics2D, graphview: Graphview, info: Layout.Info): Unit = |
66 def paint_dummy(gfx: Graphics2D, graphview: Graphview, info: Layout.Info): Unit = { |
70 { |
|
71 gfx.setStroke(default_stroke) |
67 gfx.setStroke(default_stroke) |
72 gfx.setColor(graphview.dummy_color) |
68 gfx.setColor(graphview.dummy_color) |
73 gfx.draw(shape(info)) |
69 gfx.draw(shape(info)) |
74 } |
70 } |
75 |
71 |
76 object Straight_Edge |
72 object Straight_Edge { |
77 { |
73 def paint(gfx: Graphics2D, graphview: Graphview, edge: Graph_Display.Edge): Unit = { |
78 def paint(gfx: Graphics2D, graphview: Graphview, edge: Graph_Display.Edge): Unit = |
|
79 { |
|
80 val p = graphview.layout.get_node(edge._1) |
74 val p = graphview.layout.get_node(edge._1) |
81 val q = graphview.layout.get_node(edge._2) |
75 val q = graphview.layout.get_node(edge._2) |
82 val ds = |
76 val ds = { |
83 { |
|
84 val a = p.y min q.y |
77 val a = p.y min q.y |
85 val b = p.y max q.y |
78 val b = p.y max q.y |
86 graphview.layout.dummies_iterator(edge).filter(d => a < d.y && d.y < b).toList |
79 graphview.layout.dummies_iterator(edge).filter(d => a < d.y && d.y < b).toList |
87 } |
80 } |
88 val path = new GeneralPath(Path2D.WIND_EVEN_ODD, ds.length + 2) |
81 val path = new GeneralPath(Path2D.WIND_EVEN_ODD, ds.length + 2) |
99 |
92 |
100 if (graphview.show_arrow_heads) Arrow_Head.paint(gfx, path, Shapes.shape(q)) |
93 if (graphview.show_arrow_heads) Arrow_Head.paint(gfx, path, Shapes.shape(q)) |
101 } |
94 } |
102 } |
95 } |
103 |
96 |
104 object Cardinal_Spline_Edge |
97 object Cardinal_Spline_Edge { |
105 { |
|
106 private val slack = 0.1 |
98 private val slack = 0.1 |
107 |
99 |
108 def paint(gfx: Graphics2D, graphview: Graphview, edge: Graph_Display.Edge): Unit = |
100 def paint(gfx: Graphics2D, graphview: Graphview, edge: Graph_Display.Edge): Unit = { |
109 { |
|
110 val p = graphview.layout.get_node(edge._1) |
101 val p = graphview.layout.get_node(edge._1) |
111 val q = graphview.layout.get_node(edge._2) |
102 val q = graphview.layout.get_node(edge._2) |
112 val ds = |
103 val ds = { |
113 { |
|
114 val a = p.y min q.y |
104 val a = p.y min q.y |
115 val b = p.y max q.y |
105 val b = p.y max q.y |
116 graphview.layout.dummies_iterator(edge).filter(d => a < d.y && d.y < b).toList |
106 graphview.layout.dummies_iterator(edge).filter(d => a < d.y && d.y < b).toList |
117 } |
107 } |
118 |
108 |
152 if (graphview.show_arrow_heads) Arrow_Head.paint(gfx, path, Shapes.shape(q)) |
142 if (graphview.show_arrow_heads) Arrow_Head.paint(gfx, path, Shapes.shape(q)) |
153 } |
143 } |
154 } |
144 } |
155 } |
145 } |
156 |
146 |
157 object Arrow_Head |
147 object Arrow_Head { |
158 { |
|
159 type Point = (Double, Double) |
148 type Point = (Double, Double) |
160 |
149 |
161 private def position(path: GeneralPath, shape: Shape): Option[AffineTransform] = |
150 private def position(path: GeneralPath, shape: Shape): Option[AffineTransform] = { |
162 { |
151 def intersecting_line(path: GeneralPath, shape: Shape): Option[(Point, Point)] = { |
163 def intersecting_line(path: GeneralPath, shape: Shape): Option[(Point, Point)] = |
|
164 { |
|
165 val i = path.getPathIterator(null, 1.0) |
152 val i = path.getPathIterator(null, 1.0) |
166 val seg = Array[Double](0.0, 0.0, 0.0, 0.0, 0.0, 0.0) |
153 val seg = Array[Double](0.0, 0.0, 0.0, 0.0, 0.0, 0.0) |
167 var p1 = (0.0, 0.0) |
154 var p1 = (0.0, 0.0) |
168 var p2 = (0.0, 0.0) |
155 var p2 = (0.0, 0.0) |
169 while (!i.isDone) { |
156 while (!i.isDone) { |
180 i.next() |
167 i.next() |
181 } |
168 } |
182 None |
169 None |
183 } |
170 } |
184 |
171 |
185 def binary_search(line: (Point, Point), shape: Shape): Option[AffineTransform] = |
172 def binary_search(line: (Point, Point), shape: Shape): Option[AffineTransform] = { |
186 { |
|
187 val ((fx, fy), (tx, ty)) = line |
173 val ((fx, fy), (tx, ty)) = line |
188 if (shape.contains(fx, fy) == shape.contains(tx, ty)) |
174 if (shape.contains(fx, fy) == shape.contains(tx, ty)) |
189 None |
175 None |
190 else { |
176 else { |
191 val (dx, dy) = (fx - tx, fy - ty) |
177 val (dx, dy) = (fx - tx, fy - ty) |
208 case None => None |
194 case None => None |
209 case Some(line) => binary_search(line, shape) |
195 case Some(line) => binary_search(line, shape) |
210 } |
196 } |
211 } |
197 } |
212 |
198 |
213 def paint(gfx: Graphics2D, path: GeneralPath, shape: Shape): Unit = |
199 def paint(gfx: Graphics2D, path: GeneralPath, shape: Shape): Unit = { |
214 { |
|
215 position(path, shape) match { |
200 position(path, shape) match { |
216 case None => |
201 case None => |
217 case Some(at) => |
202 case Some(at) => |
218 val arrow = new GeneralPath(Path2D.WIND_EVEN_ODD, 3) |
203 val arrow = new GeneralPath(Path2D.WIND_EVEN_ODD, 3) |
219 arrow.moveTo(0, 0) |
204 arrow.moveTo(0, 0) |