ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/deliantra/gde/GCE/MapEditor.pm
Revision: 1.48
Committed: Fri Jan 5 13:38:07 2007 UTC (17 years, 5 months ago) by elmex
Branch: MAIN
Changes since 1.47: +3 -1 lines
Log Message:
improved error handling a bit when opening maps.

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