ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/deliantra/gde/GCE/MapEditor.pm
Revision: 1.50
Committed: Wed Feb 7 09:18:21 2007 UTC (17 years, 4 months ago) by elmex
Branch: MAIN
CVS Tags: rel-2_0
Changes since 1.49: +3 -1 lines
Log Message:
fixed bug with map property settings.

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