ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/deliantra/gde/GCE/StackRef.pm
(Generate patch)

Comparing deliantra/gde/GCE/StackRef.pm (file contents):
Revision 1.1 by elmex, Mon Dec 21 15:51:30 2009 UTC vs.
Revision 1.1.2.1 by elmex, Mon Dec 21 15:51:30 2009 UTC

1package GCE::StackRef;
2use strict;
3=head1 NAME
4
5 GCE::StackRef - a intelligent reference to a mapspace or inventory (arch stack)
6
7=head1 SYNOPSIS
8
9 GCE::StackRef->new (...);
10
11=over 4
12
13=cut
14
15use Scalar::Util qw/weaken/;
16use Storable qw/dclone/;
17use Deliantra;
18use Carp;
19use GCE::Util;
20use base qw/Object::Event/;
21
22sub new {
23 my $class = shift;
24 my $self = { cursors => [], @_ };
25
26 $self->{src} ||= [];
27
28 if (@{$self->{src}} == 3) {
29 return GCE::StackRef::Map->_new ($self);
30 } elsif (@{$self->{src}} == 2) {
31 return GCE::StackRef::Arch->_new ($self);
32 } else {
33 return GCE::StackRef::Dummy->_new ($self);
34 }
35
36 bless $self, $class;
37
38 return $self;
39}
40
41sub _new {
42 my $class = shift;
43 my $self = shift;
44 bless $self, $class;
45
46 $self->init_object_events;
47
48 $self->init;
49 $self
50}
51
52sub cursor {
53 my ($self, $z) = @_;
54 my $c =
55 ($self->{cursors}->[$z]
56 ||= GCE::StackRef->new (src => [$self, $z]));
57 weaken $self->{cursors}->[$z];
58 $c
59}
60
61sub cursor_change {
62 my ($self, $z, $msg, $inval) = @_;
63 $self->{cursors}->[$z]->changed ($msg, $inval)
64 if defined $self->{cursors}->[$z];
65
66 $self->{cursors}->[$z] = undef if $inval;
67}
68
69sub changed : event_cb {
70 my ($self, $msg, $invalidated) = @_;
71
72 warn "$self (@{$self->{src}}) owner $self->{owner}"
73 . " changed: $msg, invalid? ($invalidated)\n";
74 if ($invalidated) {
75 $_->changed ($msg, $invalidated)
76 for grep { defined $_ } @{$self->{cursors}};
77
78 delete $self->{src};
79 delete $self->{ref};
80 delete $self->{map};
81 }
82}
83
84sub overlay {
85 my ($self) = @_;
86}
87
88package GCE::StackRef::Dummy;
89use Storable qw/dclone/;
90
91use base qw/GCE::StackRef/;
92
93sub init {
94 my ($self) = @_;
95}
96
97sub push {
98 my ($self, $arch) = @_;
99 $self->commit ('push_dummy');
100}
101
102sub swap {
103 my ($self, $swapidx, $ownidx) = @_;
104 $self->commit ('swap_dummy');
105}
106
107sub replace {
108 my ($self, $idx, $new) = @_;
109 $self->cursor_change ($idx, 'replace_dummy');
110 $self->commit ('replace_dummy');
111}
112
113sub remove {
114 my ($self, $idx) = @_;
115 $self->cursor_change ($idx, 'remove_dummy');
116 $self->commit ('remove_dummy');
117}
118
119sub commit {
120 my ($self, $change) = @_;
121 $self->changed ($self->{owner} . '#' . $change);
122}
123
124sub size {
125 0
126}
127
128sub get {
129 my $self = shift;
130 my $z = shift;
131
132 return () unless defined $z;
133
134 $self->{template}
135 ? dclone ($self->{template})
136 : { _name => 'empty_archetype' }
137}
138
139package GCE::StackRef::Map;
140use GCE::Util;
141use Deliantra;
142use Deliantra::MapWidget;
143
144use base qw/GCE::StackRef/;
145
146sub init {
147 my ($self) = @_;
148 $self->{map} = $self->{src}->[0];
149 $self->{x} = $self->{src}->[1];
150 $self->{y} = $self->{src}->[2];
151 $self->{ms} = $self->{map}->{map}->get ($self->{x}, $self->{y});
152}
153
154sub overlay {
155 my ($self) = @_;
156 # XXX: Fixme! there is still a bug in removing overlays!!
157 $self->update_cursor_overlay ('stack_view');
158}
159
160sub push {
161 my ($self, $arch) = @_;
162
163 push @{$self->{ms}}, dclone ($arch->getarch);
164
165 $self->commit ('push_ms');
166}
167
168sub swap {
169 my ($self, $swapidx, $ownidx) = @_;
170
171 my $ms = $self->{ms};
172
173 ($ms->[$swapidx], $ms->[$ownidx])
174 = ($ms->[$ownidx], $ms->[$swapidx]);
175
176 $self->cursor_change ($swapidx, 'swap_ms');
177 $self->cursor_change ($ownidx, 'swap_ms');
178
179 $self->commit ('swap_ms');
180}
181
182sub replace {
183 my ($self, $idx, $new) = @_;
184
185 splice @{$self->{'ms'}}, $idx, 1, $new;
186 $self->cursor_change ($idx, 'replace_ms');
187
188 $self->commit ('replace_ms');
189}
190
191sub remove {
192 my ($self, $idx) = @_;
193
194 splice @{$self->{ms}}, $idx, 1;
195 $self->cursor_change ($idx, 'remove_ms');
196
197 $self->commit ('remove_ms');
198}
199
200sub commit {
201 my ($self, $change) = @_;
202
203 $change = 'unknown_edit' unless defined $change;
204 $change = $self->{owner} . '#' . $change;
205
206 my $map = $self->{map};
207 $map = $map->{map};
208
209 $map->change_begin ($change . ' on ' . $self);
210
211 $map->change_stack ($self->{x}, $self->{y}, $self->{ms});
212
213 if (my $changeset = $map->change_end) {
214 my $undo_stack = ($map->{undo_stack} ||= []);
215
216 my $str_self = "$self";
217
218 if ($map->{undo_stack_pos} > 0
219 && $undo_stack->[$map->{undo_stack_pos} - 1]->{title}
220 =~ /^attribute_edit:.*? on \Q$str_self\E$/) {
221 $map->{undo_stack_pos}--;
222
223 warn "merged change ($changeset->{title})\n";
224 } else {
225 warn "added change ($changeset->{title})\n";
226 }
227
228 splice @{ $map->{undo_stack} ||= [] },
229 $map->{undo_stack_pos}++, 1e6,
230 $changeset;
231 }
232 $self->{ms} = $self->{map}->{map}->get ($self->{x}, $self->{y});
233
234 $::MAINWIN->broadcast_cursor_changes ($self->{map}, $self->{x}, $self->{y});
235
236 $self->changed ($change);
237}
238
239sub size {
240 @{$_[0]->{ms} || []}
241}
242
243sub get {
244 my ($self, $z) = @_;
245
246 if (defined $z) {
247 return undef unless @{$self->{ms}};
248 return $self->{ms}->[$z]
249 } else {
250 return @{$self->{ms} || []}
251 }
252}
253
254sub update_cursor_overlay {
255 my ($self, $owner) = @_;
256
257 $self->{map}->{map}->{overlay_holder}->{$owner} = "$self";
258
259 $self->{map}->{map}->overlay ('srovl_' . $owner =>
260 $self->{x} * TILESIZE,
261 $self->{y} * TILESIZE,
262 TILESIZE,
263 TILESIZE,
264 sub {
265 my ($self, $x, $y) = @_;
266
267 if (!$self->{_conn_upd_curs_gc_fg}->{$owner}) {
268 my $gc
269 = $self->{_conn_upd_curs_gc_fg}->{$owner}
270 = Gtk2::Gdk::GC->new ($self->{window});
271 my $cm = $self->{window}->get_colormap;
272 $gc->set_foreground (
273 gtk2_get_color (
274 $self, $owner eq 'stack_view' ? "green" : "blue"));
275 $gc->set_background (gtk2_get_color ($self, "black"));
276 }
277
278 $self->{window}->draw_rectangle (
279 $self->{_conn_upd_curs_gc_fg}->{$owner},
280 0,
281 $x + ($owner eq 'stack_view' ? 1 : 0),
282 $y + ($owner eq 'stack_view' ? 1 : 0),
283 TILESIZE - ($owner eq 'stack_view' ? 3 : 1),
284 TILESIZE - ($owner eq 'stack_view' ? 3 : 1),
285 );
286 }
287 );
288}
289
290sub DESTROY {
291 my ($self) = @_;
292 if ($self->{map}->{map}->{overlay_holder}->{'stack_view'} eq "$self") {
293 $self->{map}->{map}->overlay ('srovl_stack_view')
294 }
295 warn "$self StackRef::Map DESTROYED!\n";
296}
297
298package GCE::StackRef::Arch;
299
300use Carp;
301use GCE::Util;
302use base qw/GCE::StackRef/;
303
304sub init {
305 my ($self) = @_;
306 $self->{ref} = $self->{src}->[0];
307 $self->{z} = $self->{src}->[1];
308}
309
310sub get {
311 my ($self, $z) = @_;
312 my $a = $self->{ref}->get ($self->{z});
313 $a = $a->{inventory}->[$z] if defined $z;
314 unless (defined $a) {
315 Carp::confess "GOT UNDEF ARCH IN ARCHREF $self->{ref}, $self->{z}, $z!";
316 }
317 $a
318}
319
320sub push {
321 my ($self, $arch) = @_;
322
323 my $a = $self->get;
324 push @{$a->{inventory}}, $arch;
325 $self->commit ('push_inv');
326}
327
328sub swap {
329 my ($self, $swapidx, $ownidx) = @_;
330
331 my $a = $self->get;
332 my $inv = $a->{inventory};
333 ($inv->[$swapidx], $inv->[$ownidx])
334 = ($inv->[$ownidx], $inv->[$swapidx]);
335 $self->commit ('swap_inv');
336}
337
338sub replace {
339 my ($self, $idx, $new) = @_;
340
341 my $a = $self->get;
342 splice @{$a->{inventory}}, $idx, 1, $new;
343 $self->cursor_change ($idx, 'replace_inv');
344 $self->commit ('replace_inv');
345}
346
347sub remove {
348 my ($self, $idx) = @_;
349
350 my $a = $self->get;
351 splice @{$a->{inventory}}, $idx, 1;
352 $self->cursor_change ($idx, 'remove_inv', 1);
353
354 $self->commit ('remove_inv');
355}
356
357sub commit {
358 my ($self, $msg) = @_;
359 $self->{ref}->commit ($msg);
360 $self->changed ($self->{owner} . '#' . $msg);
361}
362
363sub type {
364 my ($self) = @_;
365 Deliantra::arch_attr $self->get;
366}
367
368sub attr {
369 my ($self, $key) = @_;
370 $self->get->{$key}
371}
372
373sub attr_or_arch {
374 my ($self, $key) = @_;
375 def ($self->attr ($key), $self->archetype->{$key})
376}
377
378sub archetype {
379 my ($self) = @_;
380
381 $Deliantra::ARCH{$self->get->{_name}} || $Deliantra::ARCH{empty_archetype};
382}
383
384sub picker_folder {
385 my ($self) = @_;
386 my $folder = $self->archetype->{editor_folder};
387 my @a = split /\//, $folder;
388 $a[0]
389}
390
391sub longname {
392 my ($self) = @_;
393
394 my $name = $self->attr ('_name');
395 my $rname = $self->attr ('name');
396 my $t = $self->type;
397
398 $name . ($rname ? " - $rname" : "") . " ($t->{name})"
399}
400
401sub field_value_is_default {
402 my ($self, $key, $val) = @_;
403 my $al_arch = $self->archetype;
404
405 # XXX: Was '... and $val', does this fix problems?
406 (defined ($al_arch->{$key}) && $al_arch->{$key} ne $val)
407 || (not (defined $al_arch->{$key}) and $val)
408}
409
410sub reset_to_defaults {
411 my ($self) = @_;
412
413 my $arch = $self->get;
414
415 for (keys %$arch) {
416 delete $arch->{$_} if $_ ne '_name'
417 }
418
419 $self->commit ('reset_to_defaults');
420}
421
422sub attr_set {
423 my ($self, $key, $value, $type, $src) = @_;
424
425 my $arch = $self->get;
426 my $al_arch = $self->archetype;
427
428 if (ref $value) {
429 $arch->{$key} = $value;
430
431 } else {
432 if (not defined $al_arch->{$key}) {
433 if ((not defined $value) || $value eq ''
434 || ($type eq 'bool' && $value eq '0')) {
435 # try to normalize
436 delete $arch->{$key};
437 } else {
438 # try to normalize
439 $arch->{$key} = $value;
440 }
441 } else {
442 if ($al_arch->{$key} ne $value) {
443 $arch->{$key} = $value;
444 } else {
445 # try to normalize
446 delete $arch->{$key};
447 }
448 }
449 }
450
451 $self->commit ($src . '!attribute_edit:' . $key);
452}
453
454=head1 AUTHOR
455
456 Marc Lehmann <schmorp@schmorp.de>
457 http://home.schmorp.de/
458
459 Robin Redeker <elmex@ta-sa.org>
460 http://www.ta-sa.org/
461
462=cut
4631;

Diff Legend

Removed lines
+ Added lines
< Changed lines
> Changed lines