ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/deliantra/gde/GCE/EditAction.pm
Revision: 1.26
Committed: Sat Apr 1 18:45:05 2006 UTC (18 years, 2 months ago) by elmex
Branch: MAIN
Changes since 1.25: +12 -18 lines
Log Message:
some improvements

File Contents

# Content
1 package GCE::EditAction;
2
3 =head1 NAME
4
5 GCE::EditActions - this is the abstraction of edit actions (placing, deleting, etc.)
6
7 =cut
8
9 use Gtk2;
10 use Gtk2::Gdk::Keysyms;
11 use Gtk2::SimpleMenu;
12
13 use Crossfire;
14 use Crossfire::MapWidget;
15
16 use GCE::StackRef;
17
18 use strict;
19
20 sub new {
21 my $class = shift;
22 my $self = { @_ };
23 bless $self, $class;
24 $self->init;
25 return $self;
26 }
27
28 sub name { } # a unique name for this tool (for storing it in a hash in the main window)
29
30 sub tool_widget { if ($_[1]) { $_[0]->{widget} = $_[1] } $_[0]->{widget} }
31 sub init { }
32
33 sub want_cursor { 1 }
34
35 sub special_arrow { }
36
37 # edits one tile of the map
38 sub edit_one {
39 my ($self, $x, $y) = @_;
40 # do one edition
41 }
42
43 # edits a selection
44 sub edit_selection {
45 }
46
47 # abstraction for edit_one and edit_selection ?
48 # takes selection if present
49 sub edit {
50 my ($self, $map, $x, $y) = @_;
51 }
52
53 sub begin {
54 my ($self, $map, $x, $y) = @_;
55
56 $map->change_begin (ref $self);
57 }
58
59 sub end {
60 my ($self, $map) = @_;
61
62 if (my $changeset = $map->change_end) {
63 splice @{ $map->{undo_stack} ||= [] },
64 $map->{undo_stack_pos}++, 1e6,
65 $changeset;
66
67 #TODO: limit undo stack size to some preconfigured limit
68 }
69 }
70
71 package GCE::EditAction::RadioModed;
72
73 our @ISA = qw/GCE::EditAction/;
74
75 sub add_mode_button {
76 my ($self, $vb, $lbl, $mode, $default) = @_;
77
78 $vb->pack_start (my $b = Gtk2::RadioButton->new ($self->{place_radio_grp}, $lbl), 0, 1, 0);
79 unless (defined $self->{place_radio_grp}) {
80 $self->{place_radio_grp} = $b->get_group;
81
82 unless (defined $default) {
83 $b->set_active (1);
84 $self->set_mode ($mode);
85 }
86 }
87 if ($default) {
88 $b->set_active (1);
89 $self->set_mode ($mode);
90 }
91 $b->signal_connect (clicked => sub {
92 $self->set_mode ($mode);
93 });
94 }
95
96 sub set_mode {
97 my ($self, $mode) = @_;
98 $self->{place_mode} = $mode;
99 }
100
101 sub get_mode {
102 my ($self) = @_;
103 $self->{place_mode}
104 }
105
106 sub init {
107 my ($self) = @_;
108
109 die "Implement me!!";
110
111 # my $vb = new Gtk2::VBox;
112 # $self->_add_mode_button ($vb, "auto", "auto");
113 # $self->_add_mode_button ($vb, "top", "top");
114 # $self->_add_mode_button ($vb, "above floor", "above");
115 # $self->_add_mode_button ($vb, "below floor", "below");
116 # $self->_add_mode_button ($vb, "bottom", "bottom");
117 #
118 # $self->{widget} = $vb;
119 }
120
121 package GCE::EditAction::Pick;
122 use strict;
123
124 our @ISA = qw/GCE::EditAction::RadioModed/;
125
126 sub name { 'pick' }
127
128 sub want_cursor { 0 }
129
130 sub special_arrow { 'GDK_HAND2' }
131
132 sub init {
133 my ($self) = @_;
134
135 my $vb = new Gtk2::VBox;
136 $vb->pack_start ($self->{only_attr} = Gtk2::CheckButton->new ('pick attr'), 0, 1, 0);
137 $self->{widget} = $vb;
138 }
139
140 sub begin {
141 my ($self, $map, $x, $y) = @_;
142 $self->edit ($map, $x, $y);
143 }
144
145 sub edit {
146 my ($self, $map, $x, $y) = @_;
147
148 $::MAINWIN->update_stack_view ($map, $x, $y);
149
150 my $cstack = $map->get ($x, $y);
151
152 my $arch = $cstack->[-1];
153
154 # virtual... grmbl....
155 # FIXME: I have to patch the stack of the real arch??? argl.. how??
156 if ($arch->{_virtual}) {
157 $x = $arch->{virtual_x};
158 $y = $arch->{virtual_y};
159 $arch = $arch->{_virtual};
160 $cstack = $map->get ($x, $y);
161 }
162
163 unless ($self->{only_attr}->get_active) {
164 $::MAINWIN->set_pick ($arch)
165 if @$cstack;
166 }
167
168 $::MAINWIN->update_attr_editor ($arch, sub {
169 $map->change_begin (ref $self);
170 $map->change_stack ($x, $y, $cstack);
171 # XXX: Put this into a generic function!!! See also EditTools.pm
172 # FIXME: Fix the automatic update on undo here!
173 if (my $changeset = $map->change_end) {
174 splice @{ $map->{undo_stack} ||= [] },
175 $map->{undo_stack_pos}++, 1e6,
176 $changeset;
177 }
178 });
179 }
180
181 sub end {}
182
183 package GCE::EditAction::Perl;
184
185 use GCE::Util;
186 use Gtk2;
187 use strict;
188
189 our @ISA = qw/GCE::EditAction/;
190
191 sub name { 'perl' }
192
193 sub special_arrow { 'GDK_HEART' }
194
195 sub init {
196 my ($self) = @_;
197
198 my $vb = new Gtk2::VBox;
199 $vb->pack_start (my $combo = Gtk2::ComboBox->new_text, 0, 1, 0);
200 $vb->pack_start (my $sw = Gtk2::ScrolledWindow->new, 1, 1, 0);
201 $sw->add ($self->{txt} = Gtk2::TextView->new);
202
203 my $code = {};
204 for (['unique floor' => 'my $i = 0; for (@$os) { $_->{is_floor} and $as->[$i]->{unique} = 1; $i++ }']) {
205 $combo->append_text ($_->[0]);
206 $code->{$_->[0]} = $_->[1];
207 }
208
209 $combo->signal_connect (changed => sub {
210 my ($combo) = @_;
211 my $str = $combo->get_active_text;
212 $self->{txt}->get_buffer->set_text ($code->{$str});
213 });
214
215 $self->tool_widget ($vb);
216 }
217
218 sub want_cursor { 0 }
219
220 sub begin {
221 my ($self, $map, $x, $y) = @_;
222
223 $self->SUPER::begin ($map, $x, $y);
224 $self->edit ($map, $x, $y);
225 }
226
227 sub edit {
228 my ($self, $map, $x, $y) = @_;
229
230 my $pick = $::MAINWIN->get_pick;
231 my $as = $map->get ($x, $y);
232
233 $as = $self->eval ($map, $pick, $as, $x, $y);
234 $map->change_stack ($x, $y, $as); # insert_arch_stack_layer ($as, $arch));
235 }
236
237 sub eval {
238 my ($self, $map, $pick, $as, $x, $y) = @_;
239 my $buf = $self->{txt}->get_buffer;
240 my $code = $buf->get_text ($buf->get_start_iter, $buf->get_end_iter, 0);
241 my $f_idx = stack_find_floor ($as, 'from_top');
242 my $w_idx = stack_find_wall ($as, 'from_top');
243 my $os = [ map { $Crossfire::ARCH{$_->{_name}} } @$as ];
244
245 unless (arch_is_floor ($as->[$f_idx])) { $f_idx = undef; }
246 unless (arch_is_floor ($as->[$w_idx])) { $w_idx = undef; }
247
248 eval $code;
249 return $as;
250 }
251
252 package GCE::EditAction::FollowExit;
253 use Storable qw/dclone/;
254 use File::Spec::Functions;
255 use GCE::Util;
256 use Gtk2;
257 use strict;
258
259 our @ISA = qw/GCE::EditAction/;
260
261 sub name { 'place' }
262
263 sub init {
264 my ($self) = @_;
265
266 my $vb = new Gtk2::VBox;
267
268 $self->tool_widget ($vb);
269 }
270
271 sub want_cursor { 0 }
272
273 sub begin {
274 my ($self, $map, $x, $y, $mape) = @_;
275
276 # $self->SUPER::begin ($map, $x, $y);
277 $self->edit ($map, $x, $y, $mape);
278 }
279
280 sub edit {
281 my ($self, $map, $x, $y, $mape) = @_;
282
283 my $as = $map->get ($x, $y);
284
285 my $exit;
286 for (@$as) {
287 my $a = $Crossfire::ARCH{$_->{_name}};
288 if (arch_is_exit ($_)) {
289 $exit = $_;
290 }
291 }
292
293 if ($exit) {
294 my $dest = map2abs ($exit->{slaying}, $mape);
295 $::MAINWIN->open_map_editor ($dest);
296 }
297 }
298
299 sub end {
300 my ($self, $map, $x, $y, $mape) = @_;
301 # $::MAINWIN->{edit_collection}{pick}->edit ($map, $x, $y);
302 #$self->SUPER::end ($map, $x, $y, $mape);
303 }
304
305 package GCE::EditAction::Place;
306 use Storable qw/dclone/;
307 use GCE::Util;
308 use Gtk2;
309 use strict;
310
311 our @ISA = qw/GCE::EditAction::RadioModed/;
312
313 sub name { 'place' }
314
315 sub init {
316 my ($self) = @_;
317
318 my $vb = new Gtk2::VBox;
319 $self->add_mode_button ($vb, "auto", "auto");
320 $self->add_mode_button ($vb, "top", "top");
321 $self->add_mode_button ($vb, "above floor", "above");
322 $self->add_mode_button ($vb, "below floor", "below");
323 $self->add_mode_button ($vb, "bottom", "bottom");
324
325 $self->tool_widget ($vb);
326 }
327
328 sub want_cursor { 0 }
329
330 sub begin {
331 my ($self, $map, $x, $y) = @_;
332
333 $self->SUPER::begin ($map, $x, $y);
334 $self->edit ($map, $x, $y);
335 }
336
337 sub edit {
338 my ($self, $map, $x, $y) = @_;
339
340 my $pick = $::MAINWIN->get_pick;
341 my $as = $map->get ($x, $y);
342
343 $self->stack_action ($as, dclone ($pick));
344 $map->change_stack ($x, $y, $as); # insert_arch_stack_layer ($as, $arch));
345 }
346
347 sub end {
348 my ($self, $map, $x, $y, $mape) = @_;
349 # $::MAINWIN->{edit_collection}{pick}->edit ($map, $x, $y);
350 # now actualize stack and attr editor
351 $::MAINWIN->update_stack_view ($map, $x, $y);
352
353 my $cstack = $map->get ($x, $y);
354
355 my $arch = $cstack->[-1];
356
357 # virtual... grmbl....
358 # FIXME: I have to patch the stack of the real arch??? argl.. how??
359 if ($arch->{_virtual}) {
360 $x = $arch->{virtual_x};
361 $y = $arch->{virtual_y};
362 $arch = $arch->{_virtual};
363 $cstack = $map->get ($x, $y);
364 }
365
366
367 $::MAINWIN->update_attr_editor ($arch, sub {
368 $map->change_begin (ref $self);
369 $map->change_stack ($x, $y, $cstack);
370 # XXX: Put this into a generic function!!! See also EditTools.pm
371 # FIXME: Fix the automatic update on undo here!
372 if (my $changeset = $map->change_end) {
373 splice @{ $map->{undo_stack} ||= [] },
374 $map->{undo_stack_pos}++, 1e6,
375 $changeset;
376 }
377 });
378
379
380 $self->SUPER::end ($map, $x, $y, $mape);
381 }
382
383 sub stack_action {
384 my ($self, $stack, $arch) = @_;
385
386 my $m = $self->get_mode;
387
388 if ($m eq 'top') {
389 if (@$stack == 0 or $stack->[-1]->{_name} ne $arch->{_name}) {
390 push @$stack, $arch;
391 }
392
393 } elsif ($m eq 'bottom') {
394 if (@$stack == 0 or $stack->[0]->{_name} ne $arch->{_name}) {
395 unshift @$stack, $arch;
396 }
397
398 } elsif ($m eq 'above') {
399 my $fidx = stack_find_floor ($stack, 'from_top');
400
401 if (@$stack == 0
402 or not ($stack->[$fidx + 1])
403 or $stack->[$fidx + 1]->{_name} ne $arch->{_name})
404 {
405 splice (@$stack, $fidx + 1, 0, $arch);
406 }
407
408 } elsif ($m eq 'below') {
409 my $fidx = stack_find_floor ($stack, 'from_bottom');
410
411 if (@$stack == 0
412 or $fidx == 0
413 or not ($stack->[$fidx - 1])
414 or $stack->[$fidx - 1]->{_name} ne $arch->{_name})
415 {
416 splice (@$stack, $fidx, 0, $arch);
417 }
418
419 } elsif ($m eq 'auto') {
420 my $fidx = stack_find_floor ($stack, 'from_top');
421 my $widx = stack_find_wall ($stack);
422
423 if (arch_is_floor ($arch)) { # we want to place a floor tile
424
425 if (arch_is_floor ($stack->[$fidx])) { # replace
426 $stack->[$fidx] = $arch;
427
428 } else { # insert on bottom
429 unshift @$stack, $arch;
430 }
431
432 } elsif (arch_is_wall ($arch)) { # we want to place a wall
433
434 if (arch_is_wall ($stack->[$widx])) { # replace
435 $stack->[$widx] = $arch;
436
437 } else { # insert above floor
438 splice (@$stack, $fidx + 1, 0, $arch);
439 }
440
441 } else {
442
443 if (arch_is_wall ($stack->[$widx])) {
444 # if we have a wall above the floor, replace it with the to place item
445 $stack->[$widx] = $arch;
446 return;
447 }
448
449 if (@$stack == 0
450 or not ($stack->[-1])
451 or $stack->[-1]->{_name} ne $arch->{_name})
452 {
453 push @$stack, $arch;
454 }
455 }
456 }
457 }
458
459 package GCE::EditAction::Select;
460 use GCE::Util;
461 use Gtk2;
462 use Crossfire;
463 use Storable qw/dclone/;
464 use strict;
465
466 our @ISA = qw/GCE::EditAction::RadioModed/;
467
468 sub name { 'select' }
469
470 sub special_arrow { 'GDK_CIRCLE' }
471
472 sub init {
473 my ($self) = @_;
474
475 my $vb = new Gtk2::VBox;
476
477 $vb->pack_start (my $bt = Gtk2::Button->new_with_mnemonic ("_copy"), 0, 1, 0);
478 $bt->signal_connect (clicked => sub { $self->copy });
479 $vb->pack_start ($self->{paste_top} = Gtk2::CheckButton->new ('paste on top'), 0, 1, 0);
480 $vb->pack_start (my $bt = Gtk2::Button->new_with_mnemonic ("paste (_v)"), 0, 1, 0);
481 $bt->signal_connect (clicked => sub { $self->paste });
482 $vb->pack_start (Gtk2::HSeparator->new, 0, 1, 0);
483 $self->add_mode_button ($vb, "place", "place");
484 $self->add_mode_button ($vb, "erase", "erase");
485 $self->add_mode_button ($vb, "perl", "perl");
486 $vb->pack_start (my $bt = Gtk2::Button->new_with_mnemonic ("i_nvoke"), 0, 1, 0);
487 $bt->signal_connect (clicked => sub { $self->invoke });
488
489 $self->tool_widget ($vb);
490 }
491
492 sub copy {
493 my ($self) = @_;
494
495 return unless $self->{selection}->{a};
496 my ($x1, $y1) = @{$self->{selection}->{a}};
497 my ($x2, $y2) = @{$self->{selection}->{b}};
498
499 if ($x1 > $x2) { ($x2, $x1) = ($x1, $x2) }
500 if ($y1 > $y2) { ($y2, $y1) = ($y1, $y2) }
501
502 my $map = $self->{selection}->{map};
503
504 $self->{copy_coords} = [$x1, $y1, $x2, $y2];
505 $self->{copy};
506 for (my $x = $x1; $x <= $x2; $x++) {
507 for (my $y = $y1; $y <= $y2; $y++) {
508 $self->{copy}->[$x - $x1]->[$y - $y1] = $map->get ($x, $y);
509 }
510 }
511 }
512
513 sub paste {
514 my ($self, $map, $xp, $yp) = @_;
515
516 return unless $self->{selection}->{a};
517
518 my ($x1, $y1);
519
520 if (defined $xp) {
521 ($x1, $y1) = ($xp, $yp);
522 } else {
523 ($x1, $y1) = @{$self->{selection}->{a}};
524 }
525
526 $map ||= $self->{selection}->{map};
527
528 my $p_o_top = $self->{paste_top}->get_active * 1;
529
530 my $w = $self->{copy_coords}->[2] - $self->{copy_coords}->[0];
531 my $h = $self->{copy_coords}->[3] - $self->{copy_coords}->[1];
532 $self->{copy};
533 $self->SUPER::begin ($map, $x1, $y1);
534 for (my $x = $x1; $x <= ($x1 + $w); $x++) {
535 for (my $y = $y1; $y <= ($y1 + $h); $y++) {
536 my $cstck = $map->get ($x, $y);
537
538 if ($p_o_top) {
539 push @$cstck, @{dclone ($self->{copy}->[$x - $x1]->[$y - $y1] || [])};
540 $map->change_stack ($x, $y, $cstck);
541 } else {
542 $map->change_stack ($x, $y, dclone ($self->{copy}->[$x - $x1]->[$y - $y1] || []));
543 }
544 }
545 }
546 $self->SUPER::end ($map);
547 $map->invalidate_all;
548 }
549
550 sub invoke {
551 my ($self) = @_;
552
553 return unless $self->{selection}->{a};
554 my ($x1, $y1) = @{$self->{selection}->{a}};
555 my ($x2, $y2) = @{$self->{selection}->{b}};
556
557 if ($x1 > $x2) { ($x2, $x1) = ($x1, $x2) }
558 if ($y1 > $y2) { ($y2, $y1) = ($y1, $y2) }
559
560 my $map = $self->{selection}->{map};
561
562 my $m = $self->get_mode;
563 $self->SUPER::begin ($map, $x1, $y1);
564 for (my $x = $x1; $x <= $x2; $x++) {
565 for (my $y = $y1; $y <= $y2; $y++) {
566 if ($m eq 'place') {
567 $::MAINWIN->{edit_collection}{place}->edit ($map, $x, $y);
568 } elsif ($m eq 'erase') {
569 $::MAINWIN->{edit_collection}{erase}->edit ($map, $x, $y);
570 } elsif ($m eq 'perl') {
571 $::MAINWIN->{edit_collection}{perl}->edit ($map, $x, $y);
572 }
573 }
574 }
575 $self->SUPER::end ($map);
576 }
577
578 sub want_cursor { 0 }
579
580 sub begin {
581 my ($self, $map, $x, $y) = @_;
582
583 delete $self->{selection};
584
585 $self->{selection}->{a} = [$x, $y];
586 $self->edit ($map, $x, $y);
587 }
588
589 sub end {
590 }
591
592 sub edit {
593 my ($self, $map, $x, $y) = @_;
594
595 $self->{selection}->{b} = [$x, $y];
596 $self->{selection}->{map} = $map;
597 $self->update_overlay ($map);
598 }
599
600 sub update_overlay {
601 my ($self, $map) = @_;
602
603 my ($x1, $y1) = @{$self->{selection}->{a}};
604 my ($x2, $y2) = @{$self->{selection}->{b}};
605
606 if ($x1 > $x2) { ($x2, $x1) = ($x1, $x2) }
607 if ($y1 > $y2) { ($y2, $y1) = ($y1, $y2) }
608
609 my $w = ($x2 - $x1) + 1;
610 my $h = ($y2 - $y1) + 1;
611
612 $map->overlay (selection =>
613 $x1 * TILESIZE, $y1 * TILESIZE,
614 $w * TILESIZE, $h * TILESIZE,
615 sub {
616 my ($self, $x, $y) = @_;
617 $self->{window}->draw_rectangle (
618 $_ & 1 ? $self->style->black_gc : $self->style->white_gc,
619 0,
620 $x + $_, $y + $_,
621 ($w * TILESIZE) - 1 - $_ * 2,
622 ($h * TILESIZE) - 1 - $_ * 2
623 ) for 0..3;
624 }
625 );
626 }
627
628 package GCE::EditAction::Erase;
629 use GCE::Util;
630 use Gtk2;
631 use strict;
632
633 our @ISA = qw/GCE::EditAction::RadioModed/;
634
635 sub name { 'erase' }
636
637 sub want_cursor { 0 }
638
639 sub special_arrow { 'GDK_DIAMOND_CROSS' }
640
641 sub init {
642 my ($self) = @_;
643
644 my $vb = new Gtk2::VBox;
645 $self->add_mode_button ($vb, "top", "top");
646 $self->add_mode_button ($vb, "walls", "walls");
647 $self->add_mode_button ($vb, "above floor", "above", 'default');
648 $self->add_mode_button ($vb, "floor", "floor");
649 $self->add_mode_button ($vb, "below floor", "below");
650 $self->add_mode_button ($vb, "bottom", "bottom");
651 $self->add_mode_button ($vb, "pick match", "match");
652
653 $self->tool_widget ($vb);
654
655 $vb->pack_start ($self->{no_wall_check} = Gtk2::CheckButton->new ("protect walls"), 0, 1, 0);
656 $vb->pack_start ($self->{no_monsters_check} = Gtk2::CheckButton->new ("protect monsters"), 0, 1, 0);
657 }
658
659 sub check_excluded {
660 my ($self, $arch) = @_;
661
662 my $a1 = $self->{no_monsters_check}->get_active;
663 my $a2 = $self->{no_wall_check}->get_active;
664
665 my $r = ($self->{no_wall_check}->get_active && arch_is_wall ($arch))
666 || ($self->{no_monsters_check}->get_active && arch_is_monster ($arch));
667 return $r;
668 }
669
670 sub begin {
671 my ($self, $map, $x, $y) = @_;
672
673 $self->SUPER::begin ($map, $x, $y);
674 $self->edit ($map, $x, $y);
675 }
676
677 sub edit {
678 my ($self, $map, $x, $y) = @_;
679
680 my $as = $map->get ($x, $y);
681 $self->stack_action ($as);
682 $map->change_stack ($x, $y, $as);
683 }
684
685 sub stack_action {
686 my ($self, $stack) = @_;
687
688 my $m = $self->get_mode;
689
690 if ($m eq 'top') {
691 pop @$stack;
692
693 } elsif ($m eq 'bottom') {
694 shift @$stack;
695
696 } elsif ($m eq 'above') {
697 my $fidx = stack_find_floor ($stack, 'from_top');
698
699 if (arch_is_floor ($stack->[$fidx]) and $stack->[$fidx + 1]) {
700 splice (@$stack, $fidx + 1, 1)
701 unless $self->check_excluded ($stack->[$fidx + 1])
702
703 } elsif (not arch_is_floor ($stack->[$fidx])) {
704 splice (@$stack, $fidx, 1)
705 unless $self->check_excluded ($stack->[$fidx])
706
707 }
708
709 } elsif ($m eq 'below') {
710 my $fidx = stack_find_floor ($stack, 'from_bottom');
711
712 if ($fidx > 0 and not arch_is_floor ($stack->[$fidx - 1])) {
713 splice (@$stack, $fidx - 1, 1)
714 unless $self->check_excluded ($stack->[$fidx - 1])
715
716 } elsif (not arch_is_floor ($stack->[$fidx])) { # no floor found
717 splice (@$stack, $fidx, 1)
718 unless $self->check_excluded ($stack->[$fidx])
719
720 }
721
722 } elsif ($m eq 'walls') {
723 my $widx = stack_find_wall ($stack, 'from_top');
724
725 while (arch_is_wall ($stack->[$widx])) {
726 splice (@$stack, $widx, 1);
727 $widx = stack_find_wall ($stack, 'from_top')
728 }
729
730 } elsif ($m eq 'floor') {
731 my $fidx = stack_find_floor ($stack, 'from_top');
732
733 while (arch_is_floor ($stack->[$fidx])) {
734 splice (@$stack, $fidx, 1);
735 $fidx = stack_find_floor ($stack, 'from_top')
736 }
737
738 } elsif ($m eq 'match') {
739 my $pick_name = $::MAINWIN->get_pick ()->{_name};
740 my $idx = stack_find ($stack, 'from_top', sub { $_[0]->{_name} eq $pick_name });
741
742 while ($stack->[$idx] and $stack->[$idx]->{_name} eq $pick_name) {
743 splice (@$stack, $idx, 1);
744 $idx = stack_find ($stack, 'from_top', sub { $_[0]->{_name} eq $pick_name });
745 }
746 }
747 }
748
749 package GCE::EditAction::ConnectExit;
750 use Storable qw/dclone/;
751 use GCE::Util;
752 use Gtk2;
753 use File::Spec::Functions;
754 use strict;
755
756 our @ISA = qw/GCE::EditAction::RadioModed/;
757
758 sub name { 'connectexit' }
759
760 sub init {
761 my ($self) = @_;
762
763 my $vb = new Gtk2::VBox;
764 $self->add_mode_button ($vb, "exit", "exit");
765 # $self->add_mode_button ($vb, "triggers", "trig");
766 $vb->pack_start ($self->{sel_edt} = Gtk2::Entry->new, 0, 1, 0);
767 $self->{sel_edt}->set_text (catfile ($::CFG->{MAPDIR}));
768
769 $vb->pack_start ($self->{sel_lbl} = Gtk2::Label->new, 0, 0, 0);
770 $self->tool_widget ($vb);
771 }
772
773 sub want_cursor { 0 }
774
775 sub begin {
776 my ($self, $map, $x, $y, $mapedit) = @_;
777
778 $self->edit ($map, $x, $y, $mapedit);
779 }
780
781 sub edit {
782 my ($self, $map, $x, $y, $mapedit) = @_;
783
784 my $pick = $::MAINWIN->get_pick;
785 my $as = $map->get ($x, $y);
786
787 my $exit;
788 for (@$as) {
789 if (arch_is_exit ($_)) {
790 $exit = $_;
791 }
792 }
793
794 my $mappath = $::CFG->{MAPDIR};
795
796 if ($exit) {
797 if ($self->{sel_exit}) {
798
799 $exit->{hp} = $self->{sel_exit}->[3];
800 $exit->{sp} = $self->{sel_exit}->[4];
801 #$exit->{slaying} = File::Spec->abs2rel ($self->{sel_exit}->[5], $ent);
802
803 my $exit2 = $self->{sel_exit}->[0];
804
805 $exit2->{hp} = $x;
806 $exit2->{sp} = $y;
807
808 my ($m1, $m2) = exit_paths ($mappath, $self->{sel_exit}->[5], $mapedit->{path});
809
810 $exit2->{slaying} = $m2;
811 $exit->{slaying} = $m1;
812
813 $self->SUPER::begin ($map, $x, $y, $mapedit);
814 $map->change_stack ($x, $y, $as);
815 $self->SUPER::end ($map);
816 $self->SUPER::begin ($self->{sel_exit}->[1], $exit->{hp}, $exit->{sp});
817 $self->{sel_exit}->[1]->change_stack ($exit->{hp}, $exit->{sp}, $self->{sel_exit}->[2]);
818 $self->SUPER::end ($self->{sel_exit}->[1]);
819
820 quick_msg ($mapedit, "$exit->{slaying} ($exit->{hp}:$exit->{sp}) $exit->{_name} <=> $exit2->{slaying} ($exit2->{hp}:$exit2->{sp}) $exit2->{_name}", 0);
821
822 $::MAINWIN->{edit_collection}{pick}->edit ($map, $x, $y);
823
824 $self->{sel_exit} = undef;
825 $self->{sel_lbl}->set_text ('');
826 } else {
827 $self->{sel_lbl}->set_text ("src: ($x:$y) $exit->{_name}");
828 $self->{sel_exit} = [$exit, $map, $as, $x, $y, $mapedit->{path}];
829 }
830 } else {
831 if ($self->{sel_exit}) {
832
833 my $exit2 = $self->{sel_exit}->[0];
834
835 $exit2->{hp} = $x;
836 $exit2->{sp} = $y;
837 $exit2->{slaying} = undef;
838
839 unless ($exit2->{slaying} =~ m/^\.\./) {
840 $exit2->{slaying} = '/' . $exit2->{slaying};
841 }
842
843 $self->SUPER::begin ($self->{sel_exit}->[1], $exit->{hp}, $exit->{sp});
844 $self->{sel_exit}->[1]->change_stack ($self->{sel_exit}->[3], $self->{sel_exit}->[4], $self->{sel_exit}->[2]);
845 $self->SUPER::end ($self->{sel_exit}->[1]);
846
847 quick_msg ($mapedit, "($self->{sel_exit}->[3]:$self->{sel_exit}->[4]) $self->{sel_exit}->[0]->{_name} => ($x:$y) $exit2->{_name}", 0);
848
849 $::MAINWIN->{edit_collection}{pick}->edit ($map, $x, $y);
850
851 $self->{sel_exit} = undef;
852 $self->{sel_lbl}->set_text ('');
853 } else {
854 quick_msg ($mapedit, "no exit object found");
855 }
856 }
857
858 # $self->stack_action ($as, dclone ($pick));
859 #$map->change_stack ($x, $y, $as); # insert_arch_stack_layer ($as, $arch));
860 }
861
862 sub end {}
863
864
865 =head1 AUTHOR
866
867 Marc Lehmann <schmorp@schmorp.de>
868 http://home.schmorp.de/
869
870 Robin Redeker <elmex@ta-sa.org>
871 http://www.ta-sa.org/
872
873 =cut
874
875 1
876