ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/deliantra/gde/GCE/MapEditor.pm
Revision: 1.58
Committed: Sun Aug 19 22:27:55 2007 UTC (16 years, 9 months ago) by elmex
Branch: MAIN
Changes since 1.57: +3 -2 lines
Log Message:
map resize problem is now hopefully fixed

File Contents

# User Rev Content
1 elmex 1.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 root 1.3 use Crossfire::Map;
15 elmex 1.1 use Crossfire::MapWidget;
16    
17     use GCE::AttrEdit;
18 elmex 1.22 use GCE::Util;
19 elmex 1.44 use GCE::HashDialog;
20 elmex 1.1
21 elmex 1.49 use POSIX qw/strftime/;
22    
23 elmex 1.4 use Glib::Object::Subclass
24 elmex 1.6 Gtk2::Window;
25 elmex 1.1
26 elmex 1.45 use Storable qw/dclone/;
27    
28 elmex 1.1 use strict;
29    
30 elmex 1.44 #################################################################
31     ###### WINDOW MANAGEMENT ########################################
32     #################################################################
33    
34     sub save_layout {
35     my ($self) = @_;
36    
37     $self->{attach_editor}->save_layout if $self->{attach_editor};
38     $self->{map_properties}->save_layout if $self->{map_properties};
39     $self->{meta_info_win}->save_layout if $self->{meta_info_win};
40 elmex 1.49
41     $main::CFG->{map_info} = main::get_pos_and_size ($self->{map_info})
42     if $self->{map_info};
43 elmex 1.44 }
44    
45     sub close_windows {
46     my ($self) = @_;
47    
48     $self->{attach_editor}->destroy if $self->{attach_editor};
49     $self->{map_properties}->destroy if $self->{map_properties};
50     $self->{meta_info_win}->destroy if $self->{meta_info_win};
51     }
52    
53     #################################################################
54     ###### MENU MANAGEMENT ##########################################
55     #################################################################
56    
57 elmex 1.35 sub do_context_menu {
58     my ($self, $map, $event) = @_;
59    
60     my ($x, $y) = $map->coord ($event->x, $event->y);
61    
62     my $menu = Gtk2::Menu->new;
63     foreach my $cm (
64     [
65     Follow => sub {
66 elmex 1.36 $::MAINWIN->{edit_collection}{followexit}->edit ($map, $x, $y, $self)
67 elmex 1.38 },
68 elmex 1.35 ]
69     ) {
70     my $item = Gtk2::MenuItem->new ($cm->[0]);
71     $menu->append ($item);
72     $item->show;
73     $item->signal_connect (activate => $cm->[1]);
74     }
75 elmex 1.38
76 elmex 1.47 $menu->append (my $sep = new Gtk2::SeparatorMenuItem);
77     $sep->show;
78 elmex 1.38
79     for my $sr (reverse $self->get_stack_refs ($map, $x, $y)) {
80     my $item = Gtk2::MenuItem->new ($sr->longname);
81 elmex 1.47 $menu->append ($item);
82     $item->set_submenu (my $smenu = new Gtk2::Menu);
83    
84     for my $act (
85     [ 'Add inventory' => sub { $_[0]->add_inv ($::MAINWIN->get_pick) } ],
86     [ 'Find in picker' => sub { $::MAINWIN->open_pick_window ({ selection => $sr->picker_folder }) } ],
87     ) {
88     my $sitem = Gtk2::MenuItem->new ($act->[0]);
89     $smenu->append ($sitem);
90     $sitem->signal_connect (activate => sub { $act->[1]->($sr) });
91     $sitem->show;
92     }
93    
94 elmex 1.38 $item->show;
95     }
96    
97 elmex 1.35 $menu->popup (undef, undef, undef, undef, $event->button, $event->time);
98     }
99    
100 root 1.9 sub build_menu {
101     my ($self) = @_;
102    
103     my $menu_tree = [
104     _File => {
105     item_type => '<Branch>',
106     children => [
107     "_Save" => {
108 root 1.10 callback => sub { $self->save_map },
109 root 1.9 accelerator => '<ctrl>S'
110     },
111 root 1.10 "Save As" => {
112     callback => sub { $self->save_map_as },
113     },
114 elmex 1.49 "Map _Info" => {
115     callback => sub { $self->open_map_info },
116     accelerator => "<ctrl>I",
117     },
118 elmex 1.42 "Map _Properties" => {
119 elmex 1.32 callback => sub { $self->open_map_prop },
120     accelerator => "<ctrl>P"
121     },
122 elmex 1.42 "Map _Attachments" => {
123     callback => sub { $self->open_attach_edit },
124     accelerator => "<ctrl>A"
125     },
126 elmex 1.44 "Map Meta _Info" => {
127     callback => sub { $self->open_meta_info },
128     },
129 elmex 1.45 Upload => {
130     item_type => '<Branch>',
131     children => [
132     "Upload for testing" => {
133     callback => sub { $self->upload_map_test },
134     },
135     "Upload for inclusion" => {
136     callback => sub { $self->upload_map_incl },
137     },
138     ]
139     },
140 elmex 1.32 "_Map Resize" => {
141     callback => sub { $self->open_resize_map },
142     },
143 root 1.13 "Close" => {
144 elmex 1.31 callback => sub { $self->destroy },
145 root 1.13 },
146 root 1.10 ]
147 root 1.9 },
148     _Edit => {
149     item_type => '<Branch>',
150     children => [
151     "_Undo" => {
152     callback => sub { $self->undo },
153 elmex 1.17 accelerator => "<ctrl>Z"
154 root 1.9 },
155     "_Redo" => {
156     callback => sub { $self->redo },
157 elmex 1.17 accelerator => "<ctrl>Y"
158     },
159 root 1.9 ]
160     },
161 elmex 1.27 _Go => {
162     item_type => '<Branch>',
163     children => [
164     "_Up" => {
165     callback => sub { $self->follow ('u') },
166 elmex 1.33 accelerator => "<ctrl>Up"
167 elmex 1.27 },
168     "_Down" => {
169     callback => sub { $self->follow ('d') },
170 elmex 1.33 accelerator => "<ctrl>Down"
171 elmex 1.27 },
172     "_Right" => {
173     callback => sub { $self->follow ('r') },
174 elmex 1.33 accelerator => "<ctrl>Right"
175 elmex 1.27 },
176     "_Left" => {
177     callback => sub { $self->follow ('l') },
178 elmex 1.33 accelerator => "<ctrl>Left"
179 elmex 1.27 },
180     ]
181     },
182 elmex 1.29 _Help => {
183     item_type => '<Branch>',
184     children => [
185 elmex 1.30 _Manual => {
186 elmex 1.29 callback => sub { $::MAINWIN->show_help_window },
187     accelerator => "<ctrl>H"
188     },
189     ]
190     },
191 root 1.9 ];
192    
193     my $men =
194     Gtk2::SimpleMenu->new (
195     menu_tree => $menu_tree,
196     default_callback => \&default_cb,
197     );
198    
199 elmex 1.23 for (
200     [i => 'pick'],
201     [p => 'place'],
202 elmex 1.24 [e => 'erase'],
203     [s => 'select'],
204     [l => 'eval'],
205 elmex 1.37 [t => 'connect'],
206 elmex 1.24 [f => 'followexit']
207 elmex 1.23 )
208     {
209 elmex 1.24 my $tool = $_->[1];
210 elmex 1.23 $men->{accel_group}->connect ($Gtk2::Gdk::Keysyms{$_->[0]}, [], 'visible',
211 elmex 1.24 sub { $::MAINWIN->set_edit_tool ($tool) });
212 elmex 1.23 }
213    
214 elmex 1.39 $men->{accel_group}->connect ($Gtk2::Gdk::Keysyms{'r'}, ['control-mask'], 'visible',
215     sub { $self->redo });
216    
217 root 1.9 $self->add_accel_group ($men->{accel_group});
218    
219     return $men->{widget};
220     }
221    
222 elmex 1.44 #################################################################
223     ###### EDIT TOOL STUFF ##########################################
224     #################################################################
225    
226 elmex 1.31 sub set_edit_tool {
227     my ($self, $tool) = @_;
228    
229     $self->{etool} = $tool;
230    
231     if ($self->ea->special_arrow) {
232     $self->{map}{window}->set_cursor (Gtk2::Gdk::Cursor->new ($self->ea->special_arrow));
233 elmex 1.34 } else {
234     # FIXME: Get the original cursor and insert it here
235     $self->{map}{window}->set_cursor (Gtk2::Gdk::Cursor->new ('GDK_LEFT_PTR'));
236 elmex 1.31 }
237     }
238    
239 elmex 1.19 sub ea {
240     my ($self) = @_;
241 elmex 1.31 $self->{ea_alt} || $self->{etool};
242 elmex 1.19 }
243    
244 elmex 1.34 sub start_drawmode {
245     my ($self, $map) = @_;
246    
247     $self->{draw_mode} and return;
248    
249     # XXX: is this okay? my ($x, $y) = $map->coord ($event->x, $event->y);
250     my ($x, $y) = $map->coord ($map->get_pointer);
251    
252     my $ea = $self->ea;
253    
254 elmex 1.36 $ea->begin ($map, $x, $y, $self);
255    
256     $ea->edit ($map, $x, $y, $self)
257 elmex 1.34 if $x >= 0 and $y >= 0 and $x < $map->{map}{width} and $y < $map->{map}{height};
258    
259     $self->{draw_mode} = [$x, $y];
260     }
261    
262     sub stop_drawmode {
263     my ($self, $map) = @_;
264    
265     $self->{draw_mode} or return;
266    
267     my ($x, $y) = $map->coord ($map->get_pointer);
268    
269     my $ea = $self->ea;
270     $ea->end ($map, $x, $y, $self);
271    
272     delete $self->{draw_mode};
273     }
274    
275 elmex 1.44 #################################################################
276     ###### UTILITY FUNCTIONS ########################################
277     #################################################################
278    
279     sub follow {
280     my ($self, $dir) = @_;
281    
282     my %dir_to_path = (
283     u => 'tile_path_1',
284     d => 'tile_path_3',
285     r => 'tile_path_2',
286     l => 'tile_path_4',
287     );
288    
289     defined $dir_to_path{$dir}
290     or return;
291     my $map = $self->{map}{map}{info}{$dir_to_path{$dir}}
292     or return;
293    
294     $map = map2abs ($map, $self);
295     $::MAINWIN->open_map_editor ($map);
296     }
297    
298 elmex 1.16 # FIXME: Fix the automatic update of the attribute editor! and also the stack view!
299 root 1.9 sub undo {
300     my ($self) = @_;
301 elmex 1.8
302 root 1.9 my $map = $self->{map}; # the Crossfire::MapWidget
303 elmex 1.1
304 root 1.9 $map->{undo_stack_pos}
305     or return;
306 elmex 1.1
307 root 1.9 $map->change_swap ($map->{undo_stack}[--$map->{undo_stack_pos}]);
308     }
309 elmex 1.1
310 elmex 1.38 sub get_stack_refs {
311     my ($self, $map, $x, $y) = @_;
312    
313     my $cstack = $map->get ($x, $y);
314    
315     return [] unless @$cstack;
316    
317     my @refs;
318    
319     for my $arch (@$cstack) {
320     my ($ox, $oy) = ($x, $y);
321     if ($arch->{_virtual}) {
322     $ox = $arch->{virtual_x};
323     $oy = $arch->{virtual_y};
324     $arch = $arch->{_virtual};
325     $cstack = $map->get ($ox, $oy);
326     # XXX: This heavily blows up if $arch isn't on $cstack now.. and it actually really does :(
327     }
328    
329     push @refs,
330     GCE::ArchRef->new (
331     arch => $arch,
332 elmex 1.56 source => 'map',
333 elmex 1.38 cb => sub {
334     $map->change_begin ('attredit');
335     $map->change_stack ($ox, $oy, $cstack);
336    
337     if (my $changeset = $map->change_end) {
338     splice @{ $map->{undo_stack} ||= [] },
339     $map->{undo_stack_pos}++, 1e6,
340     $changeset;
341     }
342     }
343     );
344     }
345    
346     return @refs;
347     }
348    
349 root 1.9 sub redo {
350     my ($self) = @_;
351 elmex 1.7
352 root 1.9 my $map = $self->{map}; # the Crossfire::MapWidget
353 elmex 1.7
354 elmex 1.14 $map->{undo_stack}
355     and $map->{undo_stack_pos} < @{$map->{undo_stack}}
356     or return;
357 elmex 1.1
358 root 1.9 $map->change_swap ($map->{undo_stack}[$map->{undo_stack_pos}++]);
359 root 1.3 }
360    
361 elmex 1.43 sub load_meta_info {
362     my ($mapfile) = @_;
363     if (-e "$mapfile.meta") {
364     open my $metafh, "<", "$mapfile.meta"
365     or warn "Couldn't open meta file $mapfile.meta: $!";
366     my $metadata = do { local $/; <$metafh> };
367     return Crossfire::from_json ($metadata);
368     }
369     }
370    
371     sub save_meta_info {
372     my ($mapfile, $metainfo) = @_;
373     open my $metafh, ">", "$mapfile.meta"
374     or warn "Couldn't write meta file $mapfile.meta: $!";
375     print $metafh Crossfire::to_json ($metainfo);
376     }
377    
378 root 1.3 sub open_map {
379 elmex 1.26 my ($self, $path, $key) = @_;
380    
381     $self->{mapkey} = $key;
382 root 1.3
383 elmex 1.18 if (ref $path) {
384     $self->{map}->set_map ($path);
385 elmex 1.43 delete $self->{meta_info};
386 elmex 1.39 $self->set_title ('<ram>');
387 elmex 1.18
388     } else {
389 elmex 1.51 my $ok = 0;
390 elmex 1.52 if (-e $path && -f $path) {
391     $ok = 1;
392     } else {
393 elmex 1.51 unless ($path =~ m/\.map$/) { # yuck
394     my $p = $path . '.map';
395     if ($ok = -e $p && -f $p) {
396     $path = $p;
397     }
398     }
399     }
400     unless ($ok) {
401 elmex 1.52 die "Couldn't open '$path' or find '$path.map': No such file or it is not a file.\n";
402 elmex 1.48 }
403 elmex 1.18 $self->{path} = $path;
404     $self->{map}->set_map (my $m = new_from_file Crossfire::Map $path);
405 elmex 1.43 $self->{meta_info} = load_meta_info ($path);
406 elmex 1.39 $self->set_title ("gce - map editor - $self->{path}");
407 elmex 1.18 }
408 elmex 1.44 $self->close_windows;
409 root 1.3 }
410    
411 root 1.13 sub save_map {
412     my ($self) = @_;
413    
414 elmex 1.19 if ($self->{path}) {
415     $self->{map}{map}->write_file ($self->{path});
416 elmex 1.43 if ($self->{meta_info}) {
417     save_meta_info ($self->{path}, $self->{meta_info});
418     }
419 elmex 1.22 quick_msg ($self, "saved to $self->{path}");
420 elmex 1.39 $self->set_title ("gce - map editor - $self->{path}");
421 elmex 1.22 } else {
422     $self->save_map_as;
423 elmex 1.19 }
424 root 1.13 }
425    
426     sub save_map_as {
427     my ($self) = @_;
428 elmex 1.19
429 elmex 1.22 my $fc = $::MAINWIN->new_filechooser ('gce - save map', 1, $self->{path});
430 elmex 1.19
431     if ('ok' eq $fc->run) {
432    
433     $::MAINWIN->{fc_last_folder} = $fc->get_current_folder;
434     $::MAINWIN->{fc_last_folders}->{$self->{fc_last_folder}}++;
435    
436     $self->{map}{map}->write_file ($self->{path} = $fc->get_filename);
437 elmex 1.43 if ($self->{meta_info}) {
438     save_meta_info ($self->{path}, $self->{meta_info});
439     }
440 elmex 1.22 quick_msg ($self, "saved to $self->{path}");
441 elmex 1.39 $self->set_title ("gce - map editor - $self->{path}");
442 elmex 1.19 }
443    
444     $fc->destroy;
445 root 1.13 }
446    
447 elmex 1.44 #################################################################
448     ###### DIALOGOUES ###############################################
449     #################################################################
450 elmex 1.17
451     sub open_resize_map {
452     my ($self) = @_;
453    
454 elmex 1.44 return if $self->{meta_info_win};
455 elmex 1.17
456 elmex 1.44 my $w = $self->{meta_info_win} = GCE::HashDialogue->new ();
457 elmex 1.17
458 elmex 1.44 $w->init (
459     dialog_default_size => [500, 200, 220, 20],
460     layout_name => 'resize_win',
461     title => 'resize map',
462     ref_hash => $self->{map}{map}{info},
463     dialog => [
464     [width => 'Width' => 'string'],
465     [height => 'Height' => 'string'],
466     ],
467 elmex 1.58 close_on_save => 1,
468     save_button_label => 'resize',
469 elmex 1.44 save_cb => sub {
470     my ($info) = @_;
471     $self->{map}{map}->resize ($info->{width}, $info->{height});
472 elmex 1.58 $self->{map}->set_map ($self->{map}{map});
473 elmex 1.44 }
474 elmex 1.27 );
475    
476 elmex 1.44 $w->signal_connect (destroy => sub { delete $self->{meta_info_win} });
477 elmex 1.27
478 elmex 1.44 $w->show_all;
479 elmex 1.27 }
480    
481 elmex 1.42 sub open_attach_edit {
482     my ($self) = @_;
483    
484     my $w = GCE::AttachEditor->new;
485     $w->set_attachment (
486     $self->{map}{map}{info}{attach},
487     sub {
488     if (@{$_[0]}) {
489     $self->{map}{map}{info}{attach} = $_[0]
490     } else {
491     delete $self->{map}{map}{info}{attach};
492     }
493     }
494     );
495     $self->{attach_editor} = $w;
496     $w->signal_connect (destroy => sub { delete $self->{attach_editor} });
497     $w->show_all;
498     }
499    
500 elmex 1.45 sub upload_map_incl {
501     my ($self) = @_;
502    
503     my $meta = dclone $self->{meta_info};
504    
505     my $w = $self->{meta_info_win} = GCE::HashDialogue->new ();
506    
507     $w->init (
508     dialog_default_size => [500, 300, 220, 20],
509     layout_name => 'map_upload_incl',
510     title => 'gce - map inclusion upload',
511     ref_hash => $meta,
512     text_entry => { key => 'changes', label => 'Changes (required for inclusion):' },
513     dialog => [
514     [gameserver => 'Game server' => 'label'],
515     [testserver => 'Test server' => 'label'],
516     [undef => x => 'sep' ],
517     [cf_login => 'Server login name' => 'string'],
518     [cf_password=> 'Password' => 'password'],
519     [path => 'Map path' => 'string'],
520     ],
521 elmex 1.50 close_on_save => 1,
522 elmex 1.45 save_cb => sub {
523     my ($meta) = @_;
524     warn "UPLOAD[".Crossfire::to_json ($meta)."]\n";
525     }
526     );
527    
528     $w->signal_connect (destroy => sub { delete $self->{meta_info_win} });
529    
530     $w->show_all;
531     }
532    
533     sub upload_map_test {
534     my ($self) = @_;
535    
536     my $meta = dclone $self->{meta_info};
537    
538     my $w = $self->{meta_info_win} = GCE::HashDialogue->new ();
539    
540     $w->init (
541     dialog_default_size => [500, 300, 220, 20],
542     layout_name => 'map_upload_test',
543     title => 'gce - map test upload',
544     ref_hash => $meta,
545     dialog => [
546     [gameserver => 'Game server' => 'string'],
547     [testserver => 'Test server' => 'string'],
548     [undef => x => 'sep' ],
549     [cf_login => 'Server login name' => 'string'],
550     [cf_password=> 'Password' => 'password'],
551     [path => 'Map path' => 'string'],
552     ],
553     save_cb => sub {
554     my ($meta) = @_;
555     warn "UPLOAD[".Crossfire::to_json ($meta)."]\n";
556     }
557     );
558    
559     $w->signal_connect (destroy => sub { delete $self->{meta_info_win} });
560    
561     $w->show_all;
562    
563    
564     }
565 elmex 1.44
566     sub open_meta_info {
567 elmex 1.42 my ($self) = @_;
568    
569 elmex 1.44 return if $self->{meta_info_win};
570    
571     my $w = $self->{meta_info_win} = GCE::HashDialogue->new ();
572    
573     $w->init (
574     dialog_default_size => [500, 300, 220, 20],
575     layout_name => 'meta_info_win',
576     title => 'meta info',
577     ref_hash => $self->{meta_info},
578     dialog => [
579     [path => 'Map path' => 'string'],
580     [cf_login => 'Login name' => 'string'],
581     [revision => 'CVS Revision' => 'label'],
582     [cvs_root => 'CVS Root' => 'label'],
583     [lib_root => 'LIB Root' => 'label'],
584     [testserver => 'Test server' => 'label'],
585     [gameserver => 'Game server' => 'label'],
586     ],
587     );
588    
589     $w->signal_connect (destroy => sub { delete $self->{meta_info_win} });
590    
591     $w->show_all;
592 elmex 1.42 }
593    
594 elmex 1.49 sub open_map_info {
595     my ($self) = @_;
596     return if $self->{map_info};
597    
598     my $w = $self->{map_info} = Gtk2::Window->new ('toplevel');
599     $w->set_title ("gcrossedit - map info");
600    
601     $w->add (my $vb = Gtk2::VBox->new);
602     $vb->add (my $sw = Gtk2::ScrolledWindow->new);
603     $sw->set_policy ('automatic', 'automatic');
604     $sw->add (my $txt = Gtk2::TextView->new);
605     $vb->pack_start (my $hb = Gtk2::HBox->new (1, 1), 0, 1, 0);
606     $hb->pack_start (my $svbtn = Gtk2::Button->new ("save"), 1, 1, 0);
607     $hb->pack_start (my $logbtn = Gtk2::Button->new ("add log"), 1, 1, 0);
608     $hb->pack_start (my $closebtn = Gtk2::Button->new ("close"), 1, 1, 0);
609    
610     my $buf = $txt->get_buffer ();
611     $buf->set_text ($self->{map}{map}{info}{msg});
612    
613     $svbtn->signal_connect (clicked => sub {
614     my $buf = $txt->get_buffer ();
615     my $txt = $buf->get_text ($buf->get_start_iter, $buf->get_end_iter, 0);
616     $self->{map}{map}{info}{msg} = $txt;
617     });
618    
619     $logbtn->signal_connect (clicked => sub {
620     my $buf = $txt->get_buffer ();
621     $buf->insert ($buf->get_start_iter, "- " . strftime ("%F %T %Z", localtime (time)) . " by " . ($main::CFG->{username} || $ENV{USER}) . ":\n");
622     $txt->set_buffer ($buf);
623     });
624    
625     $closebtn->signal_connect (clicked => sub {
626     $w->destroy;
627     });
628    
629     ::set_pos_and_size ($w, $main::CFG->{map_info}, 400, 400, 220, 20);
630     $w->signal_connect (destroy => sub {
631     delete $self->{map_info};
632     });
633     $w->show_all;
634     }
635    
636 elmex 1.17 sub open_map_prop {
637     my ($self) = @_;
638    
639 elmex 1.42 return if $self->{map_properties};
640    
641 elmex 1.44 my $w = $self->{map_properties} = GCE::HashDialogue->new ();
642 elmex 1.17
643 elmex 1.44 $w->init (
644     dialog_default_size => [500, 500, 220, 20],
645     layout_name => 'map_prop_win',
646     title => 'map properties',
647     ref_hash => $self->{map}{map}{info},
648 elmex 1.50 close_on_save => 1,
649 elmex 1.44 dialog => [
650 elmex 1.27 [qw/name Name string/],
651     [qw/region Region string/],
652     [qw/enter_x Enter-x string/],
653     [qw/enter_y Enter-y string/],
654     [qw/reset_timeout Reset-timeout string/],
655     [qw/swap_time Swap-timeout string/],
656 elmex 1.44 [undef, qw/x sep/],
657 elmex 1.27 [qw/difficulty Difficulty string/],
658     [qw/windspeed Windspeed string/],
659     [qw/pressure Pressure string/],
660     [qw/humid Humid string/],
661     [qw/temp Temp string/],
662     [qw/darkness Darkness string/],
663     [qw/sky Sky string/],
664     [qw/winddir Winddir string/],
665 elmex 1.44 [undef, qw/x sep/],
666 elmex 1.27 [qw/width Width label/], # sub { $self->{map}{map}->resize ($_[0], $self->{map}{map}{height}) }],
667     [qw/height Height label/], # sub { $self->{map}{map}->resize ($self->{map}{map}{width}, $_[0]) }],
668 elmex 1.44 [undef, qw/x sep/],
669     # [qw/msg Text text/],
670     # [qw/maplore Maplore text/],
671 elmex 1.27 [qw/outdoor Outdoor check/],
672     [qw/unique Unique check/],
673     [qw/fixed_resettime Fixed-resettime check/],
674 elmex 1.55 [per_player => 'Per player' => 'check'],
675     [per_party => 'Per party' => 'check'],
676 elmex 1.54 [no_reset => 'No reset' => 'check'],
677 elmex 1.57 [music => 'Map Music' => 'string'],
678 elmex 1.44 [undef, qw/x sep/],
679 elmex 1.27 [qw/tile_path_1 Northpath string/],
680     [qw/tile_path_2 Eastpath string/],
681     [qw/tile_path_3 Southpath string/],
682     [qw/tile_path_4 Westpath string/],
683     [qw/tile_path_5 Toppath string/],
684     [qw/tile_path_6 Bottompath string/],
685 elmex 1.44 [undef, qw/x sep/],
686     [undef, 'For shop description look in the manual',
687     'button', sub { $::MAINWIN->show_help_window }],
688 elmex 1.39 [qw/shopmin Shopmin string/],
689     [qw/shopmax Shopmax string/],
690     [qw/shoprace Shoprace string/],
691     [qw/shopgreed Shopgreed string/],
692     [qw/shopitems Shopitems string/],
693 elmex 1.44 ]
694     );
695 elmex 1.17
696 elmex 1.44 $w->signal_connect (destroy => sub { delete $self->{map_properties} });
697 elmex 1.17 $w->show_all;
698     }
699    
700 elmex 1.44 #################################################################
701     ###### MAP EDITOR INIT ##########################################
702     #################################################################
703    
704     sub INIT_INSTANCE {
705     my ($self) = @_;
706    
707     $self->set_title ('gce - map editor');
708     $self->add (my $vb = Gtk2::VBox->new);
709    
710     $vb->pack_start (my $menu = $self->build_menu, 0, 1, 0);
711    
712     $vb->pack_start (my $map = $self->{map} = Crossfire::MapWidget->new, 1, 1, 0);
713    
714     $map->signal_connect_after (key_press_event => sub {
715     my ($map, $event) = @_;
716    
717     my $kv = $event->keyval;
718    
719     my $ret = 0;
720    
721     my ($x, $y) = $map->coord ($map->get_pointer);
722     for ([Control_L => sub { $self->{ea_alt} = $::MAINWIN->{edit_collection}{erase} }],
723     [Alt_L => sub { $self->{ea_alt} = $::MAINWIN->{edit_collection}{pick} }],
724     [c => sub { $::MAINWIN->{edit_collection}{select}->copy }],
725     [v => sub { $::MAINWIN->{edit_collection}{select}->paste ($map, $x, $y) }],
726     [n => sub { $::MAINWIN->{edit_collection}{select}->invoke }],
727     )
728     {
729     my $ed = $_;
730    
731     if ($kv == $Gtk2::Gdk::Keysyms{$ed->[0]}) {
732     my $was_in_draw = defined $self->{draw_mode};
733    
734     $self->stop_drawmode ($map)
735     if $was_in_draw && grep { $ed->[0] eq $_ } qw/Control_L Alt_L/;
736    
737     $ed->[1]->();
738     $ret = 1;
739    
740     $self->start_drawmode ($map)
741     if $was_in_draw && grep { $ed->[0] eq $_ } qw/Control_L Alt_L/;
742     }
743     }
744    
745     if ($self->ea->special_arrow) {
746     $map->{window}->set_cursor (Gtk2::Gdk::Cursor->new ($self->ea->special_arrow));
747     } else {
748     # FIXME: Get the original cursor and insert it here
749     $map->{window}->set_cursor (Gtk2::Gdk::Cursor->new ('GDK_LEFT_PTR'));
750     }
751    
752     $ret
753     });
754    
755     $map->signal_connect_after (key_release_event => sub {
756     my ($map, $event) = @_;
757    
758     my $ret = 0;
759    
760     if ($event->keyval == $Gtk2::Gdk::Keysyms{Control_L}
761     or $event->keyval == $Gtk2::Gdk::Keysyms{Alt_L})
762     {
763     my $was_in_draw = defined $self->{draw_mode};
764    
765     $self->stop_drawmode ($map)
766     if $was_in_draw;
767    
768     delete $self->{ea_alt};
769     $ret = 1;
770    
771     $self->start_drawmode ($map)
772     if $was_in_draw;
773     }
774    
775     if ($self->ea->special_arrow) {
776     $map->{window}->set_cursor (Gtk2::Gdk::Cursor->new ($self->ea->special_arrow));
777     } else {
778     # FIXME: Get the original cursor and insert it here
779     $map->{window}->set_cursor (Gtk2::Gdk::Cursor->new ('GDK_LEFT_PTR'));
780     }
781    
782     $ret
783     });
784     $map->signal_connect_after (button_press_event => sub {
785     my ($map, $event) = @_;
786    
787     if ((not $self->{draw_mode}) and $event->button == 1) {
788     my $ea = $self->ea;
789    
790     $self->start_drawmode ($map);
791    
792     $ea->want_cursor
793     or $map->disable_tooltip;
794    
795     return 1;
796     } elsif ($event->button == 3) {
797     $self->do_context_menu ($map, $event);
798     return 1;
799     }
800    
801     0
802     });
803    
804     $map->signal_connect_after (motion_notify_event => sub {
805     my ($map, $event) = @_;
806    
807     $self->{draw_mode}
808     or return;
809    
810     my $ea = $self->ea;
811    
812     my ($X, $Y) = @{$self->{draw_mode}}[0,1];
813     my ($x, $y) = $map->coord ($map->get_pointer);
814    
815     while ($x != $X || $y != $Y) {
816    
817     $X++ if $X < $x;
818     $X-- if $X > $x;
819     $Y++ if $Y < $y;
820     $Y-- if $Y > $y;
821    
822     unless ($ea->only_on_click) {
823     $ea->edit ($map, $X, $Y, $self)
824     if $X >= 0 and $Y >= 0 and $X < $map->{map}{width} and $Y < $map->{map}{height};
825     }
826     }
827    
828     @{$self->{draw_mode}}[0,1] = ($X, $Y);
829    
830     1
831     });
832    
833     $map->signal_connect_after (button_release_event => sub {
834     my ($map, $event) = @_;
835    
836     if ($self->{draw_mode} and $event->button == 1) {
837     my $ea = $self->ea;
838    
839     $self->stop_drawmode ($map);
840    
841     $ea->want_cursor
842     or $map->enable_tooltip;
843    
844     return 1;
845     }
846    
847     0
848     });
849    
850     ::set_pos_and_size ($self, $main::CFG->{map_window}, 500, 500, 200, 0);
851     }
852    
853 elmex 1.1 =head1 AUTHOR
854    
855     Marc Lehmann <schmorp@schmorp.de>
856     http://home.schmorp.de/
857    
858     Robin Redeker <elmex@ta-sa.org>
859     http://www.ta-sa.org/
860    
861     =cut
862 root 1.46
863     1
864 elmex 1.1