ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/deliantra/gde/GCE/MapEditor.pm
Revision: 1.18
Committed: Sun Mar 12 23:32:58 2006 UTC (18 years, 3 months ago) by elmex
Branch: MAIN
Changes since 1.17: +11 -4 lines
Log Message:
implemented file->new and implemented attredit

File Contents

# Content
1 package GCE::MapEditor;
2
3 =head1 NAME
4
5 GCE::MapEditor - the map editing widget
6
7 =cut
8
9 use Gtk2;
10 use Gtk2::Gdk::Keysyms;
11 use Gtk2::SimpleMenu;
12
13 use Crossfire;
14 use Crossfire::Map;
15 use Crossfire::MapWidget;
16
17 use GCE::AttrEdit;
18
19 use Glib::Object::Subclass
20 Gtk2::Window;
21
22 use strict;
23
24 sub build_menu {
25 my ($self) = @_;
26
27 my $menu_tree = [
28 _File => {
29 item_type => '<Branch>',
30 children => [
31 "_Save" => {
32 callback => sub { $self->save_map },
33 accelerator => '<ctrl>S'
34 },
35 "Save As" => {
36 callback => sub { $self->save_map_as },
37 },
38 "Close" => {
39 callback => sub { $self->delete; 1 },
40 },
41 ]
42 },
43 _Edit => {
44 item_type => '<Branch>',
45 children => [
46 "_Undo" => {
47 callback => sub { $self->undo },
48 accelerator => "<ctrl>Z"
49 },
50 "_Redo" => {
51 callback => sub { $self->redo },
52 accelerator => "<ctrl>Y"
53 },
54 "_Map Properties" => {
55 callback => sub { $self->open_map_prop },
56 accelerator => "<ctrl>P"
57 },
58 "_Map Resize" => {
59 callback => sub { $self->open_resize_map },
60 accelerator => "<ctrl>R"
61 },
62 ]
63 },
64
65 ];
66
67 my $men =
68 Gtk2::SimpleMenu->new (
69 menu_tree => $menu_tree,
70 default_callback => \&default_cb,
71 );
72
73 $self->add_accel_group ($men->{accel_group});
74
75 return $men->{widget};
76 }
77
78 sub INIT_INSTANCE {
79 my ($self) = @_;
80
81 $self->set_title ('gce - map editor');
82 $self->add (my $vb = Gtk2::VBox->new);
83
84 $self->signal_connect (delete_event => sub { $self->delete });
85
86 $vb->pack_start (my $menu = $self->build_menu, 0, 1, 0);
87
88 $vb->pack_start (my $map = $self->{map} = Crossfire::MapWidget->new, 1, 1, 0);
89
90 $map->signal_connect (button_press_event => sub {
91 my ($map, $event) = @_;
92
93 my ($x, $y) = $map->coord ($event->x, $event->y);
94 my $as = $map->get ($x, $y);
95
96 my $btn = $event->button;
97
98 if ((not $self->{draw_mode})
99 and $btn != 2
100 and my $ea = $::MAINWIN->{sel_editaction}) {
101
102 $ea->begin ($map, $x, $y, $btn)
103 if $x >= 0 and $y >= 0 and $x < $map->{map}{width} and $y < $map->{map}{height};
104
105 $self->{draw_mode} = [$ea, $x, $y, $btn];
106
107 $ea->want_cursor
108 or $map->disable_tooltip;
109
110 if ($ea->special_arrow) {
111
112 $map->{window}->set_cursor (Gtk2::Gdk::Cursor->new ($ea->special_arrow));
113 #'GDK_QUESTION_ARROW'));
114 }
115
116 return 1;
117 }
118
119 0
120 });
121
122 $map->signal_connect_after (motion_notify_event => sub {
123 my ($map, $event) = @_;
124
125 $self->{draw_mode}
126 or return;
127
128 my ($X, $Y) = @{$self->{draw_mode}}[1,2];
129 my ($x, $y) = $map->coord ($map->get_pointer);
130
131 while ($x != $X || $y != $Y) {
132
133 $X++ if $X < $x;
134 $X-- if $X > $x;
135 $Y++ if $Y < $y;
136 $Y-- if $Y > $y;
137
138 $self->{draw_mode}[0]->edit ($map, $X, $Y, $self->{draw_mode}[3])
139 if $X >= 0 and $Y >= 0 and $X < $map->{map}{width} and $Y < $map->{map}{height};
140 }
141
142 @{$self->{draw_mode}}[1,2] = ($X, $Y);
143
144 1
145 });
146
147 $map->signal_connect (button_release_event => sub {
148 my ($map, $event) = @_;
149
150 if ($self->{draw_mode}
151 and my $ea = $self->{draw_mode}[0]
152 and $self->{draw_mode}[3] == $event->button) {
153
154 my ($x, $y) = $map->coord ($map->get_pointer);
155
156 $ea->end ($map, $x, $y, $event->button);
157
158 if ($ea->special_arrow) {
159
160 # XXX: Get the original cursor and insert it here
161 $map->{window}->set_cursor (Gtk2::Gdk::Cursor->new ('GDK_LEFT_PTR'));
162 }
163
164 delete $self->{draw_mode};
165
166 $ea->want_cursor
167 or $map->enable_tooltip;
168
169 return 1;
170 }
171
172 0
173 });
174 }
175
176 # FIXME: Fix the automatic update of the attribute editor! and also the stack view!
177 sub undo {
178 my ($self) = @_;
179
180 my $map = $self->{map}; # the Crossfire::MapWidget
181
182 $map->{undo_stack_pos}
183 or return;
184
185 $map->change_swap ($map->{undo_stack}[--$map->{undo_stack_pos}]);
186 }
187
188 sub redo {
189 my ($self) = @_;
190
191 my $map = $self->{map}; # the Crossfire::MapWidget
192
193 $map->{undo_stack}
194 and $map->{undo_stack_pos} < @{$map->{undo_stack}}
195 or return;
196
197 $map->change_swap ($map->{undo_stack}[$map->{undo_stack_pos}++]);
198 }
199
200 sub delete_arch {
201 my ($self, $x, $y) = @_;
202
203 defined $self->{map}
204 or return 0;
205
206 my $as = $self->{map}->get ($x, $y);
207 pop @$as;
208 $self->{map}->set ($x, $y, $as);
209 }
210
211 sub place_pick {
212 my ($self, $x, $y) = @_;
213
214 my $pick = $::MAINWIN->get_pick;
215 my $as = $self->{map}->get ($x, $y);
216
217 my $arch = { _name => $pick->{_name} };
218
219 push @$as, $arch
220 unless @$as && $as->[-1]->{_name} eq $arch->{_name};
221
222 $self->{map}->set ($x, $y, $as);
223 }
224
225 sub delete {
226 my ($self) = @_;
227
228 # check and modla dialog if "dirty"
229
230 $self->destroy;
231 }
232
233 sub open_map {
234 my ($self, $path) = @_;
235
236 if (ref $path) {
237 print "REFE\n";
238 $self->{map}->set_map ($path);
239 print "UNREF\n";
240
241 } else {
242 $self->{path} = $path;
243 # print "OPENMAP $path\n";
244 $self->{map}->set_map (my $m = new_from_file Crossfire::Map $path);
245 require Data::Dumper;
246 # print "FOO:" .Data::Dumper::Dumper ($m) . "\n";
247 }
248 }
249
250 sub save_map {
251 my ($self) = @_;
252
253 $self->{map}{map}->write_file ($self->{path});
254 }
255
256 sub save_map_as {
257 my ($self) = @_;
258 warn "save_map_as nyi\n";
259 }
260
261 sub _add_prop_entry {
262 my ($self, $table, $idx, $key, $desc, $type, $changecb) = @_;
263
264
265 my $edwid;
266
267 if ($type eq 'string') {
268 $table->attach_defaults (my $lbl = Gtk2::Label->new ($desc), 0, 1, $idx, $idx + 1);
269 $edwid = Gtk2::Entry->new;
270 $edwid->set_text ($self->{map}{map}{info}{$key});
271 $edwid->signal_connect (changed => sub {
272 $self->{map}{map}{info}{$key} = $_[0]->get_text;
273 if ($changecb) {
274 print "CHANGECB " . $_[0]->get_text . "\n";
275 $changecb->($_[0]->get_text);
276 }
277 });
278 $table->attach_defaults ($edwid, 1, 2, $idx, $idx + 1);
279
280 } elsif ($type eq 'button') {
281 $table->attach_defaults (my $b = Gtk2::Button->new_with_label ($desc), 0, 2, $idx, $idx + 1);
282 $b->signal_connect (clicked => ($changecb || sub {}));
283
284 } elsif ($type eq 'label') {
285 $table->attach_defaults (my $lbl = Gtk2::Label->new ($desc), 0, 1, $idx, $idx + 1);
286 $edwid = Gtk2::Label->new ($self->{map}{map}{info}{$key});
287 $table->attach_defaults ($edwid, 1, 2, $idx, $idx + 1);
288
289 } else {
290 $edwid = Gtk2::Label->new ("FOO");
291 }
292 }
293
294 sub open_resize_map {
295 my ($self) = @_;
296
297 my $w = Gtk2::Window->new ('toplevel');
298 $w->set_default_size (250, 150);
299 $w->add (my $sw = Gtk2::ScrolledWindow->new);
300 $sw->add_with_viewport (my $v = Gtk2::VBox->new);
301 $sw->set_policy ('automatic', 'automatic');
302 $v->pack_start (my $t = Gtk2::Table->new (2, 10), 0, 0, 0);
303
304 my $i = 0;
305 for (
306 [qw/width Width string/],
307 [qw/height Height string/],
308 [qw/save Save button/,
309 sub {
310 $self->{map}{map}->resize ($self->{map}{map}{info}{width}, $self->{map}{map}{info}{height});
311 $self->{map}->invalidate_all
312 }
313 ],
314 )
315 {
316 $self->_add_prop_entry ($t, $i++, @$_);
317 }
318
319 $w->show_all;
320 }
321
322 sub open_map_prop {
323 my ($self) = @_;
324
325
326 my $w = Gtk2::Window->new ('toplevel');
327 $w->set_default_size (500, 500);
328 $w->add (my $sw = Gtk2::ScrolledWindow->new);
329 $sw->add_with_viewport (my $v = Gtk2::VBox->new);
330 $sw->set_policy ('automatic', 'automatic');
331 $v->pack_start (my $t = Gtk2::Table->new (2, 10), 0, 0, 0);
332
333 my $i = 0;
334 for (
335 [qw/name Name string/],
336 [qw/region Region string/],
337 [qw/difficulty Difficulty string/],
338 [qw/width Width label/], # sub { $self->{map}{map}->resize ($_[0], $self->{map}{map}{height}) }],
339 [qw/height Height label/],# sub { $self->{map}{map}->resize ($self->{map}{map}{width}, $_[0]) }],
340 [qw/msg Text text/],
341 [qw/tile_path_1 Northpath string/],
342 [qw/tile_path_2 Eastpath string/],
343 [qw/tile_path_3 Southpath string/],
344 [qw/tile_path_4 Westpath string/],
345 [qw/tile_path_5 Toppath string/],
346 [qw/tile_path_6 Bottompath string/],
347 )
348 {
349 $self->_add_prop_entry ($t, $i++, @$_);
350 }
351
352 $w->show_all;
353 }
354
355 # 'info' => {
356 # 'windspeed' => '10',
357 # 'outdoor' => '1',
358 # 'width' => '20',
359 # 'pressure' => '8',
360 # 'test' => '',
361 # 'tile_path_2' => 'east',
362 # 'tile_path_3' => 'south',
363 # 'enter_y' => '2',
364 # 'tile_path_6' => 'bottom',
365 # 'enter_x' => '1',
366 # 'tile_path_5' => 'top',
367 # 'darkness' => '4',
368 # 'maplore' => '',
369 # 'sky' => '12',
370 # 'winddir' => '11',
371 # 'unique' => '1',
372 # 'msg' => 'Creator: CF Java FUCK Map Editor
373 #Date: 3/12/2006
374 #',
375 # 'difficulty' => '3',
376 # 'humid' => '9',
377 # 'endmaplore' => '',
378 # 'fixed_resettime' => '1',
379 # 'name' => 'test',
380 # 'region' => 'REGION',
381 # 'height' => '40',
382 # 'reset_timeout' => '6',
383 # '_name' => 'map',
384 # 'swap_time' => '5',
385 # 'temp' => '7',
386 # 'tile_path_4' => 'west',
387 # 'tile_path_1' => 'north'
388 # },
389
390
391 =head1 AUTHOR
392
393 Marc Lehmann <schmorp@schmorp.de>
394 http://home.schmorp.de/
395
396 Robin Redeker <elmex@ta-sa.org>
397 http://www.ta-sa.org/
398
399 =cut
400 1;
401