--- deliantra/gde/GCE/MapEditor.pm 2006/02/20 13:30:28 1.6 +++ deliantra/gde/GCE/MapEditor.pm 2006/03/16 01:13:57 1.21 @@ -21,119 +21,404 @@ use strict; +sub build_menu { + my ($self) = @_; + + my $menu_tree = [ + _File => { + item_type => '', + children => [ + "_Save" => { + callback => sub { $self->save_map }, + accelerator => 'S' + }, + "Save As" => { + callback => sub { $self->save_map_as }, + }, + "Close" => { + callback => sub { $self->delete; 1 }, + }, + ] + }, + _Edit => { + item_type => '', + children => [ + "_Undo" => { + callback => sub { $self->undo }, + accelerator => "Z" + }, + "_Redo" => { + callback => sub { $self->redo }, + accelerator => "Y" + }, + "_Map Properties" => { + callback => sub { $self->open_map_prop }, + accelerator => "P" + }, + "_Map Resize" => { + callback => sub { $self->open_resize_map }, + accelerator => "R" + }, + ] + }, + + ]; + + my $men = + Gtk2::SimpleMenu->new ( + menu_tree => $menu_tree, + default_callback => \&default_cb, + ); + + $men->{accel_group}->connect ($Gtk2::Gdk::Keysyms{'i'}, [], 'visible', + sub { $::MAINWIN->set_edit_tool ('pick') }); + $men->{accel_group}->connect ($Gtk2::Gdk::Keysyms{'p'}, [], 'visible', + sub { $::MAINWIN->set_edit_tool ('place') }); + $men->{accel_group}->connect ($Gtk2::Gdk::Keysyms{'e'}, [], 'visible', + sub { $::MAINWIN->set_edit_tool ('erase') }); + $self->add_accel_group ($men->{accel_group}); + + return $men->{widget}; +} + +sub ea { + my ($self) = @_; + $self->{ea_alt} || $::MAINWIN->{sel_editaction}; +} + sub INIT_INSTANCE { my ($self) = @_; $self->set_title ('gce - map editor'); $self->add (my $vb = Gtk2::VBox->new); - $vb->pack_start (my $map = $self->{map} = Crossfire::MapWidget->new, 1, 1, 0); - $map->signal_connect (button_press_event => sub { - my ($map, $event) = @_; - my ($x, $y) = $map->coord ($event->x, $event->y); - my $as = $map->get ($x, $y); + $self->signal_connect (delete_event => sub { $self->delete }); - my $btn = $event->button; + $vb->pack_start (my $menu = $self->build_menu, 0, 1, 0); - if ($btn != 2 and my $ea = $GCE::MainWindow::MAINWIN->{sel_editaction}) { + $vb->pack_start (my $map = $self->{map} = Crossfire::MapWidget->new, 1, 1, 0); - $ea->begin ($map, $x, $y, $btn); + $self->signal_connect (focus_in_event => sub { + my $ea = $::MAINWIN->{sel_editaction}; + if ($ea->special_arrow) { + $self->{map}->{window}->set_cursor (Gtk2::Gdk::Cursor->new ($ea->special_arrow)); + } else { + $self->{map}->{window}->set_cursor (Gtk2::Gdk::Cursor->new ('GDK_LEFT_PTR')); + } + }); - $self->{draw_mode} = [$ea, $x, $y, $btn]; + $map->signal_connect (key_press_event => sub { + my ($map, $event) = @_; - $ea->want_cursor - or $map->disable_tooltip; + my $kv = $event->keyval; - if ($ea->special_arrow) { + if ($kv == $Gtk2::Gdk::Keysyms{Control_L}) { + $self->{ea_alt} = $::MAINWIN->{edit_collection}{erase}; - $map->{window}->set_cursor (Gtk2::Gdk::Cursor->new ($ea->special_arrow)); - #'GDK_QUESTION_ARROW')); - } + } elsif ($kv == $Gtk2::Gdk::Keysyms{Alt_L}) { + $self->{ea_alt} = $::MAINWIN->{edit_collection}{pick}; + } elsif ($kv == $Gtk2::Gdk::Keysyms{x}) { + $::MAINWIN->{edit_collection}{select}->move; + } elsif ($kv == $Gtk2::Gdk::Keysyms{c}) { + $::MAINWIN->{edit_collection}{select}->copy; + } elsif ($kv == $Gtk2::Gdk::Keysyms{v}) { + my ($x, $y) = $map->coord ($map->get_pointer); + $::MAINWIN->{edit_collection}{select}->paste ($x, $y); + } - return 1; - } + if ($self->ea->special_arrow) { + $map->{window}->set_cursor (Gtk2::Gdk::Cursor->new ($self->ea->special_arrow)); + } + 1; + }); + $map->signal_connect (key_release_event => sub { + my ($map, $event) = @_; - 0 - }); + if ($event->keyval == $Gtk2::Gdk::Keysyms{Control_L} + or $event->keyval == $Gtk2::Gdk::Keysyms{Alt_L}) + { + delete $self->{ea_alt}; + } - $map->signal_connect_after (motion_notify_event => sub { - my ($map, $event) = @_; + if ($self->ea->special_arrow) { + $map->{window}->set_cursor (Gtk2::Gdk::Cursor->new ($self->ea->special_arrow)); + } else { + # XXX: Get the original cursor and insert it here + $map->{window}->set_cursor (Gtk2::Gdk::Cursor->new ('GDK_LEFT_PTR')); + } + 1; + }); + $map->signal_connect (button_press_event => sub { + my ($map, $event) = @_; - $self->{draw_mode} - or return; + my ($x, $y) = $map->coord ($event->x, $event->y); + my $as = $map->get ($x, $y); - my ($X, $Y) = @{$self->{draw_mode}}[1,2]; - my ($x, $y) = $map->coord ($map->get_pointer); + if ((not $self->{draw_mode}) and $event->button != 2) { - while ($x != $X || $y != $Y) { + my $ea = $self->ea; - $X++ if $X < $x; - $X-- if $X > $x; - $Y++ if $Y < $y; - $Y-- if $Y > $y; + $ea->begin ($map, $x, $y) + if $x >= 0 and $y >= 0 and $x < $map->{map}{width} and $y < $map->{map}{height}; - $self->{draw_mode}[0]->edit ($map, $X, $Y, $self->{draw_mode}[3]); - } + $self->{draw_mode} = [$x, $y]; - @{$self->{draw_mode}}[1,2] = ($X, $Y); + $ea->want_cursor + or $map->disable_tooltip; - 1 - }); + return 1; + } + 0 + }); - $map->signal_connect (button_release_event => sub { - my ($map, $event) = @_; + $map->signal_connect_after (motion_notify_event => sub { + my ($map, $event) = @_; - if ($self->{draw_mode} and my $ea = $self->{draw_mode}[0]) { - $ea->end; + $self->{draw_mode} + or return; - $ea->want_cursor - or $map->enable_tooltip; + my $ea = $self->ea; + my ($X, $Y) = @{$self->{draw_mode}}[0,1]; + my ($x, $y) = $map->coord ($map->get_pointer); - if ($ea->special_arrow) { + while ($x != $X || $y != $Y) { - # XXX: Get the original cursor and insert it here - $map->{window}->set_cursor (Gtk2::Gdk::Cursor->new ('GDK_LEFT_PTR')); - } + $X++ if $X < $x; + $X-- if $X > $x; + $Y++ if $Y < $y; + $Y-- if $Y > $y; - delete $self->{draw_mode}; - } + $ea->edit ($map, $X, $Y) + if $X >= 0 and $Y >= 0 and $X < $map->{map}{width} and $Y < $map->{map}{height}; + } - 0 - }); + @{$self->{draw_mode}}[0,1] = ($X, $Y); + + 1 + }); + + $map->signal_connect (button_release_event => sub { + my ($map, $event) = @_; + + if ($self->{draw_mode}) { + my ($x, $y) = $map->coord ($map->get_pointer); + + my $ea = $self->ea; + $ea->end ($map, $x, $y); + + delete $self->{draw_mode}; + + $ea->want_cursor + or $map->enable_tooltip; + + return 1; + } + + 0 + }); } -sub delete_arch { - my ($self, $x, $y) = @_; +# FIXME: Fix the automatic update of the attribute editor! and also the stack view! +sub undo { + my ($self) = @_; + + my $map = $self->{map}; # the Crossfire::MapWidget - defined $self->{map} - or return 0; + $map->{undo_stack_pos} + or return; - my $as = $self->{map}->get ($x, $y); - pop @$as; - $self->{map}->set ($x, $y, $as); + $map->change_swap ($map->{undo_stack}[--$map->{undo_stack_pos}]); } -sub place_pick { - my ($self, $x, $y) = @_; +sub redo { + my ($self) = @_; - my $pick = $GCE::MainWindow::MAINWIN->get_pick; - my $as = $self->{map}->get ($x, $y); + my $map = $self->{map}; # the Crossfire::MapWidget - my $arch = { _name => $pick->{_name} }; + $map->{undo_stack} + and $map->{undo_stack_pos} < @{$map->{undo_stack}} + or return; - push @$as, $arch - unless @$as && $as->[-1]->{_name} eq $arch->{_name}; + $map->change_swap ($map->{undo_stack}[$map->{undo_stack_pos}++]); +} + +sub delete { + my ($self) = @_; + + # check and modla dialog if "dirty" - $self->{map}->set ($x, $y, $as); + $self->destroy; } sub open_map { my ($self, $path) = @_; - $self->{map}->set_map (new_from_file Crossfire::Map $path); + if (ref $path) { + $self->{map}->set_map ($path); + + } else { + $self->{path} = $path; +# print "OPENMAP $path\n"; + $self->{map}->set_map (my $m = new_from_file Crossfire::Map $path); + require Data::Dumper; +# print "FOO:" .Data::Dumper::Dumper ($m) . "\n"; + } +} + +sub save_map { + my ($self) = @_; + + if ($self->{path}) { + $self->{map}{map}->write_file ($self->{path}); + } +} + +sub save_map_as { + my ($self) = @_; + + my $fc = $::MAINWIN->new_filechooser ('gce - save map', 1); + + if ('ok' eq $fc->run) { + + $::MAINWIN->{fc_last_folder} = $fc->get_current_folder; + $::MAINWIN->{fc_last_folders}->{$self->{fc_last_folder}}++; + + $self->{map}{map}->write_file ($self->{path} = $fc->get_filename); + } + + $fc->destroy; } +sub _add_prop_entry { + my ($self, $table, $idx, $key, $desc, $type, $changecb) = @_; + + my $edwid; + + if ($type eq 'string') { + $table->attach_defaults (my $lbl = Gtk2::Label->new ($desc), 0, 1, $idx, $idx + 1); + $edwid = Gtk2::Entry->new; + $edwid->set_text ($self->{map}{map}{info}{$key}); + $edwid->signal_connect (changed => sub { + $self->{map}{map}{info}{$key} = $_[0]->get_text; + if ($changecb) { + $changecb->($_[0]->get_text); + } + }); + $table->attach_defaults ($edwid, 1, 2, $idx, $idx + 1); + + } elsif ($type eq 'button') { + $table->attach_defaults (my $b = Gtk2::Button->new_with_label ($desc), 0, 2, $idx, $idx + 1); + $b->signal_connect (clicked => ($changecb || sub {})); + + } elsif ($type eq 'label') { + $table->attach_defaults (my $lbl = Gtk2::Label->new ($desc), 0, 1, $idx, $idx + 1); + $edwid = Gtk2::Label->new ($self->{map}{map}{info}{$key}); + $table->attach_defaults ($edwid, 1, 2, $idx, $idx + 1); + + } else { + $edwid = Gtk2::Label->new ("FOO"); + } +} + +sub open_resize_map { + my ($self) = @_; + + my $w = Gtk2::Window->new ('toplevel'); + $w->set_default_size (250, 150); + $w->add (my $sw = Gtk2::ScrolledWindow->new); + $sw->add_with_viewport (my $v = Gtk2::VBox->new); + $sw->set_policy ('automatic', 'automatic'); + $v->pack_start (my $t = Gtk2::Table->new (2, 10), 0, 0, 0); + + my $i = 0; + for ( + [qw/width Width string/], + [qw/height Height string/], + [qw/save Save button/, + sub { + $self->{map}{map}->resize ($self->{map}{map}{info}{width}, $self->{map}{map}{info}{height}); + $self->{map}->invalidate_all; + $w->destroy; + } + ], + ) + { + $self->_add_prop_entry ($t, $i++, @$_); + } + + $w->show_all; +} + +sub open_map_prop { + my ($self) = @_; + + + my $w = Gtk2::Window->new ('toplevel'); + $w->set_default_size (500, 500); + $w->add (my $sw = Gtk2::ScrolledWindow->new); + $sw->add_with_viewport (my $v = Gtk2::VBox->new); + $sw->set_policy ('automatic', 'automatic'); + $v->pack_start (my $t = Gtk2::Table->new (2, 10), 0, 0, 0); + + my $i = 0; + for ( + [qw/name Name string/], + [qw/region Region string/], + [qw/difficulty Difficulty string/], + [qw/width Width label/], # sub { $self->{map}{map}->resize ($_[0], $self->{map}{map}{height}) }], + [qw/height Height label/],# sub { $self->{map}{map}->resize ($self->{map}{map}{width}, $_[0]) }], + [qw/msg Text text/], + [qw/tile_path_1 Northpath string/], + [qw/tile_path_2 Eastpath string/], + [qw/tile_path_3 Southpath string/], + [qw/tile_path_4 Westpath string/], + [qw/tile_path_5 Toppath string/], + [qw/tile_path_6 Bottompath string/], + ) + { + $self->_add_prop_entry ($t, $i++, @$_); + } + + $w->show_all; +} + +# 'info' => { +# 'windspeed' => '10', +# 'outdoor' => '1', +# 'width' => '20', +# 'pressure' => '8', +# 'test' => '', +# 'tile_path_2' => 'east', +# 'tile_path_3' => 'south', +# 'enter_y' => '2', +# 'tile_path_6' => 'bottom', +# 'enter_x' => '1', +# 'tile_path_5' => 'top', +# 'darkness' => '4', +# 'maplore' => '', +# 'sky' => '12', +# 'winddir' => '11', +# 'unique' => '1', +# 'msg' => 'Creator: CF Java FUCK Map Editor +#Date: 3/12/2006 +#', +# 'difficulty' => '3', +# 'humid' => '9', +# 'endmaplore' => '', +# 'fixed_resettime' => '1', +# 'name' => 'test', +# 'region' => 'REGION', +# 'height' => '40', +# 'reset_timeout' => '6', +# '_name' => 'map', +# 'swap_time' => '5', +# 'temp' => '7', +# 'tile_path_4' => 'west', +# 'tile_path_1' => 'north' +# }, + + =head1 AUTHOR Marc Lehmann