ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/deliantra/Deliantra-Client/DC/UI.pm
Revision: 1.75
Committed: Tue Apr 11 20:44:49 2006 UTC (18 years, 2 months ago) by root
Branch: MAIN
Changes since 1.74: +104 -95 lines
Log Message:
fix(?) table

File Contents

# User Rev Content
1 root 1.73 package CFClient::UI;
2 root 1.8
3 elmex 1.1 use strict;
4 root 1.18
5 root 1.74 use Scalar::Util ();
6     use List::Util ();
7 root 1.18
8 root 1.60 use CFClient;
9 root 1.41
10 root 1.51 our ($FOCUS, $HOVER, $GRAB); # various widgets
11    
12     our $TOPLEVEL;
13     our $BUTTON_STATE;
14    
15 elmex 1.1 # class methods for events
16 root 1.51 sub feed_sdl_key_down_event {
17     $FOCUS->key_down ($_[0]) if $FOCUS;
18     }
19    
20     sub feed_sdl_key_up_event {
21     $FOCUS->key_up ($_[0]) if $FOCUS;
22     }
23    
24     sub feed_sdl_button_down_event {
25     my ($ev) = @_;
26     my ($x, $y) = ($ev->motion_x, $ev->motion_y);
27    
28     if (!$BUTTON_STATE) {
29     my $widget = $TOPLEVEL->find_widget ($x, $y);
30    
31     $GRAB = $widget;
32     $GRAB->update if $GRAB;
33     }
34    
35     $BUTTON_STATE |= 1 << ($ev->button - 1);
36    
37 root 1.58 $GRAB->button_down ($ev, $GRAB->translate ($x, $y)) if $GRAB;
38 root 1.51 }
39    
40     sub feed_sdl_button_up_event {
41     my ($ev) = @_;
42     my ($x, $y) = ($ev->motion_x, $ev->motion_y);
43    
44     my $widget = $GRAB || $TOPLEVEL->find_widget ($x, $y);
45    
46     $BUTTON_STATE &= ~(1 << ($ev->button - 1));
47    
48 root 1.58 $GRAB->button_down ($ev, $GRAB->translate ($x, $y)) if $GRAB;
49    
50 root 1.51 if (!$BUTTON_STATE) {
51     my $grab = $GRAB; undef $GRAB;
52     $grab->update if $grab;
53     $GRAB->update if $GRAB;
54     }
55     }
56    
57     sub feed_sdl_motion_event {
58     my ($ev) = @_;
59     my ($x, $y) = ($ev->motion_x, $ev->motion_y);
60    
61     my $widget = $GRAB || $TOPLEVEL->find_widget ($x, $y);
62    
63     if ($widget != $HOVER) {
64     my $hover = $HOVER; $HOVER = $widget;
65    
66     $hover->update if $hover;
67     $HOVER->update if $HOVER;
68     }
69    
70 root 1.58 $HOVER->mouse_motion ($ev, $HOVER->translate ($x, $y)) if $HOVER;
71 root 1.51 }
72 elmex 1.1
73 root 1.73 #############################################################################
74    
75     package CFClient::UI::Base;
76    
77     use strict;
78    
79     use SDL::OpenGL;
80    
81 elmex 1.1 sub new {
82     my $class = shift;
83 root 1.10
84 root 1.65 bless {
85     x => 0,
86     y => 0,
87     z => 0,
88 root 1.75 w => -1,
89     h => -1,
90 root 1.65 @_
91     }, $class
92 elmex 1.1 }
93    
94 root 1.18 sub move {
95     my ($self, $x, $y, $z) = @_;
96     $self->{x} = $x;
97     $self->{y} = $y;
98     $self->{z} = $z if defined $z;
99     }
100    
101 elmex 1.20 sub needs_redraw {
102     0
103     }
104    
105 root 1.14 sub size_request {
106 elmex 1.36 require Carp;
107     Carp::confess "size_request is abtract";
108     }
109    
110 root 1.75 sub _size_allocate {
111     my ($self, $x, $y, $w, $h) = @_;
112    
113     $self->{x} = $x;
114     $self->{y} = $y;
115    
116     return unless $self->{w} != $w || $self->{h} != $h;
117 root 1.40
118     $self->{w} = $w;
119     $self->{h} = $h;
120 root 1.75
121     1
122     }
123    
124     sub size_allocate {
125     my ($self, $x, $y, $w, $h) = @_;
126    
127     $self->_size_allocate ($x, $y, $w, $h);
128 root 1.14 }
129    
130 root 1.58 # translate global koordinates to local coordinate system
131     sub translate {
132     my ($self, $x, $y) = @_;
133    
134     $self->{parent}->translate ($x - $self->{x}, $y - $self->{y});
135     }
136    
137 elmex 1.1 sub focus_in {
138 root 1.51 my ($self) = @_;
139    
140 root 1.68 return if $FOCUS == $self;
141    
142 root 1.51 my $focus = $FOCUS; $FOCUS = $self;
143     $focus->update if $focus;
144     $FOCUS->update;
145 elmex 1.1 }
146 root 1.4
147 elmex 1.1 sub focus_out {
148 root 1.51 my ($self) = @_;
149 root 1.4
150 root 1.51 return unless $FOCUS == $self;
151 root 1.4
152 root 1.51 my $focus = $FOCUS; undef $FOCUS;
153     $focus->update if $focus; #?
154 elmex 1.1 }
155 root 1.4
156 root 1.51 sub mouse_motion { }
157     sub button_up { }
158     sub key_down { }
159     sub key_up { }
160    
161 root 1.68 sub button_down {
162     my ($self, $ev, $x, $y) = @_;
163    
164     $self->focus_in;
165     }
166    
167 root 1.51 sub w { $_[0]{w} = $_[1] if @_ > 1; $_[0]{w} }
168     sub h { $_[0]{h} = $_[1] if @_ > 1; $_[0]{h} }
169     sub x { $_[0]{x} = $_[1] if @_ > 1; $_[0]{x} }
170     sub y { $_[0]{y} = $_[1] if @_ > 1; $_[0]{y} }
171     sub z { $_[0]{z} = $_[1] if @_ > 1; $_[0]{z} }
172 elmex 1.11
173 elmex 1.1 sub draw {
174 elmex 1.11 my ($self) = @_;
175    
176 root 1.68 return unless $self->{h} && $self->{w};
177    
178 elmex 1.11 glPushMatrix;
179 root 1.12 glTranslate $self->{x}, $self->{y}, 0;
180 elmex 1.11 $self->_draw;
181 root 1.72 glPopMatrix;
182    
183 root 1.51 if ($self == $HOVER) {
184 root 1.73 my ($x, $y) = @$self{qw(x y)};
185 root 1.72
186     glColor 1, 1, 1, 0.1;
187 root 1.50 glEnable GL_BLEND;
188 root 1.74 glBlendFunc GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA;
189 root 1.48 glBegin GL_QUADS;
190 root 1.72 glVertex $x , $y;
191     glVertex $x + $self->{w}, $y;
192     glVertex $x + $self->{w}, $y + $self->{h};
193     glVertex $x , $y + $self->{h};
194 root 1.47 glEnd;
195 root 1.50 glDisable GL_BLEND;
196 root 1.47 }
197 elmex 1.11 }
198    
199     sub _draw {
200 root 1.38 my ($self) = @_;
201    
202     warn "no draw defined for $self\n";
203 elmex 1.1 }
204 root 1.4
205 elmex 1.1 sub bbox {
206 elmex 1.32 my ($self) = @_;
207     my ($w, $h) = $self->size_request;
208     (
209     $self->{x},
210     $self->{y},
211     $self->{x} = $w,
212     $self->{y} = $h
213     )
214     }
215    
216 root 1.38 sub find_widget {
217     my ($self, $x, $y) = @_;
218    
219     return $self
220     if $x >= $self->{x} && $x < $self->{x} + $self->{w}
221     && $y >= $self->{y} && $y < $self->{y} + $self->{h};
222    
223     ()
224     }
225    
226 elmex 1.32 sub del_parent { $_[0]->{parent} = undef }
227    
228     sub set_parent {
229     my ($self, $par) = @_;
230    
231     $self->{parent} = $par;
232     Scalar::Util::weaken $self->{parent};
233     }
234    
235     sub get_parent {
236     $_[0]->{parent}
237     }
238    
239     sub update {
240     my ($self) = @_;
241    
242     $self->{parent}->update
243     if $self->{parent};
244 elmex 1.1 }
245 elmex 1.2
246 root 1.72 sub connect {
247     my ($self, $signal, $cb) = @_;
248    
249     push @{ $self->{cb}{$signal} }, $cb;
250     }
251    
252     sub emit {
253     my ($self, $signal, @args) = @_;
254    
255     $_->($self, @args)
256     for @{$self->{cb}{$signal} || []};
257     }
258    
259 root 1.18 sub DESTROY {
260     my ($self) = @_;
261    
262 elmex 1.32 #$self->deactivate;
263 root 1.18 }
264    
265 root 1.39 #############################################################################
266    
267 root 1.73 package CFClient::UI::DrawBG;
268 root 1.68
269 root 1.73 our @ISA = CFClient::UI::Base::;
270 root 1.68
271     use strict;
272     use SDL::OpenGL;
273    
274     sub new {
275     my $class = shift;
276    
277     # range [value, low, high, page]
278    
279     $class->SUPER::new (
280     bg => [0, 0, 0, 0.4],
281     active_bg => [1, 1, 1],
282     @_
283     )
284     }
285    
286     sub _draw {
287     my ($self) = @_;
288    
289     my ($w, $h) = @$self{qw(w h)};
290    
291     glColor @{ $FOCUS == $self ? $self->{active_bg} : $self->{bg} };
292     glBegin GL_QUADS;
293     glVertex 0 , 0;
294     glVertex 0 , $h;
295     glVertex $w, $h;
296     glVertex $w, 0;
297     glEnd;
298     }
299    
300     #############################################################################
301    
302 root 1.73 package CFClient::UI::Empty;
303 root 1.66
304 root 1.73 our @ISA = CFClient::UI::Base::;
305 root 1.66
306     sub size_request {
307     (0, 0)
308     }
309    
310 root 1.67 sub draw { }
311 root 1.66
312     #############################################################################
313    
314 root 1.73 package CFClient::UI::Container;
315 elmex 1.15
316 root 1.73 our @ISA = CFClient::UI::Base::;
317 elmex 1.15
318 root 1.38 sub new {
319 root 1.64 my ($class, %arg) = @_;
320    
321     my $children = delete $arg{children} || [];
322 root 1.38
323 root 1.65 my $self = $class->SUPER::new (children => [], %arg);
324 root 1.64 $self->add ($_) for @$children;
325 root 1.38
326     $self
327     }
328    
329     sub add {
330     my ($self, $chld, $expand) = @_;
331    
332     $chld->{expand} = $expand;
333     $chld->set_parent ($self);
334    
335 root 1.66 $self->{children} = [
336 root 1.38 sort { $a->{z} <=> $b->{z} }
337 root 1.66 @{$self->{children}}, $chld
338     ];
339 root 1.38
340 root 1.75 $self->{w} = $self->{h} = -1;
341     $self->update;
342 root 1.38 }
343 root 1.35
344 elmex 1.32 sub remove {
345 root 1.38 my ($self, $widget) = @_;
346    
347     $self->{children} = [ grep $_ != $widget, @{ $self->{children} } ];
348    
349 root 1.75 $self->size_allocate (0, 0, $self->{w}, $self->{h});
350 root 1.38 }
351    
352     sub find_widget {
353     my ($self, $x, $y) = @_;
354    
355 root 1.45 $x -= $self->{x};
356     $y -= $self->{y};
357    
358 root 1.38 my $res;
359    
360 root 1.46 for (reverse @{ $self->{children} }) {
361 root 1.45 $res = $_->find_widget ($x, $y)
362 root 1.38 and return $res;
363     }
364    
365 root 1.46 $self->SUPER::find_widget ($x + $self->{x}, $y + $self->{y})
366 elmex 1.32 }
367 elmex 1.15
368 root 1.35 sub _draw {
369     my ($self) = @_;
370    
371 root 1.38 $_->draw for @{$self->{children}};
372 root 1.35 }
373 elmex 1.15
374 root 1.39 #############################################################################
375    
376 root 1.73 package CFClient::UI::Bin;
377 elmex 1.32
378 root 1.73 our @ISA = CFClient::UI::Container::;
379 elmex 1.32
380 root 1.66 sub new {
381     my ($class, %arg) = @_;
382    
383 root 1.73 my $child = (delete $arg{child}) || new CFClient::UI::Empty::;
384 root 1.66
385     $class->SUPER::new (children => [$child], %arg)
386     }
387    
388     sub add {
389     my ($self, $widget) = @_;
390    
391     $self->{children} = [];
392    
393     $self->SUPER::add ($widget);
394     }
395    
396     sub remove {
397     my ($self, $widget) = @_;
398    
399     $self->SUPER::remove ($widget);
400    
401 root 1.73 $self->{children} = [new CFClient::UI::Empty]
402 root 1.66 unless @{$self->{children}};
403     }
404    
405 root 1.39 sub child { $_[0]->{children}[0] }
406 elmex 1.32
407 root 1.38 sub size_request {
408 root 1.68 $_[0]{children}[0]->size_request
409 root 1.38 }
410 elmex 1.32
411 root 1.38 sub size_allocate {
412 root 1.75 my ($self, $x, $y, $w, $h) = @_;
413 root 1.42
414 root 1.75 $self->_size_allocate ($x, $y, $w, $h) or return;
415 root 1.68
416 root 1.75 $self->{children}[0]->size_allocate (0, 0, $w, $h);
417 root 1.38 }
418 elmex 1.32
419 root 1.39 #############################################################################
420    
421 root 1.73 package CFClient::UI::Window;
422 elmex 1.20
423 root 1.73 our @ISA = CFClient::UI::Bin::;
424 elmex 1.20
425     use SDL::OpenGL;
426    
427 root 1.42 sub new {
428 root 1.64 my ($class, %arg) = @_;
429 elmex 1.32
430 root 1.64 my $self = $class->SUPER::new (%arg);
431 elmex 1.32 }
432    
433     sub update {
434     my ($self) = @_;
435 root 1.42
436 root 1.63 # we want to do this delayed...
437 elmex 1.32 $self->render_chld;
438 root 1.42 $self->SUPER::update;
439 elmex 1.20 }
440    
441     sub render_chld {
442     my ($self) = @_;
443    
444     $self->{texture} =
445 root 1.60 CFClient::Texture->new_from_opengl (
446 root 1.42 $self->{w}, $self->{h}, sub { $self->child->draw }
447 elmex 1.20 );
448 elmex 1.36 }
449    
450     sub size_allocate {
451 root 1.75 my ($self, $x, $y, $w, $h) = @_;
452 elmex 1.36
453 root 1.75 $self->_size_allocate ($x, $y, $w, $h) or return;
454 root 1.68
455 root 1.75 $self->child->size_allocate (0, 0, $w, $h);
456 elmex 1.36
457 root 1.42 $self->render_chld;
458 elmex 1.20 }
459    
460     sub _draw {
461     my ($self) = @_;
462    
463 elmex 1.36 my ($w, $h) = ($self->w, $self->h);
464 root 1.29
465 elmex 1.20 my $tex = $self->{texture}
466     or return;
467    
468     glEnable GL_BLEND;
469 root 1.74 glBlendFunc GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA;
470 elmex 1.20 glEnable GL_TEXTURE_2D;
471 root 1.35 glTexEnv GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE;
472 elmex 1.20
473 root 1.56 $tex->draw_quad (0, 0, $w, $h);
474 elmex 1.20
475     glDisable GL_BLEND;
476     glDisable GL_TEXTURE_2D;
477     }
478    
479 root 1.39 #############################################################################
480    
481 root 1.73 package CFClient::UI::Frame;
482 elmex 1.15
483 root 1.73 our @ISA = CFClient::UI::Bin::;
484 elmex 1.15
485     use SDL::OpenGL;
486    
487     sub size_request {
488     my ($self) = @_;
489 root 1.39 my $chld = $self->child
490 elmex 1.15 or return (0, 0);
491 root 1.30
492     $chld->move (2, 2);
493    
494 elmex 1.15 map { $_ + 4 } $chld->size_request;
495     }
496    
497 elmex 1.36 sub size_allocate {
498 root 1.75 my ($self, $x, $y, $w, $h) = @_;
499 root 1.42
500 root 1.75 $self->_size_allocate ($x, $y, $w, $h) or return;
501 elmex 1.36
502 root 1.75 $self->child->size_allocate (2, 2, $w - 4, $h - 4);
503 elmex 1.36 }
504    
505 elmex 1.15 sub _draw {
506     my ($self) = @_;
507    
508 root 1.39 my $chld = $self->child;
509 elmex 1.15
510     my ($w, $h) = $chld->size_request;
511    
512     glBegin GL_QUADS;
513 root 1.30 glColor 0, 0, 0;
514 root 1.56 glVertex 0 , 0;
515     glVertex 0 , $h + 4;
516     glVertex $w + 4 , $h + 4;
517     glVertex $w + 4 , 0;
518 elmex 1.15 glEnd;
519    
520 root 1.23 $chld->draw;
521 elmex 1.15 }
522    
523 root 1.39 #############################################################################
524    
525 root 1.73 package CFClient::UI::FancyFrame;
526 elmex 1.31
527 root 1.73 our @ISA = CFClient::UI::Bin::;
528 elmex 1.31
529     use SDL::OpenGL;
530    
531 root 1.41 my @tex =
532 root 1.60 map { new_from_file CFClient::Texture CFClient::find_rcfile $_ }
533 root 1.41 qw(d1_bg.png d1_border_top.png d1_border_right.png d1_border_left.png d1_border_bottom.png);
534 elmex 1.34
535     sub size_request {
536     my ($self) = @_;
537 root 1.39
538     my ($w, $h) = $self->SUPER::size_request;
539 elmex 1.34
540 root 1.72 $h += $tex[1]->{h};
541     $h += $tex[4]->{h};
542     $w += $tex[2]->{w};
543     $w += $tex[3]->{w};
544 elmex 1.34
545 elmex 1.36 ($w, $h)
546     }
547    
548     sub size_allocate {
549 root 1.75 my ($self, $x, $y, $w, $h) = @_;
550 root 1.68
551 root 1.75 $self->_size_allocate ($x, $y, $w, $h) or return;
552 root 1.40
553 root 1.72 $h -= $tex[1]->{h};
554     $h -= $tex[4]->{h};
555     $w -= $tex[2]->{w};
556     $w -= $tex[3]->{w};
557 elmex 1.36
558     $h = $h < 0 ? 0 : $h;
559     $w = $w < 0 ? 0 : $w;
560 root 1.43
561 root 1.66 my $child = $self->child;
562    
563 root 1.75 $child->size_allocate ($tex[3]->{w}, $tex[1]->{h}, $w, $h);
564 elmex 1.34 }
565    
566     sub _draw {
567     my ($self) = @_;
568    
569 root 1.43 my ($w, $h) = ($self->{w}, $self->{h});
570     my ($cw, $ch) = ($self->child->{w}, $self->child->{h});
571 elmex 1.34
572     glEnable GL_BLEND;
573 root 1.74 glBlendFunc GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA;
574 elmex 1.34 glEnable GL_TEXTURE_2D;
575 elmex 1.36 glTexEnv GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE;
576 elmex 1.34
577 root 1.41 my $top = $tex[1];
578 root 1.72 $top->draw_quad (0, 0, $w, $top->{h});
579 elmex 1.34
580 root 1.41 my $left = $tex[3];
581 root 1.72 $left->draw_quad (0, $top->{h}, $left->{w}, $ch);
582 elmex 1.34
583 root 1.41 my $right = $tex[2];
584 root 1.72 $right->draw_quad ($w - $right->{w}, $top->{h}, $right->{w}, $ch);
585 elmex 1.34
586 root 1.41 my $bottom = $tex[4];
587 root 1.72 $bottom->draw_quad (0, $h - $bottom->{h}, $w, $bottom->{h});
588 elmex 1.34
589 root 1.41 my $bg = $tex[0];
590 elmex 1.36 glBindTexture GL_TEXTURE_2D, $bg->{name};
591     glTexEnv GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE;
592     glTexParameter GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT;
593     glTexParameter GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT;
594 elmex 1.34
595 root 1.72 my $rep_x = $cw / $bg->{w};
596     my $rep_y = $ch / $bg->{h};
597 elmex 1.34
598 root 1.72 $bg->draw_quad ($left->{w}, $top->{h}, $cw, $ch);
599 elmex 1.34
600     glDisable GL_BLEND;
601     glDisable GL_TEXTURE_2D;
602 elmex 1.36
603 root 1.39 $self->child->draw;
604 elmex 1.36
605 elmex 1.34 }
606 elmex 1.31
607 root 1.39 #############################################################################
608    
609 root 1.73 package CFClient::UI::Table;
610 elmex 1.15
611 root 1.73 our @ISA = CFClient::UI::Base::;
612 elmex 1.15
613 root 1.75 use List::Util qw(max sum);
614    
615 elmex 1.15 use SDL::OpenGL;
616    
617     sub add {
618     my ($self, $x, $y, $chld) = @_;
619 elmex 1.32
620 root 1.38 $self->{children}[$y][$x] = $chld;
621 elmex 1.32 $chld->set_parent ($self);
622 root 1.75
623     $self->{w} = $self->{h} = -1;
624 elmex 1.32 $self->update;
625 elmex 1.15 }
626    
627 root 1.75 sub get_wh {
628     my ($self) = @_;
629    
630     my (@w, @h);
631 elmex 1.15
632 root 1.75 for my $y (0 .. $#{$self->{children}}) {
633     my $row = $self->{children}[$y]
634     or next;
635 elmex 1.15
636 root 1.75 for my $x (0 .. $#$row) {
637     my $widget = $row->[$x]
638     or next;
639     my ($w, $h) = $widget->size_request;
640 elmex 1.15
641 root 1.75 $w[$x] = max $w[$x], $w;
642     $h[$y] = max $h[$y], $h;
643 elmex 1.17 }
644 elmex 1.15 }
645 root 1.75
646     (\@w, \@h)
647 elmex 1.15 }
648    
649     sub size_request {
650     my ($self) = @_;
651    
652 root 1.75 my ($ws, $hs) = $self->get_wh;
653 elmex 1.15
654 root 1.75 (
655     (List::Util::sum @$ws),
656     (List::Util::sum @$hs),
657     )
658     }
659    
660     sub size_allocate {
661     my ($self, $x, $y, $w, $h) = @_;
662    
663     $self->_size_allocate ($x, $y, $w, $h) or return;
664    
665     my ($ws, $hs) = $self->get_wh;
666    
667     my $req_w = List::Util::sum @$ws;
668     my $req_h = List::Util::sum @$hs;
669 elmex 1.15
670 root 1.75 # linearly scale sizes
671     $_ *= $req_w / $w for @$ws;
672     $_ *= $req_h / $h for @$hs;
673 elmex 1.15
674 root 1.75 my $y;
675 elmex 1.15
676 root 1.75 for my $r (0 .. $#{$self->{children}}) {
677     my $row = $self->{children}[$r]
678     or next;
679 elmex 1.15
680     my $x = 0;
681 root 1.75 my $row_h = $hs->[$r];
682    
683     for my $c (0 .. $#$row) {
684     my $widget = $row->[$c]
685     or next;
686 elmex 1.15
687 root 1.75 my $col_w = $ws->[$c];
688 elmex 1.15
689 root 1.75 $widget->size_allocate ($x, $y, $col_w, $row_h);
690 elmex 1.15
691 root 1.75 $x += $col_w;
692 elmex 1.15 }
693    
694 root 1.75 $y += $row_h;
695     }
696    
697     }
698    
699     sub _draw {
700     my ($self) = @_;
701    
702     for (grep $_, @{$self->{children}}) {
703     $_->draw for grep $_, @$_;
704 elmex 1.15 }
705     }
706    
707 root 1.39 #############################################################################
708    
709 root 1.73 package CFClient::UI::VBox;
710 elmex 1.15
711 root 1.73 our @ISA = CFClient::UI::Container::;
712 elmex 1.15
713     use SDL::OpenGL;
714    
715 root 1.43 sub size_request {
716     my ($self) = @_;
717    
718     my @alloc = map [$_->size_request], @{$self->{children}};
719    
720     (
721     (List::Util::max map $_->[0], @alloc),
722     (List::Util::sum map $_->[1], @alloc),
723     )
724     }
725    
726 elmex 1.36 sub size_allocate {
727 root 1.75 my ($self, $x, $y, $w, $h) = @_;
728 elmex 1.36
729 root 1.75 $self->_size_allocate ($x, $y, $w, $h) or return;
730 root 1.68
731     return unless $self->{h};
732    
733     my $children = $self->{children};
734    
735     my @h = map +($_->size_request)[1], @$children;
736    
737     my $req_h = List::Util::sum @h;
738    
739     if ($req_h > $h) {
740     # ah well, not enough space
741     $_ = $h[$_] * $h / $req_h for @h;
742     } else {
743     my @exp = grep $_->{expand}, @$children;
744     @exp = @$children unless @exp;
745    
746     my %exp = map +($_ => 1), @exp;
747 elmex 1.36
748 root 1.68 for (0 .. $#$children) {
749     my $child = $children->[$_];
750 elmex 1.36
751 root 1.68 my $alloc_h = $h[$_];
752     $alloc_h += ($h - $req_h) / @exp if $exp{$child};
753     $h[$_] = $alloc_h;
754     }
755 elmex 1.36 }
756    
757     my $y = 0;
758 root 1.68 for (0 .. $#$children) {
759     my $child = $children->[$_];
760     my $h = $h[$_];
761 root 1.75 $child->size_allocate (0, $y, $w, $h);
762 elmex 1.36
763 root 1.68 $y += $h;
764 elmex 1.36 }
765     }
766    
767 root 1.39 #############################################################################
768    
769 root 1.73 package CFClient::UI::Label;
770 root 1.10
771 root 1.73 our @ISA = CFClient::UI::Base::;
772 root 1.12
773 root 1.10 use SDL::OpenGL;
774    
775     sub new {
776 root 1.64 my ($class, %arg) = @_;
777 root 1.51
778 root 1.59 my $self = $class->SUPER::new (
779 root 1.68 fg => [1, 1, 1],
780 root 1.64 height => $::FONTSIZE,
781     text => "",
782 root 1.72 align => -1,
783 root 1.64 layout => new CFClient::Layout,
784     %arg
785 root 1.59 );
786 root 1.10
787 root 1.64 $self->set_text ($self->{text});
788 root 1.10
789     $self
790     }
791    
792 root 1.68 sub escape_text {
793     local $_ = $_[1];
794    
795     s/&/&amp;/g;
796     s/>/&gt;/g;
797     s/</&lt;/g;
798    
799     $_[1]
800     }
801    
802 elmex 1.15 sub set_text {
803     my ($self, $text) = @_;
804 root 1.28
805     $self->{text} = $text;
806 root 1.59 $self->{layout}->set_markup ($text);
807 root 1.28
808 root 1.59 delete $self->{texture};
809 root 1.68 $self->update;
810 elmex 1.15 }
811    
812     sub get_text {
813     my ($self, $text) = @_;
814 root 1.28
815 elmex 1.15 $self->{text}
816     }
817    
818 root 1.14 sub size_request {
819     my ($self) = @_;
820    
821 root 1.59 $self->{layout}->set_width;
822 root 1.64 $self->{layout}->set_height ($self->{height});
823 root 1.59 $self->{layout}->size
824 root 1.72 # if ($self->{texture}{w} > 1 && $self->{texture}{height} > 1) { #TODO: hack
825 root 1.59 # (
826 root 1.72 # $self->{texture}{w},
827     # $self->{texture}{h},
828 root 1.59 # )
829     # } else {
830 root 1.72 # my ($w, $h, $data) = CFClient::font_render "Yy", $self->{h};
831 root 1.59 #
832     # ($w, $h)
833     # }
834     }
835 root 1.51
836 root 1.59 sub size_allocate {
837 root 1.75 my ($self, $x, $y, $w, $h) = @_;
838 root 1.51
839 root 1.75 $self->_size_allocate ($x, $y, $w, $h) or return;
840 root 1.68
841 root 1.59 delete $self->{texture};
842 root 1.14 }
843    
844 root 1.68 sub update {
845     my ($self) = @_;
846    
847     delete $self->{texture};
848     $self->SUPER::update;
849     }
850    
851 elmex 1.11 sub _draw {
852 root 1.10 my ($self) = @_;
853    
854 root 1.59 my $tex = $self->{texture} ||= do {
855     $self->{layout}->set_width ($self->{w});
856 root 1.74 new_from_layout CFClient::Texture $self->{layout}
857 root 1.59 };
858 root 1.10
859 root 1.12 glEnable GL_BLEND;
860 root 1.74 glBlendFunc GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA;
861 root 1.10 glEnable GL_TEXTURE_2D;
862 root 1.28 glTexEnv GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE;
863 root 1.10
864 root 1.68 glColor @{$self->{fg}};
865 root 1.12
866 root 1.72 my $x =
867     $self->{align} < 0 ? 0
868 root 1.74 : $self->{align} > 0 ? $self->{w} - $tex->{w}
869     : ($self->{w} - $tex->{w}) * 0.5;
870 root 1.72
871     $tex->draw_quad ($x, 0);
872 root 1.10
873 root 1.74 glDisable GL_TEXTURE_2D;
874 root 1.12 glDisable GL_BLEND;
875 root 1.10 }
876    
877 root 1.39 #############################################################################
878    
879 root 1.73 package CFClient::UI::Entry;
880 elmex 1.31
881 root 1.73 our @ISA = CFClient::UI::Label::;
882 elmex 1.31
883     use SDL;
884     use SDL::OpenGL;
885    
886 root 1.68 sub new {
887     my $class = shift;
888    
889     $class->SUPER::new (
890     fg => [1, 1, 1],
891     bg => [0, 0, 0, 0.4],
892     active_bg => [1, 1, 1],
893     active_fg => [0, 0, 0],
894     @_
895     )
896     }
897    
898     sub _set_text {
899     my ($self, $text) = @_;
900    
901     $self->{last_activity} = $::NOW;
902    
903     $self->{text} = $text;
904     $self->{layout}->set_width ($self->{w});
905 root 1.72
906     $text =~ s/./*/g if $self->{hidden};
907    
908    
909 root 1.68 $self->{layout}->set_markup ($self->escape_text ($text));
910    
911     $text = substr $text, 0, $self->{cursor};
912     utf8::encode $text;
913    
914     @$self{qw(cur_x cur_y cur_h)} = $self->{layout}->cursor_pos (length $text);
915     }
916    
917     sub size_request {
918     my ($self) = @_;
919    
920     my ($w, $h) = $self->SUPER::size_request;
921    
922     ($w + 1, $h) # add 1 for cursor
923     }
924    
925     sub size_allocate {
926 root 1.75 my ($self, $x, $y, $w, $h) = @_;
927 root 1.68
928 root 1.75 $self->SUPER::size_allocate ($x, $y, $w, $h);
929 root 1.68
930     $self->_set_text ($self->{text});
931     }
932    
933     sub set_text {
934     my ($self, $text) = @_;
935    
936     $self->{cursor} = length $text;
937     $self->_set_text ($text);
938     $self->update;
939     }
940    
941 elmex 1.31 sub key_down {
942     my ($self, $ev) = @_;
943    
944     my $mod = $ev->key_mod;
945     my $sym = $ev->key_sym;
946    
947     my $uni = $ev->key_unicode;
948    
949     my $text = $self->get_text;
950    
951     if ($sym == SDLK_BACKSPACE) {
952 root 1.68 substr $text, --$self->{cursor}, 1, "" if $self->{cursor};
953     } elsif ($sym == SDLK_DELETE) {
954     substr $text, $self->{cursor}, 1, "";
955     } elsif ($sym == SDLK_LEFT) {
956     --$self->{cursor} if $self->{cursor};
957     } elsif ($sym == SDLK_RIGHT) {
958     ++$self->{cursor} if $self->{cursor} < length $self->{text};
959 elmex 1.31 } elsif ($uni) {
960 root 1.68 substr $text, $self->{cursor}++, 0, chr $uni;
961 elmex 1.31 }
962 root 1.51
963 root 1.68 $self->_set_text ($text);
964     $self->update;
965     }
966    
967     sub focus_in {
968     my ($self) = @_;
969    
970     $self->{last_activity} = $::NOW;
971    
972     $self->SUPER::focus_in;
973 elmex 1.31 }
974    
975 root 1.51 sub button_down {
976 root 1.68 my ($self, $ev, $x, $y) = @_;
977    
978     $self->SUPER::button_down ($ev, $x, $y);
979    
980     my $idx = $self->{layout}->xy_to_index ($x, $y);
981    
982     # byte-index to char-index
983     my $text = $self->{layout};
984     utf8::encode $text;
985     $self->{cursor} = length substr $text, 0, $idx;
986 root 1.51
987 root 1.68 $self->_set_text ($self->{text});
988     $self->update;
989 root 1.51 }
990    
991 root 1.58 sub mouse_motion {
992     my ($self, $ev, $x, $y) = @_;
993 root 1.68 # printf "M %d,%d %d,%d\n", $ev->motion_x, $ev->motion_y, $x, $y;#d#
994 root 1.58 }
995    
996 root 1.51 sub _draw {
997     my ($self) = @_;
998    
999 root 1.68 local $self->{fg} = $self->{fg};
1000    
1001 root 1.51 if ($FOCUS == $self) {
1002 root 1.68 glColor @{$self->{active_bg}};
1003     $self->{fg} = $self->{active_fg};
1004 root 1.51 } else {
1005 root 1.68 glColor @{$self->{bg}};
1006 root 1.51 }
1007    
1008     glBegin GL_QUADS;
1009 root 1.68 glVertex 0 , 0;
1010     glVertex 0 , $self->{h};
1011     glVertex $self->{w}, $self->{h};
1012     glVertex $self->{w}, 0;
1013 root 1.51 glEnd;
1014    
1015     $self->SUPER::_draw;
1016 root 1.68
1017     #TODO: force update every cursor change :(
1018     if ($FOCUS == $self && (($::NOW - $self->{last_activity}) & 1023) < 600) {
1019     glColor @{$self->{fg}};
1020     glBegin GL_LINES;
1021     glVertex $self->{cur_x}, $self->{cur_y};
1022     glVertex $self->{cur_x}, $self->{cur_y} + $self->{cur_h};
1023     glEnd;
1024     }
1025     }
1026    
1027     #############################################################################
1028    
1029 root 1.73 package CFClient::UI::Slider;
1030 root 1.68
1031     use strict;
1032    
1033     use SDL::OpenGL;
1034    
1035 root 1.73 our @ISA = CFClient::UI::DrawBG::;
1036 root 1.68
1037     sub size_request {
1038     my ($self) = @_;
1039    
1040 root 1.71 my $w = 50;
1041 root 1.68 my $h = 10;
1042    
1043     $self->{vertical} ? ($h, $w) : ($w, $h)
1044     }
1045    
1046     sub new {
1047     my $class = shift;
1048    
1049     # range [value, low, high, page]
1050    
1051     $class->SUPER::new (
1052     fg => [1, 1, 1],
1053     active_fg => [0, 0, 0],
1054     range => [0, 0, 100, 10],
1055 root 1.70 vertical => 1,
1056 root 1.68 @_
1057     )
1058     }
1059    
1060 root 1.69 sub button_down {
1061     my ($self, $ev, $x, $y) = @_;
1062    
1063     $self->SUPER::button_down ($ev, $x, $y);
1064     $self->mouse_motion ($ev, $x, $y);
1065     }
1066    
1067     sub mouse_motion {
1068     my ($self, $ev, $x, $y) = @_;
1069    
1070     if ($GRAB == $self) {
1071     my ($value, $lo, $hi, $page) = @{$self->{range}};
1072    
1073 root 1.71 my ($x, $w) = $self->{vertical} ? ($y, $self->{h}) : ($x, $self->{w});
1074    
1075     $x = $x * ($hi - $lo) / $w + $lo;
1076 root 1.69 $x = $lo if $x < $lo;
1077     $x = $hi - $page if $x > $hi - $page;
1078     $self->{range}[0] = $x;
1079    
1080 root 1.72 $self->emit (changed => $x);
1081 root 1.69 $self->update;
1082     }
1083     }
1084    
1085 root 1.68 sub _draw {
1086     my ($self) = @_;
1087    
1088     $self->SUPER::_draw ();
1089    
1090     my ($w, $h) = @$self{qw(w h)};
1091    
1092     if ($self->{vertical}) {
1093     # draw a vertical slider like a rotated horizontal slider
1094    
1095     glRotate 90, 0, 0, 1;
1096 root 1.71 glTranslate 0, -$self->{w}, 0;
1097 root 1.68
1098     ($w, $h) = ($h, $w);
1099     }
1100    
1101     my $fg = $FOCUS == $self ? $self->{active_fg} : $self->{fg};
1102     my $bg = $FOCUS == $self ? $self->{active_bg} : $self->{bg};
1103    
1104 root 1.69 my ($value, $lo, $hi, $page) = @{$self->{range}};
1105    
1106     $page = int $page * $w / ($hi - $lo);
1107     $value = int +($value - $lo) * $w / ($hi - $lo);
1108    
1109     $w -= $page;
1110     $page &= ~1;
1111     glTranslate $page * 0.5, 0, 0;
1112    
1113 root 1.68 glColor @$fg;
1114     glBegin GL_LINES;
1115     glVertex 0, 0; glVertex 0, $h;
1116     glVertex $w - 1, 0; glVertex $w - 1, $h;
1117     glVertex 0, $h * 0.5; glVertex $w, $h * 0.5;
1118     glEnd;
1119 root 1.69
1120     my $knob_a = $value - $page * 0.5;
1121     my $knob_b = $value + $page * 0.5;
1122    
1123     glBegin GL_QUADS;
1124     glColor @$fg;
1125     glVertex $knob_a, 0;
1126     glVertex $knob_a, $h;
1127     glVertex $knob_b, $h;
1128     glVertex $knob_b, 0;
1129    
1130     if ($knob_a < $knob_b - 2) {
1131     glColor @$bg;
1132     glVertex $knob_a + 1, 1;
1133     glVertex $knob_a + 1, $h - 1;
1134     glVertex $knob_b - 1, $h - 1;
1135     glVertex $knob_b - 1, 1;
1136     }
1137     glEnd;
1138 root 1.51 }
1139    
1140 root 1.39 #############################################################################
1141    
1142 root 1.73 package CFClient::UI::MapWidget;
1143 root 1.4
1144 elmex 1.2 use strict;
1145 elmex 1.7
1146 root 1.25 use List::Util qw(min max);
1147 elmex 1.2
1148 root 1.16 use SDL;
1149 elmex 1.2 use SDL::OpenGL;
1150    
1151 root 1.73 our @ISA = CFClient::UI::Base::;
1152 root 1.25
1153 root 1.64 sub new {
1154     my $class = shift;
1155    
1156 root 1.65 $class->SUPER::new (
1157     z => -1,
1158     list => (glGenLists 1),
1159     @_
1160     )
1161 root 1.64 }
1162    
1163 elmex 1.2 sub key_down {
1164     print "MAPKEYDOWN\n";
1165     }
1166    
1167     sub key_up {
1168     }
1169    
1170 elmex 1.36 sub size_request {
1171 root 1.52 (
1172     1 + int $::WIDTH / 32,
1173     1 + int $::HEIGHT / 32,
1174     )
1175 elmex 1.36 }
1176    
1177 root 1.65 sub update {
1178     my ($self) = @_;
1179    
1180     $self->{need_update} = 1;
1181 root 1.74 $self->SUPER::update;
1182 root 1.65 }
1183    
1184 elmex 1.11 sub _draw {
1185 root 1.21 my ($self) = @_;
1186    
1187 root 1.65 if (delete $self->{need_update}) {
1188     glNewList $self->{list}, GL_COMPILE;
1189 root 1.25
1190 root 1.65 my $mx = $::CONN->{mapx};
1191     my $my = $::CONN->{mapy};
1192 root 1.25
1193 root 1.65 my $map = $::CONN->{map};
1194 root 1.25
1195 root 1.65 my ($xofs, $yofs);
1196 root 1.25
1197 root 1.65 my $sw = 1 + int $::WIDTH / 32;
1198     my $sh = 1 + int $::HEIGHT / 32;
1199 root 1.25
1200 root 1.65 if ($::CONN->{mapw} > $sw) {
1201     $xofs = $mx + ($::CONN->{mapw} - $sw) * 0.5;
1202     } else {
1203     $xofs = $self->{xofs} = min $mx, max $mx + $::CONN->{mapw} - $sw + 1, $self->{xofs};
1204     }
1205 root 1.25
1206 root 1.65 if ($::CONN->{maph} > $sh) {
1207     $yofs = $my + ($::CONN->{maph} - $sh) * 0.5;
1208     } else {
1209     $yofs = $self->{yofs} = min $my, max $my + $::CONN->{maph} - $sh + 1, $self->{yofs};
1210     }
1211 root 1.35
1212 root 1.65 glEnable GL_TEXTURE_2D;
1213     glEnable GL_BLEND;
1214 root 1.74 glBlendFunc GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA;
1215 root 1.65 glTexEnv GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE;
1216 elmex 1.2
1217 root 1.65 my $sw4 = ($sw + 3) & ~3;
1218     my $darkness = "\x00" x ($sw4 * $sh);
1219 elmex 1.2
1220 root 1.65 for my $x (0 .. $sw - 1) {
1221     my $row = $map->[$x + $xofs];
1222     for my $y (0 .. $sh - 1) {
1223    
1224     my $cell = $row->[$y + $yofs]
1225     or next;
1226    
1227     my $dark = $cell->[0];
1228     if ($dark < 0) {
1229     substr $darkness, $y * $sw4 + $x, 1, chr 224;
1230     } else {
1231     substr $darkness, $y * $sw4 + $x, 1, chr 255 - $dark;
1232     }
1233    
1234     for my $num (grep $_, @$cell[1,2,3]) {
1235     my $tex = $::CONN->{face}[$num]{texture} || next;
1236    
1237 root 1.72 my ($w, $h) = @$tex{qw(w h)};
1238 root 1.19
1239 root 1.65 $tex->draw_quad (($x + 1) * 32 - $w, ($y + 1) * 32 - $h, $w, $h);
1240     }
1241 elmex 1.2 }
1242     }
1243    
1244 root 1.35 # if (1) { # higher quality darkness
1245     # $lighting =~ s/(.)/$1$1$1/gs;
1246     # my $pb = new_from_data Gtk2::Gdk::Pixbuf $lighting, "rgb", 0, 8, $sw4, $sh, $sw4 * 3;
1247     #
1248     # $pb = $pb->scale_simple ($sw4 * 0.5, $sh * 0.5, "bilinear");
1249     #
1250     # $lighting = $pb->get_pixels;
1251     # $lighting =~ s/(.)../$1/gs;
1252     # }
1253    
1254 root 1.65 glTexEnv GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE;
1255    
1256     $darkness = new CFClient::Texture
1257 root 1.74 w => $sw4,
1258     h => $sh,
1259 root 1.65 data => $darkness,
1260     internalformat => GL_ALPHA,
1261     format => GL_ALPHA;
1262 root 1.57
1263 root 1.65 glColor 0.45, 0.45, 0.45, 1;
1264     $darkness->draw_quad (0, 0, $sw4 * 32, $sh * 32);
1265 root 1.35
1266 root 1.65 glDisable GL_TEXTURE_2D;
1267     glDisable GL_BLEND;
1268 root 1.35
1269 root 1.65 glEndList;
1270     }
1271    
1272     glCallList $self->{list};
1273 elmex 1.2 }
1274    
1275 root 1.16 my %DIR = (
1276     SDLK_KP8, [1, "north"],
1277 root 1.18 SDLK_KP9, [2, "northeast"],
1278 root 1.16 SDLK_KP6, [3, "east"],
1279     SDLK_KP3, [4, "southeast"],
1280     SDLK_KP2, [5, "south"],
1281     SDLK_KP1, [6, "southwest"],
1282     SDLK_KP4, [7, "west"],
1283     SDLK_KP7, [8, "northwest"],
1284 root 1.18
1285     SDLK_UP, [1, "north"],
1286     SDLK_RIGHT, [3, "east"],
1287     SDLK_DOWN, [5, "south"],
1288     SDLK_LEFT, [7, "west"],
1289 root 1.16 );
1290    
1291     sub key_down {
1292     my ($self, $ev) = @_;
1293    
1294     my $mod = $ev->key_mod;
1295     my $sym = $ev->key_sym;
1296    
1297     if ($sym == SDLK_KP5) {
1298     $::CONN->send ("command stay fire");
1299     } elsif (exists $DIR{$sym}) {
1300     if ($mod & KMOD_SHIFT) {
1301 root 1.18 $self->{shft}++;
1302 root 1.16 $::CONN->send ("command fire $DIR{$sym}[0]");
1303     } elsif ($mod & KMOD_CTRL) {
1304 root 1.18 $self->{ctrl}++;
1305 root 1.16 $::CONN->send ("command run $DIR{$sym}[0]");
1306     } else {
1307 root 1.18 $::CONN->send ("command $DIR{$sym}[1]");
1308 root 1.16 }
1309     }
1310     }
1311    
1312     sub key_up {
1313     my ($self, $ev) = @_;
1314    
1315     my $mod = $ev->key_mod;
1316     my $sym = $ev->key_sym;
1317    
1318 root 1.18 if (!($mod & KMOD_SHIFT) && delete $self->{shft}) {
1319     $::CONN->send ("command fire_stop");
1320     }
1321     if (!($mod & KMOD_CTRL ) && delete $self->{ctrl}) {
1322     $::CONN->send ("command run_stop");
1323 root 1.16 }
1324     }
1325    
1326 root 1.39 #############################################################################
1327    
1328 root 1.73 package CFClient::UI::Animator;
1329 root 1.35
1330     use SDL::OpenGL;
1331    
1332 root 1.73 our @ISA = CFClient::UI::Bin::;
1333 root 1.35
1334     sub moveto {
1335     my ($self, $x, $y) = @_;
1336    
1337     $self->{moveto} = [$self->{x}, $self->{y}, $x, $y];
1338 root 1.56 $self->{speed} = 0.001;
1339 root 1.35 $self->{time} = 1;
1340    
1341     ::animation_start $self;
1342     }
1343    
1344     sub animate {
1345     my ($self, $interval) = @_;
1346    
1347     $self->{time} -= $interval * $self->{speed};
1348     if ($self->{time} <= 0) {
1349     $self->{time} = 0;
1350     ::animation_stop $self;
1351     }
1352    
1353     my ($x0, $y0, $x1, $y1) = @{$self->{moveto}};
1354    
1355     $self->{x} = $x0 * $self->{time} + $x1 * (1 - $self->{time});
1356     $self->{y} = $y0 * $self->{time} + $y1 * (1 - $self->{time});
1357     }
1358    
1359     sub _draw {
1360     my ($self) = @_;
1361    
1362     glPushMatrix;
1363 root 1.51 glRotate $self->{time} * 1000, 0, 1, 0;
1364 root 1.38 $self->{children}[0]->draw;
1365 root 1.35 glPopMatrix;
1366     }
1367    
1368 root 1.51 #############################################################################
1369    
1370 root 1.73 package CFClient::UI::Toplevel;
1371 root 1.51
1372 root 1.73 our @ISA = CFClient::UI::Container::;
1373 root 1.51
1374     sub size_request {
1375     ($::WIDTH, $::HEIGHT)
1376     }
1377    
1378     sub size_allocate {
1379 root 1.75 my ($self, $x, $y, $w, $h) = @_;
1380 root 1.51
1381 root 1.75 $self->_size_allocate ($x, $y, $w, $h);
1382 root 1.51
1383 root 1.75 $_->size_allocate ($_->{x}, $_->{y}, $_->size_request)
1384 root 1.51 for @{$self->{children}};
1385     }
1386    
1387 root 1.58 sub translate {
1388     my ($self, $x, $y) = @_;
1389    
1390     ($x, $y)
1391     }
1392    
1393 root 1.51 sub update {
1394     my ($self) = @_;
1395    
1396 root 1.75 $self->size_allocate (0, 0, $::WIDTH, $::HEIGHT);
1397 root 1.51 ::refresh ();
1398     }
1399    
1400     sub add {
1401     my ($self, $widget) = @_;
1402    
1403     $self->SUPER::add ($widget);
1404    
1405 root 1.75 $widget->size_allocate ($widget->{x}, $widget->{y}, $widget->size_request);
1406 root 1.51 }
1407    
1408     sub draw {
1409     my ($self) = @_;
1410    
1411     $self->_draw;
1412     }
1413    
1414     #############################################################################
1415    
1416 root 1.73 package CFClient::UI;
1417 root 1.51
1418 root 1.73 $TOPLEVEL = new CFClient::UI::Toplevel;
1419 root 1.51
1420     1
1421 root 1.5