Assorted away-tpope updates
[tpope-extra.git] / perl / relational-schema
1 #!/usr/bin/perl -w
2 # $Id$
3 # -*- perl -*- vim:set ft=perl sw=4 sts=4:
4
5 # Usage: relational-schema out.png RELATION:_Primary_Key,.Foreign_Key,Etc
6 # To clarifiy, specifiy the relation name, followed by a colon, followed by
7 # the attributes seperated by commas.  Primary keys should be prefixed with
8 # an underscore, and foreign keys with a period.
9 # It is also possible to override or augment the functional dependencies by
10 # adding a second colon and additional specifications.  Since this was
11 # unnecessary for the assignment, it is not documented here.
12
13 use strict;
14 use Image::Imlib2;
15
16 use vars qw($font $maxwidth $pd $fh);
17 $font = "Verdana/11";
18 $maxwidth = 550;
19 $pd = 4; # Padding
20
21 my $out = shift or die "No output file specified.\n";
22 my @rows = @ARGV;
23 die "No rows.\n" unless (@rows);
24
25 my $image = new Image::Imlib2->new(1,1);
26 $image->add_font_path ("/usr/share/fonts/truetype/msttcorefonts");
27 $image->load_font($font);
28 ($fh, $fh) = $image->get_text_size("(Ay)");
29 $image = new Image::Imlib2->new($maxwidth, ($#rows+1)*($fh*2+$pd*12+2));
30 $image->add_font_path ("/usr/share/fonts/truetype/msttcorefonts");
31 $image->load_font($font);
32 $image->set_color(255,255,255,255);
33 #$image->fill_rectangle(0,0,$maxwidth,($#rows+1)*($fh*2+$pd*12+2));
34
35 sub draw_boxed_text {
36     my ($image, $text, $x, $y, $underline)=@_;
37     $image->load_font($font);
38     my ($w, $h) = $image->get_text_size($text);
39     $image->set_color(255,255,255,255);
40     $image->fill_rectangle($x,$y,$w+2*$pd+2,$fh+2*$pd+2);
41     $image->set_color(0,0,0,255);
42     $image->draw_rectangle($x,$y,$w+2*$pd+2,$fh+2*$pd+2);
43     $image->draw_text($x+$pd,$y+$pd,$text);
44     if(($underline||0)==1) { # Solid underline
45         $image->draw_line($x+$pd,$y+$pd+$fh,$x+$w+$pd,$y+$pd+$fh);
46     } elsif(($underline||0)==2) { # Dashed underline
47         for(my $i=0;$i<$w;$i+=5) {
48             $image->draw_line($x+$pd+$i,$y+$pd+$fh,
49                 $x+$pd+($i+2>$w?$w$i+2),$y+$pd+$fh);
50         }
51     }
52     return $w+2*$pd+1;
53 }
54
55 my $line=0;
56
57 foreach my $row (@rows) {
58     my ($title,$element,@depends) = split (':',$row);
59     my @elements = split (',',$element);
60     my %elcenters = ();
61     my (@in,@out);
62     my ($toffset)=(2*$pd);
63     while ($title =~ s/^>//) {
64         $toffset += 16*$pd;
65     }
66     my ($offset) = ($toffset);
67     foreach $element (@elements) {
68         my $under=0;
69         if ($element =~ s/^_//) {
70             $under=1;
71             push @out,($element);
72         } elsif ($element =~ s/^\.//) {
73             $under=2;
74             push @in,($element);
75         } else {
76             push @in,($element);
77             warn "Element $element in $title not marked as ".
78             "primary or foreign key.\n" if ($element=~/_ID$/);
79         }
80         my $o=draw_boxed_text($image,$element,$offset,$line+$fh+5*$pd,$under);
81         $elcenters{$element}=($offset+$o/2);
82         $offset+=$o;
83     }
84     my $updown=0;
85     my $shifttitle=0;
86     if((($#depends>=0 and $depends[0] eq 'auto') or $#depends=-1)
87             and $#in>=0 and $#out>=0) {
88         $depends[0]=(join(",",@out)."/".join(",",@in));
89     } elsif($#depends>=0 and $depends[0] eq 'auto') {
90         shift @depends;
91     }
92     foreach my $depend (@depends) {
93         unless ($depend) {
94             $updown++;
95             next;
96         }
97         $image->set_color(0,(32*($updown>>1))%128,(64*($updown>>1))%256,255);
98         my ($out,$in) = split('/',$depend);
99         my ($near, $far);
100         my @out = split(',', $out);
101         my @in  = split(',', $in );
102         my @temp = sort { $elcenters{$a} <=> $elcenters{$b} } (@out, @in);
103         if($updown%2==1) {
104             $shifttitle=1;
105             $near=$line+$fh+5*$pd-1;
106             $far=$line+$fh+1*$pd-1;
107         } else {
108             $near=$line+2*$fh+7*$pd+2;
109             $far=$line+2*$fh+11*$pd+2;
110         }
111         $image->draw_line($elcenters{$temp[0]}+$pd*($updown>>1),
112             $far,$elcenters{$temp[$#temp]}+$pd*($updown>>1),$far);
113         foreach $out (@out) {
114             $image->draw_line($elcenters{$out}+$pd*($updown>>1),
115                 $far,$elcenters{$out}+$pd*($updown>>1),$near);
116         }
117         foreach $in (@in) { # Draw arrowheads
118             my $arrow = Image::Imlib2::Polygon->new();
119             $arrow->add_point($elcenters{$in}+$pd*($updown>>1),$near);
120             $arrow->add_point($elcenters{$in}+$pd+$pd*($updown>>1),
121                 ($near+$far)/2);
122             $arrow->add_point($elcenters{$in}-$pd+$pd*($updown>>1),
123                 ($near+$far)/2);
124             $arrow->add_point($elcenters{$in},$near);
125             $arrow->fill();
126             $image->draw_line($elcenters{$in}+$pd*($updown>>1),
127                 $far,$elcenters{$in}+$pd*($updown>>1),$near);
128             $image->draw_polygon($arrow,1);
129         }
130         $updown++;
131     }
132     $image->set_color(0,0,0,255);
133     $image->draw_text($toffset+$pd*2,$line+4*$pd-$shifttitle*(7*$pd/2),$title);
134     $line+=2*$fh+12*$pd+2;
135 }
136
137
138 $image->save($out);