… | |
… | |
19 | use Glib::Object::Subclass |
19 | use Glib::Object::Subclass |
20 | Gtk2::Window; |
20 | Gtk2::Window; |
21 | |
21 | |
22 | use strict; |
22 | use strict; |
23 | |
23 | |
|
|
24 | sub build_menu { |
|
|
25 | my ($self) = @_; |
|
|
26 | |
|
|
27 | my $menu_tree = [ |
|
|
28 | _File => { |
|
|
29 | item_type => '<Branch>', |
|
|
30 | children => [ |
|
|
31 | "_Save" => { |
|
|
32 | callback => sub { $self->save_map }, |
|
|
33 | accelerator => '<ctrl>S' |
|
|
34 | }, |
|
|
35 | "Save As" => { |
|
|
36 | callback => sub { $self->save_map_as }, |
|
|
37 | }, |
|
|
38 | "Close" => { |
|
|
39 | callback => sub { $self->delete; 1 }, |
|
|
40 | }, |
|
|
41 | ] |
|
|
42 | }, |
|
|
43 | _Edit => { |
|
|
44 | item_type => '<Branch>', |
|
|
45 | children => [ |
|
|
46 | "_Undo" => { |
|
|
47 | callback => sub { $self->undo }, |
|
|
48 | accelerator => "<ctrl>Z" |
|
|
49 | }, |
|
|
50 | "_Redo" => { |
|
|
51 | callback => sub { $self->redo }, |
|
|
52 | 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 | }, |
|
|
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 | $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 | $self->add_accel_group ($men->{accel_group}); |
|
|
80 | |
|
|
81 | return $men->{widget}; |
|
|
82 | } |
|
|
83 | |
|
|
84 | sub ea { |
|
|
85 | my ($self) = @_; |
|
|
86 | $self->{ea_alt} || $::MAINWIN->{sel_editaction}; |
|
|
87 | } |
|
|
88 | |
24 | sub INIT_INSTANCE { |
89 | sub INIT_INSTANCE { |
25 | my ($self) = @_; |
90 | my ($self) = @_; |
26 | |
91 | |
27 | $self->set_title ('gce - map editor'); |
92 | $self->set_title ('gce - map editor'); |
28 | $self->add (my $vb = Gtk2::VBox->new); |
93 | $self->add (my $vb = Gtk2::VBox->new); |
|
|
94 | |
|
|
95 | $self->signal_connect (delete_event => sub { $self->delete }); |
|
|
96 | |
|
|
97 | $vb->pack_start (my $menu = $self->build_menu, 0, 1, 0); |
|
|
98 | |
29 | $vb->pack_start (my $map = $self->{map} = Crossfire::MapWidget->new, 1, 1, 0); |
99 | $vb->pack_start (my $map = $self->{map} = Crossfire::MapWidget->new, 1, 1, 0); |
30 | $map->signal_connect (button_press_event => sub { |
|
|
31 | my ($map, $event) = @_; |
|
|
32 | |
100 | |
33 | my ($x, $y) = $map->coord ($event->x, $event->y); |
101 | $self->signal_connect (focus_in_event => sub { |
34 | my $as = $map->get ($x, $y); |
102 | my $ea = $::MAINWIN->{sel_editaction}; |
35 | |
|
|
36 | my $btn = $event->button; |
|
|
37 | |
|
|
38 | if ($btn != 2 and my $ea = $GCE::MainWindow::MAINWIN->{sel_editaction}) { |
|
|
39 | |
|
|
40 | $ea->begin ($map, $x, $y, $btn); |
|
|
41 | |
|
|
42 | $self->{draw_mode} = [$ea, $x, $y, $btn]; |
|
|
43 | |
|
|
44 | $ea->want_cursor |
|
|
45 | or $map->disable_tooltip; |
|
|
46 | |
|
|
47 | if ($ea->special_arrow) { |
103 | if ($ea->special_arrow) { |
48 | |
|
|
49 | $map->{window}->set_cursor (Gtk2::Gdk::Cursor->new ($ea->special_arrow)); |
104 | $self->{map}->{window}->set_cursor (Gtk2::Gdk::Cursor->new ($ea->special_arrow)); |
50 | #'GDK_QUESTION_ARROW')); |
105 | } else { |
51 | } |
106 | $self->{map}->{window}->set_cursor (Gtk2::Gdk::Cursor->new ('GDK_LEFT_PTR')); |
|
|
107 | } |
|
|
108 | }); |
52 | |
109 | |
53 | return 1; |
110 | $map->signal_connect (key_press_event => sub { |
54 | } |
|
|
55 | |
|
|
56 | 0 |
|
|
57 | }); |
|
|
58 | |
|
|
59 | $map->signal_connect_after (motion_notify_event => sub { |
|
|
60 | my ($map, $event) = @_; |
111 | my ($map, $event) = @_; |
61 | |
112 | |
62 | $self->{draw_mode} |
113 | my $kv = $event->keyval; |
63 | or return; |
|
|
64 | |
114 | |
65 | my ($X, $Y) = @{$self->{draw_mode}}[1,2]; |
115 | if ($kv == $Gtk2::Gdk::Keysyms{Control_L}) { |
|
|
116 | $self->{ea_alt} = $::MAINWIN->{edit_collection}{erase}; |
|
|
117 | |
|
|
118 | } elsif ($kv == $Gtk2::Gdk::Keysyms{Alt_L}) { |
|
|
119 | $self->{ea_alt} = $::MAINWIN->{edit_collection}{pick}; |
|
|
120 | } elsif ($kv == $Gtk2::Gdk::Keysyms{x}) { |
|
|
121 | $::MAINWIN->{edit_collection}{select}->move; |
|
|
122 | } elsif ($kv == $Gtk2::Gdk::Keysyms{c}) { |
|
|
123 | $::MAINWIN->{edit_collection}{select}->copy; |
|
|
124 | } elsif ($kv == $Gtk2::Gdk::Keysyms{v}) { |
66 | my ($x, $y) = $map->coord ($map->get_pointer); |
125 | my ($x, $y) = $map->coord ($map->get_pointer); |
|
|
126 | $::MAINWIN->{edit_collection}{select}->paste ($x, $y); |
|
|
127 | } |
67 | |
128 | |
|
|
129 | 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 | |
|
|
154 | my ($x, $y) = $map->coord ($event->x, $event->y); |
|
|
155 | my $as = $map->get ($x, $y); |
|
|
156 | |
|
|
157 | if ((not $self->{draw_mode}) and $event->button != 2) { |
|
|
158 | |
|
|
159 | my $ea = $self->ea; |
|
|
160 | |
|
|
161 | $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 | |
|
|
166 | $ea->want_cursor |
|
|
167 | or $map->disable_tooltip; |
|
|
168 | |
|
|
169 | return 1; |
|
|
170 | } |
|
|
171 | 0 |
|
|
172 | }); |
|
|
173 | |
|
|
174 | $map->signal_connect_after (motion_notify_event => sub { |
|
|
175 | my ($map, $event) = @_; |
|
|
176 | |
|
|
177 | $self->{draw_mode} |
|
|
178 | or return; |
|
|
179 | |
|
|
180 | my $ea = $self->ea; |
|
|
181 | |
|
|
182 | my ($X, $Y) = @{$self->{draw_mode}}[0,1]; |
|
|
183 | my ($x, $y) = $map->coord ($map->get_pointer); |
|
|
184 | |
68 | while ($x != $X || $y != $Y) { |
185 | while ($x != $X || $y != $Y) { |
69 | |
186 | |
70 | $X++ if $X < $x; |
187 | $X++ if $X < $x; |
71 | $X-- if $X > $x; |
188 | $X-- if $X > $x; |
72 | $Y++ if $Y < $y; |
189 | $Y++ if $Y < $y; |
73 | $Y-- if $Y > $y; |
190 | $Y-- if $Y > $y; |
74 | |
191 | |
75 | $self->{draw_mode}[0]->edit ($map, $X, $Y, $self->{draw_mode}[3]); |
192 | $ea->edit ($map, $X, $Y) |
76 | } |
193 | if $X >= 0 and $Y >= 0 and $X < $map->{map}{width} and $Y < $map->{map}{height}; |
|
|
194 | } |
77 | |
195 | |
78 | @{$self->{draw_mode}}[1,2] = ($X, $Y); |
196 | @{$self->{draw_mode}}[0,1] = ($X, $Y); |
79 | |
197 | |
80 | 1 |
198 | 1 |
81 | }); |
199 | }); |
82 | |
200 | |
83 | $map->signal_connect (button_release_event => sub { |
201 | $map->signal_connect (button_release_event => sub { |
84 | my ($map, $event) = @_; |
202 | my ($map, $event) = @_; |
85 | |
203 | |
86 | if ($self->{draw_mode} and my $ea = $self->{draw_mode}[0]) { |
204 | if ($self->{draw_mode}) { |
87 | $ea->end; |
205 | my ($x, $y) = $map->coord ($map->get_pointer); |
88 | |
206 | |
|
|
207 | my $ea = $self->ea; |
|
|
208 | $ea->end ($map, $x, $y); |
|
|
209 | |
|
|
210 | delete $self->{draw_mode}; |
|
|
211 | |
89 | $ea->want_cursor |
212 | $ea->want_cursor |
90 | or $map->enable_tooltip; |
213 | or $map->enable_tooltip; |
91 | |
214 | |
|
|
215 | return 1; |
|
|
216 | } |
92 | |
217 | |
93 | if ($ea->special_arrow) { |
218 | 0 |
94 | |
219 | }); |
95 | # XXX: Get the original cursor and insert it here |
|
|
96 | $map->{window}->set_cursor (Gtk2::Gdk::Cursor->new ('GDK_LEFT_PTR')); |
|
|
97 | } |
|
|
98 | |
|
|
99 | delete $self->{draw_mode}; |
|
|
100 | } |
|
|
101 | |
|
|
102 | 0 |
|
|
103 | }); |
|
|
104 | } |
220 | } |
105 | |
221 | |
106 | sub delete_arch { |
222 | # FIXME: Fix the automatic update of the attribute editor! and also the stack view! |
|
|
223 | sub undo { |
107 | my ($self, $x, $y) = @_; |
224 | my ($self) = @_; |
108 | |
225 | |
109 | defined $self->{map} |
226 | my $map = $self->{map}; # the Crossfire::MapWidget |
|
|
227 | |
|
|
228 | $map->{undo_stack_pos} |
110 | or return 0; |
229 | or return; |
111 | |
230 | |
112 | my $as = $self->{map}->get ($x, $y); |
231 | $map->change_swap ($map->{undo_stack}[--$map->{undo_stack_pos}]); |
113 | pop @$as; |
|
|
114 | $self->{map}->set ($x, $y, $as); |
|
|
115 | } |
232 | } |
116 | |
233 | |
117 | sub place_pick { |
234 | sub redo { |
118 | my ($self, $x, $y) = @_; |
235 | my ($self) = @_; |
119 | |
236 | |
120 | my $pick = $GCE::MainWindow::MAINWIN->get_pick; |
237 | my $map = $self->{map}; # the Crossfire::MapWidget |
121 | my $as = $self->{map}->get ($x, $y); |
|
|
122 | |
238 | |
123 | my $arch = { _name => $pick->{_name} }; |
239 | $map->{undo_stack} |
|
|
240 | and $map->{undo_stack_pos} < @{$map->{undo_stack}} |
|
|
241 | or return; |
124 | |
242 | |
125 | push @$as, $arch |
243 | $map->change_swap ($map->{undo_stack}[$map->{undo_stack_pos}++]); |
126 | unless @$as && $as->[-1]->{_name} eq $arch->{_name}; |
244 | } |
127 | |
245 | |
128 | $self->{map}->set ($x, $y, $as); |
246 | sub delete { |
|
|
247 | my ($self) = @_; |
|
|
248 | |
|
|
249 | # check and modla dialog if "dirty" |
|
|
250 | |
|
|
251 | $self->destroy; |
129 | } |
252 | } |
130 | |
253 | |
131 | sub open_map { |
254 | sub open_map { |
132 | my ($self, $path) = @_; |
255 | my ($self, $path) = @_; |
133 | |
256 | |
|
|
257 | if (ref $path) { |
|
|
258 | $self->{map}->set_map ($path); |
|
|
259 | |
|
|
260 | } else { |
|
|
261 | $self->{path} = $path; |
|
|
262 | # print "OPENMAP $path\n"; |
134 | $self->{map}->set_map (new_from_file Crossfire::Map $path); |
263 | $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 | } |
135 | } |
267 | } |
|
|
268 | |
|
|
269 | sub save_map { |
|
|
270 | my ($self) = @_; |
|
|
271 | |
|
|
272 | if ($self->{path}) { |
|
|
273 | $self->{map}{map}->write_file ($self->{path}); |
|
|
274 | } |
|
|
275 | } |
|
|
276 | |
|
|
277 | sub save_map_as { |
|
|
278 | my ($self) = @_; |
|
|
279 | |
|
|
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 | } |
|
|
292 | |
|
|
293 | 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 | $self->{map}->invalidate_all; |
|
|
342 | $w->destroy; |
|
|
343 | } |
|
|
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 | |
136 | |
421 | |
137 | =head1 AUTHOR |
422 | =head1 AUTHOR |
138 | |
423 | |
139 | Marc Lehmann <schmorp@schmorp.de> |
424 | Marc Lehmann <schmorp@schmorp.de> |
140 | http://home.schmorp.de/ |
425 | http://home.schmorp.de/ |