]> mj.ucw.cz Git - anim.git/blob - AA/UI.pm
5abf093c0476aa706896ddd16860c55d18f5d7b5
[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 my @u_last_frame = ();
39
40 my $window;
41 my $cairo;
42 my $area;
43 my $pixmap;
44 my $timer;
45 my $stopped = 0;
46 my $fullscreen = 0;
47 my $movie = 0;
48 my ($lastw, $lasth, $lastd) = (-1, -1, -1);
49 my ($pixw, $pixh) = (-1, -1);
50 my ($last_scene, $last_frame) = (-1, -1);
51
52 sub draw($) {
53         my ($force) = @_;
54         my $win = $area->window;
55         my $wgc = Gtk2::Gdk::GC->new($win);
56         my $alloc = $area->allocation;
57         my $w = $alloc->width;
58         my $h = $alloc->height;
59         my $d = $win->get_depth;
60         # print "Area $w x $h x $d, xx=$xx\n";
61
62         if (!defined($pixmap) || $lastw != $w || $lasth != $h || $lastd != $d) {
63                 ($lastw, $lasth, $lastd) = ($w, $h, $d);
64                 if ($w/$h >= 4/3) {
65                         $pixh = $h;
66                         $pixw = int($h/3*4);
67                 } else {
68                         $pixw = $w;
69                         $pixh = int($w/4*3);
70                 }
71                 print "Resized to ${w}x${h}, pixmap size ${pixw}x${pixh}\n" if $debug;
72
73                 $pixmap = Gtk2::Gdk::Pixmap->new($win, $pixw, $pixh, $d);
74                 $cairo = Gtk2::Gdk::Cairo::Context->create($pixmap);
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_last_frame[$u_scene]) {
111                                 $u_frame++;
112                         } elsif ($u_scene < @u_scenes - 1) {
113                                 $u_scene++;
114                                 $u_frame = 0;
115                         }
116                         if ($u_frame == $u_last_frame[$u_scene]) {
117                                 $u_direction = 0 unless $movie;
118                         }
119                 } elsif ($u_direction < 0) {
120                         if ($u_frame) {
121                                 $u_frame--;
122                         } elsif ($u_scene) {
123                                 $u_scene--;
124                                 $u_frame = $u_last_frame[$u_scene];
125                                 $u_direction = 0 unless $movie;
126                         }
127                 }
128                 return if ($u_scene == $last_scene && $u_frame == $last_frame);
129         } else {
130                 AA::Anim->step;
131         }
132         draw(0);
133 }
134
135 sub prepare() {
136         $window = Gtk2::Window->new ('toplevel');
137         $area = Gtk2::DrawingArea->new();
138         $area->signal_connect("expose-event" => sub {
139                 draw(1);
140                 if (!defined $timer) {
141                         $timer = Glib::Timeout->add(30, sub { $stopped || step(); return 1; });
142                 }
143         });
144         $area->set_flags('can-focus');
145         # $area->add_events('key-press-mask');
146         $area->signal_connect('key-press-event' => sub {
147                 my ($w, $evt) = @_;
148                 my $k = Gtk2::Gdk::keyval_name(0, $evt->keyval);
149                 print "Pressed key $k\n" if $debug;
150                 if ($k eq "Escape") {
151                         Gtk2->main_quit;
152                 } elsif ($k eq "f") {
153                         if ($fullscreen = !$fullscreen) {
154                                 $window->fullscreen;
155                         } else {
156                                 $window->unfullscreen;
157                         }
158                 } elsif ($k eq "space" || $k eq "Right" || $k eq "Page_Down") {
159                         if (@u_scenes) {
160                                 if ($stopped || $k eq "Page_Down") {
161                                         if ($u_scene+1 < @u_scenes) {
162                                                 $u_scene++;
163                                                 $u_frame = $u_last_frame[$u_scene];
164                                         }
165                                         $u_direction = 0;
166                                 } elsif ($u_direction > 0) {
167                                         $u_frame = $u_last_frame[$u_scene];
168                                         $u_direction = 0;
169                                 } else {
170                                         $u_direction = 1;
171                                 }
172                                 draw(0);
173                         } else {
174                                 while (AA::Anim->step) { AA->calculate; }
175                                 if ($u_scene+1 < @$u_scenario) {
176                                         $u_scene++;
177                                         AA::Anim->start;
178                                         &{$u_scenario->[$u_scene]};
179                                         draw(0);
180                                 }
181                         }
182                 } elsif ($k eq "BackSpace" || $k eq "Left" || $k eq "Page_Up") {
183                         if (@u_scenes) {
184                                 if ($stopped || $k eq "Page_Up") {
185                                         if ($u_scene > 0) {
186                                                 $u_scene--;
187                                                 $u_frame = $u_last_frame[$u_scene];
188                                         }
189                                         $u_direction = 0;
190                                 } elsif ($u_direction < 0) {
191                                         $u_frame = 0;
192                                 } else {
193                                         $u_direction = -1;
194                                 }
195                                 draw(0);
196                         }
197                 } elsif ($k eq "Home" || $k eq "0") {
198                         if (@u_scenes) {
199                                 $u_scene = 0;
200                                 $u_frame = 0;
201                                 $u_direction = 0;
202                                 draw(0);
203                         }
204                 } elsif ($k eq "End" || $k eq "9") {
205                         if (@u_scenes) {
206                                 $u_scene = $#u_scenes;
207                                 $u_frame = $u_last_frame[$u_scene];
208                                 $u_direction = 0;
209                                 draw(0);
210                         }
211                 } elsif ($k eq "p") {
212                         $stopped = !$stopped;
213                         $u_direction = 0 if $stopped;
214                         print "Stopped is $stopped\n" if $debug;
215                 } elsif ($k eq "m") {
216                         $movie = !$movie;
217                         print "Movie mode is $movie\n" if $debug;
218                 } elsif ($k eq "Return") {
219                         if (@u_scenes) {
220                                 $u_frame = ($u_direction > 0) ? $u_last_frame[$u_scene] : 0;
221                         } else {
222                                 while (AA::Anim->step) { AA->calculate; }
223                         }
224                 }
225         });
226
227         $window->signal_connect ("delete-event" => sub { Gtk2->main_quit });
228         $window->set_title("Brum");
229         $window->set_wmclass("brum", "Brum");
230         $window->set_default_size(640, 480);
231         $window->add ($area);
232         $window->show_all;
233 }
234
235 sub RunScenario($$) {
236         my ($ui, $scenario) = @_;
237
238         if ($ui->{MODE}) {
239                 print "Rendering...\n";
240                 foreach my $s (@$scenario) {
241                         print ">>> Scene ", scalar @u_scenes, "\n" if $debug;
242                         AA::Anim->start;
243                         &$s;
244                         my $show = [];
245                         while (AA::Anim->step) {
246                                 print "\t>>> Frame ", scalar @$show, "\n" if $debug;
247                                 AA->calculate;
248                                 push @$show, AA::Scene->new();
249                         }
250                         push @u_scenes, $show;
251                         push @u_last_frame, scalar @$show - 1;
252                 }
253                 print "Ready.\n";
254         } else {
255                 $u_scenario = $scenario;
256                 AA::Anim->start;
257                 &{$scenario->[0]};
258         }
259
260         $u_scene = 0;
261         $u_frame = 0;
262         $u_direction = 0;
263         prepare();
264         Gtk2->main;
265 }
266
267 package AA::UI::PDF;
268
269 our @ISA = ('AA::UI');
270
271 sub new($$) {
272         my ($class, $name) = @_;
273         my $ui = { };
274         $ui->{SURF} = Cairo::PdfSurface->create($name, 512, 384) or die "Unable to create PDF surface $name\n";
275         $ui->{CAIRO} = Cairo::Context->create($ui->{SURF});
276         $ui->{CAIRO}->scale(.5, .5);
277         return bless($ui, $class);
278 }
279
280 sub RunScenario($$$) {
281         my ($ui, $scenario) = @_;
282         my $page = 0;
283         print "Rendering to PDF\n";
284         foreach my $s (@$scenario) {
285                 $page++;
286                 print "### Page $page ###\n";
287                 AA::Anim->start;
288                 &$s();
289                 do {
290                         AA->calculate;
291                 } while (AA::Anim->step);
292                 AA->draw($ui->{CAIRO});
293                 $ui->{CAIRO}->show_page;
294         }
295 }
296
297 package AA::UI::PNG;
298
299 our @ISA = ('AA::UI');
300
301 sub new($$) {
302         my ($class, $name) = @_;
303         my $ui = { };
304         $ui->{NAME} = $name;
305         $ui->{SURF} = Cairo::ImageSurface->create('argb32', 1024, 768) or die "Unable to create image surface $name\n";
306         $ui->{CAIRO} = Cairo::Context->create($ui->{SURF});
307         return bless($ui, $class);
308 }
309
310 sub RunScenario($$$) {
311         my ($ui, $scenario) = @_;
312         my $cairo = $ui->{CAIRO};
313         my $page = 0;
314         print "Rendering to PNG images\n";
315         foreach my $s (@$scenario) {
316                 $page++;
317                 print "### Page $page ###\n";
318                 AA::Anim->start;
319                 &$s();
320                 do {
321                         AA->calculate;
322                 } while (AA::Anim->step);
323                 AA->draw($cairo);
324                 $cairo->show_page;
325                 my $name = sprintf($ui->{NAME}, $page);
326                 $ui->{SURF}->write_to_png($name) or die "Unable to write to $name\n";
327         }
328 }
329
330 1;