-
-
Save zhuomingliang/2549879 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
use v6; | |
role Signal { | |
has @.slots; # a nice list of callbacks (that are methods) | |
multi method connect(Any:D $sender, Any:D $rcpt, Method $method){ | |
@.slots.push([$sender, self, $rcpt, $method]); | |
} | |
multi method connect(Any:D $rcpt, Method $method){ | |
@.slots.push([Mu, self, $rcpt, $method]); | |
} | |
multi method connect(Any:D $sender, Method $signal, Routine $slot){ | |
@.slots.push([$sender, $signal, Mu, $slot]); | |
} | |
multi method connect(Routine $r){ | |
@.slots.push([Mu, self, Mu, $r]); | |
} | |
method disconnect(Mu $sender, Mu $rcpt, Routine $method){ | |
my $offset = 0; | |
for @.slots -> $slot { | |
@.slots.splice($offset, 1) if $slot == [$sender, self, $rcpt, $method]; | |
$offset++; | |
} | |
} | |
} | |
multi trait_mod:<is>(Routine $_signal, :$signal!){ | |
$_signal does Signal; | |
$_signal.slots; # WORKAROUND RT112666 | |
$_signal.wrap(sub (*@args) { | |
for $_signal.slots -> [$sender, $signal, $receiver, $slot] { | |
@args.shift; | |
if $slot ~~ Method { | |
@args.unshift($receiver); | |
} | |
$slot(|@args); | |
} | |
}); | |
} | |
#multi trait_mod:<is>(Method $_signal: $signal!){ | |
# $_signal does Signal; | |
# | |
# $_signal.slots; # WORKAROUNG RT112666 | |
# | |
# $_signal.warp(sub (*@args) { | |
# for $_signal.slots -> [$sender, $signal, $receiver, $slot] { | |
# $receiver.$slot(|@args); | |
# } | |
# }); | |
#} | |
multi sub connect(Any:D $sender, Method $signal, Any:D $rcpt, Method $slot){ | |
$signal.connect($sender, $rcpt, $slot); | |
} | |
multi sub connect(Signal $signal, Any:D $rcpt, Method $slot){ | |
$signal.connect($rcpt, $slot); | |
} | |
multi sub connect(Any:D $sender, Method $signal, Routine $slot){ | |
$signal.connect($sender, $signal, $slot); | |
} | |
multi sub connect(Routine $signal, Routine $slot){ | |
$signal.connect($slot); | |
} | |
multi disconnect(Any:D $sender, Method $signal, Any:D $receiver, Method $slot){ | |
$signal.disconnect($sender, $receiver, $slot); | |
} | |
multi disconnect(Signal $signal, Any:D $receiver, Method $slot){ | |
$signal.disconnect(Mu, $receiver, $slot); | |
} | |
multi disconnect(Any:D $sender, Method $signal, Routine $slot){ | |
$signal.disconnect($sender, Mu, $slot); | |
} | |
multi disconnect(Routine $signal, Routine $slot){ | |
$signal.disconnect(Mu, Mu, $slot); | |
} | |
class Btn { | |
our method sig_pressed is signal { warn "signal fired without slots" } | |
our method sig_released is signal { warn "signal fired without slots" } | |
} | |
class App { | |
our method exit { say "App::exit called" } | |
} | |
my Btn $btn_exit .= new; | |
my App $app .= new; | |
connect($btn_exit, &Btn::sig_pressed, $app, &App::exit); | |
$btn_exit.sig_pressed; # one slot connected | |
sub bare_signal_exit is signal {} | |
connect(&bare_signal_exit, $app, &App::exit); | |
bare_signal_exit; | |
sub bare_slot_exit { say "bare_slot_exit called" }; | |
connect(&bare_signal_exit, &bare_slot_exit); | |
connect($btn_exit, &Btn::sig_released, &bare_slot_exit); | |
bare_signal_exit; | |
$btn_exit.sig_released; | |
say "disconnecting"; | |
disconnect($btn_exit, &Btn::sig_pressed, $app, &App::exit); | |
disconnect(&bare_signal_exit, $app, &App::exit); | |
disconnect(&bare_signal_exit, &bare_slot_exit); | |
disconnect($btn_exit, &Btn::sig_released, &bare_slot_exit); | |
$btn_exit.sig_pressed; | |
$btn_exit.sig_released; | |
bare_signal_exit; | |
# simple example | |
class Input { | |
has Str $.text is rw; | |
our method sig_changed(Str $s) is signal {}; | |
our method sig_keyup is signal {}; | |
method fake_event_handler() { | |
$.text = (1..10).pick(5).join; | |
$.sig_changed($.text); | |
} | |
} | |
class Button { | |
has Str $.text is rw; | |
our method sig_pressed is signal {}; | |
our method sig_lowered is signal {}; | |
our method sig_raised is signal {}; | |
method fake_event_handler() { self.sig_pressed } | |
} | |
class Person { | |
has Str $.name is rw; | |
has Int $.age is rw; | |
has Int $.sexiness is rw; | |
our method set_name($name){ $.name = $name } | |
our method set_age($age){ $.age = $age.Int } | |
our method set_sexiness($sexiness) { $.sexiness = $sexiness.Int } | |
our method foo(){}; | |
} | |
class PersonDialog { | |
has Person $.person; | |
has Input $.name; | |
has Input $.age; | |
has Input $.sexiness; | |
has Button $.ok; | |
method new(){ | |
my Person $person .= new, | |
my Input $name .= new, | |
my Input $age .= new, | |
my Input $sexiness .= new, | |
my Button $ok .= new(:text('OK')); | |
my $self = self.bless(*, person => $person, name => $name, age => $age, sexiness => $sexiness, ok => $ok); | |
connect($name, &Input::sig_changed, $person, &Person::set_name); | |
connect($age, &Input::sig_changed, $person, &Person::set_age); | |
connect($sexiness, &Input::sig_changed, $person, &Person::set_sexiness); | |
connect($ok, &Button::sig_pressed, $self, &PersonDialog::finished); | |
return $self; | |
} | |
our method finished() { | |
die "ohh no!" unless $.person.name && $.person.age && $.person.sexiness; | |
say "Person name: {$.person.name}, age: {$.person.age}, sexiness: {$.person.sexiness}"; | |
} | |
} | |
my PersonDialog $pd .= new; | |
.fake_event_handler for $pd.name, $pd.age, $pd.sexiness, $pd.ok; | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment