ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/deliantra/Deliantra-Client/DC/UI.pm
Revision: 1.19
Committed: Sat Apr 8 14:04:14 2006 UTC (18 years, 1 month ago) by root
Branch: MAIN
Changes since 1.18: +10 -4 lines
Log Message:
bigface support

File Contents

# Content
1 package Crossfire::Client::Widget;
2
3 use strict;
4
5 use Scalar::Util;
6
7 use SDL::OpenGL;
8 use SDL::OpenGL::Constants;
9
10 our $FOCUS; # the widget with current focus
11 our @ACTIVE_WIDGETS;
12
13 # class methods for events
14 sub feed_sdl_key_down_event { $FOCUS->key_down ($_[0]) if $FOCUS }
15 sub feed_sdl_key_up_event { $FOCUS->key_up ($_[0]) if $FOCUS }
16 sub feed_sdl_button_down_event { $FOCUS->button_down ($_[0]) if $FOCUS }
17 sub feed_sdl_button_up_event { $FOCUS->button_up ($_[0]) if $FOCUS }
18
19 sub new {
20 my $class = shift;
21
22 bless { @_ }, $class
23 }
24
25 sub activate {
26 push @ACTIVE_WIDGETS, $_[0];
27 Scalar::Util::weaken $ACTIVE_WIDGETS[-1];
28 }
29
30 sub deactivate {
31 @ACTIVE_WIDGETS =
32 sort { $a->{z} <=> $b->{z} }
33 grep { $_ && $_ != $_[0] }
34 @ACTIVE_WIDGETS;
35 }
36
37 sub move {
38 my ($self, $x, $y, $z) = @_;
39 $self->{x} = $x;
40 $self->{y} = $y;
41 $self->{z} = $z if defined $z;
42 }
43
44 sub size_request {
45 die "size_request is abtract";
46 }
47
48 sub focus_in {
49 my ($widget) = @_;
50 $FOCUS = $widget;
51 }
52
53 sub focus_out {
54 my ($widget) = @_;
55 }
56
57 sub key_down {
58 my ($widget, $sdlev) = @_;
59 }
60
61 sub key_up {
62 my ($widget, $sdlev) = @_;
63 }
64
65 sub button_down {
66 my ($widget, $sdlev) = @_;
67 }
68
69 sub button_up {
70 my ($widget, $sdlev) = @_;
71 }
72
73 sub w { $_[0]->{w} }
74 sub h { $_[0]->{h} }
75 sub x { $_[0]->{x} = $_[1] if $_[1]; $_[0]->{x} }
76 sub y { $_[0]->{y} = $_[1] if $_[1]; $_[0]->{y} }
77 sub z { $_[0]->{z} = $_[1] if $_[1]; $_[0]->{z} }
78
79 sub draw {
80 my ($self) = @_;
81
82 glPushMatrix;
83 glTranslate $self->{x}, $self->{y}, 0;
84 $self->_draw;
85 glPopMatrix;
86 }
87
88 sub _draw {
89 my ($widget) = @_;
90 }
91
92 sub bbox {
93 my ($widget) = @_;
94 }
95
96 sub DESTROY {
97 my ($self) = @_;
98
99 $self->deactivate;
100 }
101
102 package Crossfire::Client::Widget::Container;
103
104 our @ISA = Crossfire::Client::Widget::;
105
106 use SDL::OpenGL;
107
108 sub add { $_[0]->{child} = $_[1] }
109 sub get { $_[0]->{child} }
110
111 sub size_request { $_[0]->{child}->size_request if $_[0]->{child} }
112
113 sub _draw { die "Containers can't be drawn!" }
114
115 package Crossfire::Client::Widget::Frame;
116
117 our @ISA = Crossfire::Client::Widget::Container::;
118
119 use SDL::OpenGL;
120
121 sub size_request {
122 my ($self) = @_;
123 my $chld = $self->get
124 or return (0, 0);
125 map { $_ + 4 } $chld->size_request;
126 }
127
128 sub _draw {
129 my ($self) = @_;
130
131 my $chld = $self->get;
132
133 my ($w, $h) = $chld->size_request;
134
135 glColor 1, 0, 0;
136 glBegin GL_QUADS;
137 glTexCoord 0, 0; glVertex 0 , 0;
138 glTexCoord 0, 1; glVertex 0 , $h + 4;
139 glTexCoord 1, 1; glVertex $w + 4 , $h + 4;
140 glTexCoord 1, 0; glVertex $w + 4 , 0;
141 glEnd;
142
143 glPushMatrix;
144 glTranslate (2, 2, 0);
145 $chld->_draw;
146 glPopMatrix;
147 }
148
149 package Crossfire::Client::Widget::Table;
150
151 our @ISA = Crossfire::Client::Widget::Container::;
152
153 use SDL::OpenGL;
154
155 sub add {
156 my ($self, $x, $y, $chld) = @_;
157 $self->{childs}[$y][$x] = $chld;
158 }
159
160 sub max_row_height {
161 my ($self, $row) = @_;
162
163 my $hs = 0;
164 for (my $xi = 0; $xi <= $#{$self->{childs}->[$row] || []}; $xi++) {
165 my $c = $self->{childs}->[$row]->[$xi];
166 if ($c) {
167 my ($w, $h) = $c->size_request;
168 if ($hs < $h) { $hs = $h }
169 }
170 }
171 return $hs;
172 }
173
174 sub max_col_width {
175 my ($self, $col) = @_;
176
177 my $ws = 0;
178 for (my $yi = 0; $yi <= $#{$self->{childs} || []}; $yi++) {
179 my $c = ($self->{childs}->[$yi] || [])->[$col];
180 if ($c) {
181 my ($w, $h) = $c->size_request;
182 if ($ws < $w) { $ws = $w }
183 }
184 }
185 return $ws;
186 }
187
188 sub size_request {
189 my ($self) = @_;
190
191 my ($hs, $ws) = (0, 0);
192
193 for (my $yi = 0; $yi <= $#{$self->{childs}}; $yi++) {
194 $hs += $self->max_row_height ($yi);
195 }
196
197 for (my $yi = 0; $yi <= $#{$self->{childs}}; $yi++) {
198 my $wm = 0;
199 for (my $xi = 0; $xi <= $#{$self->{childs}->[$yi]}; $xi++) {
200 $wm += $self->max_col_width ($xi)
201 }
202 if ($ws < $wm) { $ws = $wm }
203 }
204
205 return ($ws, $hs);
206 }
207
208 sub _draw {
209 my ($self) = @_;
210
211 my $y = 0;
212 for (my $yi = 0; $yi <= $#{$self->{childs}}; $yi++) {
213 my $x = 0;
214
215 for (my $xi = 0; $xi <= $#{$self->{childs}->[$yi]}; $xi++) {
216
217 glPushMatrix;
218 glTranslate ($x, $y, 0);
219 my $c = $self->{childs}->[$yi]->[$xi];
220 $c->_draw if $c;
221 glPopMatrix;
222
223 $x += $self->max_col_width ($xi);
224 }
225
226 $y += $self->max_row_height ($yi);
227 }
228 }
229
230 package Crossfire::Client::Widget::VBox;
231
232 our @ISA = Crossfire::Client::Widget::Container::;
233
234 use SDL::OpenGL;
235
236 sub add {
237 my ($self, $chld) = @_;
238 push @{$self->{childs}}, $chld;
239 }
240
241 sub size_request {
242 my ($self) = @_;
243
244 my ($hs, $ws) = (0, 0);
245 for (@{$self->{childs} || []}) {
246 my ($w, $h) = $_->size_request;
247 $hs += $h;
248 if ($ws < $w) { $ws = $w }
249 }
250
251 return ($ws, $hs);
252 }
253
254 sub _draw {
255 my ($self) = @_;
256
257 my ($x, $y);
258 for (@{$self->{childs} || []}) {
259 glPushMatrix;
260 glTranslate (0, $y, 0);
261 $_->_draw;
262 glPopMatrix;
263 my ($w, $h) = $_->size_request;
264 $y += $h;
265 }
266 }
267
268 package Crossfire::Client::Widget::Label;
269
270 our @ISA = Crossfire::Client::Widget::;
271
272 use SDL::OpenGL;
273
274 sub new {
275 my ($class, $x, $y, $z, $ttf, $text) = @_;
276
277 my $self = $class->SUPER::new (x => $x, y => $y, z => $z, ttf => $ttf);
278
279 $self->set_text ($text);
280
281 $self
282 }
283
284 sub set_text {
285 my ($self, $text) = @_;
286 $self->{texture} = new_from_ttf Crossfire::Client::Texture $self->{ttf}, $self->{text} = $text;
287 }
288
289 sub get_text {
290 my ($self, $text) = @_;
291 $self->{text}
292 }
293
294 sub size_request {
295 my ($self) = @_;
296
297 (
298 $self->{texture}{width},
299 $self->{texture}{height},
300 )
301 }
302
303 sub _draw {
304 my ($self) = @_;
305
306 my $tex = $self->{texture};
307
308 glEnable GL_BLEND;
309 glEnable GL_TEXTURE_2D;
310 glTexEnv GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE;
311 glBindTexture GL_TEXTURE_2D, $tex->{name};
312
313 glColor 1, 1, 1;
314
315 glBegin GL_QUADS;
316 glTexCoord 0, 0; glVertex 0 , 0;
317 glTexCoord 0, 1; glVertex 0 , $tex->{height};
318 glTexCoord 1, 1; glVertex $tex->{width}, $tex->{height};
319 glTexCoord 1, 0; glVertex $tex->{width}, 0;
320 glEnd;
321
322 glDisable GL_BLEND;
323 glDisable GL_TEXTURE_2D;
324 }
325
326 package Crossfire::Client::Widget::TextView;
327
328 use strict;
329
330 our @ISA = qw/Crossfire::Client::Widget/;
331
332 use SDL::OpenGL;
333 use SDL::OpenGL::Constants;
334
335 sub add_line {
336 my ($self, $line) = @_;
337 push @{$self->{lines}}, $line;
338 }
339
340 sub _draw {
341 my ($self) = @_;
342
343 }
344
345 package Crossfire::Client::Widget::MapWidget;
346
347 use strict;
348
349 our @ISA = qw/Crossfire::Client::Widget/;
350
351 use SDL;
352 use SDL::OpenGL;
353 use SDL::OpenGL::Constants;
354
355 sub key_down {
356 print "MAPKEYDOWN\n";
357 }
358
359 sub key_up {
360 }
361
362 sub _draw {
363 glEnable GL_TEXTURE_2D;
364 glEnable GL_BLEND;
365 glTexEnv GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE;
366
367 my $map = $::CONN->{map};
368
369 for my $x (0 .. $::CONN->{mapw} - 1) {
370 for my $y (0 .. $::CONN->{maph} - 1) {
371
372 my $cell = $map->[$x][$y]
373 or next;
374
375 my $darkness = $cell->[3] * (1 / 255);
376 glColor $darkness, $darkness, $darkness;
377
378 for my $num (grep $_, $cell->[0], $cell->[1], $cell->[2]) {
379 my $tex = $::CONN->{face}[$num]{texture} || next;
380
381 glBindTexture GL_TEXTURE_2D, $tex->{name};
382
383 my $w = $tex->{width};
384 my $h = $tex->{height};
385
386 my $px = ($x + 1) * 32 - $w;
387 my $py = ($y + 1) * 32 - $h;
388
389 glBegin GL_QUADS;
390 glTexCoord 0, 0; glVertex $px , $py;
391 glTexCoord 0, 1; glVertex $px , $py + $h;
392 glTexCoord 1, 1; glVertex $px + $w, $py + $h;
393 glTexCoord 1, 0; glVertex $px + $w, $py;
394 glEnd;
395 }
396 }
397 }
398
399 glDisable GL_TEXTURE_2D;
400 glDisable GL_BLEND;
401 }
402
403 my %DIR = (
404 SDLK_KP8, [1, "north"],
405 SDLK_KP9, [2, "northeast"],
406 SDLK_KP6, [3, "east"],
407 SDLK_KP3, [4, "southeast"],
408 SDLK_KP2, [5, "south"],
409 SDLK_KP1, [6, "southwest"],
410 SDLK_KP4, [7, "west"],
411 SDLK_KP7, [8, "northwest"],
412
413 SDLK_UP, [1, "north"],
414 SDLK_RIGHT, [3, "east"],
415 SDLK_DOWN, [5, "south"],
416 SDLK_LEFT, [7, "west"],
417 );
418
419 sub key_down {
420 my ($self, $ev) = @_;
421
422 my $mod = $ev->key_mod;
423 my $sym = $ev->key_sym;
424
425 if ($sym == SDLK_KP5) {
426 $::CONN->send ("command stay fire");
427 } elsif (exists $DIR{$sym}) {
428 if ($mod & KMOD_SHIFT) {
429 $self->{shft}++;
430 $::CONN->send ("command fire $DIR{$sym}[0]");
431 } elsif ($mod & KMOD_CTRL) {
432 $self->{ctrl}++;
433 $::CONN->send ("command run $DIR{$sym}[0]");
434 } else {
435 $::CONN->send ("command $DIR{$sym}[1]");
436 }
437 }
438 }
439
440 sub key_up {
441 my ($self, $ev) = @_;
442
443 my $mod = $ev->key_mod;
444 my $sym = $ev->key_sym;
445
446 if (!($mod & KMOD_SHIFT) && delete $self->{shft}) {
447 $::CONN->send ("command fire_stop");
448 }
449 if (!($mod & KMOD_CTRL ) && delete $self->{ctrl}) {
450 $::CONN->send ("command run_stop");
451 }
452 }
453
454 1;
455