ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/deliantra/Deliantra-Client/DC/UI.pm
Revision: 1.50
Committed: Sun Apr 9 22:27:24 2006 UTC (18 years, 2 months ago) by root
Branch: MAIN
Changes since 1.49: +2 -0 lines
Log Message:
*** empty log message ***

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