ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/deliantra/gde/GCE/EditAction.pm
Revision: 1.9
Committed: Wed Mar 15 19:04:07 2006 UTC (18 years, 2 months ago) by elmex
Branch: MAIN
Changes since 1.8: +2 -2 lines
Log Message:
added inventory editor and fixed some bugs in the attr editor

File Contents

# User Rev Content
1 elmex 1.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 strict;
17    
18     sub new {
19     my $class = shift;
20     my $self = { @_ };
21     bless $self, $class;
22 elmex 1.6 $self->init;
23 elmex 1.1 return $self;
24     }
25    
26 elmex 1.7 sub tool_widget { if ($_[1]) { $_[0]->{widget} = $_[1] } $_[0]->{widget} }
27 elmex 1.6 sub init { }
28    
29 elmex 1.1 sub want_cursor { 1 }
30    
31     sub special_arrow { }
32    
33     # edits one tile of the map
34     sub edit_one {
35     my ($self, $x, $y) = @_;
36     # do one edition
37     }
38    
39     # edits a selection
40     sub edit_selection {
41     }
42    
43     # abstraction for edit_one and edit_selection ?
44     # takes selection if present
45     sub edit {
46     my ($self, $map, $x, $y, $btn) = @_;
47     }
48    
49     sub begin {
50     my ($self, $map, $x, $y, $btn) = @_;
51 root 1.3
52     $map->change_begin (ref $self);
53 elmex 1.1 }
54 root 1.3
55 elmex 1.1 sub end {
56 root 1.3 my ($self, $map) = @_;
57    
58     if (my $changeset = $map->change_end) {
59     splice @{ $map->{undo_stack} ||= [] },
60 root 1.4 $map->{undo_stack_pos}++, 1e6,
61 root 1.3 $changeset;
62    
63     #TODO: limit undo stack size to some preconfigured limit
64     }
65 elmex 1.1 }
66    
67 elmex 1.7 package GCE::EditAction::RadioModed;
68    
69     our @ISA = qw/GCE::EditAction/;
70    
71     sub add_mode_button {
72     my ($self, $vb, $lbl, $mode, $default) = @_;
73    
74     $vb->pack_start (my $b = Gtk2::RadioButton->new ($self->{place_radio_grp}, $lbl), 0, 1, 0);
75     unless (defined $self->{place_radio_grp}) {
76     $self->{place_radio_grp} = $b->get_group;
77    
78     unless (defined $default) {
79     $b->set_active (1);
80     $self->set_mode ($mode);
81     }
82     }
83     if ($default) {
84     $b->set_active (1);
85     $self->set_mode ($mode);
86     }
87     $b->signal_connect (clicked => sub {
88     $self->set_mode ($mode);
89     });
90     }
91    
92     sub set_mode {
93     my ($self, $mode) = @_;
94     $self->{place_mode} = $mode;
95     }
96    
97     sub get_mode {
98     my ($self) = @_;
99     $self->{place_mode}
100     }
101    
102     sub init {
103     my ($self) = @_;
104    
105     die "Implement me!!";
106    
107     # my $vb = new Gtk2::VBox;
108     # $self->_add_mode_button ($vb, "auto", "auto");
109     # $self->_add_mode_button ($vb, "top", "top");
110     # $self->_add_mode_button ($vb, "above floor", "above");
111     # $self->_add_mode_button ($vb, "below floor", "below");
112     # $self->_add_mode_button ($vb, "bottom", "bottom");
113     #
114     # $self->{widget} = $vb;
115     }
116 elmex 1.1
117     package GCE::EditAction::Pick;
118 elmex 1.7 use strict;
119 elmex 1.1
120     our @ISA = qw/GCE::EditAction/;
121    
122 elmex 1.7 sub want_cursor { 0 }
123    
124 elmex 1.1 sub special_arrow { 'GDK_HAND2' }
125    
126     sub begin {
127     my ($self, $map, $x, $y, $btn) = @_;
128    
129 root 1.3 $self->SUPER::begin ($map, $x, $y, $btn);
130 elmex 1.1 $self->edit ($map, $x, $y, $btn);
131     }
132    
133     sub edit {
134     my ($self, $map, $x, $y, $btn) = @_;
135    
136     my $cstack = $map->get ($x, $y);
137    
138     my $arch = $cstack->[-1];
139    
140     # virtual... grmbl....
141     # FIXME: I have to patch the stack of the real arch??? argl.. how??
142     if ($arch->{_virtual}) {
143 root 1.3 $x = $arch->{virtual_x};
144     $y = $arch->{virtual_y};
145 elmex 1.1 $arch = $arch->{_virtual};
146 elmex 1.6 $cstack = $map->get ($x, $y);
147 elmex 1.1 }
148    
149 root 1.5 $::MAINWIN->set_pick ($arch)
150 root 1.3 if @$cstack && $btn == 1;
151 elmex 1.1
152 root 1.5 $::MAINWIN->update_attr_editor ($arch, sub {
153 elmex 1.8 $map->change_begin (ref $self);
154 root 1.3 $map->change_stack ($x, $y, $cstack);
155 elmex 1.8 # XXX: Put this into a generic function!!! See also EditTools.pm
156     # FIXME: Fix the automatic update on undo here!
157     if (my $changeset = $map->change_end) {
158     splice @{ $map->{undo_stack} ||= [] },
159     $map->{undo_stack_pos}++, 1e6,
160     $changeset;
161     }
162 elmex 1.1 });
163    
164 root 1.5 $::MAINWIN->update_stack_view ($map, $x, $y);
165 elmex 1.1 }
166    
167     package GCE::EditAction::Place;
168    
169 elmex 1.2 use GCE::Util;
170 elmex 1.6 use Gtk2;
171     use strict;
172 elmex 1.2
173 elmex 1.7 our @ISA = qw/GCE::EditAction::RadioModed/;
174 elmex 1.6
175     sub init {
176     my ($self) = @_;
177    
178     my $vb = new Gtk2::VBox;
179 elmex 1.7 $self->add_mode_button ($vb, "auto", "auto");
180     $self->add_mode_button ($vb, "top", "top");
181     $self->add_mode_button ($vb, "above floor", "above");
182     $self->add_mode_button ($vb, "below floor", "below");
183     $self->add_mode_button ($vb, "bottom", "bottom");
184 elmex 1.6
185 elmex 1.7 $self->tool_widget ($vb);
186 elmex 1.6 }
187    
188 elmex 1.1 sub want_cursor { 0 }
189    
190     sub begin {
191     my ($self, $map, $x, $y, $btn) = @_;
192    
193 root 1.3 $self->SUPER::begin ($map, $x, $y, $btn);
194 elmex 1.1 $self->edit ($map, $x, $y, $btn);
195     }
196    
197     sub edit {
198     my ($self, $map, $x, $y, $btn) = @_;
199    
200     if ($btn == 3) { # btn 3 does pick
201    
202     my $cstack = $map->get ($x, $y) or return;
203 root 1.3 my $arch = $cstack->[-1];
204 elmex 1.1
205     $arch->{_virtual}
206     and $arch = $arch->{_virtual};
207    
208 root 1.5 $::MAINWIN->set_pick ($arch)
209 elmex 1.1 if @$cstack;;
210    
211     } else {
212    
213 root 1.5 my $pick = $::MAINWIN->get_pick;
214 elmex 1.1 my $as = $map->get ($x, $y);
215    
216     my $arch = { _name => $pick->{_name} };
217    
218 elmex 1.6 $self->stack_action ($as, $arch);
219     $map->change_stack ($x, $y, $as); # insert_arch_stack_layer ($as, $arch));
220 elmex 1.2 # push @$as, $arch
221     # unless @$as && $as->[-1]->{_name} eq $arch->{_name};
222 elmex 1.1
223 elmex 1.2 #$map->set ($x, $y, $as);
224 elmex 1.1 }
225     }
226    
227 elmex 1.6 sub stack_action {
228     my ($self, $stack, $arch) = @_;
229    
230 elmex 1.7 my $m = $self->get_mode;
231 elmex 1.6
232     if ($m eq 'top') {
233     if (@$stack == 0 or $stack->[-1]->{_name} ne $arch->{_name}) {
234     push @$stack, $arch;
235     }
236    
237     } elsif ($m eq 'bottom') {
238     if (@$stack == 0 or $stack->[0]->{_name} ne $arch->{_name}) {
239     unshift @$stack, $arch;
240     }
241    
242     } elsif ($m eq 'above') {
243     my $fidx = stack_find_floor ($stack, 'from_top');
244    
245     if (@$stack == 0
246     or not ($stack->[$fidx + 1])
247     or $stack->[$fidx + 1]->{_name} ne $arch->{_name})
248     {
249     splice (@$stack, $fidx + 1, 0, $arch);
250     }
251    
252     } elsif ($m eq 'below') {
253     my $fidx = stack_find_floor ($stack, 'from_bottom');
254    
255     if (@$stack == 0
256     or $fidx == 0
257     or not ($stack->[$fidx - 1])
258     or $stack->[$fidx - 1]->{_name} ne $arch->{_name})
259     {
260     splice (@$stack, $fidx, 0, $arch);
261     }
262    
263     } elsif ($m eq 'auto') {
264     my $fidx = stack_find_floor ($stack, 'from_top');
265     my $widx = stack_find_wall ($stack);
266    
267     if (arch_is_floor ($arch)) { # we want to place a floor tile
268    
269     if (arch_is_floor ($stack->[$fidx])) { # replace
270     $stack->[$fidx] = $arch;
271    
272     } else { # insert on bottom
273     unshift @$stack, $arch;
274     }
275    
276     } elsif (arch_is_wall ($arch)) { # we want to place a wall
277    
278     if (arch_is_wall ($stack->[$widx])) { # replace
279     $stack->[$widx] = $arch;
280    
281     } else { # insert above floor
282     splice (@$stack, $fidx + 1, 0, $arch);
283     }
284    
285     } else {
286    
287     if (arch_is_wall ($stack->[$widx])) {
288 elmex 1.9 # if we have a wall above the floor, replace it with the to place item
289     $stack->[$widx] = $arch;
290 elmex 1.6 return;
291     }
292    
293     if (@$stack == 0
294     or not ($stack->[-1])
295     or $stack->[-1]->{_name} ne $arch->{_name})
296     {
297     push @$stack, $arch;
298     }
299     }
300     }
301     }
302    
303 elmex 1.1 package GCE::EditAction::Erase;
304 elmex 1.7 use GCE::Util;
305     use Gtk2;
306     use strict;
307 elmex 1.1
308 elmex 1.7 our @ISA = qw/GCE::EditAction::RadioModed/;
309 elmex 1.1
310     sub want_cursor { 0 }
311    
312 elmex 1.7 sub init {
313     my ($self) = @_;
314    
315     my $vb = new Gtk2::VBox;
316     $self->add_mode_button ($vb, "top", "top");
317     $self->add_mode_button ($vb, "walls", "walls");
318     $self->add_mode_button ($vb, "above floor", "above", 'default');
319     $self->add_mode_button ($vb, "floor", "floor");
320     $self->add_mode_button ($vb, "below floor", "below");
321     $self->add_mode_button ($vb, "bottom", "bottom");
322     $self->add_mode_button ($vb, "pick match", "match");
323    
324     $self->tool_widget ($vb);
325    
326     $vb->pack_start ($self->{no_wall_check} = Gtk2::CheckButton->new ("exclude walls"), 0, 1, 0);
327     $vb->pack_start ($self->{no_monsters_check} = Gtk2::CheckButton->new ("exclude monsters"), 0, 1, 0);
328     }
329    
330     sub check_excluded {
331     my ($self, $arch) = @_;
332    
333     my $a1 = $self->{no_monsters_check}->get_active;
334     my $a2 = $self->{no_wall_check}->get_active;
335    
336     my $r = ($self->{no_wall_check}->get_active && arch_is_wall ($arch))
337     || ($self->{no_monsters_check}->get_active && arch_is_monster ($arch));
338     return $r;
339     }
340    
341 elmex 1.1 sub begin {
342     my ($self, $map, $x, $y, $btn) = @_;
343    
344 root 1.3 $self->SUPER::begin ($map, $x, $y, $btn);
345 elmex 1.1 $self->edit ($map, $x, $y, $btn);
346     }
347    
348     sub edit {
349     my ($self, $map, $x, $y, $btn) = @_;
350    
351     my $as = $map->get ($x, $y);
352 elmex 1.7 $self->stack_action ($as);
353 root 1.3 $map->change_stack ($x, $y, $as);
354 elmex 1.1 }
355    
356 elmex 1.7 sub stack_action {
357     my ($self, $stack) = @_;
358    
359     my $m = $self->get_mode;
360    
361     if ($m eq 'top') {
362     pop @$stack;
363    
364     } elsif ($m eq 'bottom') {
365     shift @$stack;
366    
367     } elsif ($m eq 'above') {
368     my $fidx = stack_find_floor ($stack, 'from_top');
369    
370     if (arch_is_floor ($stack->[$fidx]) and $stack->[$fidx + 1]) {
371     splice (@$stack, $fidx + 1, 1)
372     unless $self->check_excluded ($stack->[$fidx + 1])
373    
374     } elsif (not arch_is_floor ($stack->[$fidx])) {
375     splice (@$stack, $fidx, 1)
376     unless $self->check_excluded ($stack->[$fidx])
377    
378     }
379    
380     } elsif ($m eq 'below') {
381     my $fidx = stack_find_floor ($stack, 'from_bottom');
382    
383     if ($fidx > 0 and not arch_is_floor ($stack->[$fidx - 1])) {
384     splice (@$stack, $fidx - 1, 1)
385     unless $self->check_excluded ($stack->[$fidx - 1])
386    
387     } elsif (not arch_is_floor ($stack->[$fidx])) { # no floor found
388     splice (@$stack, $fidx, 1)
389     unless $self->check_excluded ($stack->[$fidx])
390    
391     }
392    
393     } elsif ($m eq 'walls') {
394     my $widx = stack_find_wall ($stack, 'from_top');
395    
396     while (arch_is_wall ($stack->[$widx])) {
397     splice (@$stack, $widx, 1);
398     $widx = stack_find_wall ($stack, 'from_top')
399     }
400    
401     } elsif ($m eq 'floor') {
402     my $fidx = stack_find_floor ($stack, 'from_top');
403    
404     while (arch_is_floor ($stack->[$fidx])) {
405     splice (@$stack, $fidx, 1);
406     $fidx = stack_find_floor ($stack, 'from_top')
407     }
408    
409     } elsif ($m eq 'match') {
410     my $pick_name = $::MAINWIN->get_pick ()->{_name};
411     my $idx = stack_find ($stack, 'from_top', sub { $_[0]->{_name} eq $pick_name });
412    
413     while ($stack->[$idx] and $stack->[$idx]->{_name} eq $pick_name) {
414     splice (@$stack, $idx, 1);
415     $idx = stack_find ($stack, 'from_top', sub { $_[0]->{_name} eq $pick_name });
416     }
417     }
418     }
419    
420    
421    
422 elmex 1.1 =head1 AUTHOR
423    
424     Marc Lehmann <schmorp@schmorp.de>
425     http://home.schmorp.de/
426    
427     Robin Redeker <elmex@ta-sa.org>
428     http://www.ta-sa.org/
429    
430     =cut
431 root 1.5
432     1
433 elmex 1.1