ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/deliantra/gde/GCE/Map.pm
Revision: 1.1
Committed: Sun Feb 5 04:30:17 2006 UTC (18 years, 4 months ago) by root
Branch: MAIN
Log Message:
*** empty log message ***

File Contents

# Content
1 =head1 NAME
2
3 Gtk2::CV::Schnauzer - a widget for displaying image collections
4
5 =head1 SYNOPSIS
6
7 use Gtk2::CV::Schnauzer;
8
9 =head1 DESCRIPTION
10
11 =head2 METHODS
12
13 =over 4
14
15 =cut
16
17 package GCE::Map::DrawingArea;
18
19 use Glib::Object::Subclass Gtk2::DrawingArea,
20 signals => { size_allocate => \&GCE::Map::do_size_allocate_rounded };
21
22 package GCE::Map;
23
24 use strict;
25
26 use Gtk2;
27
28 use Crossfire;
29 use Crossfire::Gtk2;
30
31 use Glib::Object::Subclass
32 'GCE::Map::DrawingArea';
33
34 use List::Util qw(min max);
35
36 sub INIT_INSTANCE {
37 my ($self) = @_;
38
39 $self->signal_connect (destroy => sub { %{$_[0]} = () });
40 $self->signal_connect (realize => sub {
41 my ($self) = @_;
42
43 $self->{window} = $self->window;
44
45 my $window = $self->get_toplevel
46 or return;
47
48 my $hints = new Gtk2::Gdk::Geometry;
49 $hints->base_width (TILESIZE); $hints->base_height (TILESIZE);
50 $hints->width_inc (TILESIZE); $hints->height_inc (TILESIZE);
51
52 $window->set_geometry_hints ($self, $hints, [qw(base-size resize-inc)]);
53
54 1
55 });
56
57 #$self->set_redraw_on_allocate (0); # nope
58 $self->double_buffered (1);
59
60 $self->signal_connect (size_request => sub {
61 $_[1]->width (20 * TILESIZE);
62 $_[1]->height (20 * TILESIZE);
63
64 1
65 });
66
67 $self->signal_connect (expose_event => sub {
68 $self->expose ($_[1]);
69 });
70
71 $self->signal_connect (button_press_event => sub {
72 my ($self, $event) = @_;
73
74 my ($x, $y) = ($event->x, $event->y);
75
76 if ($_[1]->button == 2) {
77 $_[0]->grab_focus;
78 $self->{in_drag} = [$self->{x}, $self->{y}, $x, $y];
79 }
80
81 1
82 });
83
84 $self->signal_connect (motion_notify_event => sub {
85 my ($self) = @_;
86
87 my ($x, $y) = $self->get_pointer;
88
89 if (my $di = $self->{in_drag}) {
90 my $dx = $x - $di->[2];
91 my $dy = $y - $di->[3];
92
93 my $nx = max 0, $di->[0] - $dx;
94 my $ny = max 0, $di->[1] - $dy;
95
96 $self->window->scroll ($self->{x} - $nx, $self->{y} - $ny);
97
98 ($self->{x}, $self->{y}) = ($nx, $ny);
99 }
100
101 1;
102 });
103
104 $self->signal_connect (button_release_event => sub {
105 my ($self) = @_;
106
107 # if ($self->{in_drag}) {
108 # }
109 delete $self->{in_drag};
110
111 1
112 });
113
114 # unnecessary redraws...
115 $self->signal_connect (focus_in_event => sub { 1 });
116 $self->signal_connect (focus_out_event => sub { 1 });
117
118 # gtk+ supports no motion compression, a major lacking feature. we have to pay for the
119 # workaround with incorrect behaviour and extra server-turnarounds.
120 $self->add_events ([qw(key_press_mask key_release_mask button_press_mask button_release_mask button-motion-mask scroll_mask pointer-motion-hint-mask)]);
121 $self->can_focus (1);
122
123 # $self->signal_connect (key_press_event => sub { $self->handle_key ($_[1]->keyval, $_[1]->state) });
124 }
125
126 sub do_size_allocate_rounded {
127 use integer;
128
129 $_[1]->width ($_[1]->width / TILESIZE * TILESIZE);
130 $_[1]->height ($_[1]->height / TILESIZE * TILESIZE);
131
132 $_[0]->signal_chain_from_overridden ($_[1]);
133 }
134
135 sub coord {
136 my ($self, $x, $y) = @_;
137
138 (
139 int $self->{x} + $x / TILESIZE,
140 int $self->{y} + $y / TILESIZE,
141 )
142 }
143
144 #sub handle_key {
145 # my ($self, $key, $state) = @_;
146 #
147 # $self->prefetch_cancel;
148 #
149 # if ($state * "control-mask") {
150 # if ($key == $Gtk2::Gdk::Keysyms{g}) {
151 # my @sel = keys %{$self->{sel}};
152 # $self->generate_thumbnails (@sel ? @sel : 0 .. $#{$self->{entry}});
153 # } elsif ($key == $Gtk2::Gdk::Keysyms{a}) {
154 # $self->select_all;
155 # } elsif ($key == $Gtk2::Gdk::Keysyms{A}) {
156 # $self->select_range ($self->{offs}, $self->{offs} + $self->{cols} * $self->{page} - 1);
157 # } elsif ($key == $Gtk2::Gdk::Keysyms{s}) {
158 # $self->rescan;
159 # } elsif ($key == $Gtk2::Gdk::Keysyms{d}) {
160 # $self->unlink (keys %{$self->{sel}});
161 # } elsif ($key == $Gtk2::Gdk::Keysyms{u}) {
162 # my @sel = keys %{$self->{sel}};
163 # $self->update_thumbnails (@sel ? @sel : 0 .. $#{$self->{entry}});
164 #
165 # } elsif ($key == $Gtk2::Gdk::Keysyms{Return}) {
166 # $self->cursor_move (0) unless $self->cursor_valid;
167 # $self->emit_activate ($self->{cursor});
168 # } elsif ($key == $Gtk2::Gdk::Keysyms{space}) {
169 # $self->cursor_move (1) or return 1
170 # if $self->{cursor_current} || !$self->cursor_valid;
171 # $self->emit_activate ($self->{cursor}) if $self->cursor_valid;
172 # $self->prefetch (1);
173 # } elsif ($key == $Gtk2::Gdk::Keysyms{BackSpace}) {
174 # $self->cursor_move (-1) or return 1;
175 # $self->emit_activate ($self->{cursor}) if $self->cursor_valid;
176 # $self->prefetch (-1);
177 #
178 # } else {
179 # return 0;
180 # }
181 # } else {
182 # if ($key == $Gtk2::Gdk::Keysyms{Page_Up}) {
183 # my $value = $self->{adj}->value;
184 # $self->{adj}->set_value ($value >= $self->{page} ? $value - $self->{page} : 0);
185 # $self->clear_cursor;
186 # } elsif ($key == $Gtk2::Gdk::Keysyms{Page_Down}) {
187 # my $value = $self->{adj}->value + $self->{page};
188 # $self->{adj}->set_value ($value <= $self->{maxrow} ? $value : $self->{maxrow});
189 # $self->clear_cursor;
190 #
191 # } elsif ($key == $Gtk2::Gdk::Keysyms{Home}) {
192 # $self->{adj}->set_value (0);
193 # $self->clear_cursor;
194 # } elsif ($key == $Gtk2::Gdk::Keysyms{End}) {
195 # $self->{adj}->set_value ($self->{maxrow});
196 # $self->clear_cursor;
197 #
198 # } elsif ($key == $Gtk2::Gdk::Keysyms{Up}) {
199 # $self->cursor_move (-$self->{cols});
200 # } elsif ($key == $Gtk2::Gdk::Keysyms{Down}) {
201 # $self->cursor_move (+$self->{cols});
202 # } elsif ($key == $Gtk2::Gdk::Keysyms{Left}) {
203 # $self->cursor_move (-1);
204 # } elsif ($key == $Gtk2::Gdk::Keysyms{Right}) {
205 # $self->cursor_move (+1);
206 #
207 # } elsif ($key == $Gtk2::Gdk::Keysyms{Return}) {
208 # $self->cursor_move (0) unless $self->cursor_valid;
209 # $self->emit_activate ($self->{cursor});
210 # } elsif ($key == $Gtk2::Gdk::Keysyms{space}) {
211 # $self->cursor_move (1) or return 1
212 # if $self->{cursor_current} || !$self->cursor_valid;
213 # $self->emit_activate ($self->{cursor}) if $self->cursor_valid;
214 # $self->prefetch (1);
215 # } elsif ($key == $Gtk2::Gdk::Keysyms{BackSpace}) {
216 # $self->cursor_move (-1) or return 1;
217 # $self->emit_activate ($self->{cursor}) if $self->cursor_valid;
218 # $self->prefetch (-1);
219 #
220 # } elsif ($key == ord '^') {
221 # $self->updir if exists $self->{dir};
222 #
223 # } elsif (($key >= (ord '0') && $key <= (ord '9'))
224 # || ($key >= (ord 'a') && $key <= (ord 'z'))) {
225 #
226 # $key = chr $key;
227 #
228 # my ($idx, $cursor) = (0, 0);
229 #
230 # $self->clear_selection;
231 #
232 # for my $entry (@{$self->{entry}}) {
233 # $idx++;
234 # $cursor = $idx if $key gt lcfirst $entry->[1];
235 # }
236 #
237 # if ($cursor < @{$self->{entry}}) {
238 # delete $self->{cursor_current};
239 # $self->{sel}{$cursor} = $self->{entry}[$cursor];
240 # $self->{cursor} = $cursor;
241 #
242 # $self->{adj}->set_value (min $self->{maxrow}, $cursor / $self->{cols});
243 # $self->emit_sel_changed;
244 # $self->invalidate_all;
245 # }
246 # } else {
247 # return 0;
248 # }
249 # }
250 #
251 # 1
252 #}
253
254 #sub invalidate {
255 # my ($self, $x1, $y1, $x2, $y2) = @_;
256 #
257 # return unless $self->{window};
258 #
259 # $self->{draw}->queue_draw_area (
260 # $x1 * (IW + IX), $y1 * (IH + IY),
261 # ($x2 - $x1 + 1) * (IW + IX), ($y2 - $y1 + 1) * (IH + IY),
262 # );
263 #}
264
265 sub invalidate_all {
266 my ($self) = @_;
267
268 # $self->invalidate (0, 0, $self->{cols} - 1, $self->{page} - 1);
269 }
270
271 sub expose {
272 my ($self, $event) = @_;
273
274 no integer;
275
276 my $ox = $self->{x}; my $ix = int $ox / TILESIZE;
277 my $oy = $self->{y}; my $iy = int $oy / TILESIZE;
278
279 for my $area ($event->region->get_rectangles) {
280 my ($x, $y, $w, $h) = $area->values; # x y w h
281
282 my @x = ((int ($ox + $x) / TILESIZE) .. int +($ox + $x + $w + TILESIZE - 1) / TILESIZE);
283 my @y = ((int ($oy + $y) / TILESIZE) .. int +($oy + $y + $h + TILESIZE - 1) / TILESIZE);
284
285 my $PB = $Crossfire::Gtk2::TILECACHE;
286 my $TC = \%Crossfire::Gtk2::TILECACHE;
287
288 my $window = $self->{window};
289
290 my $pb = new Gtk2::Gdk::Pixbuf 'rgb', 0, 8, TILESIZE * (@x + 1), TILESIZE * (@y + 1);
291 $pb->fill (0x00000000);
292
293 for my $x (@x) {
294 for my $y (@y) {
295 for my $a (@{ $self->{map}{map}[$x][$y] || [] }) {
296 my $o = $ARCH->{$a->{_name}}
297 or (warn "arch '$a->{_name}' not found at ($x|$y)\n"), next;
298
299 my $face = $a->{face} || $o->{face};
300 my $tile = $TC->{$face}
301 or (warn "no gfx found for arch '$a->{_name}' at ($x|$y)\n"), next;
302
303 my $idx = $tile->{idx}; # + $a->{x} * $tile->{w} + $a->{y};
304
305 my $dx = ($x - $x[0]) * TILESIZE;
306 my $dy = ($y - $y[0]) * TILESIZE;
307
308 $PB->composite ($pb,
309 $dx, $dy,
310 TILESIZE, TILESIZE,
311 $dx - ($idx % 64) * TILESIZE, $dy - TILESIZE * int $idx / 64,
312 1, 1, 'nearest', 255
313 );
314 }
315 }
316 }
317
318 $pb->render_to_drawable ($window, $self->style->black_gc,
319 0, 0,
320 $x[0] * TILESIZE - $ox, $y[0] * TILESIZE - $oy,
321 TILESIZE * @x, TILESIZE * @y,
322 'max', 0, 0);
323 }
324
325 1
326 }
327
328 my $win = new Gtk2::Window 'toplevel';
329 my $map = new GCE::Map;
330 $win->add ($map);
331 $win->show_all;
332 $map->{map} = arch2map read_arch "$Crossfire::LIB/maps/dungeons/xyzzy-mines";
333 main Gtk2;
334
335 =back
336
337 =head1 AUTHOR
338
339 Marc Lehmann <schmorp@schmorp.de>
340
341 =cut
342
343 1
344