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