ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/deliantra/gde/GCE/EditAction.pm
Revision: 1.7
Committed: Sun Mar 12 12:18:55 2006 UTC (18 years, 3 months ago) by elmex
Branch: MAIN
Changes since 1.6: +161 -36 lines
Log Message:
Implemented first parts of the new attribute 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.6 my ($arch) = @_;
154     print "UPD: $arch\n"; #d#
155    
156 root 1.3 $map->change_stack ($x, $y, $cstack);
157 elmex 1.1 });
158    
159 root 1.5 $::MAINWIN->update_stack_view ($map, $x, $y);
160 elmex 1.1 }
161    
162     package GCE::EditAction::Place;
163    
164 elmex 1.2 use GCE::Util;
165 elmex 1.6 use Gtk2;
166     use strict;
167 elmex 1.2
168 elmex 1.7 our @ISA = qw/GCE::EditAction::RadioModed/;
169 elmex 1.6
170     sub init {
171     my ($self) = @_;
172    
173     my $vb = new Gtk2::VBox;
174 elmex 1.7 $self->add_mode_button ($vb, "auto", "auto");
175     $self->add_mode_button ($vb, "top", "top");
176     $self->add_mode_button ($vb, "above floor", "above");
177     $self->add_mode_button ($vb, "below floor", "below");
178     $self->add_mode_button ($vb, "bottom", "bottom");
179 elmex 1.6
180 elmex 1.7 $self->tool_widget ($vb);
181 elmex 1.6 }
182    
183 elmex 1.1 sub want_cursor { 0 }
184    
185     sub begin {
186     my ($self, $map, $x, $y, $btn) = @_;
187    
188 root 1.3 $self->SUPER::begin ($map, $x, $y, $btn);
189 elmex 1.1 $self->edit ($map, $x, $y, $btn);
190     }
191    
192     sub edit {
193     my ($self, $map, $x, $y, $btn) = @_;
194    
195     if ($btn == 3) { # btn 3 does pick
196    
197     my $cstack = $map->get ($x, $y) or return;
198 root 1.3 my $arch = $cstack->[-1];
199 elmex 1.1
200     $arch->{_virtual}
201     and $arch = $arch->{_virtual};
202    
203 root 1.5 $::MAINWIN->set_pick ($arch)
204 elmex 1.1 if @$cstack;;
205    
206     } else {
207    
208 root 1.5 my $pick = $::MAINWIN->get_pick;
209 elmex 1.1 my $as = $map->get ($x, $y);
210    
211     my $arch = { _name => $pick->{_name} };
212    
213 elmex 1.6 $self->stack_action ($as, $arch);
214     $map->change_stack ($x, $y, $as); # insert_arch_stack_layer ($as, $arch));
215 elmex 1.2 # push @$as, $arch
216     # unless @$as && $as->[-1]->{_name} eq $arch->{_name};
217 elmex 1.1
218 elmex 1.2 #$map->set ($x, $y, $as);
219 elmex 1.1 }
220     }
221    
222 elmex 1.6 sub stack_action {
223     my ($self, $stack, $arch) = @_;
224    
225 elmex 1.7 my $m = $self->get_mode;
226 elmex 1.6
227     if ($m eq 'top') {
228     if (@$stack == 0 or $stack->[-1]->{_name} ne $arch->{_name}) {
229     push @$stack, $arch;
230     }
231    
232     } elsif ($m eq 'bottom') {
233     if (@$stack == 0 or $stack->[0]->{_name} ne $arch->{_name}) {
234     unshift @$stack, $arch;
235     }
236    
237     } elsif ($m eq 'above') {
238     my $fidx = stack_find_floor ($stack, 'from_top');
239    
240     if (@$stack == 0
241     or not ($stack->[$fidx + 1])
242     or $stack->[$fidx + 1]->{_name} ne $arch->{_name})
243     {
244     splice (@$stack, $fidx + 1, 0, $arch);
245     }
246    
247     } elsif ($m eq 'below') {
248     my $fidx = stack_find_floor ($stack, 'from_bottom');
249    
250     if (@$stack == 0
251     or $fidx == 0
252     or not ($stack->[$fidx - 1])
253     or $stack->[$fidx - 1]->{_name} ne $arch->{_name})
254     {
255     splice (@$stack, $fidx, 0, $arch);
256     }
257    
258     } elsif ($m eq 'auto') {
259     my $fidx = stack_find_floor ($stack, 'from_top');
260     my $widx = stack_find_wall ($stack);
261    
262     if (arch_is_floor ($arch)) { # we want to place a floor tile
263    
264     if (arch_is_floor ($stack->[$fidx])) { # replace
265     $stack->[$fidx] = $arch;
266    
267     } else { # insert on bottom
268     unshift @$stack, $arch;
269     }
270    
271     } elsif (arch_is_wall ($arch)) { # we want to place a wall
272    
273     if (arch_is_wall ($stack->[$widx])) { # replace
274     $stack->[$widx] = $arch;
275    
276     } else { # insert above floor
277     splice (@$stack, $fidx + 1, 0, $arch);
278     }
279    
280     } else {
281    
282     if (arch_is_wall ($stack->[$widx])) {
283     # if we have a wall above the floor, we don't want to place anything
284     # on that tile anymore
285     return;
286     }
287    
288     if (@$stack == 0
289     or not ($stack->[-1])
290     or $stack->[-1]->{_name} ne $arch->{_name})
291     {
292     push @$stack, $arch;
293     }
294     }
295     }
296     }
297    
298 elmex 1.1 package GCE::EditAction::Erase;
299 elmex 1.7 use GCE::Util;
300     use Gtk2;
301     use strict;
302 elmex 1.1
303 elmex 1.7 our @ISA = qw/GCE::EditAction::RadioModed/;
304 elmex 1.1
305     sub want_cursor { 0 }
306    
307 elmex 1.7 sub init {
308     my ($self) = @_;
309    
310     my $vb = new Gtk2::VBox;
311     $self->add_mode_button ($vb, "top", "top");
312     $self->add_mode_button ($vb, "walls", "walls");
313     $self->add_mode_button ($vb, "above floor", "above", 'default');
314     $self->add_mode_button ($vb, "floor", "floor");
315     $self->add_mode_button ($vb, "below floor", "below");
316     $self->add_mode_button ($vb, "bottom", "bottom");
317     $self->add_mode_button ($vb, "pick match", "match");
318    
319     $self->tool_widget ($vb);
320    
321     $vb->pack_start ($self->{no_wall_check} = Gtk2::CheckButton->new ("exclude walls"), 0, 1, 0);
322     $vb->pack_start ($self->{no_monsters_check} = Gtk2::CheckButton->new ("exclude monsters"), 0, 1, 0);
323     }
324    
325     sub check_excluded {
326     my ($self, $arch) = @_;
327    
328     my $a1 = $self->{no_monsters_check}->get_active;
329     my $a2 = $self->{no_wall_check}->get_active;
330    
331     my $r = ($self->{no_wall_check}->get_active && arch_is_wall ($arch))
332     || ($self->{no_monsters_check}->get_active && arch_is_monster ($arch));
333     return $r;
334     }
335    
336 elmex 1.1 sub begin {
337     my ($self, $map, $x, $y, $btn) = @_;
338    
339 root 1.3 $self->SUPER::begin ($map, $x, $y, $btn);
340 elmex 1.1 $self->edit ($map, $x, $y, $btn);
341     }
342    
343     sub edit {
344     my ($self, $map, $x, $y, $btn) = @_;
345    
346     my $as = $map->get ($x, $y);
347 elmex 1.7 $self->stack_action ($as);
348 root 1.3 $map->change_stack ($x, $y, $as);
349 elmex 1.1 }
350    
351 elmex 1.7 sub stack_action {
352     my ($self, $stack) = @_;
353    
354     my $m = $self->get_mode;
355    
356     if ($m eq 'top') {
357     pop @$stack;
358    
359     } elsif ($m eq 'bottom') {
360     shift @$stack;
361    
362     } elsif ($m eq 'above') {
363     my $fidx = stack_find_floor ($stack, 'from_top');
364    
365     if (arch_is_floor ($stack->[$fidx]) and $stack->[$fidx + 1]) {
366     splice (@$stack, $fidx + 1, 1)
367     unless $self->check_excluded ($stack->[$fidx + 1])
368    
369     } elsif (not arch_is_floor ($stack->[$fidx])) {
370     splice (@$stack, $fidx, 1)
371     unless $self->check_excluded ($stack->[$fidx])
372    
373     }
374    
375     } elsif ($m eq 'below') {
376     my $fidx = stack_find_floor ($stack, 'from_bottom');
377    
378     if ($fidx > 0 and not arch_is_floor ($stack->[$fidx - 1])) {
379     splice (@$stack, $fidx - 1, 1)
380     unless $self->check_excluded ($stack->[$fidx - 1])
381    
382     } elsif (not arch_is_floor ($stack->[$fidx])) { # no floor found
383     splice (@$stack, $fidx, 1)
384     unless $self->check_excluded ($stack->[$fidx])
385    
386     }
387    
388     } elsif ($m eq 'walls') {
389     my $widx = stack_find_wall ($stack, 'from_top');
390    
391     while (arch_is_wall ($stack->[$widx])) {
392     splice (@$stack, $widx, 1);
393     $widx = stack_find_wall ($stack, 'from_top')
394     }
395    
396     } elsif ($m eq 'floor') {
397     my $fidx = stack_find_floor ($stack, 'from_top');
398    
399     while (arch_is_floor ($stack->[$fidx])) {
400     splice (@$stack, $fidx, 1);
401     $fidx = stack_find_floor ($stack, 'from_top')
402     }
403    
404     } elsif ($m eq 'match') {
405     my $pick_name = $::MAINWIN->get_pick ()->{_name};
406     my $idx = stack_find ($stack, 'from_top', sub { $_[0]->{_name} eq $pick_name });
407    
408     while ($stack->[$idx] and $stack->[$idx]->{_name} eq $pick_name) {
409     splice (@$stack, $idx, 1);
410     $idx = stack_find ($stack, 'from_top', sub { $_[0]->{_name} eq $pick_name });
411     }
412     }
413     }
414    
415    
416    
417 elmex 1.1 =head1 AUTHOR
418    
419     Marc Lehmann <schmorp@schmorp.de>
420     http://home.schmorp.de/
421    
422     Robin Redeker <elmex@ta-sa.org>
423     http://www.ta-sa.org/
424    
425     =cut
426 root 1.5
427     1
428 elmex 1.1