]> git.sur5r.net Git - i3/i3/blob - render-tree/render.pl
Merge branch 'master' into next
[i3/i3] / render-tree / render.pl
1 #!/usr/bin/env perl
2 # vim:ts=4:sw=4:expandtab
3 # © 2011 Michael Stapelberg, see LICENSE
4 #
5 # Needs SVG (libsvg-perl), IO::All (libio-all-perl), JSON::XS (libjson-xs-perl) and Moose (libmoose-perl)
6 #
7 # XXX: unfinished proof-of-concept. awaits a json dump in my.tree, renders to test.svg
8 # XXX: needs more beautifying (in the SVG but also in the code)
9 # XXX: has some rendering differences between firefox and chromium. maybe inkscape makes the file look the same in both browsers
10
11 use strict;
12 use warnings;
13 use SVG;
14 use Data::Dumper;
15 use JSON::XS;
16 use IO::All;
17 use List::Util qw(sum);
18 use lib qw(.);
19 use Con;
20 use v5.10;
21
22 my $input = io('my.tree')->slurp;
23 my $tree = decode_json($input);
24 my $root = parse_tree($tree);
25 render_tree($root);
26
27 sub parse_tree {
28     my ($input, $parent) = @_;
29     my $con = Con->new(name => $input->{name});
30     $con->parent($parent) if defined($parent);
31     for my $node (@{$input->{nodes}}) {
32         $con->add_node(parse_tree($node, $con));
33     }
34
35     return $con;
36 }
37
38 sub render_tree {
39     my ($con) = @_;
40     say 'rendering con ' . $con->name;
41     my @nodes = $con->nodes;
42     for my $node (@nodes) {
43         render_tree($node);
44     }
45
46     # nothing to calculate when there are no children
47     return unless @nodes > 0;
48
49     $con->width((@nodes > 1 ? (@nodes - 1) * 20 : 0) + sum map { $_->width } @nodes);
50
51     say $con->name . ' has width ' . $con->width;
52 }
53
54 # TODO: figure out the height
55 my $svg = SVG->new(id => "tree", width => $root->width + 5, height => '1052');
56
57 my $l1 = $svg->group(id => 'layer1');
58
59 # gaussian blur (for drop shadows)
60 $svg->defs()->filter(id => 'dropshadow')->fe(-type => 'gaussianblur', stdDeviation => '2.19');
61
62 my $idcnt = 0;
63 my $y = 10;
64 render_svg($root, 0, 0);
65
66 sub render_svg {
67     my ($con, $level, $x) = @_;
68
69     my $indent = ' ' x $level;
70
71     say $indent . 'svg-rendering con ' . $con->name . ' on level ' . $level;
72     say $indent . 'width: ' . $con->width;
73
74     # render the dropshadow rect
75     $l1->rect(
76         id => 'outer_rect_shadow' . $idcnt,
77         style => 'opacity:1.0;fill:#000000;fill-opacity:1;stroke:#000000;stroke-width:4;stroke-opacity:1;stroke-miterlimit:4;filter:url(#dropshadow)',
78         width => "96",
79         height => '50',
80         #x => $x + ($con->has_parent ? ($con->parent->width - 100) / 2 : 0),
81         x => $x + ($con->width / 2) - (96 / 2) + 0,
82         y => 4 + $level * 70 + 0,
83     );
84     $idcnt++;
85
86     # render the main rect
87     $l1->rect(
88         id => 'outer_rect' . $idcnt,
89         style => 'opacity:1.0;fill:#c30000;fill-opacity:1;stroke:#000000;stroke-width:4;stroke-opacity:1;stroke-miterlimit:4',
90         width => "96",
91         height => '50',
92         x => $x + ($con->width / 2) - (96 / 2),
93         y => 4 + $level * 70,
94     );
95
96     $idcnt++;
97
98     # render the text
99     $l1->text(
100         style => 'font-size:14px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:left;line-height:125%;letter-spacing:0px;word-spacing:0px;text-anchor:middle;fill:#000000;fill-opacity:1;stroke:none;font-family:Trebuchet MS;-inkscape-font-specification:Trebuchet MS',
101         x => $x + ($con->width / 2) - (100/2) + 5,
102         y => 4 + 15 + $level * 70,
103         id => 'title_'.$idcnt,
104     )->tspan(style => 'text-align:start;text-anchor:start')->cdata($con->name);
105     $idcnt++;
106
107     $y = $y + 50;
108     my @nodes = $con->nodes;
109     my $startx = $x + ($con->width / 2);
110
111     for my $node (@nodes) {
112         render_svg($node, $level + 1, $x);
113         my $mid = $x + ($node->width / 2);
114         $l1->path(
115             d => 'M ' . $startx . ',' . (4 + $level * 70 + 50) . ' ' . $mid . ',' . (4 + ($level+1) * 70),
116             id => 'path' . $idcnt,
117             style => 'fill:none;stroke:#000000;stroke-width:2px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1'
118         );
119         $x += $node->width + 20;
120         $idcnt++;
121     }
122
123 }
124
125 $svg->render > io('test.svg');