ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/cvsroot/cf.schmorp.de/gde/GCE/Map.pm
Revision: 1.6
Committed: Sun Feb 5 18:08:52 2006 UTC (20 years, 8 months ago) by root
Branch: MAIN
Changes since 1.5: +3 -3 lines
Log Message:
*** empty log message ***

File Contents

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