ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/cvsroot/cf.schmorp.de/gde/GCE/MapEditor.pm
Revision: 1.21
Committed: Thu Mar 16 01:13:57 2006 UTC (20 years, 7 months ago) by elmex
Branch: MAIN
Changes since 1.20: +2 -25 lines
Log Message:
removed face checking and implemented pick editing

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    
19 elmex 1.4 use Glib::Object::Subclass
20 elmex 1.6 Gtk2::Window;
21 elmex 1.1
22     use strict;
23    
24 root 1.9 sub build_menu {
25     my ($self) = @_;
26    
27     my $menu_tree = [
28     _File => {
29     item_type => '<Branch>',
30     children => [
31     "_Save" => {
32 root 1.10 callback => sub { $self->save_map },
33 root 1.9 accelerator => '<ctrl>S'
34     },
35 root 1.10 "Save As" => {
36     callback => sub { $self->save_map_as },
37     },
38 root 1.13 "Close" => {
39     callback => sub { $self->delete; 1 },
40     },
41 root 1.10 ]
42 root 1.9 },
43     _Edit => {
44     item_type => '<Branch>',
45     children => [
46     "_Undo" => {
47     callback => sub { $self->undo },
48 elmex 1.17 accelerator => "<ctrl>Z"
49 root 1.9 },
50     "_Redo" => {
51     callback => sub { $self->redo },
52 elmex 1.17 accelerator => "<ctrl>Y"
53     },
54     "_Map Properties" => {
55     callback => sub { $self->open_map_prop },
56     accelerator => "<ctrl>P"
57     },
58     "_Map Resize" => {
59     callback => sub { $self->open_resize_map },
60     accelerator => "<ctrl>R"
61 root 1.9 },
62     ]
63     },
64    
65     ];
66    
67     my $men =
68     Gtk2::SimpleMenu->new (
69     menu_tree => $menu_tree,
70     default_callback => \&default_cb,
71     );
72    
73 elmex 1.19 $men->{accel_group}->connect ($Gtk2::Gdk::Keysyms{'i'}, [], 'visible',
74     sub { $::MAINWIN->set_edit_tool ('pick') });
75     $men->{accel_group}->connect ($Gtk2::Gdk::Keysyms{'p'}, [], 'visible',
76     sub { $::MAINWIN->set_edit_tool ('place') });
77     $men->{accel_group}->connect ($Gtk2::Gdk::Keysyms{'e'}, [], 'visible',
78     sub { $::MAINWIN->set_edit_tool ('erase') });
79 root 1.9 $self->add_accel_group ($men->{accel_group});
80    
81     return $men->{widget};
82     }
83    
84 elmex 1.19 sub ea {
85     my ($self) = @_;
86     $self->{ea_alt} || $::MAINWIN->{sel_editaction};
87     }
88    
89 elmex 1.1 sub INIT_INSTANCE {
90     my ($self) = @_;
91    
92 elmex 1.6 $self->set_title ('gce - map editor');
93     $self->add (my $vb = Gtk2::VBox->new);
94 elmex 1.1
95 root 1.13 $self->signal_connect (delete_event => sub { $self->delete });
96    
97 root 1.9 $vb->pack_start (my $menu = $self->build_menu, 0, 1, 0);
98    
99     $vb->pack_start (my $map = $self->{map} = Crossfire::MapWidget->new, 1, 1, 0);
100    
101 elmex 1.19 $self->signal_connect (focus_in_event => sub {
102     my $ea = $::MAINWIN->{sel_editaction};
103     if ($ea->special_arrow) {
104     $self->{map}->{window}->set_cursor (Gtk2::Gdk::Cursor->new ($ea->special_arrow));
105     } else {
106     $self->{map}->{window}->set_cursor (Gtk2::Gdk::Cursor->new ('GDK_LEFT_PTR'));
107     }
108     });
109    
110     $map->signal_connect (key_press_event => sub {
111     my ($map, $event) = @_;
112 root 1.9
113 elmex 1.19 my $kv = $event->keyval;
114 root 1.9
115 elmex 1.19 if ($kv == $Gtk2::Gdk::Keysyms{Control_L}) {
116     $self->{ea_alt} = $::MAINWIN->{edit_collection}{erase};
117 root 1.9
118 elmex 1.19 } elsif ($kv == $Gtk2::Gdk::Keysyms{Alt_L}) {
119     $self->{ea_alt} = $::MAINWIN->{edit_collection}{pick};
120 elmex 1.21 } elsif ($kv == $Gtk2::Gdk::Keysyms{x}) {
121     $::MAINWIN->{edit_collection}{select}->move;
122 elmex 1.20 } elsif ($kv == $Gtk2::Gdk::Keysyms{c}) {
123     $::MAINWIN->{edit_collection}{select}->copy;
124     } elsif ($kv == $Gtk2::Gdk::Keysyms{v}) {
125     my ($x, $y) = $map->coord ($map->get_pointer);
126     $::MAINWIN->{edit_collection}{select}->paste ($x, $y);
127 elmex 1.19 }
128 root 1.9
129 elmex 1.19 if ($self->ea->special_arrow) {
130     $map->{window}->set_cursor (Gtk2::Gdk::Cursor->new ($self->ea->special_arrow));
131     }
132     1;
133     });
134     $map->signal_connect (key_release_event => sub {
135     my ($map, $event) = @_;
136    
137     if ($event->keyval == $Gtk2::Gdk::Keysyms{Control_L}
138     or $event->keyval == $Gtk2::Gdk::Keysyms{Alt_L})
139     {
140     delete $self->{ea_alt};
141     }
142    
143     if ($self->ea->special_arrow) {
144     $map->{window}->set_cursor (Gtk2::Gdk::Cursor->new ($self->ea->special_arrow));
145     } else {
146     # XXX: Get the original cursor and insert it here
147     $map->{window}->set_cursor (Gtk2::Gdk::Cursor->new ('GDK_LEFT_PTR'));
148     }
149     1;
150     });
151     $map->signal_connect (button_press_event => sub {
152     my ($map, $event) = @_;
153 elmex 1.1
154 elmex 1.19 my ($x, $y) = $map->coord ($event->x, $event->y);
155     my $as = $map->get ($x, $y);
156 elmex 1.1
157 elmex 1.19 if ((not $self->{draw_mode}) and $event->button != 2) {
158 elmex 1.4
159 elmex 1.19 my $ea = $self->ea;
160 elmex 1.4
161 elmex 1.19 $ea->begin ($map, $x, $y)
162     if $x >= 0 and $y >= 0 and $x < $map->{map}{width} and $y < $map->{map}{height};
163    
164     $self->{draw_mode} = [$x, $y];
165 root 1.9
166 elmex 1.19 $ea->want_cursor
167     or $map->disable_tooltip;
168 root 1.9
169 elmex 1.19 return 1;
170     }
171     0
172 root 1.9 });
173    
174     $map->signal_connect_after (motion_notify_event => sub {
175     my ($map, $event) = @_;
176    
177     $self->{draw_mode}
178     or return;
179    
180 elmex 1.19 my $ea = $self->ea;
181    
182     my ($X, $Y) = @{$self->{draw_mode}}[0,1];
183 root 1.9 my ($x, $y) = $map->coord ($map->get_pointer);
184 elmex 1.4
185 root 1.9 while ($x != $X || $y != $Y) {
186 elmex 1.4
187 root 1.9 $X++ if $X < $x;
188     $X-- if $X > $x;
189     $Y++ if $Y < $y;
190     $Y-- if $Y > $y;
191 elmex 1.4
192 elmex 1.19 $ea->edit ($map, $X, $Y)
193 elmex 1.15 if $X >= 0 and $Y >= 0 and $X < $map->{map}{width} and $Y < $map->{map}{height};
194 root 1.9 }
195 elmex 1.4
196 elmex 1.19 @{$self->{draw_mode}}[0,1] = ($X, $Y);
197 elmex 1.1
198 root 1.9 1
199     });
200 elmex 1.1
201 root 1.9 $map->signal_connect (button_release_event => sub {
202     my ($map, $event) = @_;
203 elmex 1.1
204 elmex 1.19 if ($self->{draw_mode}) {
205 root 1.9 my ($x, $y) = $map->coord ($map->get_pointer);
206 elmex 1.4
207 elmex 1.19 my $ea = $self->ea;
208     $ea->end ($map, $x, $y);
209 elmex 1.1
210 root 1.9 delete $self->{draw_mode};
211 elmex 1.4
212 root 1.9 $ea->want_cursor
213     or $map->enable_tooltip;
214 elmex 1.1
215 root 1.9 return 1;
216     }
217 elmex 1.1
218 root 1.9 0
219     });
220     }
221 elmex 1.8
222 elmex 1.16 # FIXME: Fix the automatic update of the attribute editor! and also the stack view!
223 root 1.9 sub undo {
224     my ($self) = @_;
225 elmex 1.8
226 root 1.9 my $map = $self->{map}; # the Crossfire::MapWidget
227 elmex 1.1
228 root 1.9 $map->{undo_stack_pos}
229     or return;
230 elmex 1.1
231 root 1.9 $map->change_swap ($map->{undo_stack}[--$map->{undo_stack_pos}]);
232     }
233 elmex 1.1
234 root 1.9 sub redo {
235     my ($self) = @_;
236 elmex 1.7
237 root 1.9 my $map = $self->{map}; # the Crossfire::MapWidget
238 elmex 1.7
239 elmex 1.14 $map->{undo_stack}
240     and $map->{undo_stack_pos} < @{$map->{undo_stack}}
241     or return;
242 elmex 1.1
243 root 1.9 $map->change_swap ($map->{undo_stack}[$map->{undo_stack_pos}++]);
244 root 1.3 }
245    
246 root 1.13 sub delete {
247     my ($self) = @_;
248    
249     # check and modla dialog if "dirty"
250    
251     $self->destroy;
252     }
253    
254 root 1.3 sub open_map {
255     my ($self, $path) = @_;
256    
257 elmex 1.18 if (ref $path) {
258     $self->{map}->set_map ($path);
259    
260     } else {
261     $self->{path} = $path;
262 elmex 1.17 # print "OPENMAP $path\n";
263 elmex 1.18 $self->{map}->set_map (my $m = new_from_file Crossfire::Map $path);
264     require Data::Dumper;
265     # print "FOO:" .Data::Dumper::Dumper ($m) . "\n";
266     }
267 root 1.3 }
268    
269 root 1.13 sub save_map {
270     my ($self) = @_;
271    
272 elmex 1.19 if ($self->{path}) {
273     $self->{map}{map}->write_file ($self->{path});
274     }
275 root 1.13 }
276    
277     sub save_map_as {
278     my ($self) = @_;
279 elmex 1.19
280     my $fc = $::MAINWIN->new_filechooser ('gce - save map', 1);
281    
282     if ('ok' eq $fc->run) {
283    
284     $::MAINWIN->{fc_last_folder} = $fc->get_current_folder;
285     $::MAINWIN->{fc_last_folders}->{$self->{fc_last_folder}}++;
286    
287     $self->{map}{map}->write_file ($self->{path} = $fc->get_filename);
288     }
289    
290     $fc->destroy;
291 root 1.13 }
292    
293 elmex 1.17 sub _add_prop_entry {
294     my ($self, $table, $idx, $key, $desc, $type, $changecb) = @_;
295    
296     my $edwid;
297    
298     if ($type eq 'string') {
299     $table->attach_defaults (my $lbl = Gtk2::Label->new ($desc), 0, 1, $idx, $idx + 1);
300     $edwid = Gtk2::Entry->new;
301     $edwid->set_text ($self->{map}{map}{info}{$key});
302     $edwid->signal_connect (changed => sub {
303     $self->{map}{map}{info}{$key} = $_[0]->get_text;
304     if ($changecb) {
305     $changecb->($_[0]->get_text);
306     }
307     });
308     $table->attach_defaults ($edwid, 1, 2, $idx, $idx + 1);
309    
310     } elsif ($type eq 'button') {
311     $table->attach_defaults (my $b = Gtk2::Button->new_with_label ($desc), 0, 2, $idx, $idx + 1);
312     $b->signal_connect (clicked => ($changecb || sub {}));
313    
314     } elsif ($type eq 'label') {
315     $table->attach_defaults (my $lbl = Gtk2::Label->new ($desc), 0, 1, $idx, $idx + 1);
316     $edwid = Gtk2::Label->new ($self->{map}{map}{info}{$key});
317     $table->attach_defaults ($edwid, 1, 2, $idx, $idx + 1);
318    
319     } else {
320     $edwid = Gtk2::Label->new ("FOO");
321     }
322     }
323    
324     sub open_resize_map {
325     my ($self) = @_;
326    
327     my $w = Gtk2::Window->new ('toplevel');
328     $w->set_default_size (250, 150);
329     $w->add (my $sw = Gtk2::ScrolledWindow->new);
330     $sw->add_with_viewport (my $v = Gtk2::VBox->new);
331     $sw->set_policy ('automatic', 'automatic');
332     $v->pack_start (my $t = Gtk2::Table->new (2, 10), 0, 0, 0);
333    
334     my $i = 0;
335     for (
336     [qw/width Width string/],
337     [qw/height Height string/],
338     [qw/save Save button/,
339     sub {
340     $self->{map}{map}->resize ($self->{map}{map}{info}{width}, $self->{map}{map}{info}{height});
341 elmex 1.19 $self->{map}->invalidate_all;
342     $w->destroy;
343 elmex 1.17 }
344     ],
345     )
346     {
347     $self->_add_prop_entry ($t, $i++, @$_);
348     }
349    
350     $w->show_all;
351     }
352    
353     sub open_map_prop {
354     my ($self) = @_;
355    
356    
357     my $w = Gtk2::Window->new ('toplevel');
358     $w->set_default_size (500, 500);
359     $w->add (my $sw = Gtk2::ScrolledWindow->new);
360     $sw->add_with_viewport (my $v = Gtk2::VBox->new);
361     $sw->set_policy ('automatic', 'automatic');
362     $v->pack_start (my $t = Gtk2::Table->new (2, 10), 0, 0, 0);
363    
364     my $i = 0;
365     for (
366     [qw/name Name string/],
367     [qw/region Region string/],
368     [qw/difficulty Difficulty string/],
369     [qw/width Width label/], # sub { $self->{map}{map}->resize ($_[0], $self->{map}{map}{height}) }],
370     [qw/height Height label/],# sub { $self->{map}{map}->resize ($self->{map}{map}{width}, $_[0]) }],
371     [qw/msg Text text/],
372     [qw/tile_path_1 Northpath string/],
373     [qw/tile_path_2 Eastpath string/],
374     [qw/tile_path_3 Southpath string/],
375     [qw/tile_path_4 Westpath string/],
376     [qw/tile_path_5 Toppath string/],
377     [qw/tile_path_6 Bottompath string/],
378     )
379     {
380     $self->_add_prop_entry ($t, $i++, @$_);
381     }
382    
383     $w->show_all;
384     }
385    
386     # 'info' => {
387     # 'windspeed' => '10',
388     # 'outdoor' => '1',
389     # 'width' => '20',
390     # 'pressure' => '8',
391     # 'test' => '',
392     # 'tile_path_2' => 'east',
393     # 'tile_path_3' => 'south',
394     # 'enter_y' => '2',
395     # 'tile_path_6' => 'bottom',
396     # 'enter_x' => '1',
397     # 'tile_path_5' => 'top',
398     # 'darkness' => '4',
399     # 'maplore' => '',
400     # 'sky' => '12',
401     # 'winddir' => '11',
402     # 'unique' => '1',
403     # 'msg' => 'Creator: CF Java FUCK Map Editor
404     #Date: 3/12/2006
405     #',
406     # 'difficulty' => '3',
407     # 'humid' => '9',
408     # 'endmaplore' => '',
409     # 'fixed_resettime' => '1',
410     # 'name' => 'test',
411     # 'region' => 'REGION',
412     # 'height' => '40',
413     # 'reset_timeout' => '6',
414     # '_name' => 'map',
415     # 'swap_time' => '5',
416     # 'temp' => '7',
417     # 'tile_path_4' => 'west',
418     # 'tile_path_1' => 'north'
419     # },
420    
421    
422 elmex 1.1 =head1 AUTHOR
423    
424     Marc Lehmann <schmorp@schmorp.de>
425     http://home.schmorp.de/
426    
427     Robin Redeker <elmex@ta-sa.org>
428     http://www.ta-sa.org/
429    
430     =cut
431     1;
432