ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/deliantra/gde/GCE/MapEditor.pm
Revision: 1.46
Committed: Thu Dec 7 20:30:25 2006 UTC (17 years, 6 months ago) by root
Branch: MAIN
Changes since 1.45: +2 -3 lines
Log Message:
*** empty log message ***

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