--- deliantra/server/ext/widget.ext 2007/08/19 09:27:08 1.18 +++ deliantra/server/ext/widget.ext 2007/12/28 12:44:45 1.22 @@ -5,13 +5,13 @@ # ws_n ws # widgetset new # ws_d ws # widgetset destroy # ws_c ws id class @args # widgetset create +# ws_ct ws ttype ttext done_cb \%cfg # widgetset create from template # w_c id rid name @args # widget method call # w_s id @attr # widget member set # w_g id rid @attr # widget member get # # and expects the following exti message types -# w_r rid res # widget call return -# w_e id rid @args # widget_event +# w_e id @args # widget_call our $DEBUG = 1; @@ -22,9 +22,8 @@ Scalar::Util::weaken (my $weakns = $ns); $ns->{id} = "a"; - $ns->{json_coder}->filter_json_single_key_object (__w_ => sub { - # cannot deserialise ATM - undef + $ns->{json_coder}->filter_json_single_key_object ("\fw" => sub { + $weakns->{widget}{$_[0]} }); }, ); @@ -37,16 +36,67 @@ } } -sub demo_start { - my ($ns) = @_; - - my $ws = $ns->{csc} = $ns->new_widgetset; - - $ws->{tab} = $ws->new (Label => text => "dumb tst", c_tab => ["hull"]); - - $ws->find ("setup_notebook")->add ($ws->{tab}); - $ws->find ("setup_dialog")->toggle_visibility; -} +my $cg_template = eval < { + s_id => "toplevel", + title => "Character Creation", + x => "center", + y => "center", + z => 5, + force_w => 760, + force_h => 440, + s_cl => [VBox => { s_cl => [ + Label => { + text => "Character Creation", + fontsize => 1, + align => 0, + }, + Label => { + markup => "View or Edit your character attributes below, then press Finish to create your character", + fontsize => 0.8, + align => 0, + }, + HBox => { s_cl => [ + Face => { + s_id => "face", + face => 0, + bg => [.2, .2, .2, 1], + min_w => 64, + min_h => 64, + }, + Label => { + s_id => "desc", + fontsize => 0.8, + ellipsize => 0, + }, + ]}, + Notebook => { + expand => 1, + s_cl => [ + Table => { + c_tab => ["Basics", "Title, background and other information of your character."], + }, + Table => { + c_tab => ["Stats", "Your character's primary stats such as strength, dexterity and so on."], + }, + Table => { + c_tab => ["Race", "Your character's race."], + }, + Table => { + c_tab => ["Class", "Your character's initial class."], + }, + ], + }, + Button => { + s_id => "finish", + text => "Finish", + }, + ]}], + }, +] +EOF +die if $@; sub csc_start { my ($ns) = @_; @@ -96,39 +146,45 @@ $ws->{tl} = $w; $w->show; + +# my ($tl, $entry) = $ws->template (inline => $cg_template, +# [ +# toplevel => {}, +# entry => { +# text => "xyz", +# on_changed => sub { +# warn "changed<@_>\n";#d# +# }, +# }, +# ], +# ); +# +# $tl->show; +# +# $ns->{xxxw} = [$tl, $entry];#d# +# +# $ws->find ("setup_notebook")->add ($ws->{tab}); +# $ws->find ("setup_dialog")->toggle_visibility; } cf::player->attach ( on_login => sub { my ($pl) = @_; - return unless $cf::CFG{devel}; - my $ns = $pl->ns; - return unless $ns->{can_widget}; + + return unless $cf::CFG{devel}; + #csc_start $ns; - #demo_start $ns; }, ); cf::register_exticmd w_e => sub { - my ($ns, $id, $rid, @args) = @_; - - if (my $w = $ns->{widget}{$id}) { - if (my $cb = $w->{ev}{$rid}) { - $cb->($w, @args); - } - } - - () -}; - -cf::register_exticmd w_r => sub { - my ($ns, $rid, $res) = @_; + my ($ns, $id, @args) = @_; - if (my $cb = delete $ns->{widget_return}{$rid}) { - $cb->(@$res); + if (my $cb = $ns->{widget_cb}{$id}) { + $cb->(@args); } () @@ -150,6 +206,15 @@ $ws } +sub cf::client::alloc_wid { + pop @{ $_[0]{ids} } + or ++$_[0]{id} +} + +sub cf::client::free_wid { + push @{ $_[0]{ids} }, $_[1]; +} + ############################################################################# package ext::widget::set; @@ -179,7 +244,7 @@ sub alloc { my ($self) = @_; - my $id = ++$self->{ns}{id}; + my $id = $self->{ns}->alloc_wid; my $proxy = bless { id => $id, @@ -200,9 +265,7 @@ Scalar::Util::weaken ($proxy->{ws} = $self); for my $ev (grep /^on_/, keys %args) { - my $rid = ++$self->{ns}{id}; - $proxy->{ev}{$rid} = $args{$ev}; - $args{$ev} = $rid; + $args{$ev} = $proxy->{"_$ev"} = $proxy->cb ($args{$ev}); } $self->msg (ws_c => @@ -215,6 +278,54 @@ $proxy } +sub template { + my ($self, $type, $template, $args, $done_cb) = @_; + + my %cfg; + + while (@$args) { + my ($name, $args) = splice @$args, 0, 2, (); + + my $proxy = $self->alloc; + + $self->{delete $args->{alias} or $name} = $proxy; + + Scalar::Util::weaken ($self->{_w}{$proxy->{id}} = $proxy); + Scalar::Util::weaken ($proxy->{ws} = $self); + + for my $ev (grep /^on_/, keys %$args) { + $args->{$ev} = $proxy->{"_$ev"} = $proxy->cb ($args->{$ev}); + } + + $cfg{$name} = { + %$args, + id => $proxy->{id}, + }; + } + + if ($done_cb) { + my $proxy = $self->alloc; + my $ocb = $done_cb; + $done_cb = $proxy->cb (sub { + undef $proxy; + undef $done_cb; + &$ocb + }); + } + + if ($type eq "face") { + $self->{ns}->send_face ($template, 100); + $self->{ns}->flush_fx; + } + + $self->msg (ws_ct => + $self->{id}, + $type => $template, + $done_cb, + \%cfg, + ); +} + sub find { my ($self, @names) = @_; @@ -252,6 +363,35 @@ } } +sub cb { + my ($self, $cb) = @_; + + my $proxy = bless { + ns => $self->{ns}, + id => $self->{ns}->alloc_wid, + }, "ext::widget::callback"; + + Scalar::Util::weaken $proxy->{ns}; + + $self->{ns}{widget_cb}{$proxy->{id}} = $cb; + + $proxy +} + +sub oneshot_cb { + my ($self, $cb) = @_; + + if ("CODE" eq ref $cb) { + my $ocb = $cb; + $cb = $self->cb (sub { + undef $cb; + &$ocb + }); + } + + $cb +} + sub msg { my ($self, $type, @arg) = @_; @@ -266,21 +406,29 @@ my ($self, $cb, $type, @arg) = @_; if (my $ws = $self->{ws}) { - my $rid = ++$ws->{ns}{id}; - - $self->msg ($type, $rid, @arg); + my $rid = $ws->{ns}->alloc_wid; if ($cb) { - $ws->{ns}{widget_return}{$rid} = $cb; + $ws->{ns}{widget_cb}{$rid} = sub { + delete $ws->{ns}{widget_cb}{$rid}; + $ws->{ns}->free_wid ($rid); + &$cb + }; + + $self->msg ($type, $rid, @arg); } else { # synchronous case my $wait = new Coro::Signal; my @res; - $ws->{ns}{widget_return}{$rid} = sub { + $ws->{ns}{widget_cb}{$rid} = sub { + delete $ws->{ns}{widget_cb}{$rid}; + $ws->{ns}->free_wid ($rid); + @res = @_; $wait->send; }; + $self->msg ($type, $rid, @arg); $wait->wait; return @res; @@ -299,11 +447,11 @@ sub get { my ($self, $member, $cb) = @_; - $self->msg_cb ($cb, w_g => [$member]); + $self->msg_cb ($cb, w_g => ref $member ? @$member : $member); } sub TO_JSON { - { __w_ => $_[0]{id} } + { "\fw" => $_[0]{id} } } our $AUTOLOAD; @@ -320,3 +468,18 @@ () } +package ext::widget::callback; + +sub DESTROY { + my ($self) = @_; + + if (my $ns = $self->{ns}) { + delete $ns->{widget_cb}{$self->{id}}; + $ns->free_wid ($self->{id}); + } +} + +sub TO_JSON { + { "\fc" => $_[0]{id} } +} +