From: Andrew Ruthven Date: Mon, 27 Oct 2008 09:13:16 +0000 (+1300) Subject: The Notifications object now handles displaying multiple notifications. X-Git-Url: http://git.etc.gen.nz/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=9a637ebe239fec3ad8a33cf7c1b9e1fda2b2382c;p=picture-display.git The Notifications object now handles displaying multiple notifications. When a new notification is submitted the existing ones are moved up the screen, then the new one is faded in. The blocks get expired after a pre-set amount of time. Also allows the submitted notification to just be a text string and we'll take care of creating the Clutter::Label. --- diff --git a/lib/Display/Notifications.pm b/lib/Display/Notifications.pm index b4bb858..082c17e 100644 --- a/lib/Display/Notifications.pm +++ b/lib/Display/Notifications.pm @@ -5,7 +5,7 @@ use POE::Session; use Set::Object; use strict; -my $delay = 5; +my $delay = 15; sub new { my ($proto, $kernel, $session, $stage) = @_; @@ -15,17 +15,33 @@ sub new { 'kernel' => $kernel, 'session' => $session, 'stage' => $stage, + 'moving' => 0, }; $self->{'blocks'} = Set::Object->new(); + @{ $self->{'new'} } = (); + @{ $self->{'paths'} } = (); + @{ $self->{'pending_move'} } = (); bless ($self, $class); - $self->init(); + + $self->{'kernel'}->state('notifications_add', $self, 'add'); + $self->{'kernel'}->state('notifications_expire', $self, 'expire'); + return $self; } sub add { - my ($self, $kernel, $notification, $logo) = @_[OBJECT, KERNEL, ARG0, ARG1]; + my ($self, $kernel, $notification, $logo_file) = @_[OBJECT, KERNEL, ARG0, ARG1]; + + my $text = undef; + if ($notification->isa("Clutter::Label")) { + $text = $notification; + } else { + $text = Clutter::Label->new('Sans 20', $notification); + $text->set_color(Clutter::Color->parse('White')); + $text->set_ellipsize('end'); + } my $block = Clutter::Group->new(); $block->set_opacity(0); @@ -34,43 +50,45 @@ sub add { $bg->set_width($self->{'stage'}->get_width() - 20); $bg->set_opacity(100); - $block->add($bg); - $block->add($notification); + $bg->set_height($text->get_height() + 10); - $bg->set_height($notification->get_height() + 10); - $bg->set_anchor_point(1, $bg->get_height()); - $bg->set_position(10, $self->{'stage'}->get_height() - 10); + $text->set_position(5, 5); - $notification->set_anchor_point(1, $notification->get_height()); + $block->set_height($bg->get_height()); + $block->set_anchor_point(1, $block->get_height()); + $block->set_position(10, $self->{'stage'}->get_height() - 10); - if (defined $logo) { + $block->add($bg); + $block->add($text); + + if (defined $logo_file) { + my $logo = Clutter::Texture->new($logo_file); $block->add($logo); $logo->set('keep-aspect-ratio' => 1); $logo->set('sync-size' => 1); - $logo->set_height($notification->get_height()); + $logo->set_height($text->get_height()); + $logo->set_position(5, 5); - $logo->set_position(20, $self->{'stage'}->get_height() - $bg->get_height - 20); - $notification->set_width($bg->get_width() - $logo->get_width() - 20 - 20); - $notification->set_position(20 + $logo->get_width() + 20, $self->{'stage'}->get_height() - 20); + $text->set_width($bg->get_width() - $logo->get_width() - 20 - 20); + $text->set_x(20 + $logo->get_width() + 20); } else { - $notification->set_position(20, $self->{'stage'}->get_height() - 20); - $notification->set_width($bg->get_width() - 20); + $text->set_width($bg->get_width() - 20); + $text->set_x(20); } - my $expire = time() + $delay; - - $self->{'blocks'}->insert( { - 'expire' => $expire, - 'block' => $block - }); + if ($self->{'blocks'}->size() > 0) { + if (! $self->{'moving'}) { + push @{ $self->{'new'} }, $block; - $self->{'stage'}->add($block); - my $effect = Clutter::EffectTemplate->new_for_duration(1000, 'main::smoothstep_inc'); - my $timeline = Clutter::Effect->fade($effect, $block, 255); - - $kernel->delay_add('notifications_expire', $delay); + $self->move_blocks(); + } else { + push @{ $self->{'pending_move'} }, $block; + } + } else { + push @{ $self->{'new'} }, $block; - $timeline->start(); + fade_in(undef, $self); + } } sub expire { @@ -78,11 +96,30 @@ sub expire { for my $block ($self->{'blocks'}->members()) { if ($block->{'expire'} <= time()) { - my $old_effect = Clutter::EffectTemplate->new_for_duration(1000, 'main::smoothstep_inc' ); - my $old = Clutter::Effect->fade($old_effect, $block->{'block'}, 0, $self->can('post_fade_out'), $self); + my $old_effect = + Clutter::EffectTemplate->new_for_duration(1000, + 'main::smoothstep_inc' ); + my $old = + Clutter::Effect->fade($old_effect, $block->{'block'}, 0, + $self->can('post_fade_out'), $self); $old->start(); } } + + # What a hack! It seems that multiple alarm_ardds aren't being + # honoured. So, we check and see when the next expire should run, and + # call ourselves again then. + while (scalar(@{ $self->{'expire_times'} }) > 0 + && $self->{'expire_times'}[0] <= time()) { + my $old = shift @{ $self->{'expire_times'} }; + } + + if (defined $self->{'expire_times'}[0]) { + my $timer = shift @{ $self->{'expire_times'} }; + $self->{'kernel'}->alarm_add('notifications_expire', $timer); + } + + return 1; } sub post_fade_out { @@ -90,7 +127,6 @@ sub post_fade_out { for my $block ($self->{'blocks'}->members()) { if ($block->{'expire'} <= time()) { - $self->{'stage'}->remove($block->{'block'}); $self->{'blocks'}->remove($block); $block->{'block'}->remove_all() @@ -98,11 +134,76 @@ sub post_fade_out { } } -sub init { - my $self = shift; +sub fade_in { + my ($score, $self) = @_; - $self->{'kernel'}->state('notifications_add', $self, 'add'); - $self->{'kernel'}->state('notifications_expire', $self, 'expire'); + # Clean out no longer required state. + $self->{'paths'} = (); + + while (my $block = shift @{ $self->{'new'} }) { + if (defined $block) { + $self->{'stage'}->add($block); + my $effect = Clutter::EffectTemplate->new_for_duration(1000, 'main::smoothstep_inc'); + my $timeline = Clutter::Effect->fade($effect, $block, 255); + + my $expire = time() + $delay; + + $self->{'blocks'}->insert( { + 'expire' => $expire, + 'block' => $block + }); + + $self->{'kernel'}->delay_add('notifications_expire', $delay); + push @{ $self->{'expire_times'} }, $expire; + + $timeline->start(); + $self->{'moving'} = 0; + } + } + + # Check and see if there are any blocks that have been added since we + # started moving, and start the process of showing them. + if (scalar(@{ $self->{'pending_move'} }) > 0) { + while (my $block = shift @{ $self->{'pending_move'} }) { + push @{ $self->{'new'} }, $block; + } + + $self->move_blocks(); + } +} + +sub move_blocks { + my ($self) = @_; + + # We're in the process of moving blocks. + $self->{'moving'} = 1; + + my $score = Clutter::Score->new(); + $score->signal_connect('completed' => $self->can('fade_in'), $self); + + # Work out the total height + my $height = 10; + for my $new (@{ $self->{'new'} }) { + $height += $new->get_height(); + } + + for my $obj ($self->{'blocks'}->members()) { + my $block = $obj->{'block'}; + my $timeline = Clutter::Timeline->new_for_duration(1000); + my $alpha = Clutter::Alpha->new($timeline, 'main::smoothstep_inc'); + + my $path = Clutter::Behaviour::Path->new($alpha, + [ $block->get_position() ], + [ $block->get_x(), $block->get_y() - $height ]); + $path->apply($block); + + push @{ $self->{'paths'} }, $path; + + $score->append(undef, $timeline); + } + + $score->start(); + $self->{'score'} = $score; } 1; diff --git a/lib/Display/Plugins/MPD.pm b/lib/Display/Plugins/MPD.pm index 7acb4ee..13d92df 100644 --- a/lib/Display/Plugins/MPD.pm +++ b/lib/Display/Plugins/MPD.pm @@ -45,11 +45,9 @@ sub display { push @lines, $current->album() if defined $current->album(); push @lines, $current->artist() if defined $current->artist(); - $self->{'status'}->set_text(join("\n", @lines)); - $self->{'file'} = $current->file(); - $kernel->yield('notifications_add', $self->{'status'}, $self->{'logo'}); + $kernel->post('display', 'notifications_add', join("\n", @lines), $self->{'logo'}); } $self->delay(); @@ -60,10 +58,6 @@ sub init { $self->{'kernel'}->state('mpd_display', $self, 'display'); - $self->{'status'} = Clutter::Label->new('Sans 20', "Song\nAlbum"); - $self->{'status'}->set_color(Clutter::Color->parse('White')); - $self->{'status'}->set_ellipsize('end'); - $self->{'logo'} = "$Bin/share/MPD.png"; $self->{'kernel'}->yield('mpd_display'); diff --git a/lib/Display/Plugins/NotifyTest.pm b/lib/Display/Plugins/NotifyTest.pm index 95660ad..213214d 100644 --- a/lib/Display/Plugins/NotifyTest.pm +++ b/lib/Display/Plugins/NotifyTest.pm @@ -28,10 +28,10 @@ sub display { my ($self, $kernel) = @_[OBJECT, KERNEL]; my $text = Clutter::Label->new('Sans 20', "Notify " . ++$self->{'count'}); - $text->set_color(Clutter::Color->parse('White')); + $text->set_color(Clutter::Color->parse('Blue')); $text->set_ellipsize('end'); - $kernel->yield('notifications_add', $text); + $kernel->post('display', 'notifications_add', $text); $self->delay(); }