ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/deliantra/Deliantra-Client/DC/UI.pm
Revision: 1.39
Committed: Sun Apr 9 21:39:08 2006 UTC (18 years, 2 months ago) by root
Branch: MAIN
Changes since 1.38: +35 -10 lines
Log Message:
cleanup, but somewhat broken now

File Contents

# User Rev Content
1 elmex 1.6 package Crossfire::Client::Widget;
2 root 1.8
3 elmex 1.1 use strict;
4 root 1.18
5     use Scalar::Util;
6    
7 elmex 1.11 use SDL::OpenGL;
8     use SDL::OpenGL::Constants;
9 elmex 1.1
10     our $FOCUS; # the widget with current focus
11    
12     # class methods for events
13     sub feed_sdl_key_down_event { $FOCUS->key_down ($_[0]) if $FOCUS }
14     sub feed_sdl_key_up_event { $FOCUS->key_up ($_[0]) if $FOCUS }
15 elmex 1.32 sub feed_sdl_button_down_event { }
16     sub feed_sdl_button_up_event { }
17 elmex 1.1
18     sub new {
19     my $class = shift;
20 root 1.10
21     bless { @_ }, $class
22 elmex 1.1 }
23    
24 root 1.18 sub move {
25     my ($self, $x, $y, $z) = @_;
26     $self->{x} = $x;
27     $self->{y} = $y;
28     $self->{z} = $z if defined $z;
29     }
30    
31 elmex 1.20 sub needs_redraw {
32     0
33     }
34    
35 root 1.14 sub size_request {
36 elmex 1.36 require Carp;
37     Carp::confess "size_request is abtract";
38     }
39    
40     sub size_allocate {
41     my ($self, $w, $h) = @_;
42     $self->w ($w);
43     $self->h ($h);
44 root 1.14 }
45    
46 elmex 1.1 sub focus_in {
47     my ($widget) = @_;
48     $FOCUS = $widget;
49     }
50 root 1.4
51 elmex 1.1 sub focus_out {
52     my ($widget) = @_;
53     }
54 root 1.4
55 elmex 1.1 sub key_down {
56     my ($widget, $sdlev) = @_;
57     }
58 root 1.4
59 elmex 1.1 sub key_up {
60     my ($widget, $sdlev) = @_;
61     }
62 root 1.4
63 elmex 1.1 sub button_down {
64     my ($widget, $sdlev) = @_;
65     }
66 root 1.4
67 elmex 1.1 sub button_up {
68     my ($widget, $sdlev) = @_;
69     }
70 root 1.4
71 elmex 1.36 sub w { $_[0]->{w} = $_[1] if $_[1]; $_[0]->{w} }
72     sub h { $_[0]->{h} = $_[1] if $_[1]; $_[0]->{h} }
73 elmex 1.11 sub x { $_[0]->{x} = $_[1] if $_[1]; $_[0]->{x} }
74     sub y { $_[0]->{y} = $_[1] if $_[1]; $_[0]->{y} }
75 elmex 1.13 sub z { $_[0]->{z} = $_[1] if $_[1]; $_[0]->{z} }
76 elmex 1.11
77 elmex 1.1 sub draw {
78 elmex 1.11 my ($self) = @_;
79    
80     glPushMatrix;
81 root 1.12 glTranslate $self->{x}, $self->{y}, 0;
82 elmex 1.11 $self->_draw;
83     glPopMatrix;
84     }
85    
86     sub _draw {
87 root 1.38 my ($self) = @_;
88    
89     warn "no draw defined for $self\n";
90 elmex 1.1 }
91 root 1.4
92 elmex 1.1 sub bbox {
93 elmex 1.32 my ($self) = @_;
94     my ($w, $h) = $self->size_request;
95     (
96     $self->{x},
97     $self->{y},
98     $self->{x} = $w,
99     $self->{y} = $h
100     )
101     }
102    
103 root 1.38 sub find_widget {
104     my ($self, $x, $y) = @_;
105    
106     return $self
107     if $x >= $self->{x} && $x < $self->{x} + $self->{w}
108     && $y >= $self->{y} && $y < $self->{y} + $self->{h};
109    
110     ()
111     }
112    
113 elmex 1.32 sub del_parent { $_[0]->{parent} = undef }
114    
115     sub set_parent {
116     my ($self, $par) = @_;
117    
118     $self->{parent} = $par;
119     Scalar::Util::weaken $self->{parent};
120     }
121    
122     sub get_parent {
123     $_[0]->{parent}
124     }
125    
126     sub update {
127     my ($self) = @_;
128    
129     $self->{parent}->update
130     if $self->{parent};
131 elmex 1.1 }
132 elmex 1.2
133 root 1.18 sub DESTROY {
134     my ($self) = @_;
135    
136 elmex 1.32 #$self->deactivate;
137 root 1.18 }
138    
139 root 1.39 #############################################################################
140    
141 root 1.38 package Crossfire::Client::Widget::Container;
142 elmex 1.15
143     our @ISA = Crossfire::Client::Widget::;
144    
145 root 1.38 sub new {
146     my ($class, @widgets) = @_;
147    
148     my $self = $class->SUPER::new (children => []);
149     $self->add ($_) for @widgets;
150    
151     $self
152     }
153    
154     sub add {
155     my ($self, $chld, $expand) = @_;
156    
157     $chld->{expand} = $expand;
158     $chld->set_parent ($self);
159    
160     @{$self->{children}} =
161     sort { $a->{z} <=> $b->{z} }
162     @{$self->{children}}, $chld;
163    
164     $self->size_allocate ($self->{w}, $self->{h});
165     }
166 root 1.35
167 elmex 1.32 sub remove {
168 root 1.38 my ($self, $widget) = @_;
169    
170     $self->{children} = [ grep $_ != $widget, @{ $self->{children} } ];
171    
172     $self->size_allocate ($self->{w}, $self->{h});
173     }
174    
175     sub find_widget {
176     my ($self, $x, $y) = @_;
177    
178     my $res;
179    
180     for (@{ $self->{children} }) {
181     $res = $_->find_widget ($x, $y)
182     and return $res;
183     }
184    
185     ()
186 elmex 1.32 }
187 elmex 1.15
188 root 1.35 sub size_request {
189 root 1.38 my ($self) = @_;
190    
191     my ($hs, $ws) = (0, 0);
192     for (@{$self->{children} || []}) {
193     my ($w, $h) = $_->size_request;
194     $hs += $h;
195     if ($ws < $w) { $ws = $w }
196     }
197    
198     return ($ws, $hs);
199 elmex 1.36 }
200 elmex 1.15
201 root 1.35 sub _draw {
202     my ($self) = @_;
203    
204 root 1.38 $_->draw for @{$self->{children}};
205 root 1.35 }
206 elmex 1.15
207 root 1.39 #############################################################################
208    
209 root 1.38 package Crossfire::Client::Widget::Bin;
210 elmex 1.32
211 root 1.38 our @ISA = Crossfire::Client::Widget::Container::;
212 elmex 1.32
213 root 1.39 sub child { $_[0]->{children}[0] }
214 elmex 1.32
215 root 1.38 sub size_request {
216     $_[0]{children}[0]->size_request if $_[0]{children}[0];
217     }
218 elmex 1.32
219 root 1.38 sub size_allocate {
220     my ($self, $w, $h) = @_;
221     $self->SUPER::size_allocate ($w, $h);
222     $self->{children}[0]->size_allocate ($w, $h)
223     if $self->{children}[0]
224     }
225 elmex 1.32
226 root 1.39 #############################################################################
227    
228 root 1.38 package Crossfire::Client::Widget::Toplevel;
229 elmex 1.32
230 root 1.38 our @ISA = Crossfire::Client::Widget::Container::;
231 elmex 1.32
232     sub update {
233     my ($self) = @_;
234 root 1.38
235 elmex 1.32 ::refresh ();
236     }
237    
238 root 1.39 #############################################################################
239    
240 elmex 1.20 package Crossfire::Client::Widget::Window;
241    
242 root 1.35 our @ISA = Crossfire::Client::Widget::Bin::;
243 elmex 1.20
244     use SDL::OpenGL;
245    
246     sub add {
247     my ($self, $chld) = @_;
248 elmex 1.36 warn "ADD $chld\n";
249 elmex 1.20 $self->SUPER::add ($chld);
250 elmex 1.32 $chld->set_parent ($self);
251     }
252    
253     sub remove {
254     my ($self) = @_;
255     # TODO FIXME: removing a child from a window will crash, see render_chld
256 elmex 1.36 # $self->update;
257 elmex 1.32 }
258    
259     sub update {
260     my ($self) = @_;
261     $self->render_chld;
262 elmex 1.20 }
263    
264     sub render_chld {
265     my ($self) = @_;
266     my $chld = $self->get;
267     my ($w, $h) = $self->size_request;
268    
269 elmex 1.36 require Carp;
270     Carp::cluck "RENDERCHI $w $h";
271     warn "RENDERCHI $w $h\n";
272 elmex 1.20 $self->{texture} =
273     Crossfire::Client::Texture->new_from_opengl (
274 root 1.23 $w, $h, sub { $chld->draw }
275 elmex 1.20 );
276     $self->{texture}->upload;
277     }
278    
279     sub size_request {
280     my ($self) = @_;
281 elmex 1.36 ($self->w, $self->h)
282     }
283    
284     sub size_allocate {
285     my ($self, $w, $h) = @_;
286    
287     $self->w ($w);
288     $self->h ($h);
289     $self->get->size_allocate ($w, $h);
290    
291     $self->update; #TODO: Move this to the size_request event propably?
292 elmex 1.20 }
293    
294     sub _draw {
295     my ($self) = @_;
296    
297 elmex 1.36 my ($w, $h) = ($self->w, $self->h);
298 root 1.29
299 elmex 1.20 my $tex = $self->{texture}
300     or return;
301    
302     glEnable GL_BLEND;
303     glEnable GL_TEXTURE_2D;
304 root 1.35 glTexEnv GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE;
305 elmex 1.20 glBindTexture GL_TEXTURE_2D, $tex->{name};
306    
307     glBegin GL_QUADS;
308 root 1.23 glTexCoord 0, 0; glVertex 0, 0;
309     glTexCoord 0, 1; glVertex 0, $h;
310     glTexCoord 1, 1; glVertex $w, $h;
311     glTexCoord 1, 0; glVertex $w, 0;
312 elmex 1.20 glEnd;
313    
314     glDisable GL_BLEND;
315     glDisable GL_TEXTURE_2D;
316     }
317    
318 root 1.39 #############################################################################
319    
320 elmex 1.15 package Crossfire::Client::Widget::Frame;
321    
322 root 1.35 our @ISA = Crossfire::Client::Widget::Bin::;
323 elmex 1.15
324     use SDL::OpenGL;
325    
326     sub size_request {
327     my ($self) = @_;
328 root 1.39 my $chld = $self->child
329 elmex 1.15 or return (0, 0);
330 root 1.30
331     $chld->move (2, 2);
332    
333 elmex 1.15 map { $_ + 4 } $chld->size_request;
334     }
335    
336 elmex 1.36 sub size_allocate {
337     my ($self, $w, $h) = @_;
338    
339     $self->w ($w);
340     $self->h ($h);
341    
342 root 1.39 $self->child->size_allocate ($w - 4, $h - 4);
343     $self->child->move (2, 2);
344 elmex 1.36 }
345    
346 elmex 1.15 sub _draw {
347     my ($self) = @_;
348    
349 root 1.39 my $chld = $self->child;
350 elmex 1.15
351     my ($w, $h) = $chld->size_request;
352    
353     glBegin GL_QUADS;
354 root 1.30 glColor 0, 0, 0;
355 elmex 1.15 glTexCoord 0, 0; glVertex 0 , 0;
356     glTexCoord 0, 1; glVertex 0 , $h + 4;
357     glTexCoord 1, 1; glVertex $w + 4 , $h + 4;
358     glTexCoord 1, 0; glVertex $w + 4 , 0;
359     glEnd;
360    
361 root 1.23 $chld->draw;
362 elmex 1.15 }
363    
364 root 1.39 #############################################################################
365    
366 elmex 1.31 package Crossfire::Client::Widget::FancyFrame;
367    
368     our @ISA = Crossfire::Client::Widget::Frame::;
369    
370     use SDL::OpenGL;
371    
372 elmex 1.34 sub new {
373     my ($self, $theme) = @_;
374     $self = $self->SUPER::new;
375    
376     $self->{txts} = [
377     map { new_from_file Crossfire::Client::Texture Crossfire::Client::find_rcfile $_ }
378     qw/d1_bg.png d1_border_top.png d1_border_right.png d1_border_left.png d1_border_bottom.png/
379     ];
380     $self
381     }
382    
383     sub size_request {
384     my ($self) = @_;
385 root 1.39
386     my ($w, $h) = $self->SUPER::size_request;
387 elmex 1.34
388     $h += $self->{txts}->[1]->{height};
389     $h += $self->{txts}->[4]->{height};
390     $w += $self->{txts}->[2]->{width};
391     $w += $self->{txts}->[3]->{width};
392    
393 elmex 1.36 ($w, $h)
394     }
395    
396     sub size_allocate {
397     my ($self, $w, $h) = @_;
398    
399     $self->w ($w);
400     $self->h ($h);
401     $h -= $self->{txts}->[1]->{height};
402     $h -= $self->{txts}->[4]->{height};
403     $w -= $self->{txts}->[2]->{width};
404     $w -= $self->{txts}->[3]->{width};
405    
406     $h = $h < 0 ? 0 : $h;
407     $w = $w < 0 ? 0 : $w;
408     warn "CHILD:$w $h\n";
409 root 1.39 $self->child->size_allocate ($w, $h);
410     $self->child->move ($self->{txts}->[3]->{width}, $self->{txts}->[1]->{height});
411 elmex 1.34 }
412    
413     sub _draw {
414     my ($self) = @_;
415    
416 elmex 1.36 my ($w, $h) = ($self->w, $self->h);
417 root 1.39 my ($cw, $ch) = ($self->child->w, $self->child->h);
418 elmex 1.34
419     glEnable GL_BLEND;
420     glEnable GL_TEXTURE_2D;
421     glBlendFunc GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA;
422 elmex 1.36 glTexEnv GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE;
423 elmex 1.34
424     my $top = $self->{txts}->[1];
425 elmex 1.36 glBindTexture GL_TEXTURE_2D, $top->{name};
426 elmex 1.34
427 elmex 1.36 glBegin GL_QUADS;
428     glTexCoord 0, 0; glVertex 0 , 0;
429     glTexCoord 0, 1; glVertex 0 , $top->{height};
430     glTexCoord 1, 1; glVertex $w , $top->{height};
431     glTexCoord 1, 0; glVertex $w , 0;
432     glEnd;
433 elmex 1.34
434     my $left = $self->{txts}->[3];
435 elmex 1.36 glBindTexture GL_TEXTURE_2D, $left->{name};
436 elmex 1.34
437 elmex 1.36 glBegin GL_QUADS;
438     glTexCoord 0, 0; glVertex 0 , $top->{height};
439     glTexCoord 0, 1; glVertex 0 , $top->{height} + $ch;
440     glTexCoord 1, 1; glVertex $left->{width}, $top->{height} + $ch;
441     glTexCoord 1, 0; glVertex $left->{width}, $top->{height};
442     glEnd;
443 elmex 1.34
444     my $right = $self->{txts}->[2];
445 elmex 1.36 glBindTexture GL_TEXTURE_2D, $right->{name};
446 elmex 1.34
447 elmex 1.36 glBegin GL_QUADS;
448     glTexCoord 0, 0; glVertex $w - $right->{width}, $top->{height};
449     glTexCoord 0, 1; glVertex $w - $right->{width}, $top->{height} + $ch;
450     glTexCoord 1, 1; glVertex $w , $top->{height} + $ch;
451     glTexCoord 1, 0; glVertex $w , $top->{height};
452     glEnd;
453 elmex 1.34
454     my $bottom = $self->{txts}->[4];
455 elmex 1.36 glBindTexture GL_TEXTURE_2D, $bottom->{name};
456 elmex 1.34
457 elmex 1.36 glBegin GL_QUADS;
458     glTexCoord 0, 0; glVertex 0 , $h - $bottom->{height};
459     glTexCoord 0, 1; glVertex 0 , $h;
460     glTexCoord 1, 1; glVertex $w , $h;
461     glTexCoord 1, 0; glVertex $w , $h - $bottom->{height};
462     glEnd;
463 elmex 1.34
464 elmex 1.36 my $bg = $self->{txts}->[0];
465     glBindTexture GL_TEXTURE_2D, $bg->{name};
466     glTexEnv GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE;
467     glTexParameter GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT;
468     glTexParameter GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT;
469 elmex 1.34
470 elmex 1.36 my $rep_x = $cw / $bg->{width};
471     my $rep_y = $ch / $bg->{height};
472 elmex 1.34
473 elmex 1.36 glBegin GL_QUADS;
474     glTexCoord 0, 0; glVertex $left->{width}, $top->{height};
475     glTexCoord 0, $rep_y; glVertex $left->{width}, $top->{height} + $ch;
476     glTexCoord $rep_x, $rep_y; glVertex $left->{width} + $cw , $top->{height} + $ch;
477     glTexCoord $rep_x, 0; glVertex $left->{width} + $cw , $top->{height};
478     glEnd;
479 elmex 1.34
480     glDisable GL_BLEND;
481     glDisable GL_TEXTURE_2D;
482 elmex 1.36
483 root 1.39 $self->child->draw;
484 elmex 1.36
485 elmex 1.34 }
486 elmex 1.31
487 root 1.39 #############################################################################
488    
489 elmex 1.15 package Crossfire::Client::Widget::Table;
490    
491 root 1.35 our @ISA = Crossfire::Client::Widget::Bin::;
492 elmex 1.15
493     use SDL::OpenGL;
494    
495     sub add {
496     my ($self, $x, $y, $chld) = @_;
497 root 1.38 my $old_chld = $self->{children}[$y][$x];
498 elmex 1.32
499 root 1.38 $self->{children}[$y][$x] = $chld;
500 elmex 1.32 $chld->set_parent ($self);
501     $self->update;
502 elmex 1.15 }
503    
504     sub max_row_height {
505     my ($self, $row) = @_;
506    
507     my $hs = 0;
508 root 1.38 for (my $xi = 0; $xi <= $#{$self->{children}->[$row] || []}; $xi++) {
509     my $c = $self->{children}->[$row]->[$xi];
510 elmex 1.17 if ($c) {
511     my ($w, $h) = $c->size_request;
512     if ($hs < $h) { $hs = $h }
513     }
514 elmex 1.15 }
515     return $hs;
516     }
517    
518     sub max_col_width {
519     my ($self, $col) = @_;
520    
521     my $ws = 0;
522 root 1.38 for (my $yi = 0; $yi <= $#{$self->{children} || []}; $yi++) {
523     my $c = ($self->{children}->[$yi] || [])->[$col];
524 elmex 1.17 if ($c) {
525     my ($w, $h) = $c->size_request;
526     if ($ws < $w) { $ws = $w }
527     }
528 elmex 1.15 }
529     return $ws;
530     }
531    
532     sub size_request {
533     my ($self) = @_;
534    
535     my ($hs, $ws) = (0, 0);
536    
537 root 1.38 for (my $yi = 0; $yi <= $#{$self->{children}}; $yi++) {
538 elmex 1.15 $hs += $self->max_row_height ($yi);
539     }
540    
541 root 1.38 for (my $yi = 0; $yi <= $#{$self->{children}}; $yi++) {
542 elmex 1.15 my $wm = 0;
543 root 1.38 for (my $xi = 0; $xi <= $#{$self->{children}->[$yi]}; $xi++) {
544 elmex 1.15 $wm += $self->max_col_width ($xi)
545     }
546     if ($ws < $wm) { $ws = $wm }
547     }
548    
549     return ($ws, $hs);
550     }
551    
552     sub _draw {
553     my ($self) = @_;
554    
555     my $y = 0;
556 root 1.38 for (my $yi = 0; $yi <= $#{$self->{children}}; $yi++) {
557 elmex 1.15 my $x = 0;
558    
559 root 1.38 for (my $xi = 0; $xi <= $#{$self->{children}->[$yi]}; $xi++) {
560 elmex 1.15
561 root 1.38 my $c = $self->{children}->[$yi]->[$xi];
562 elmex 1.26 if ($c) {
563     $c->move ($x, $y, 0); #TODO: Move to size_request
564     $c->draw if $c;
565     }
566 elmex 1.15
567     $x += $self->max_col_width ($xi);
568     }
569    
570     $y += $self->max_row_height ($yi);
571     }
572     }
573    
574 root 1.39 #############################################################################
575    
576 elmex 1.15 package Crossfire::Client::Widget::VBox;
577    
578 root 1.38 our @ISA = Crossfire::Client::Widget::Container::;
579 elmex 1.15
580     use SDL::OpenGL;
581    
582 elmex 1.36 sub size_allocate {
583     my ($self, $w, $h) = @_;
584    
585     $self->w ($w);
586     $self->h ($h);
587    
588     my $exp;
589     my @oth;
590     # find expand widget
591 root 1.38 for (@{$self->{children}}) {
592 elmex 1.36 if ($_->{expand}) {
593     $exp = $_;
594     last;
595     }
596     push @oth, $_;
597     }
598    
599     my ($ow, $oh);
600    
601     # get sizes of other widgets
602     for (@oth) {
603     my ($w, $h) = $_->size_request;
604     $oh += $h;
605     if ($ow < $w) { $ow = $w }
606     }
607    
608     my $y = 0;
609 root 1.38 for (@{$self->{children}}) {
610 elmex 1.36 $_->move (0, $y);
611    
612     if ($_ == $exp) {
613     $_->size_allocate ($w, $h - $oh);
614     $y += $h - $oh;
615     } else {
616     my ($cw, $h) = $_->size_request;
617     $_->size_allocate ($w, $h);
618     $y += $h;
619     }
620     }
621     }
622    
623 elmex 1.15 sub _draw {
624     my ($self) = @_;
625    
626     my ($x, $y);
627 root 1.38 for (@{$self->{children} || []}) {
628 root 1.23 $_->draw;
629 elmex 1.36 $y += $_->h;
630 elmex 1.15 }
631     }
632    
633 root 1.39 #############################################################################
634    
635 root 1.10 package Crossfire::Client::Widget::Label;
636    
637 root 1.12 our @ISA = Crossfire::Client::Widget::;
638    
639 root 1.10 use SDL::OpenGL;
640    
641     sub new {
642 root 1.28 my ($class, $x, $y, $z, $height, $text) = @_;
643 root 1.10
644 root 1.33 # TODO: color, and make height, xyz etc. optional
645 root 1.28 my $self = $class->SUPER::new (x => $x, y => $y, z => $z, height => $height);
646 root 1.10
647 elmex 1.15 $self->set_text ($text);
648 root 1.10
649     $self
650     }
651    
652 elmex 1.15 sub set_text {
653     my ($self, $text) = @_;
654 root 1.28
655     $self->{text} = $text;
656 elmex 1.32 $self->{texture} = new_from_text Crossfire::Client::Texture $text, $self->{height};
657 root 1.28
658 elmex 1.32 $self->update;
659 elmex 1.15 }
660    
661     sub get_text {
662     my ($self, $text) = @_;
663 root 1.28
664 elmex 1.15 $self->{text}
665     }
666    
667 root 1.14 sub size_request {
668     my ($self) = @_;
669    
670     (
671     $self->{texture}{width},
672     $self->{texture}{height},
673     )
674     }
675    
676 elmex 1.11 sub _draw {
677 root 1.10 my ($self) = @_;
678    
679     my $tex = $self->{texture};
680    
681 root 1.12 glEnable GL_BLEND;
682 root 1.10 glEnable GL_TEXTURE_2D;
683 root 1.30 glBlendFunc GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA;
684 root 1.28 glTexEnv GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE;
685 root 1.10 glBindTexture GL_TEXTURE_2D, $tex->{name};
686    
687 elmex 1.36 glColor 1, 0, 0, 1; # TODO color
688 root 1.12
689 root 1.10 glBegin GL_QUADS;
690     glTexCoord 0, 0; glVertex 0 , 0;
691     glTexCoord 0, 1; glVertex 0 , $tex->{height};
692     glTexCoord 1, 1; glVertex $tex->{width}, $tex->{height};
693     glTexCoord 1, 0; glVertex $tex->{width}, 0;
694     glEnd;
695    
696 root 1.12 glDisable GL_BLEND;
697 root 1.10 glDisable GL_TEXTURE_2D;
698     }
699    
700 root 1.39 #############################################################################
701    
702 elmex 1.31 package Crossfire::Client::Widget::TextEntry;
703    
704     our @ISA = Crossfire::Client::Widget::Label::;
705    
706     use SDL;
707     use SDL::OpenGL;
708    
709     sub key_down {
710     my ($self, $ev) = @_;
711    
712     my $mod = $ev->key_mod;
713     my $sym = $ev->key_sym;
714    
715     $ev->set_unicode (1);
716     my $uni = $ev->key_unicode;
717    
718     my $text = $self->get_text;
719    
720     if ($sym == SDLK_BACKSPACE) {
721     substr $text, -1, 1, '';
722    
723     } elsif ($uni) {
724     $text .= chr $uni;
725     }
726     $self->set_text ($text);
727     }
728    
729 root 1.39 #############################################################################
730    
731 elmex 1.9 package Crossfire::Client::Widget::MapWidget;
732 root 1.4
733 elmex 1.2 use strict;
734 elmex 1.7
735 root 1.25 use List::Util qw(min max);
736 elmex 1.2
737 root 1.16 use SDL;
738 elmex 1.2 use SDL::OpenGL;
739     use SDL::OpenGL::Constants;
740    
741 root 1.25 our @ISA = Crossfire::Client::Widget::;
742    
743 elmex 1.2 sub key_down {
744     print "MAPKEYDOWN\n";
745     }
746    
747     sub key_up {
748     }
749    
750 elmex 1.36 sub size_request {
751    
752     }
753    
754     sub size_allocate {
755     }
756    
757 elmex 1.11 sub _draw {
758 root 1.21 my ($self) = @_;
759    
760 root 1.25 my $mx = $::CONN->{mapx};
761     my $my = $::CONN->{mapy};
762    
763     my $map = $::CONN->{map};
764    
765     my ($xofs, $yofs);
766    
767     my $sw = 1 + int $::WIDTH / 32;
768     my $sh = 1 + int $::HEIGHT / 32;
769    
770     if ($::CONN->{mapw} > $sw) {
771 root 1.27 $xofs = $mx + ($::CONN->{mapw} - $sw) * 0.5;
772 root 1.25 } else {
773     $xofs = $self->{xofs} = min $mx, max $mx + $::CONN->{mapw} - $sw + 1, $self->{xofs};
774     }
775    
776     if ($::CONN->{maph} > $sh) {
777 root 1.27 $yofs = $my + ($::CONN->{maph} - $sh) * 0.5;
778 root 1.25 } else {
779     $yofs = $self->{yofs} = min $my, max $my + $::CONN->{maph} - $sh + 1, $self->{yofs};
780     }
781    
782 elmex 1.2 glEnable GL_TEXTURE_2D;
783     glEnable GL_BLEND;
784 root 1.35 glTexEnv GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE;
785    
786     my $sw4 = ($sw + 3) & ~3;
787     my $lighting = "\x00" x ($sw4 * $sh);
788 elmex 1.2
789 root 1.25 for my $x (0 .. $sw - 1) {
790     for my $y (0 .. $sh - 1) {
791 elmex 1.2
792 root 1.25 my $cell = $map->[$x + $xofs][$y + $yofs]
793 elmex 1.2 or next;
794    
795 root 1.21 my $darkness = $cell->[0] * (1 / 255);
796     if ($darkness < 0) {
797 root 1.35 $darkness = 0.15;
798 root 1.21 }
799 root 1.35 substr $lighting, $y * $sw4 + $x, 1, chr 255 - $darkness * 255;
800 elmex 1.2
801 root 1.21 for my $num (grep $_, @$cell[1,2,3]) {
802 root 1.4 my $tex = $::CONN->{face}[$num]{texture} || next;
803 elmex 1.2
804 root 1.4 glBindTexture GL_TEXTURE_2D, $tex->{name};
805 elmex 1.2
806 root 1.19 my $w = $tex->{width};
807     my $h = $tex->{height};
808    
809     my $px = ($x + 1) * 32 - $w;
810     my $py = ($y + 1) * 32 - $h;
811    
812 elmex 1.2 glBegin GL_QUADS;
813 root 1.19 glTexCoord 0, 0; glVertex $px , $py;
814     glTexCoord 0, 1; glVertex $px , $py + $h;
815     glTexCoord 1, 1; glVertex $px + $w, $py + $h;
816     glTexCoord 1, 0; glVertex $px + $w, $py;
817 elmex 1.2 glEnd;
818     }
819     }
820     }
821    
822 root 1.35 # if (1) { # higher quality darkness
823     # $lighting =~ s/(.)/$1$1$1/gs;
824     # my $pb = new_from_data Gtk2::Gdk::Pixbuf $lighting, "rgb", 0, 8, $sw4, $sh, $sw4 * 3;
825     #
826     # $pb = $pb->scale_simple ($sw4 * 0.5, $sh * 0.5, "bilinear");
827     #
828     # $lighting = $pb->get_pixels;
829     # $lighting =~ s/(.)../$1/gs;
830     # }
831    
832     $lighting = new Crossfire::Client::Texture
833     width => $sw4,
834     height => $sh,
835     data => $lighting,
836     internalformat => GL_ALPHA4,
837     format => GL_ALPHA;
838    
839     glBlendFunc GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA;
840     glColor 0, 0, 0, 0.75;
841     glTexEnv GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE;
842     glBindTexture GL_TEXTURE_2D, $lighting->{name};
843     glTexParameter GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR;
844     glBegin GL_QUADS;
845     glTexCoord 0, 0; glVertex 0 , 0;
846     glTexCoord 0, 1; glVertex 0 , $sh * 32;
847     glTexCoord 1, 1; glVertex $sw4 * 32, $sh * 32;
848     glTexCoord 1, 0; glVertex $sw4 * 32, 0;
849     glEnd;
850    
851 elmex 1.2 glDisable GL_TEXTURE_2D;
852     glDisable GL_BLEND;
853     }
854    
855 root 1.16 my %DIR = (
856     SDLK_KP8, [1, "north"],
857 root 1.18 SDLK_KP9, [2, "northeast"],
858 root 1.16 SDLK_KP6, [3, "east"],
859     SDLK_KP3, [4, "southeast"],
860     SDLK_KP2, [5, "south"],
861     SDLK_KP1, [6, "southwest"],
862     SDLK_KP4, [7, "west"],
863     SDLK_KP7, [8, "northwest"],
864 root 1.18
865     SDLK_UP, [1, "north"],
866     SDLK_RIGHT, [3, "east"],
867     SDLK_DOWN, [5, "south"],
868     SDLK_LEFT, [7, "west"],
869 root 1.16 );
870    
871     sub key_down {
872     my ($self, $ev) = @_;
873    
874     my $mod = $ev->key_mod;
875     my $sym = $ev->key_sym;
876    
877     if ($sym == SDLK_KP5) {
878     $::CONN->send ("command stay fire");
879     } elsif (exists $DIR{$sym}) {
880     if ($mod & KMOD_SHIFT) {
881 root 1.18 $self->{shft}++;
882 root 1.16 $::CONN->send ("command fire $DIR{$sym}[0]");
883     } elsif ($mod & KMOD_CTRL) {
884 root 1.18 $self->{ctrl}++;
885 root 1.16 $::CONN->send ("command run $DIR{$sym}[0]");
886     } else {
887 root 1.18 $::CONN->send ("command $DIR{$sym}[1]");
888 root 1.16 }
889     }
890     }
891    
892     sub key_up {
893     my ($self, $ev) = @_;
894    
895     my $mod = $ev->key_mod;
896     my $sym = $ev->key_sym;
897    
898 root 1.18 if (!($mod & KMOD_SHIFT) && delete $self->{shft}) {
899     $::CONN->send ("command fire_stop");
900     }
901     if (!($mod & KMOD_CTRL ) && delete $self->{ctrl}) {
902     $::CONN->send ("command run_stop");
903 root 1.16 }
904     }
905    
906 root 1.39 #############################################################################
907    
908 root 1.35 package Crossfire::Client::Widget::Animator;
909    
910     use SDL::OpenGL;
911    
912     our @ISA = Crossfire::Client::Widget::Bin::;
913    
914     sub moveto {
915     my ($self, $x, $y) = @_;
916    
917     $self->{moveto} = [$self->{x}, $self->{y}, $x, $y];
918 root 1.37 $self->{speed} = 0.2;
919 root 1.35 $self->{time} = 1;
920    
921     ::animation_start $self;
922     }
923    
924     sub animate {
925     my ($self, $interval) = @_;
926    
927     $self->{time} -= $interval * $self->{speed};
928     if ($self->{time} <= 0) {
929     $self->{time} = 0;
930     ::animation_stop $self;
931     }
932    
933     my ($x0, $y0, $x1, $y1) = @{$self->{moveto}};
934    
935     $self->{x} = $x0 * $self->{time} + $x1 * (1 - $self->{time});
936     $self->{y} = $y0 * $self->{time} + $y1 * (1 - $self->{time});
937     }
938    
939     sub _draw {
940     my ($self) = @_;
941    
942     glPushMatrix;
943     glRotate $self->{time} * 10000, 0, 1, 0;
944 root 1.38 $self->{children}[0]->draw;
945 root 1.35 glPopMatrix;
946     }
947    
948 elmex 1.1 1;
949 root 1.5