ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/deliantra/gde/GCE/EditAction.pm
Revision: 1.6
Committed: Fri Mar 10 20:32:47 2006 UTC (18 years, 3 months ago) by elmex
Branch: MAIN
Changes since 1.5: +126 -1 lines
Log Message:
implemented edit tools widgets and improved the placement tool

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 strict;
17
18 sub new {
19 my $class = shift;
20 my $self = { @_ };
21 bless $self, $class;
22 $self->init;
23 return $self;
24 }
25
26
27 sub tool_widget { }
28 sub init { }
29
30 sub want_cursor { 1 }
31
32 sub special_arrow { }
33
34 # edits one tile of the map
35 sub edit_one {
36 my ($self, $x, $y) = @_;
37 # do one edition
38 }
39
40 # edits a selection
41 sub edit_selection {
42 }
43
44 # abstraction for edit_one and edit_selection ?
45 # takes selection if present
46 sub edit {
47 my ($self, $map, $x, $y, $btn) = @_;
48 }
49
50 sub begin {
51 my ($self, $map, $x, $y, $btn) = @_;
52
53 $map->change_begin (ref $self);
54 }
55
56 sub end {
57 my ($self, $map) = @_;
58
59 if (my $changeset = $map->change_end) {
60 splice @{ $map->{undo_stack} ||= [] },
61 $map->{undo_stack_pos}++, 1e6,
62 $changeset;
63
64 #TODO: limit undo stack size to some preconfigured limit
65 }
66 }
67
68
69 package GCE::EditAction::Pick;
70
71 our @ISA = qw/GCE::EditAction/;
72
73 sub special_arrow { 'GDK_HAND2' }
74
75 sub begin {
76 my ($self, $map, $x, $y, $btn) = @_;
77
78 $self->SUPER::begin ($map, $x, $y, $btn);
79 $self->edit ($map, $x, $y, $btn);
80 }
81
82 sub edit {
83 my ($self, $map, $x, $y, $btn) = @_;
84
85 my $cstack = $map->get ($x, $y);
86
87 my $arch = $cstack->[-1];
88
89 # virtual... grmbl....
90 # FIXME: I have to patch the stack of the real arch??? argl.. how??
91 if ($arch->{_virtual}) {
92 $x = $arch->{virtual_x};
93 $y = $arch->{virtual_y};
94 $arch = $arch->{_virtual};
95 $cstack = $map->get ($x, $y);
96 }
97
98 $::MAINWIN->set_pick ($arch)
99 if @$cstack && $btn == 1;
100
101 $::MAINWIN->update_attr_editor ($arch, sub {
102 my ($arch) = @_;
103 print "UPD: $arch\n"; #d#
104
105 $map->change_stack ($x, $y, $cstack);
106 });
107
108 $::MAINWIN->update_stack_view ($map, $x, $y);
109 }
110
111 package GCE::EditAction::Place;
112
113 use GCE::Util;
114 use Gtk2;
115 use strict;
116
117 our @ISA = qw/GCE::EditAction/;
118
119 sub _add_mode_button {
120 my ($self, $vb, $lbl, $mode) = @_;
121
122 $vb->pack_start (my $b = Gtk2::RadioButton->new ($self->{place_radio_grp}, $lbl), 0, 1, 0);
123 unless (defined $self->{place_radio_grp}) {
124 $self->{place_radio_grp} = $b->get_group;
125 $b->set_active (1);
126 $self->set_place_mode ($mode);
127 }
128 $b->signal_connect (clicked => sub {
129 $self->set_place_mode ($mode);
130 });
131 }
132
133 sub set_place_mode {
134 my ($self, $mode) = @_;
135 $self->{place_mode} = $mode;
136 }
137
138 sub init {
139 my ($self) = @_;
140
141 my $vb = new Gtk2::VBox;
142 $self->_add_mode_button ($vb, "auto", "auto");
143 $self->_add_mode_button ($vb, "top", "top");
144 $self->_add_mode_button ($vb, "above floor", "above");
145 $self->_add_mode_button ($vb, "below floor", "below");
146 $self->_add_mode_button ($vb, "bottom", "bottom");
147
148 $self->{widget} = $vb;
149 }
150
151 sub tool_widget {
152 my ($self) = @_;
153 return $self->{widget};
154 }
155
156 sub want_cursor { 0 }
157
158 sub begin {
159 my ($self, $map, $x, $y, $btn) = @_;
160
161 $self->SUPER::begin ($map, $x, $y, $btn);
162 $self->edit ($map, $x, $y, $btn);
163 }
164
165 sub edit {
166 my ($self, $map, $x, $y, $btn) = @_;
167
168 if ($btn == 3) { # btn 3 does pick
169
170 my $cstack = $map->get ($x, $y) or return;
171 my $arch = $cstack->[-1];
172
173 $arch->{_virtual}
174 and $arch = $arch->{_virtual};
175
176 $::MAINWIN->set_pick ($arch)
177 if @$cstack;;
178
179 } else {
180
181 my $pick = $::MAINWIN->get_pick;
182 my $as = $map->get ($x, $y);
183
184 my $arch = { _name => $pick->{_name} };
185
186 $self->stack_action ($as, $arch);
187 $map->change_stack ($x, $y, $as); # insert_arch_stack_layer ($as, $arch));
188 # push @$as, $arch
189 # unless @$as && $as->[-1]->{_name} eq $arch->{_name};
190
191 #$map->set ($x, $y, $as);
192 }
193 }
194
195 sub stack_action {
196 my ($self, $stack, $arch) = @_;
197
198 my $m = $self->{place_mode};
199
200 if ($m eq 'top') {
201 if (@$stack == 0 or $stack->[-1]->{_name} ne $arch->{_name}) {
202 push @$stack, $arch;
203 }
204
205 } elsif ($m eq 'bottom') {
206 if (@$stack == 0 or $stack->[0]->{_name} ne $arch->{_name}) {
207 unshift @$stack, $arch;
208 }
209
210 } elsif ($m eq 'above') {
211 my $fidx = stack_find_floor ($stack, 'from_top');
212
213 if (@$stack == 0
214 or not ($stack->[$fidx + 1])
215 or $stack->[$fidx + 1]->{_name} ne $arch->{_name})
216 {
217 splice (@$stack, $fidx + 1, 0, $arch);
218 }
219
220 } elsif ($m eq 'below') {
221 my $fidx = stack_find_floor ($stack, 'from_bottom');
222
223 if (@$stack == 0
224 or $fidx == 0
225 or not ($stack->[$fidx - 1])
226 or $stack->[$fidx - 1]->{_name} ne $arch->{_name})
227 {
228 splice (@$stack, $fidx, 0, $arch);
229 }
230
231 } elsif ($m eq 'auto') {
232 my $fidx = stack_find_floor ($stack, 'from_top');
233 my $widx = stack_find_wall ($stack);
234
235 if (arch_is_floor ($arch)) { # we want to place a floor tile
236
237 if (arch_is_floor ($stack->[$fidx])) { # replace
238 $stack->[$fidx] = $arch;
239
240 } else { # insert on bottom
241 unshift @$stack, $arch;
242 }
243
244 } elsif (arch_is_wall ($arch)) { # we want to place a wall
245
246 if (arch_is_wall ($stack->[$widx])) { # replace
247 $stack->[$widx] = $arch;
248
249 } else { # insert above floor
250 splice (@$stack, $fidx + 1, 0, $arch);
251 }
252
253 } else {
254
255 if (arch_is_wall ($stack->[$widx])) {
256 # if we have a wall above the floor, we don't want to place anything
257 # on that tile anymore
258 return;
259 }
260
261 if (@$stack == 0
262 or not ($stack->[-1])
263 or $stack->[-1]->{_name} ne $arch->{_name})
264 {
265 push @$stack, $arch;
266 }
267 }
268 }
269 }
270
271 package GCE::EditAction::Erase;
272
273 our @ISA = qw/GCE::EditAction/;
274
275 sub want_cursor { 0 }
276
277 sub begin {
278 my ($self, $map, $x, $y, $btn) = @_;
279
280 $self->SUPER::begin ($map, $x, $y, $btn);
281 $self->edit ($map, $x, $y, $btn);
282 }
283
284 sub edit {
285 my ($self, $map, $x, $y, $btn) = @_;
286
287 my $as = $map->get ($x, $y);
288 pop @$as;
289 $map->change_stack ($x, $y, $as);
290 }
291
292 =head1 AUTHOR
293
294 Marc Lehmann <schmorp@schmorp.de>
295 http://home.schmorp.de/
296
297 Robin Redeker <elmex@ta-sa.org>
298 http://www.ta-sa.org/
299
300 =cut
301
302 1
303