ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/deliantra/server/ext/widget.ext
Revision: 1.20
Committed: Thu Dec 27 18:35:48 2007 UTC (16 years, 5 months ago) by root
Branch: MAIN
Changes since 1.19: +52 -4 lines
Log Message:
*** empty log message ***

File Contents

# User Rev Content
1 root 1.1 #! perl # mandatory depends=login
2    
3     # sends the following ext message types
4 root 1.17 # ws_a id name... # associate well-known widget with given id
5 root 1.14 # ws_n ws # widgetset new
6     # ws_d ws # widgetset destroy
7 root 1.17 # ws_c ws id class @args # widgetset create
8 root 1.20 # ws_ct ws templateface \%cfg # widgetset create from template
9 root 1.17 # w_c id rid name @args # widget method call
10 root 1.10 # w_s id @attr # widget member set
11     # w_g id rid @attr # widget member get
12 root 1.1 #
13     # and expects the following exti message types
14 root 1.19 # w_e id @args # widget_call
15 root 1.1
16 root 1.13 our $DEBUG = 1;
17    
18 root 1.1 cf::client->attach (
19     on_connect => sub {
20     my ($ns) = @_;
21    
22 root 1.4 Scalar::Util::weaken (my $weakns = $ns);
23    
24 root 1.1 $ns->{id} = "a";
25 root 1.19 $ns->{json_coder}->filter_json_single_key_object ("\fw" => sub {
26     $weakns->{widget}{$_[0]}
27 root 1.4 });
28 root 1.1 },
29     );
30    
31 root 1.2 sub csc_update_stats {
32     my ($ns) = @_;
33    
34     while (my ($k, $v) = each %{ $ns->{csc}{stat} }) {
35     $v->set_text ($ns->pl->ob->stats->$k);
36     }
37     }
38    
39 root 1.17 sub demo_start {
40     my ($ns) = @_;
41    
42     my $ws = $ns->{csc} = $ns->new_widgetset;
43    
44 root 1.20 my ($tl, $entry) = $ws->template (undef,
45     toplevel => {},
46     entry => {
47     text => "xyz",
48     on_changed => sub {
49     warn "changed<@_>\n";#d#
50     },
51     },
52     );
53    
54     $tl->show;
55    
56     $ns->{xxxw} = [$tl, $entry];#d#
57 root 1.17
58 root 1.20 # $ws->find ("setup_notebook")->add ($ws->{tab});
59     # $ws->find ("setup_dialog")->toggle_visibility;
60 root 1.17 }
61    
62 root 1.2 sub csc_start {
63     my ($ns) = @_;
64    
65     my $ws = $ns->{csc} = $ns->new_widgetset;
66    
67     my $w = $ws->new (Toplevel =>
68     min_w => 600,
69     min_h => 400,
70     x => "center",
71     y => "center",
72     title => "Character Creation",
73 root 1.3 has_close_button => 1,
74     on_delete => sub {
75     $ws->destroy;
76     },
77 root 1.2 );
78    
79     $w->add (my $ntb = $ws->new (Notebook => expand => 1));
80    
81 root 1.17 $ntb->add_tab (Statistics => (my $stats = $ws->new (Table => expand => 1)), "Basic statistics of your new character");
82 root 1.2
83 root 1.17 $stats->add_at (0, 0, (my $statstable = $ws->new ("Table")));
84 root 1.2
85     for (
86 root 1.3 [0, "Str"],
87     [1, "Dex"],
88     [2, "Con"],
89     [3, "Int"],
90     [4, "Wis"],
91     [5, "Pow"],
92     [6, "Cha"],
93 root 1.2 ) {
94 root 1.3 my ($x, $label) = @$_;
95 root 1.2
96 root 1.9 $statstable->add_at ($x, 0, $ws->new (Label =>
97 root 1.2 can_hover => 1, can_events => 1,
98     align => +1, text => $label, tooltip => "#stat_$label",
99     ));
100 root 1.9 $statstable->add_at ($x, 1, $ws->{stat}{$label} = $ws->new (Label =>
101 root 1.2 can_hover => 1, can_events => 1,
102     align => +1, template => "88", tooltip => "#stat_$label",
103     ));
104     }
105    
106     csc_update_stats $ns;
107    
108 root 1.17 $ws->{tl} = $w;
109 root 1.2 $w->show;
110     }
111    
112 root 1.1 cf::player->attach (
113     on_login => sub {
114     my ($pl) = @_;
115    
116 root 1.8 return unless $cf::CFG{devel};
117 root 1.1
118     my $ns = $pl->ns;
119    
120 root 1.2 return unless $ns->{can_widget};
121 root 1.5 #csc_start $ns;
122 root 1.20 demo_start $ns;
123 root 1.1 },
124     );
125    
126     cf::register_exticmd w_e => sub {
127 root 1.19 my ($ns, $id, @args) = @_;
128 root 1.1
129 root 1.19 if (my $cb = $ns->{widget_cb}{$id}) {
130     $cb->(@args);
131 root 1.1 }
132    
133     ()
134     };
135    
136     sub cf::client::new_widgetset {
137     my ($self) = @_;
138    
139     my $id = ++$self->{id};
140    
141     my $ws = bless {
142     id => $id,
143     ns => $self,
144 root 1.12 _w => {},
145 root 1.1 }, "ext::widget::set";
146    
147 root 1.14 $ws->msg (ws_n => $id);
148 root 1.1
149     $ws
150     }
151    
152 root 1.19 sub cf::client::alloc_wid {
153     pop @{ $_[0]{ids} }
154     or ++$_[0]{id}
155     }
156    
157     sub cf::client::free_wid {
158     push @{ $_[0]{ids} }, $_[1];
159     }
160    
161 root 1.1 #############################################################################
162    
163     package ext::widget::set;
164    
165     sub DESTROY {
166     $_[0]->destroy;
167     }
168    
169     sub destroy {
170     my ($self) = @_;
171    
172 root 1.14 $self->msg (ws_d => $self->{id});
173 root 1.1 delete $self->{ns};
174     $_->destroy
175     for values %{ $self->{w} };
176     }
177    
178     sub msg {
179 root 1.14 my ($self, @msg) = @_;
180 root 1.1
181     if (my $ns = shift->{ns}) {
182 root 1.14 warn "msg " . $ns->{json_coder}->encode (\@msg) if $DEBUG;#d#
183     $ns->send_packet ("ext " . $ns->{json_coder}->encode (\@msg));
184 root 1.1 }
185     }
186    
187 root 1.17 sub alloc {
188     my ($self) = @_;
189 root 1.1
190 root 1.19 my $id = $self->{ns}->alloc_wid;
191 root 1.1
192 root 1.13 my $proxy = bless {
193 root 1.1 id => $id,
194     }, "ext::widget::proxy";
195    
196     Scalar::Util::weaken ($proxy->{ns} = $self->{ns});
197     Scalar::Util::weaken ($self->{ns}{widget}{$id} = $proxy);
198    
199 root 1.17 $proxy
200     }
201    
202     sub new {
203     my ($self, $class, %args) = @_;
204    
205     my $proxy = $self->alloc;
206    
207     Scalar::Util::weaken ($self->{_w}{$proxy->{id}} = $proxy);
208     Scalar::Util::weaken ($proxy->{ws} = $self);
209    
210 root 1.1 for my $ev (grep /^on_/, keys %args) {
211 root 1.19 $args{$ev} = $proxy->{"_$ev"} = $proxy->cb ($args{$ev});
212 root 1.1 }
213    
214     $self->msg (ws_c =>
215 root 1.16 $self->{id},
216 root 1.17 $proxy->{id},
217 root 1.14 $class,
218     \%args,
219 root 1.1 );
220    
221     $proxy
222     }
223    
224 root 1.20 sub template {
225     my ($self, $template, @args) = @_;
226    
227     my %cfg;
228     my @res;
229    
230     while (@args) {
231     my ($name, $args) = splice @args, 0, 2, ();
232    
233     my $proxy = $self->alloc;
234    
235     Scalar::Util::weaken ($self->{_w}{$proxy->{id}} = $proxy);
236     Scalar::Util::weaken ($proxy->{ws} = $self);
237    
238     for my $ev (grep /^on_/, keys %$args) {
239     $args->{$ev} = $proxy->{"_$ev"} = $proxy->cb ($args->{$ev});
240     }
241    
242     $cfg{$name} = {
243     %$args,
244     id => $proxy->{id},
245     };
246    
247     push @res, $proxy;
248     }
249    
250     $self->msg (ws_ct =>
251     $self->{id},
252     $template,
253     \%cfg,
254     );
255    
256     @res
257     }
258    
259 root 1.17 sub find {
260     my ($self, @names) = @_;
261    
262     my @res;
263     my @alloc;
264    
265     for my $name (@names) {
266     push @res, $self->{ns}{widget_wkw}{$name} ||= do {
267     my $proxy = $self->alloc;
268    
269     push @alloc, $proxy->{id} => $name;
270    
271     $proxy
272     };
273     }
274    
275     $self->msg (ws_a => @alloc)
276     if @alloc;
277    
278     wantarray ? @res : $res[0]
279     }
280    
281 root 1.1 #############################################################################
282    
283     package ext::widget::proxy;
284    
285     sub DESTROY {
286     my ($self) = @_;
287    
288     delete $self->{ns}{widget}{$self->{id}};
289    
290     if (my $ws = $self->{ws}) {
291 root 1.14 $self->msg (w_c => 0, "destroy");
292 root 1.12 delete $ws->{_w}{$self->{id}};
293 root 1.1 }
294     }
295    
296 root 1.19 sub cb {
297     my ($self, $cb) = @_;
298    
299     my $proxy = bless {
300     ns => $self->{ns},
301     id => $self->{ns}->alloc_wid,
302     }, "ext::widget::callback";
303    
304     Scalar::Util::weaken $proxy->{ns};
305    
306     $self->{ns}{widget_cb}{$proxy->{id}} = $cb;
307    
308     $proxy
309     }
310    
311     sub oneshot_cb {
312     my ($self, $cb) = @_;
313    
314     if ("CODE" eq ref $cb) {
315     my $ocb = $cb;
316     $cb = $self->cb (sub {
317     undef $cb;
318     &$ocb
319     });
320     }
321    
322     $cb
323     }
324    
325 root 1.1 sub msg {
326 root 1.14 my ($self, $type, @arg) = @_;
327 root 1.1
328 root 1.17 if (my $ns = $self->{ns}) {
329     my @msg = ($type, $self->{id}, @arg);
330     warn "MSG " . $ns->{json_coder}->encode (\@msg) if $DEBUG;#d#
331     $ns->send_packet ("ext " . $ns->{json_coder}->encode (\@msg));
332 root 1.1 }
333     }
334    
335     sub msg_cb {
336 root 1.14 my ($self, $cb, $type, @arg) = @_;
337 root 1.1
338     if (my $ws = $self->{ws}) {
339 root 1.19 my $rid = $ws->{ns}->alloc_wid;
340 root 1.1
341 root 1.19 if ($cb) {
342     $ws->{ns}{widget_cb}{$rid} = sub {
343     delete $ws->{ns}{widget_cb}{$rid};
344     $ws->{ns}->free_wid ($rid);
345     &$cb
346     };
347 root 1.1
348 root 1.19 $self->msg ($type, $rid, @arg);
349 root 1.1 } else {
350     # synchronous case
351     my $wait = new Coro::Signal;
352     my @res;
353    
354 root 1.19 $ws->{ns}{widget_cb}{$rid} = sub {
355     delete $ws->{ns}{widget_cb}{$rid};
356     $ws->{ns}->free_wid ($rid);
357    
358 root 1.1 @res = @_;
359     $wait->send;
360     };
361 root 1.19 $self->msg ($type, $rid, @arg);
362 root 1.1 $wait->wait;
363    
364     return @res;
365     }
366     }
367    
368     ()
369     }
370    
371     sub set {
372 root 1.12 my ($self, @kv) = @_;
373 root 1.1
374 root 1.14 $self->msg (w_s => \@kv);
375 root 1.1 }
376    
377     sub get {
378     my ($self, $member, $cb) = @_;
379    
380 root 1.19 $self->msg_cb ($cb, w_g => ref $member ? @$member : $member);
381 root 1.1 }
382    
383     sub TO_JSON {
384 root 1.19 { "\fw" => $_[0]{id} }
385 root 1.1 }
386    
387     our $AUTOLOAD;
388    
389     sub AUTOLOAD {
390     $AUTOLOAD =~ s/^.*://
391     or return;
392    
393     my $self = shift;
394    
395 root 1.17 #TODO: handle non-void context
396     $self->msg (w_c => 0, $AUTOLOAD, @_);
397 root 1.1
398     ()
399     }
400    
401 root 1.19 package ext::widget::callback;
402    
403     sub DESTROY {
404     my ($self) = @_;
405    
406     if (my $ns = $self->{ns}) {
407     delete $ns->{widget_cb}{$self->{id}};
408     $ns->free_wid ($self->{id});
409     }
410     }
411    
412     sub TO_JSON {
413     { "\fc" => $_[0]{id} }
414     }
415