#! perl # mandatory depends=login # sends the following ext message types # ws_n id # widgetset new # ws_d id # widgetset destroy # ws_c ws id class args # widgetset create # w_c id [rid] name args # widget method call # w_s id name value # widget member set # w_g id rid name # widget member get # # and expects the following exti message types # w_r rid res # widget call return # w_e id name args # widget_event cf::client->attach ( on_connect => sub { my ($ns) = @_; $ns->{id} = "a"; }, ); sub csc_update_stats { my ($ns) = @_; while (my ($k, $v) = each %{ $ns->{csc}{stat} }) { $v->set_text ($ns->pl->ob->stats->$k); } } sub csc_start { my ($ns) = @_; my $ws = $ns->{csc} = $ns->new_widgetset; my $w = $ws->new (Toplevel => min_w => 600, min_h => 400, x => "center", y => "center", title => "Character Creation", has_close_button => 1, on_delete => sub { $ws->destroy; }, ); $w->add (my $ntb = $ws->new (Notebook => expand => 1)); $ntb->add (Statistics => (my $stats = $ws->new (Table => expand => 1)), "Basic statistics of your new character"); $stats->add (0, 0, (my $statstable = $ws->new ("Table"))); for ( [0, "Str"], [1, "Dex"], [2, "Con"], [3, "Int"], [4, "Wis"], [5, "Pow"], [6, "Cha"], ) { my ($x, $label) = @$_; $statstable->add ($x, 0, $ws->new (Label => can_hover => 1, can_events => 1, align => +1, text => $label, tooltip => "#stat_$label", )); $statstable->add ($x, 1, $ws->{stat}{$label} = $ws->new (Label => can_hover => 1, can_events => 1, align => +1, template => "88", tooltip => "#stat_$label", )); } csc_update_stats $ns; $w->show; } cf::player->attach ( on_login => sub { my ($pl) = @_; return unless $cf::CFG{devel}; my $ns = $pl->ns; return unless $ns->{can_widget}; csc_start $ns; }, ); cf::register_exticmd w_e => sub { my ($ns, $pkt) = @_; if (my $w = $ns->{widget}{$pkt->{id}}) { if (my $cb = $w->{ev}{$pkt->{name}}) { $_->($w, @{ $pkt->{args} || [] }) for @$cb; } } () }; cf::register_exticmd w_r => sub { my ($ns, $pkt) = @_; if (my $cb = delete $ns->{widget_return}{$pkt->{rid}}) { $cb->(@{$pkt->{res} || [] }); } () }; sub cf::client::new_widgetset { my ($self) = @_; my $id = ++$self->{id}; my $ws = bless { id => $id, ns => $self, w => {}, }, "ext::widget::set"; $ws->msg (ws_n => id => $id); $ws } ############################################################################# package ext::widget::set; sub DESTROY { $_[0]->destroy; } sub destroy { my ($self) = @_; $self->msg (ws_d => id => $self->{id}); delete $self->{ns}; $_->destroy for values %{ $self->{w} }; } sub msg { my ($self, $type, %msg) = @_; if (my $ns = shift->{ns}) { $msg{msgtype} = $type; $ns->send_packet ("ext " . cf::to_json \%msg); } } sub new { my ($self, $class, %args) = @_; my $id = ++$self->{ns}{id}; my $proxy = $self->{w}{$id} = bless { id => $id, }, "ext::widget::proxy"; Scalar::Util::weaken ($proxy->{ws} = $self); Scalar::Util::weaken ($proxy->{ns} = $self->{ns}); Scalar::Util::weaken ($self->{ns}{widget}{$id} = $proxy); for my $ev (grep /^on_/, keys %args) { push @{$proxy->{ev}{$ev}}, $args{$ev}; $args{$ev} = 0; } $self->msg (ws_c => ws => $self->{w}{id}, id => $id, class => $class, args => \%args, ); $proxy } ############################################################################# package ext::widget::proxy; sub DESTROY { my ($self) = @_; delete $self->{ns}{widget}{$self->{id}}; if (my $ws = $self->{ws}) { delete $ws->{w}{$self->{id}}; $self->msg (w_c => name => "destroy"); } } sub msg { my ($self, $type, %msg) = @_; if (my $ws = $self->{ws}) { $ws->msg ($type, %msg, id => $self->{id}, ); } } sub msg_cb { my ($self, $cb, $type, %msg) = @_; if (my $ws = $self->{ws}) { my $rid = ++$ws->{ns}{id}; $self->msg ($type, %msg, rid => $rid); if ($cb) { $ws->{ns}{widget_return}{$rid} = $cb; } else { # synchronous case my $wait = new Coro::Signal; my @res; $ws->{ns}{widget_return}{$rid} = sub { @res = @_; $wait->send; }; $wait->wait; return @res; } } () } sub set { my ($self, $member, $value) = @_; $self->msg (w_s => name => $member, value => $value); } sub get { my ($self, $member, $cb) = @_; $self->msg_cb ($cb, w_g => name => $member); } sub TO_JSON { { __widget_ref__ => $_[0]{id} } } our $AUTOLOAD; sub AUTOLOAD { $AUTOLOAD =~ s/^.*:// or return; my $self = shift; $self->msg (w_c => name => $AUTOLOAD, args => \@_); () }