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