… | |
… | |
140 | "_Map Resize" => { |
140 | "_Map Resize" => { |
141 | callback => sub { $self->open_resize_map }, |
141 | callback => sub { $self->open_resize_map }, |
142 | }, |
142 | }, |
143 | "Close" => { |
143 | "Close" => { |
144 | callback => sub { $self->destroy }, |
144 | callback => sub { $self->destroy }, |
|
|
145 | accelerator => "<ctrl>W", |
145 | }, |
146 | }, |
146 | ] |
147 | ] |
147 | }, |
148 | }, |
148 | _Edit => { |
149 | _Edit => { |
149 | item_type => '<Branch>', |
150 | item_type => '<Branch>', |
… | |
… | |
303 | |
304 | |
304 | $map->{undo_stack_pos} |
305 | $map->{undo_stack_pos} |
305 | or return; |
306 | or return; |
306 | |
307 | |
307 | $map->change_swap ($map->{undo_stack}[--$map->{undo_stack_pos}]); |
308 | $map->change_swap ($map->{undo_stack}[--$map->{undo_stack_pos}]); |
|
|
309 | |
|
|
310 | $::MAINWIN->update_stack_view (); |
308 | } |
311 | } |
309 | |
312 | |
310 | sub get_stack_refs { |
313 | sub get_stack_refs { |
311 | my ($self, $map, $x, $y) = @_; |
314 | my ($self, $map, $x, $y) = @_; |
312 | |
315 | |
… | |
… | |
315 | return [] unless @$cstack; |
318 | return [] unless @$cstack; |
316 | |
319 | |
317 | my @refs; |
320 | my @refs; |
318 | |
321 | |
319 | for my $arch (@$cstack) { |
322 | for my $arch (@$cstack) { |
320 | my ($ox, $oy) = ($x, $y); |
323 | my ($ix, $iy, $iarch, $istack) = devirtualize ($map, $x, $y, $arch, $cstack); |
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, |
324 | push @refs, |
330 | GCE::ArchRef->new ( |
325 | GCE::ArchRef->new ( |
331 | arch => $arch, |
326 | arch => $iarch, |
332 | source => 'map', |
327 | source => 'map', |
333 | cb => sub { |
328 | cb => sub { |
334 | $map->change_begin ('attredit'); |
329 | $map->change_begin ('attredit'); |
335 | $map->change_stack ($ox, $oy, $cstack); |
330 | $map->change_stack ($ix, $iy, $istack); |
336 | |
331 | |
337 | if (my $changeset = $map->change_end) { |
332 | if (my $changeset = $map->change_end) { |
338 | splice @{ $map->{undo_stack} ||= [] }, |
333 | splice @{ $map->{undo_stack} ||= [] }, |
339 | $map->{undo_stack_pos}++, 1e6, |
334 | $map->{undo_stack_pos}++, 1e6, |
340 | $changeset; |
335 | $changeset; |
… | |
… | |
381 | $self->{mapkey} = $key; |
376 | $self->{mapkey} = $key; |
382 | |
377 | |
383 | if (ref $path) { |
378 | if (ref $path) { |
384 | $self->{map}->set_map ($path); |
379 | $self->{map}->set_map ($path); |
385 | delete $self->{meta_info}; |
380 | delete $self->{meta_info}; |
386 | $self->set_title ('<ram>'); |
381 | $self->set_window_title; |
387 | |
382 | |
388 | } else { |
383 | } else { |
389 | my $ok = 0; |
384 | my $ok = 0; |
390 | if (-e $path && -f $path) { |
385 | if (-e $path && -f $path) { |
391 | $ok = 1; |
386 | $ok = 1; |
… | |
… | |
401 | die "Couldn't open '$path' or find '$path.map': No such file or it is not a file.\n"; |
396 | die "Couldn't open '$path' or find '$path.map': No such file or it is not a file.\n"; |
402 | } |
397 | } |
403 | $self->{path} = $path; |
398 | $self->{path} = $path; |
404 | $self->{map}->set_map (my $m = new_from_file Crossfire::Map $path); |
399 | $self->{map}->set_map (my $m = new_from_file Crossfire::Map $path); |
405 | $self->{meta_info} = load_meta_info ($path); |
400 | $self->{meta_info} = load_meta_info ($path); |
406 | $self->set_title ("gce - map editor - $self->{path}"); |
401 | $self->set_window_title ($self->{path}); |
|
|
402 | $::MAINWIN->add_recent($path); |
407 | } |
403 | } |
|
|
404 | $self->update_overlays; |
408 | $self->close_windows; |
405 | $self->close_windows; |
409 | } |
406 | } |
410 | |
407 | |
411 | sub save_map { |
408 | sub save_map { |
412 | my ($self) = @_; |
409 | my ($self) = @_; |
… | |
… | |
415 | $self->{map}{map}->write_file ($self->{path}); |
412 | $self->{map}{map}->write_file ($self->{path}); |
416 | if ($self->{meta_info}) { |
413 | if ($self->{meta_info}) { |
417 | save_meta_info ($self->{path}, $self->{meta_info}); |
414 | save_meta_info ($self->{path}, $self->{meta_info}); |
418 | } |
415 | } |
419 | quick_msg ($self, "saved to $self->{path}"); |
416 | quick_msg ($self, "saved to $self->{path}"); |
420 | $self->set_title ("gce - map editor - $self->{path}"); |
417 | $self->set_window_title ($self->{path}); |
|
|
418 | $::MAINWIN->add_recent($self->{path}); |
421 | } else { |
419 | } else { |
422 | $self->save_map_as; |
420 | $self->save_map_as; |
423 | } |
421 | } |
424 | } |
422 | } |
425 | |
423 | |
|
|
424 | sub set_window_title { |
|
|
425 | my ($self, $title) = @_; |
|
|
426 | |
|
|
427 | $title = 'Unsaved' |
|
|
428 | unless $title; |
|
|
429 | |
|
|
430 | $self->set_title(File::Basename::basename($title).' - gcrossedit'); |
|
|
431 | } |
|
|
432 | |
426 | sub save_map_as { |
433 | sub save_map_as { |
427 | my ($self) = @_; |
434 | my ($self) = @_; |
428 | |
435 | |
429 | my $fc = $::MAINWIN->new_filechooser ('gce - save map', 1, $self->{path}); |
436 | my $fc = $::MAINWIN->new_filechooser ('gce - save map', 1, $self->{path}); |
430 | |
437 | |
431 | if ('ok' eq $fc->run) { |
438 | if ('ok' eq $fc->run) { |
432 | |
439 | |
433 | $::MAINWIN->{fc_last_folder} = $fc->get_current_folder; |
440 | $::MAINWIN->{fc_last_folder} = $fc->get_current_folder; |
434 | $::MAINWIN->{fc_last_folders}->{$self->{fc_last_folder}}++; |
441 | $::MAINWIN->{fc_last_folders}->{$self->{fc_last_folder}}++; |
435 | |
442 | |
436 | $self->{map}{map}->write_file ($self->{path} = $fc->get_filename); |
443 | if($fc->get_filename) { |
437 | if ($self->{meta_info}) { |
444 | $self->{path} = $fc->get_filename; |
438 | save_meta_info ($self->{path}, $self->{meta_info}); |
445 | $self->save_map; |
439 | } |
446 | } |
440 | quick_msg ($self, "saved to $self->{path}"); |
|
|
441 | $self->set_title ("gce - map editor - $self->{path}"); |
|
|
442 | } |
447 | } |
443 | |
448 | |
444 | $fc->destroy; |
449 | $fc->destroy; |
|
|
450 | } |
|
|
451 | |
|
|
452 | sub _get_conns_for_obj { |
|
|
453 | my ($obj, $x, $y, $rconns) = @_; |
|
|
454 | |
|
|
455 | if (defined $obj->{connected}) { |
|
|
456 | $rconns->{$x}->{$y}->{$obj->{connected}} = 1; |
|
|
457 | |
|
|
458 | } elsif (defined $obj->{msg}) { |
|
|
459 | my $msg = $obj->{msg}; |
|
|
460 | |
|
|
461 | while ($msg =~ s/\@trigger\s+(\d+)//) { |
|
|
462 | $rconns->{$x}->{$y}->{$1} = 1; |
|
|
463 | } |
|
|
464 | } |
|
|
465 | } |
|
|
466 | |
|
|
467 | sub update_overlays { |
|
|
468 | my ($self, $sx, $sy, $stack) = @_; |
|
|
469 | my $conns = {}; |
|
|
470 | |
|
|
471 | if (not $stack) { |
|
|
472 | my ($w, $h) = ($self->{map}{map}{width}, $self->{map}{map}{height}); |
|
|
473 | |
|
|
474 | for (my $x = 0; $x < $w; $x++) { |
|
|
475 | for (my $y = 0; $y < $h; $y++) { |
|
|
476 | _get_conns_for_obj ($_, $x, $y, $conns) |
|
|
477 | for @{$self->{map}->get_ro ($x, $y)}; |
|
|
478 | } |
|
|
479 | } |
|
|
480 | |
|
|
481 | # delete prev. overlays |
|
|
482 | for (keys %{$self->{_conn_overlays}}) { |
|
|
483 | $self->{map}->overlay ($_); |
|
|
484 | } |
|
|
485 | } else { |
|
|
486 | # del old overlay for this place |
|
|
487 | my $ovl = "connection_$sx\_$sy"; |
|
|
488 | $self->{map}->overlay ($ovl) if delete $self->{_conn_overlays}->{$ovl}; |
|
|
489 | _get_conns_for_obj ($_, $sx, $sy, $conns) |
|
|
490 | for @$stack; |
|
|
491 | } |
|
|
492 | |
|
|
493 | # put new overlays there |
|
|
494 | for my $x (keys %$conns) { |
|
|
495 | for my $y (keys %{$conns->{$x}}) { |
|
|
496 | my $ovlname = "connection_$x\_$y"; |
|
|
497 | my $conns_ovl = join (', ', keys %{$conns->{$x}->{$y}}); |
|
|
498 | $self->{_conn_overlays}->{$ovlname} = 1; |
|
|
499 | my ($a, $t, $ac) |
|
|
500 | = Gtk2::Pango->parse_markup ( |
|
|
501 | "<span size=\"xx-small\">$conns_ovl</span>", '' |
|
|
502 | ); |
|
|
503 | my $pl = $self->{map}->create_pango_layout (''); |
|
|
504 | $pl->set_attributes ($a); |
|
|
505 | $pl->set_text ($t); |
|
|
506 | my ($ink_rect, $logical_rect) = $pl->get_pixel_extents; |
|
|
507 | |
|
|
508 | $self->{map}->overlay ( |
|
|
509 | $ovlname, $x * TILESIZE, $y * TILESIZE, TILESIZE, TILESIZE, |
|
|
510 | sub { |
|
|
511 | my ($mapwin, $x, $y) = @_; |
|
|
512 | if (!$self->{_conn_upd_ovl_gc_fg}) { |
|
|
513 | my $gc |
|
|
514 | = $self->{_conn_upd_ovl_gc_fg} |
|
|
515 | = Gtk2::Gdk::GC->new ($mapwin->{window}); |
|
|
516 | my $cm = $mapwin->{window}->get_colormap; |
|
|
517 | $gc->set_foreground (gtk2_get_color ($mapwin, "yellow")); |
|
|
518 | $gc->set_background (gtk2_get_color ($mapwin, "black")); |
|
|
519 | } |
|
|
520 | $mapwin->{window}->draw_rectangle ( |
|
|
521 | $mapwin->style->black_gc, |
|
|
522 | 1, |
|
|
523 | $x, $y, $logical_rect->{width} + 2, $logical_rect->{height} + 2, |
|
|
524 | ); |
|
|
525 | $mapwin->{window}->draw_rectangle ( |
|
|
526 | $self->{_conn_upd_ovl_gc_fg}, |
|
|
527 | 0, |
|
|
528 | $x, $y, $logical_rect->{width} + 2, $logical_rect->{height} + 2, |
|
|
529 | ); |
|
|
530 | $mapwin->{window}->draw_layout_with_colors ( |
|
|
531 | $mapwin->style->black_gc, $x + 1, $y + 1, $pl, |
|
|
532 | $self->{connection_overlay_foreground}, |
|
|
533 | $self->{connection_overlay_background}, |
|
|
534 | ) |
|
|
535 | } |
|
|
536 | ); |
|
|
537 | } |
|
|
538 | } |
445 | } |
539 | } |
446 | |
540 | |
447 | ################################################################# |
541 | ################################################################# |
448 | ###### DIALOGOUES ############################################### |
542 | ###### DIALOGOUES ############################################### |
449 | ################################################################# |
543 | ################################################################# |
… | |
… | |
462 | ref_hash => $self->{map}{map}{info}, |
556 | ref_hash => $self->{map}{map}{info}, |
463 | dialog => [ |
557 | dialog => [ |
464 | [width => 'Width' => 'string'], |
558 | [width => 'Width' => 'string'], |
465 | [height => 'Height' => 'string'], |
559 | [height => 'Height' => 'string'], |
466 | ], |
560 | ], |
467 | close_on_save => 1, |
561 | close_on_save => 1, |
|
|
562 | save_button_label => 'resize', |
468 | save_cb => sub { |
563 | save_cb => sub { |
469 | my ($info) = @_; |
564 | my ($info) = @_; |
470 | $self->{map}{map}->resize ($info->{width}, $info->{height}); |
565 | $self->{map}{map}->resize ($info->{width}, $info->{height}); |
471 | $self->{map}->invalidate_all; |
566 | $self->{map}->set_map ($self->{map}{map}); |
|
|
567 | $self->update_overlays; |
472 | } |
568 | } |
473 | ); |
569 | ); |
474 | |
570 | |
475 | $w->signal_connect (destroy => sub { delete $self->{meta_info_win} }); |
571 | $w->signal_connect (destroy => sub { delete $self->{meta_info_win} }); |
476 | |
572 | |
… | |
… | |
701 | ################################################################# |
797 | ################################################################# |
702 | |
798 | |
703 | sub INIT_INSTANCE { |
799 | sub INIT_INSTANCE { |
704 | my ($self) = @_; |
800 | my ($self) = @_; |
705 | |
801 | |
706 | $self->set_title ('gce - map editor'); |
802 | $self->set_window_title; |
707 | $self->add (my $vb = Gtk2::VBox->new); |
803 | $self->add (my $vb = Gtk2::VBox->new); |
708 | |
804 | |
709 | $vb->pack_start (my $menu = $self->build_menu, 0, 1, 0); |
805 | $vb->pack_start (my $menu = $self->build_menu, 0, 1, 0); |
710 | |
806 | |
711 | $vb->pack_start (my $map = $self->{map} = Crossfire::MapWidget->new, 1, 1, 0); |
807 | $vb->pack_start (my $map = $self->{map} = Crossfire::MapWidget->new, 1, 1, 0); |
|
|
808 | |
|
|
809 | $map->signal_connect_after (stack_change => sub { |
|
|
810 | my ($map, $x, $y, $stack) = @_; |
|
|
811 | $self->update_overlays ($x, $y, $stack); |
|
|
812 | $::MAINWIN->update_map_pos ($self, $x, $y); |
|
|
813 | }); |
|
|
814 | $map->signal_connect_after (swap_stack_change => sub { |
|
|
815 | my ($map, $x, $y, $stack) = @_; |
|
|
816 | $self->update_overlays ($x, $y, $stack); |
|
|
817 | $::MAINWIN->update_map_pos ($self, $x, $y); |
|
|
818 | }); |
|
|
819 | |
|
|
820 | $self->{connection_overlay_foreground} |
|
|
821 | = Gtk2::Gdk::Color->new (257 * 255, 257 * 255, 0); |
|
|
822 | $self->{connection_overlay_background} |
|
|
823 | = Gtk2::Gdk::Color->new (0, 0, 0); |
|
|
824 | # my $ygc |
|
|
825 | # = $self->{connection_overlay_yellow_gc} |
|
|
826 | # = Gtk2::Gdk::GC->new ($self->{map}{window}); |
|
|
827 | # $ygc->set_foreground (Gtk2::Gdk::Color->new (257 * 255, 257 * 255, 0)); |
712 | |
828 | |
713 | $map->signal_connect_after (key_press_event => sub { |
829 | $map->signal_connect_after (key_press_event => sub { |
714 | my ($map, $event) = @_; |
830 | my ($map, $event) = @_; |
715 | |
831 | |
716 | my $kv = $event->keyval; |
832 | my $kv = $event->keyval; |