]> www.fi.muni.cz Git - slotcarman.git/blob - SCX/GUI.pm
da3f9f45eb6a9256625fe9dc37ae2191d0bce495
[slotcarman.git] / SCX / GUI.pm
1 #!/usr/bin/perl -w
2
3 package SCX::GUI;
4
5 use strict;
6 use utf8;
7
8 use Carp;
9 use Encode;
10 use Gtk2 '-init';
11 use Glib qw(TRUE FALSE);
12
13 our $BASE_SIZE;
14
15 sub new {
16         my ($class, $args) = @_;
17
18         my $self = {
19                 img_height => $args->{img_height} || 100,
20                 builder => Gtk2::Builder->new,
21                 semaphore_win => Gtk2::Window->new('popup'),
22                 semaphore_img => Gtk2::Image->new,
23         };
24
25         bless $self, $class;
26
27         $self->{builder}->add_from_file('slotcarman.glade');
28
29         $self->{builder}->connect_signals(undef);
30         $self->load_all_images;
31         $self->set_font_sizes;
32
33         my $pixbuf = $self->{semaphore_images}->[0];
34         $self->{semaphore_img}->set_from_pixbuf($pixbuf);
35         $self->{semaphore_img}->show;
36         $self->{semaphore_win}->add($self->{semaphore_img});
37         $self->{semaphore_win}->set_type_hint('splashscreen');
38         $self->{semaphore_win}->set_position('center-on-parent');
39         $self->{semaphore_win}->set_transient_for(
40                 $self->get_object('slotcarman')
41         );
42
43         $self->get_object('image_car1')->signal_connect(
44                 'size_allocate' => \&watch_resize,
45                 $self,
46         );
47         
48         return $self;
49 }
50
51 sub show {
52         my ($self) = @_;
53
54         my $window = $self->{builder}->get_object('slotcarman');
55         $window->signal_connect(delete_event => \&delete_event);
56         $window->show();
57 }
58
59 sub delete_event { Gtk2->main_quit; }
60
61 sub quit { Gtk2->main_quit; }
62
63 sub fullscreen {
64         my ($self) = @_;
65
66         $self->get_object('slotcarman')->fullscreen;
67         my $h = $self->get_object('image_car1')->allocation->height;
68         print "h=$h\n";
69 }
70         
71 sub watch_resize {
72         my ($window, $rectangle, $self) = @_;
73         print "w=", $rectangle->width, ", h=", $rectangle->height, "\n";
74         # TODO
75 }
76
77 sub get_object { return shift->{builder}->get_object(@_); }
78
79 sub set_font_sizes {
80         my ($self) = @_;
81
82         if ($self->{img_height} <= 80) {
83                 $self->{label_size} = 10;
84                 $self->{value_size} = 18;
85                 $self->{lap_size} = 24;
86         } elsif ($self->{img_height} <= 100) {
87                 $self->{label_size} = 12;
88                 $self->{value_size} = 20;
89                 $self->{lap_size} = 28;
90         } elsif ($self->{img_height} <= 120) {
91                 $self->{label_size} = 14;
92                 $self->{value_size} = 24;
93                 $self->{lap_size} = 32;
94         } elsif ($self->{img_height} <= 150) {
95                 $self->{label_size} = 16;
96                 $self->{value_size} = 28;
97                 $self->{lap_size} = 36;
98         } else {
99                 $self->{label_size} = 18;
100                 $self->{value_size} = 32;
101                 $self->{lap_size} = 40;
102         }
103 }
104
105 sub load_all_images {
106         my ($self) = @_;
107
108         my $h = $self->{img_height};
109
110         $self->{throttle_images} = [
111                 load_image_set('img/throttle%d.svg', 13, $h)
112         ];
113         $self->{fuel_images} = [
114                         load_image_set('img/fuel%d.svg', 8, int(0.6 * $h))
115         ];
116         $self->{car_images} = load_images_glob('img/SCXCars/*', $h);
117         $self->{state_images} = load_images_glob('img/state*.svg', $h);
118         $self->{semaphore_images} = [
119                         load_image_set('img/semaphore%d.svg', 5, 1.5 * $h)
120         ];
121 };
122
123 sub load_image_set {
124         my ($pattern, $limit, $height) = @_;
125
126         my @rv;
127         for my $i (0..$limit) {
128                 my $file = sprintf($pattern, $i);
129                 
130                 my $dummy = Gtk2::Gdk::Pixbuf->new_from_file($file);
131                 my $width = $dummy->get_width * $height / $dummy->get_height;
132                 push @rv, Gtk2::Gdk::Pixbuf->new_from_file_at_scale(
133                         $file, $width, $height, TRUE
134                 );
135         }
136         return @rv;
137 }
138
139 sub load_images_glob {
140         my ($glob, $height) = @_;
141
142         my %rv;
143         for my $file (glob($glob)) {
144                 $file = Encode::decode('utf-8', $file);
145                 my $name = $file;
146                 $name =~ s/.*\///;
147                 $name =~ s/\..*?$//;
148                 $name =~ s/[-_]/ /g;
149                 $name =~ s/\s+/ /g;
150
151
152                 my $dummy = Gtk2::Gdk::Pixbuf->new_from_file($file)
153                         or next;
154
155                 my $width = $dummy->get_width * $height / $dummy->get_height;
156                 $rv{$name} = Gtk2::Gdk::Pixbuf->new_from_file_at_scale(
157                         $file, $width, $height, TRUE
158                 );
159         }
160         return \%rv;
161 }
162
163 sub set_label {
164         my ($self, $prefix, $row, $text, $size) = @_;
165
166         ++$row if defined $row && $row =~ /\A\d+\z/xms;
167         $size //= 'value';
168
169         my $name = defined $row ? $prefix.$row : $prefix;
170         my $label = $self->get_object($name)
171                 or croak "Can't get label named $name";
172         $label->set_markup('<span font_desc="' . $self->{$size.'_size'} . '"'
173                 . ' weight="bold">' . $text . '</span>');
174 }
175
176 sub set_image {
177         my ($self, $prefix, $row, $imgset, $value) = @_;
178
179         return if !defined $value;
180
181         ++$row if defined $row && $row =~ /\A\d+\z/xms;
182
183         my $name = defined $row ? $prefix.$row : $prefix;
184
185         my $image = $self->get_object($name)
186                 or croak "Can't get image named $name";
187
188         my $set = $self->{$imgset.'_images'};
189         my $pixbuf = (ref($set) eq 'ARRAY')
190                 ? $set->[$value]
191                 : $set->{$value};
192                 
193         $image->set_from_pixbuf($pixbuf);
194 }
195
196 sub set_throttle {
197         my ($self, $row, $val) = @_;
198
199         $val = 13 if !defined $val;
200         $self->set_image('image_throttle', $row, 'throttle', $val);
201 }
202
203 sub set_fuel {
204         my ($self, $row, $val) = @_;
205
206         $self->set_image('image_fuel', $row, 'fuel', $val || 0);
207 }
208
209 sub set_car_icon {
210         my ($self, $row, $name) = @_;
211
212         $self->set_image('image_car', $row, 'car', $name);
213 }
214
215 sub set_lap {
216         my ($self, $row, $text) = @_;
217
218         $text = '--' if !defined $text;
219
220         $self->set_label('label_lap', $row, $text, 'lap');
221 }
222
223 sub set_distance {
224         my ($self, $row, $time, $lap_diff, $time_diff) = @_;
225
226         my $text = '--';
227
228         if (defined $time) {
229                 $text = format_race_time($time);
230         } elsif (defined $time_diff) {
231                 $text = '−' . format_lap_time($time_diff);
232         } elsif (defined $lap_diff) {
233                 $text = '−' . $lap_diff . ' laps';
234         }
235
236         $self->set_label('label_distance', $row, $text);
237 }
238
239 sub set_laptime {
240         my ($self, $row, $text) = @_;
241
242         $self->set_label('label_laptime', $row, format_lap_time($text));
243 }
244
245 sub set_avg_lap {
246         my ($self, $row, $text) = @_;
247
248         $self->set_label('label_avg_lap', $row, format_lap_time($text));
249 }
250
251 sub set_best_lap {
252         my ($self, $row, $text) = @_;
253
254         $self->set_label('label_best_lap', $row, format_lap_time($text));
255 }
256
257 sub set_name {
258         my ($self, $row, $text) = @_;
259
260         $self->set_label('label_name', $row, $text);
261 }
262
263 sub set_car_id {
264         my ($self, $row, $text) = @_;
265
266         $self->set_label('label_car_id', $row, $text);
267 }
268
269 sub show_semaphore {
270         my ($self, $num) = @_;
271
272         my $win = $self->{semaphore_win};
273         if (defined $num) {
274                 my $img = $self->{semaphore_img};
275                 my $pixbuf = $self->{semaphore_images}->[$num];
276                 $img->set_from_pixbuf($pixbuf);
277                 $win->show;
278         } else {
279                 $win->hide;
280         }
281 }
282
283 sub rounds {
284         my ($self, $text) = @_;
285
286         $self->set_label('label_lap_global', undef, $text);
287 }
288
289 sub time {
290         my ($self, $text) = @_;
291
292         $self->set_label('label_time_global', undef, format_race_time($text));
293 }
294
295 sub best_lap {
296         my ($self, $time, $who) = @_;
297
298         my $text = format_lap_time($time);
299         $text .= ' by ' . $who
300                 if defined $who;
301         $self->set_label('label_best_lap_global', undef, $text);
302 }
303
304 sub format_race_time {
305         my ($seconds) = @_;
306
307         return '--' if !defined $seconds;
308
309         my $hours = int($seconds / 3600);
310         $seconds -= 3600 * $hours;
311
312         my $mins = int($seconds / 60);
313         $seconds -= 60 * $mins;
314
315         return $hours
316                 ? sprintf('%d:%02d:%04.1f', $hours, $mins, $seconds)
317                 : sprintf('%d:%04.1f', $mins, $seconds);
318 }
319
320 sub format_lap_time {
321         my ($seconds) = @_;
322
323         return defined $seconds
324                 ? sprintf('%.2f', $seconds)
325                 : '--';
326 }
327
328 sub set_state {
329         my ($self, $num, $name) = @_;
330
331         $self->set_image('image_status', $num, 'state', 'state '.$name);
332 }
333
334 1;
335