]> mj.ucw.cz Git - anim.git/blob - AA/UI.pm
A bit of animation.
[anim.git] / AA / UI.pm
1 package AA::UI;
2
3 use strict;
4 use warnings;
5
6 sub new($$) {
7         my ($class, $name) = @_;
8         if ($name eq "") {
9                 return AA::UI::GTK->new(1);
10         } elsif ($name eq "gtk") {
11                 return AA::UI::GTK->new(0);
12         } elsif ($name =~ /\.pdf$/) {
13                 return AA::UI::PDF->new($name);
14         } elsif ($name =~ /\.png$/) {
15                 return AA::UI::PNG->new($name);
16         }
17 }
18
19 package AA::UI::GTK;
20
21 my $debug = 1;
22
23 our @ISA = ('AA::UI');
24
25 sub new($$) {
26         my ($class, $mode) = @_;
27         my $ui = {
28                 MODE => $mode,
29         };
30         return bless($ui, $class);
31 }
32
33 my $u_scenario;
34 my $u_scene;
35 my $u_frame;
36 my $u_direction;
37 my @u_scenes = ();
38
39 my $window;
40 my $cairo;
41 my $area;
42 my $pixmap;
43 my $timer;
44 my $stopped = 0;
45 my $fullscreen = 0;
46 my $movie = 0;
47 my ($lastw, $lasth, $lastd) = (-1, -1, -1);
48 my ($pixw, $pixh) = (-1, -1);
49 my ($last_scene, $last_frame) = (-1, -1);
50
51 sub draw($) {
52         my ($force) = @_;
53         my $win = $area->window;
54         my $wgc = Gtk2::Gdk::GC->new($win);
55         my $alloc = $area->allocation;
56         my $w = $alloc->width;
57         my $h = $alloc->height;
58         my $d = $win->get_depth;
59         # print "Area $w x $h x $d, xx=$xx\n";
60
61         if (!defined($pixmap) || $lastw != $w || $lasth != $h || $lastd != $d) {
62                 ($lastw, $lasth, $lastd) = ($w, $h, $d);
63                 if ($w/$h >= 4/3) {
64                         $pixh = $h;
65                         $pixw = int($h/3*4);
66                 } else {
67                         $pixw = $w;
68                         $pixh = int($w/4*3);
69                 }
70                 print "Resized to ${w}x${h}, pixmap size ${pixw}x${pixh}\n" if $debug;
71
72                 $pixmap = Gtk2::Gdk::Pixmap->new($win, $pixw, $pixh, $d);
73                 $cairo = Gtk2::Gdk::Cairo::Context->create($pixmap);
74                 $cairo->select_font_face('URW Palladio L', 'normal', 'normal');
75                 my $scale = $pixw/1024;
76                 $cairo->scale($scale, $scale);
77         }
78
79         if ($force) {
80                 $wgc->set_rgb_background(0);
81                 $wgc->set_rgb_foreground(0);
82                 $win->draw_rectangle($wgc, 1, 0, 0, $w, $h);
83         }
84
85         $cairo->rectangle(0, 0, 1024, 768);
86         $cairo->set_source_rgb(0, 0, 0);
87         $cairo->fill;
88
89         if (@u_scenes) {
90                 print "@@@ Scene $u_scene frame $u_frame\n" if $debug;
91                 $u_scenes[$u_scene]->[$u_frame]->Draw($cairo);
92                 $cairo->set_source_rgb(.5, .5, .5);
93                 $cairo->set_font_size(15);
94                 $cairo->move_to(950,750);
95                 $cairo->show_text($u_scene . "/" . $#u_scenes);
96         } else {
97                 AA->calculate;
98                 AA->draw($cairo);
99         }
100
101         $win->draw_drawable($wgc, $pixmap, 0, 0, 0, 0, $pixw, $pixh);
102         $last_scene = $u_scene;
103         $last_frame = $u_frame;
104 }
105
106 sub step() {
107         # FIXME: the timer still runs
108         if (@u_scenes) {
109                 if ($u_direction > 0) {
110                         if ($u_frame < @{$u_scenes[$u_scene]}-1) {
111                                 $u_frame++;
112                         } elsif ($movie && $u_scene < @u_scenes - 1) {
113                                 $u_scene++;
114                                 $u_frame = 0;
115                         }
116                 } elsif ($u_direction < 0) {
117                         if ($u_frame) {
118                                 $u_frame--;
119                         } elsif ($movie && $u_scene) {
120                                 $u_scene--;
121                                 $u_frame = @{$u_scenes[$u_scene]} - 1;
122                         }
123                 }
124                 return if ($u_scene == $last_scene && $u_frame == $last_frame);
125         } else {
126                 AA::Anim->step;
127         }
128         draw(0);
129 }
130
131 sub prepare() {
132         $window = Gtk2::Window->new ('toplevel');
133         $area = Gtk2::DrawingArea->new();
134         $area->signal_connect("expose-event" => sub {
135                 draw(1);
136                 if (!defined $timer) {
137                         $timer = Glib::Timeout->add(30, sub { $stopped || step(); return 1; });
138                 }
139         });
140         $area->set_flags('can-focus');
141         # $area->add_events('key-press-mask');
142         $area->signal_connect('key-press-event' => sub {
143                 my ($w, $evt) = @_;
144                 my $k = Gtk2::Gdk::keyval_name(0, $evt->keyval);
145                 print "Pressed key $k\n" if $debug;
146                 if ($k eq "Escape") {
147                         Gtk2->main_quit;
148                 } elsif ($k eq "f") {
149                         if ($fullscreen = !$fullscreen) {
150                                 $window->fullscreen;
151                         } else {
152                                 $window->unfullscreen;
153                         }
154                 } elsif ($k eq "space" || $k eq "Right" || $k eq "Page_Down") {
155                         if (@u_scenes) {
156                                 if ($u_direction > 0 && $u_scene+1 < @u_scenes) {
157                                         $u_scene++;
158                                         $u_frame = 0;
159                                 }
160                                 $u_direction = 1;
161                                 draw(0);
162                         } else {
163                                 while (AA::Anim->step) { AA->calculate; }
164                                 if ($u_scene+1 < @$u_scenario) {
165                                         $u_scene++;
166                                         AA::Anim->start;
167                                         &{$u_scenario->[$u_scene]};
168                                         draw(0);
169                                 }
170                         }
171                 } elsif ($k eq "BackSpace" || $k eq "Left" || $k eq "Page_Up") {
172                         if (@u_scenes && $u_scene) {
173                                 if (!$u_frame || $u_direction < 0) {
174                                         $u_scene--;
175                                         $u_frame = @{$u_scenes[$u_scene]}-1;
176                                 }
177                                 $u_direction = -1;
178                                 draw(0);
179                         }
180                 } elsif ($k eq "Home" || $k eq "0") {
181                         if (@u_scenes) {
182                                 $u_scene = 0;
183                                 $u_frame = 0;
184                                 $u_direction = 1;
185                                 draw(0);
186                         }
187                 } elsif ($k eq "End" || $k eq "9") {
188                         if (@u_scenes) {
189                                 $u_scene = $#u_scenes;
190                                 $u_frame = @{$u_scenes[$u_scene]}-1;
191                                 $u_direction = 1;
192                                 draw(0);
193                         }
194                 } elsif ($k eq "p") {
195                         $stopped = !$stopped;
196                         print "Stopped is $stopped\n" if $debug;
197                 } elsif ($k eq "m") {
198                         $movie = !$movie;
199                         print "Movie mode is $movie\n" if $debug;
200                 } elsif ($k eq "Return") {
201                         if (@u_scenes) {
202                                 $u_frame = ($u_direction > 0) ? @{$u_scenes[$u_scene]}-1 : 0;
203                         } else {
204                                 while (AA::Anim->step) { AA->calculate; }
205                         }
206                 }
207         });
208
209         $window->signal_connect ("delete-event" => sub { Gtk2->main_quit });
210         $window->set_title("Brum");
211         $window->set_wmclass("brum", "Brum");
212         $window->set_default_size(640, 480);
213         $window->add ($area);
214         $window->show_all;
215 }
216
217 sub RunScenario($$) {
218         my ($ui, $scenario) = @_;
219
220         if ($ui->{MODE}) {
221                 print "Rendering...\n";
222                 foreach my $s (@$scenario) {
223                         print ">>> Scene ", scalar @u_scenes, "\n" if $debug;
224                         AA::Anim->start;
225                         &$s;
226                         my $show = [];
227                         while (AA::Anim->step) {
228                                 print "\t>>> Frame ", scalar @$show, "\n" if $debug;
229                                 AA->calculate;
230                                 push @$show, AA::Scene->new();
231                         }
232                         push @u_scenes, $show;
233                 }
234                 print "Ready.\n";
235         } else {
236                 $u_scenario = $scenario;
237                 AA::Anim->start;
238                 &{$scenario->[0]};
239         }
240
241         $u_scene = 0;
242         $u_frame = 0;
243         $u_direction = 1;
244         prepare();
245         Gtk2->main;
246 }
247
248 package AA::UI::PDF;
249
250 our @ISA = ('AA::UI');
251
252 sub new($$) {
253         my ($class, $name) = @_;
254         my $ui = { };
255         $ui->{SURF} = Cairo::PdfSurface->create($name, 512, 384) or die "Unable to create PDF surface $name\n";
256         $ui->{CAIRO} = Cairo::Context->create($ui->{SURF});
257         $ui->{CAIRO}->scale(.5, .5);
258         return bless($ui, $class);
259 }
260
261 sub RunScenario($$$) {
262         my ($ui, $scenario) = @_;
263         my $page = 0;
264         foreach my $s (@$scenario) {
265                 $page++;
266                 print "### Page $page ###\n";
267                 AA::Anim->start;
268                 &$s();
269                 do {
270                         AA->calculate;
271                 } while (AA::Anim->step);
272                 AA->draw($ui->{CAIRO});
273                 $ui->{CAIRO}->show_page;
274         }
275 }
276
277 package AA::UI::PNG;
278
279 our @ISA = ('AA::UI');
280
281 sub new($$) {
282         my ($class, $name) = @_;
283         my $ui = { };
284         $ui->{NAME} = $name;
285         $ui->{SURF} = Cairo::ImageSurface->create('argb32', 1024, 768) or die "Unable to create image surface $name\n";
286         $ui->{CAIRO} = Cairo::Context->create($ui->{SURF});
287         return bless($ui, $class);
288 }
289
290 sub RunScenario($$$) {
291         my ($ui, $scenario) = @_;
292         my $cairo = $ui->{CAIRO};
293         my $page = 0;
294         foreach my $s (@$scenario) {
295                 $page++;
296                 print "### Page $page ###\n";
297                 AA::Anim->start;
298                 &$s();
299                 do {
300                         AA->calculate;
301                 } while (AA::Anim->step);
302                 AA->draw($cairo);
303                 $cairo->show_page;
304                 my $name = sprintf($ui->{NAME}, $page);
305                 $ui->{SURF}->write_to_png($name) or die "Unable to write to $name\n";
306         }
307 }
308
309 1;