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