ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/deliantra/Deliantra-Client/DC/UI.pm
(Generate patch)

Comparing deliantra/Deliantra-Client/DC/UI.pm (file contents):
Revision 1.251 by root, Sun May 28 22:24:24 2006 UTC vs.
Revision 1.273 by root, Sat Jun 3 02:32:35 2006 UTC

17our $BUTTON_STATE; 17our $BUTTON_STATE;
18 18
19our %WIDGET; # all widgets, weak-referenced 19our %WIDGET; # all widgets, weak-referenced
20 20
21sub get_layout { 21sub get_layout {
22 my $layout;
23
22 for (grep { $_->{name} } values %WIDGET) { 24 for (grep { $_->{name} } values %WIDGET) {
23 $LAYOUT->{$_->{name}} = { 25 my $win = $layout->{$_->{name}} = { };
24 x => $_->{x} / $::WIDTH,
25 y => $_->{y} / $::HEIGHT,
26 w => $_->{w} / $::WIDTH,
27 h => $_->{h} / $::HEIGHT
28 }; 26
29 } 27 $win->{x} = ($_->{x} + $_->{w} * 0.5) / $::WIDTH if $_->{x} =~ /^[0-9.]+$/;
28 $win->{y} = ($_->{y} + $_->{h} * 0.5) / $::HEIGHT if $_->{y} =~ /^[0-9.]+$/;
29 $win->{w} = $_->{w} / $::WIDTH if defined $_->{w};
30 $win->{h} = $_->{h} / $::HEIGHT if defined $_->{h};
30 31
31 return $LAYOUT; 32 $win->{show} = $_->{visible} && $_->{is_toplevel};
33 }
34
35 $layout
32} 36}
33 37
34sub set_layout { 38sub set_layout {
35 my ($layout) = @_; 39 my ($layout) = @_;
40
36 $LAYOUT = $layout; 41 $LAYOUT = $layout;
37} 42}
38 43
39sub check_tooltip { 44sub check_tooltip {
45 return if $ENV{CFPLUS_DEBUG} & 8;
46
40 if (!$GRAB) { 47 if (!$GRAB) {
41 for (my $widget = $HOVER; $widget; $widget = $widget->{parent}) { 48 for (my $widget = $HOVER; $widget; $widget = $widget->{parent}) {
42 if (length $widget->{tooltip}) { 49 if (length $widget->{tooltip}) {
43
44 if ($TOOLTIP->{owner} != $widget) { 50 if ($TOOLTIP->{owner} != $widget) {
51 $TOOLTIP->hide;
52
45 $TOOLTIP->{owner} = $widget; 53 $TOOLTIP->{owner} = $widget;
46 54
47 my $tip = $widget->{tooltip}; 55 my $tip = $widget->{tooltip};
48 56
49 $tip = $tip->($widget) if CODE:: eq ref $tip; 57 $tip = $tip->($widget) if CODE:: eq ref $tip;
50 58
51 $TOOLTIP->set_tooltip_from ($widget); 59 $TOOLTIP->set_tooltip_from ($widget);
52 $TOOLTIP->show; 60 $TOOLTIP->show;
53
54 my ($x, $y) = $widget->coord2global ($widget->{w}, 0);
55
56 ($x, $y) = $widget->coord2global (-$TOOLTIP->{w}, 0)
57 if $x + $TOOLTIP->{w} > $::WIDTH;
58
59 $TOOLTIP->move ($x, $y);
60 $TOOLTIP->realloc;
61 } 61 }
62 62
63 return; 63 return;
64 } 64 }
65 } 65 }
171sub rescale_widgets { 171sub rescale_widgets {
172 my ($sx, $sy) = @_; 172 my ($sx, $sy) = @_;
173 173
174 for my $widget (values %WIDGET) { 174 for my $widget (values %WIDGET) {
175 if ($widget->{is_toplevel}) { 175 if ($widget->{is_toplevel}) {
176 $widget->{x} += int $widget->{w} * 0.5 if $widget->{x} =~ /^[0-9.]+$/;
177 $widget->{y} += int $widget->{h} * 0.5 if $widget->{y} =~ /^[0-9.]+$/;
178
176 $widget->{x} = int 0.5 + $widget->{x} * $sx if exists $widget->{x}; 179 $widget->{x} = int 0.5 + $widget->{x} * $sx if $widget->{x} =~ /^[0-9.]+$/;
177 $widget->{w} = int 0.5 + $widget->{w} * $sx if exists $widget->{w}; 180 $widget->{w} = int 0.5 + $widget->{w} * $sx if exists $widget->{w};
178 $widget->{req_w} = int 0.5 + $widget->{req_w} * $sx if exists $widget->{req_w}; 181 $widget->{force_w} = int 0.5 + $widget->{force_w} * $sx if exists $widget->{force_w};
179 $widget->{y} = int 0.5 + $widget->{y} * $sy if exists $widget->{y}; 182 $widget->{y} = int 0.5 + $widget->{y} * $sy if $widget->{y} =~ /^[0-9.]+$/;
180 $widget->{h} = int 0.5 + $widget->{h} * $sy if exists $widget->{h}; 183 $widget->{h} = int 0.5 + $widget->{h} * $sy if exists $widget->{h};
181 $widget->{req_h} = int 0.5 + $widget->{req_h} * $sy if exists $widget->{req_h}; 184 $widget->{force_h} = int 0.5 + $widget->{force_h} * $sy if exists $widget->{force_h};
185
186 $widget->{x} -= int $widget->{w} * 0.5 if $widget->{x} =~ /^[0-9.]+$/;
187 $widget->{y} -= int $widget->{h} * 0.5 if $widget->{y} =~ /^[0-9.]+$/;
188
182 } 189 }
183 } 190 }
184 191
185 reconfigure_widgets; 192 reconfigure_widgets;
186} 193}
195 202
196sub new { 203sub new {
197 my $class = shift; 204 my $class = shift;
198 205
199 my $self = bless { 206 my $self = bless {
200 x => 0, 207 x => "center",
201 y => 0, 208 y => "center",
202 z => 0, 209 z => 0,
210 w => undef,
211 h => undef,
203 can_events => 1, 212 can_events => 1,
204 @_ 213 @_
205 }, $class; 214 }, $class;
215
216 Scalar::Util::weaken ($CFClient::UI::WIDGET{$self+0} = $self);
206 217
207 for (keys %$self) { 218 for (keys %$self) {
208 if (/^on_(.*)$/) { 219 if (/^on_(.*)$/) {
209 $self->connect ($1 => delete $self->{$_}); 220 $self->connect ($1 => delete $self->{$_});
210 } 221 }
211 } 222 }
212 223
213 Scalar::Util::weaken ($CFClient::UI::WIDGET{$self+0} = $self);
214
215 if (my $layout = $CFClient::UI::LAYOUT->{$self->{name}}) { 224 if (my $layout = $CFClient::UI::LAYOUT->{$self->{name}}) {
216 $self->{req_x} = $layout->{x} * $::WIDTH; 225 $self->{x} = $layout->{x} * $CFClient::UI::ROOT->{alloc_w} if exists $layout->{x};
217 $self->{req_y} = $layout->{y} * $::HEIGHT; 226 $self->{y} = $layout->{y} * $CFClient::UI::ROOT->{alloc_h} if exists $layout->{y};
218 $self->{def_w} = ($layout->{w} != 0 ? $layout->{w} : 1) * $::WIDTH; 227 $self->{force_w} = $layout->{w} * $CFClient::UI::ROOT->{alloc_w} if exists $layout->{w};
219 $self->{def_h} = ($layout->{h} != 0 ? $layout->{h} : 1) * $::HEIGHT; 228 $self->{force_h} = $layout->{h} * $CFClient::UI::ROOT->{alloc_h} if exists $layout->{h};
229
230 $self->{x} -= $self->{force_w} * 0.5 if exists $layout->{x};
231 $self->{y} -= $self->{force_h} * 0.5 if exists $layout->{y};
232
233 $self->show if $layout->{show};
220 } 234 }
221 235
222 $self 236 $self
223} 237}
224 238
235 return if $self->{parent}; 249 return if $self->{parent};
236 250
237 $CFClient::UI::ROOT->add ($self); 251 $CFClient::UI::ROOT->add ($self);
238} 252}
239 253
240sub center {
241 my ($self) = @_;
242
243 $CFClient::UI::ROOT->on_post_alloc (
244 "center_$self" => sub {
245 $self->move (($self->{parent}{w} - $self->{w}) * 0.5, ($self->{parent}{h} - $self->{h}) * 0.5);
246 },
247 );
248
249 $self->update;
250}
251
252sub set_visible { 254sub set_visible {
253 my ($self) = @_; 255 my ($self) = @_;
254 256
255 return if $self->{visible}; 257 return if $self->{visible};
256 258
257 $self->{root} = $self->{parent}{root}; 259 $self->{root} = $self->{parent}{root};
258 $self->{visible} = $self->{parent}{visible} + 1; 260 $self->{visible} = $self->{parent}{visible} + 1;
259 261
260 $self->emit (visibility_change => 1); 262 $self->emit (visibility_change => 1);
261 263
262 $self->realloc unless exists $self->{req_w}; 264 $self->realloc if !exists $self->{req_w};
263 265
264 $_->set_visible for $self->children; 266 $_->set_visible for $self->children;
265} 267}
266 268
267sub set_invisible { 269sub set_invisible {
309 311
310 $self->{parent}->remove ($self) 312 $self->{parent}->remove ($self)
311 if $self->{parent}; 313 if $self->{parent};
312} 314}
313 315
314sub move { 316sub move_abs {
315 my ($self, $x, $y, $z) = @_; 317 my ($self, $x, $y, $z) = @_;
316 318
317 $self->{x} = int $x; 319 $self->{x} = List::Util::max 0, int $x;
318 $self->{y} = int $y; 320 $self->{y} = List::Util::max 0, int $y;
319 $self->{z} = $z if defined $z; 321 $self->{z} = $z if defined $z;
320 322
321 $self->update; 323 $self->update;
322} 324}
323 325
324sub set_size { 326sub set_size {
325 my ($self, $w, $h) = @_; 327 my ($self, $w, $h) = @_;
326 328
327 $self->{def_w} = $w; 329 $self->{force_w} = $w;
328 $self->{def_h} = $h; 330 $self->{force_h} = $h;
329 331
330 $self->realloc; 332 $self->realloc;
331} 333}
332 334
333sub size_request { 335sub size_request {
337 339
338sub configure { 340sub configure {
339 my ($self, $x, $y, $w, $h) = @_; 341 my ($self, $x, $y, $w, $h) = @_;
340 342
341 if ($self->{aspect}) { 343 if ($self->{aspect}) {
344 my ($ow, $oh) = ($w, $h);
345
342 my $w2 = List::Util::min $w, int $h * $self->{aspect}; 346 $w = List::Util::min $w, int $h * $self->{aspect};
343 my $h2 = List::Util::min $h, int $w / $self->{aspect}; 347 $h = List::Util::min $h, int $w / $self->{aspect};
344 348
345 # use alignment to adjust x, y 349 # use alignment to adjust x, y
346 350
347 $x += int +($w - $w2) * 0.5; 351 $x += int 0.5 * ($ow - $w);
348 $y += int +($h - $h2) * 0.5; 352 $y += int 0.5 * ($oh - $h);
349
350 ($w, $h) = ($w2, $h2);
351 } 353 }
352 354
353 if ($self->{x} != $x || $self->{y} != $y) { 355 if ($self->{x} ne $x || $self->{y} ne $y) {
354 $self->{x} = $x; 356 $self->{x} = $x;
355 $self->{y} = $y; 357 $self->{y} = $y;
356 $self->update; 358 $self->update;
357 } 359 }
358 360
359 if ($self->{w} != $w || $self->{h} != $h) { 361 if ($self->{alloc_w} != $w || $self->{alloc_h} != $h) {
360 return unless $self->{visible}; 362 return unless $self->{visible};
361 363
364 $self->{alloc_w} = $w;
365 $self->{alloc_h} = $h;
366
362 $self->{root}->{size_alloc}{$self+0} = [$self, $w, $h]; 367 $self->{root}{size_alloc}{$self+0} = $self;
363 } 368 }
364} 369}
365 370
366sub size_allocate { 371sub size_allocate {
367 # nothing to be done 372 # nothing to be done
368} 373}
369 374
370sub children { 375sub children {
376 # nop
377}
378
379sub visible_children {
380 $_[0]->children
371} 381}
372 382
373sub set_max_size { 383sub set_max_size {
374 my ($self, $w, $h) = @_; 384 my ($self, $w, $h) = @_;
375 385
434 444
435 $::MAPWIDGET->focus_in #d# focus mapwidget if no other widget has focus 445 $::MAPWIDGET->focus_in #d# focus mapwidget if no other widget has focus
436 unless $FOCUS; 446 unless $FOCUS;
437} 447}
438 448
439sub mouse_motion { } 449sub mouse_motion { 0 }
440sub button_up { } 450sub button_up { 0 }
441sub key_down { } 451sub key_down { 0 }
442sub key_up { } 452sub key_up { 0 }
443 453
444sub button_down { 454sub button_down {
445 my ($self, $ev, $x, $y) = @_; 455 my ($self, $ev, $x, $y) = @_;
446 456
447 $self->focus_in; 457 $self->focus_in;
448}
449 458
450sub w { $_[0]{w} = $_[1] if @_ > 1; $_[0]{w} } 459 0
451sub h { $_[0]{h} = $_[1] if @_ > 1; $_[0]{h} } 460}
452sub x { $_[0]{x} = $_[1] if @_ > 1; $_[0]{x} }
453sub y { $_[0]{y} = $_[1] if @_ > 1; $_[0]{y} }
454sub z { $_[0]{z} = $_[1] if @_ > 1; $_[0]{z} }
455 461
456sub find_widget { 462sub find_widget {
457 my ($self, $x, $y) = @_; 463 my ($self, $x, $y) = @_;
458 464
459 return () unless $self->{can_events}; 465 return () unless $self->{can_events};
467 473
468sub set_parent { 474sub set_parent {
469 my ($self, $parent) = @_; 475 my ($self, $parent) = @_;
470 476
471 Scalar::Util::weaken ($self->{parent} = $parent); 477 Scalar::Util::weaken ($self->{parent} = $parent);
472
473 $self->set_visible if $parent->{visible}; 478 $self->set_visible if $parent->{visible};
474
475 $self->realloc;
476} 479}
477 480
478sub connect { 481sub connect {
479 my ($self, $signal, $cb) = @_; 482 my ($self, $signal, $cb) = @_;
480 483
499} 502}
500 503
501sub realloc { 504sub realloc {
502 my ($self) = @_; 505 my ($self) = @_;
503 506
504 return unless $self->{visible}; 507 if ($self->{visible}) {
505
506 return if $self->{root}{realloc}{$self}; 508 return if $self->{root}{realloc}{$self+0};
507 509
508 $self->{root}{realloc}{$self} = $self; 510 $self->{root}{realloc}{$self+0} = $self;
509 $self->{root}->update; 511 $self->{root}->update;
512 } else {
513 delete $self->{req_w};
514 delete $self->{req_h};
515 }
510} 516}
511 517
512sub update { 518sub update {
513 my ($self) = @_; 519 my ($self) = @_;
514 520
515 $self->{parent}->update 521 $self->{parent}->update
516 if $self->{parent}; 522 if $self->{parent};
517} 523}
518 524
525sub reconfigure {
526 my ($self) = @_;
527
528 $self->realloc;
529 $self->update;
530}
531
532# using global variables seems a bit hacky, but passing through all drawing
533# functions seems pointless.
534our ($draw_x, $draw_y, $draw_w, $draw_h); # screen rectangle being drawn
535
519sub draw { 536sub draw {
520 my ($self) = @_; 537 my ($self) = @_;
521 538
522 return unless $self->{h} && $self->{w}; 539 return unless $self->{h} && $self->{w};
540
541 # update screen rectangle
542 local $draw_x = $draw_x + $self->{x};
543 local $draw_y = $draw_y + $self->{y};
544 local $draw_w = $draw_x + $self->{w};
545 local $draw_h = $draw_y + $self->{h};
546
547 # skip widgets that are entirely outside the drawing area
548 return if ($draw_x + $self->{w} < 0) || ($draw_x >= $draw_w)
549 || ($draw_y + $self->{h} < 0) || ($draw_y >= $draw_h);
523 550
524 glPushMatrix; 551 glPushMatrix;
525 glTranslate $self->{x}, $self->{y}, 0; 552 glTranslate $self->{x}, $self->{y}, 0;
526 $self->_draw; 553 $self->_draw;
527 glPopMatrix; 554 glPopMatrix;
539 glVertex $x , $y + $self->{h}; 566 glVertex $x , $y + $self->{h};
540 glEnd; 567 glEnd;
541 glDisable GL_BLEND; 568 glDisable GL_BLEND;
542 } 569 }
543 570
544 if ($ENV{PCLIENT_DEBUG}) { 571 if ($ENV{CFPLUS_DEBUG} & 1) {
545 glPushMatrix; 572 glPushMatrix;
546 glColor 1, 1, 0, 1; 573 glColor 1, 1, 0, 1;
547 glTranslate $self->{x} + 0.375, $self->{y} + 0.375; 574 glTranslate $self->{x} + 0.375, $self->{y} + 0.375;
548 glBegin GL_LINE_LOOP; 575 glBegin GL_LINE_LOOP;
549 glVertex 0 , 0; 576 glVertex 0 , 0;
625 my ($class, %arg) = @_; 652 my ($class, %arg) = @_;
626 $class->SUPER::new (can_events => 0, %arg); 653 $class->SUPER::new (can_events => 0, %arg);
627} 654}
628 655
629sub size_request { 656sub size_request {
630 (0, 0) 657 my ($self) = @_;
658
659 ($self->{w} + 0, $self->{h} + 0)
631} 660}
632 661
633sub draw { } 662sub draw { }
634 663
635############################################################################# 664#############################################################################
639our @ISA = CFClient::UI::Base::; 668our @ISA = CFClient::UI::Base::;
640 669
641sub new { 670sub new {
642 my ($class, %arg) = @_; 671 my ($class, %arg) = @_;
643 672
644 my $children = delete $arg{children} || []; 673 my $children = delete $arg{children};
645 674
646 my $self = $class->SUPER::new ( 675 my $self = $class->SUPER::new (
647 children => [], 676 children => [],
648 can_events => 0, 677 can_events => 0,
649 %arg, 678 %arg,
650 ); 679 );
680
651 $self->add ($_) for @$children; 681 $self->add (@$children)
682 if $children;
652 683
653 $self 684 $self
654} 685}
655 686
656sub add { 687sub add {
704 $x -= $self->{x}; 735 $x -= $self->{x};
705 $y -= $self->{y}; 736 $y -= $self->{y};
706 737
707 my $res; 738 my $res;
708 739
709 for (reverse @{ $self->{children} }) { 740 for (reverse $self->visible_children) {
710 $res = $_->find_widget ($x, $y) 741 $res = $_->find_widget ($x, $y)
711 and return $res; 742 and return $res;
712 } 743 }
713 744
714 $self->SUPER::find_widget ($x + $self->{x}, $y + $self->{y}) 745 $self->SUPER::find_widget ($x + $self->{x}, $y + $self->{y})
756sub size_request { 787sub size_request {
757 $_[0]{children}[0]->size_request 788 $_[0]{children}[0]->size_request
758} 789}
759 790
760sub size_allocate { 791sub size_allocate {
761 my ($self, $w, $h, $changed) = @_; 792 my ($self, $w, $h) = @_;
762 793
763 $self->{children}[0]->configure (0, 0, $w, $h); 794 $self->{children}[0]->configure (0, 0, $w, $h);
764} 795}
765 796
766############################################################################# 797#############################################################################
783 $ROOT->on_post_alloc ($self => sub { $self->render_child }); 814 $ROOT->on_post_alloc ($self => sub { $self->render_child });
784 $self->SUPER::update; 815 $self->SUPER::update;
785} 816}
786 817
787sub size_allocate { 818sub size_allocate {
788 my ($self, $w, $h, $changed) = @_; 819 my ($self, $w, $h) = @_;
789 820
790 $self->SUPER::size_allocate ($w, $h, $changed); 821 $self->SUPER::size_allocate ($w, $h);
791 $self->update 822 $self->update;
792 if $changed;
793} 823}
794 824
795sub _render { 825sub _render {
826 my ($self) = @_;
827
796 $_[0]{children}[0]->draw; 828 $self->{children}[0]->draw;
797} 829}
798 830
799sub render_child { 831sub render_child {
800 my ($self) = @_; 832 my ($self) = @_;
801 833
802 $self->{texture} = new_from_opengl CFClient::Texture $self->{w}, $self->{h}, sub { 834 $self->{texture} = new_from_opengl CFClient::Texture $self->{w}, $self->{h}, sub {
803 glClearColor 0, 0, 0, 0; 835 glClearColor 0, 0, 0, 0;
804 glClear GL_COLOR_BUFFER_BIT; 836 glClear GL_COLOR_BUFFER_BIT;
805 837
838 {
839 package CFClient::UI::Base;
840
841 ($draw_x, $draw_y, $draw_w, $draw_h) =
842 (0, 0, $self->{w}, $self->{h});
843 }
844
806 $self->_render; 845 $self->_render;
807 }; 846 };
808} 847}
809 848
810sub _draw { 849sub _draw {
811 my ($self) = @_; 850 my ($self) = @_;
812 851
813 my ($w, $h) = ($self->w, $self->h); 852 my ($w, $h) = @$self{qw(w h)};
814 853
815 my $tex = $self->{texture} 854 my $tex = $self->{texture}
816 or return; 855 or return;
817 856
818 glEnable GL_TEXTURE_2D; 857 glEnable GL_TEXTURE_2D;
841} 880}
842 881
843sub size_request { 882sub size_request {
844 my ($self) = @_; 883 my ($self) = @_;
845 884
846 my ($w, $h) = @$self{qw(child_w child_h)} = @{$self->child}{qw(req_w req_h)}; 885 my ($w, $h) = @{$self->child}{qw(req_w req_h)};
847 886
848 $w = 10 if $self->{scroll_x}; 887 $w = 10 if $self->{scroll_x};
849 $h = 10 if $self->{scroll_y}; 888 $h = 10 if $self->{scroll_y};
850 889
851 ($w, $h) 890 ($w, $h)
852} 891}
853 892
854sub size_allocate { 893sub size_allocate {
855 my ($self, $w, $h, $changed) = @_; 894 my ($self, $w, $h) = @_;
856 895
896 my $child = $self->child;
897
857 $w = $self->{child_w} if $self->{scroll_x} && $self->{child_w}; 898 $w = $child->{req_w} if $self->{scroll_x} && $child->{req_w};
858 $h = $self->{child_h} if $self->{scroll_y} && $self->{child_h}; 899 $h = $child->{req_h} if $self->{scroll_y} && $child->{req_h};
859 900
860 $self->child->configure (0, 0, $w, $h); 901 $self->child->configure (0, 0, $w, $h);
861 $self->update; 902 $self->update;
862} 903}
863 904
899} 940}
900 941
901sub _render { 942sub _render {
902 my ($self) = @_; 943 my ($self) = @_;
903 944
945 local $CFClient::UI::Base::draw_x = $CFClient::UI::Base::draw_x - $self->{view_x};
946 local $CFClient::UI::Base::draw_y = $CFClient::UI::Base::draw_y - $self->{view_y};
947
904 CFClient::OpenGL::glTranslate -$self->{view_x}, -$self->{view_y}; 948 CFClient::OpenGL::glTranslate -$self->{view_x}, -$self->{view_y};
905 949
906 $self->SUPER::_render; 950 $self->SUPER::_render;
907} 951}
908 952
911package CFClient::UI::ScrolledWindow; 955package CFClient::UI::ScrolledWindow;
912 956
913our @ISA = CFClient::UI::HBox::; 957our @ISA = CFClient::UI::HBox::;
914 958
915sub new { 959sub new {
916 my $class = shift; 960 my ($class, %arg) = @_;
961
962 my $child = delete $arg{child};
917 963
918 my $self; 964 my $self;
919 965
920 my $slider = new CFClient::UI::Slider 966 my $slider = new CFClient::UI::Slider
921 vertical => 1, 967 vertical => 1,
926 ; 972 ;
927 973
928 $self = $class->SUPER::new ( 974 $self = $class->SUPER::new (
929 vp => (new CFClient::UI::ViewPort expand => 1), 975 vp => (new CFClient::UI::ViewPort expand => 1),
930 slider => $slider, 976 slider => $slider,
931 @_, 977 %arg,
932 ); 978 );
933 979
934 $self->{vp}->add ($self->{scrolled});
935 $self->add ($self->{vp});
936 $self->add ($self->{slider}); 980 $self->SUPER::add ($self->{vp}, $self->{slider});
981 $self->add ($child) if $child;
937 982
938 $self 983 $self
984}
985
986sub add {
987 my ($self, $widget) = @_;
988
989 $self->{vp}->add ($self->{child} = $widget);
939} 990}
940 991
941sub update { 992sub update {
942 my ($self) = @_; 993 my ($self) = @_;
943 994
947 my $child = $self->{vp}->child; 998 my $child = $self->{vp}->child;
948 $self->{slider}->set_range ([$self->{slider}{range}[0], 0, $child->{h}, $self->{vp}{h}, 1]); 999 $self->{slider}->set_range ([$self->{slider}{range}[0], 0, $child->{h}, $self->{vp}{h}, 1]);
949} 1000}
950 1001
951sub size_allocate { 1002sub size_allocate {
952 my ($self, $w, $h, $changed) = @_; 1003 my ($self, $w, $h) = @_;
953 1004
954 $self->SUPER::size_allocate ($w, $h, $changed); 1005 $self->SUPER::size_allocate ($w, $h);
955 1006
956 my $child = $self->{vp}->child; 1007 my $child = $self->{vp}->child;
957 $self->{slider}->set_range ([$self->{slider}{range}[0], 0, $child->{h}, $self->{vp}{h}, 1]); 1008 $self->{slider}->set_range ([$self->{slider}{range}[0], 0, $child->{h}, $self->{vp}{h}, 1]);
958} 1009}
959 1010
1006 1057
1007our @ISA = CFClient::UI::Bin::; 1058our @ISA = CFClient::UI::Bin::;
1008 1059
1009use CFClient::OpenGL; 1060use CFClient::OpenGL;
1010 1061
1011my @tex = 1062my $bg =
1063 new_from_file CFClient::Texture CFClient::find_rcfile "d1_bg.png",
1064 mipmap => 1, wrap => 1;
1065
1066my @border =
1012 map { new_from_file CFClient::Texture CFClient::find_rcfile $_, mipmap => 1 } 1067 map { new_from_file CFClient::Texture CFClient::find_rcfile $_, mipmap => 1 }
1013 qw(d1_bg.png d1_border_top.png d1_border_right.png d1_border_left.png d1_border_bottom.png); 1068 qw(d1_border_top.png d1_border_right.png d1_border_left.png d1_border_bottom.png);
1014 1069
1015sub new { 1070sub new {
1016 my $class = shift; 1071 my ($class, %arg) = @_;
1072
1073 my $title = delete $arg{title};
1017 1074
1018 my $self = $class->SUPER::new ( 1075 my $self = $class->SUPER::new (
1019 bg => [1, 1, 1, 1], 1076 bg => [1, 1, 1, 1],
1020 border_bg => [1, 1, 1, 1], 1077 border_bg => [1, 1, 1, 1],
1021 border => 0.6, 1078 border => 0.6,
1022 is_toplevel => 1,
1023 can_events => 1, 1079 can_events => 1,
1024 @_ 1080 min_w => 16,
1081 min_h => 16,
1082 %arg,
1025 ); 1083 );
1026 1084
1027 $self->{title} &&= new CFClient::UI::Label 1085 $self->{title} = new CFClient::UI::Label
1028 align => 0, 1086 align => 0,
1029 valign => 1, 1087 valign => 1,
1030 text => $self->{title}, 1088 text => $title,
1031 fontsize => $self->{border}; 1089 fontsize => $self->{border}
1090 if defined $title;
1032 1091
1033 $self 1092 $self
1093}
1094
1095sub add {
1096 my ($self, @widgets) = @_;
1097
1098 $self->SUPER::add (@widgets);
1099 $self->CFClient::UI::Container::add ($self->{title}) if $self->{title};
1034} 1100}
1035 1101
1036sub border { 1102sub border {
1037 int $_[0]{border} * $::FONTSIZE 1103 int $_[0]{border} * $::FONTSIZE
1038} 1104}
1039 1105
1040sub size_request { 1106sub size_request {
1041 my ($self) = @_; 1107 my ($self) = @_;
1108
1109 $self->{title}->size_request
1110 if $self->{title};
1042 1111
1043 my ($w, $h) = $self->SUPER::size_request; 1112 my ($w, $h) = $self->SUPER::size_request;
1044 1113
1045 ( 1114 (
1046 $w + $self->border * 2, 1115 $w + $self->border * 2,
1047 $h + $self->border * 2, 1116 $h + $self->border * 2,
1048 ) 1117 )
1049} 1118}
1050 1119
1051sub size_allocate { 1120sub size_allocate {
1052 my ($self, $w, $h, $changed) = @_; 1121 my ($self, $w, $h) = @_;
1053 1122
1054 return unless $changed; 1123 if ($self->{title}) {
1124 $self->{title}{w} = $w;
1125 $self->{title}{h} = $h;
1126 $self->{title}->size_allocate ($w, $h);
1127 }
1055 1128
1129 my $border = $self->border;
1130
1056 $h -= List::Util::max 0, $self->border * 2; 1131 $h -= List::Util::max 0, $border * 2;
1057 $w -= List::Util::max 0, $self->border * 2; 1132 $w -= List::Util::max 0, $border * 2;
1058 1133
1059 $self->{title}->configure ($self->border, int $self->border - $::FONTSIZE * 2, $w, int $::FONTSIZE * 2)
1060 if $self->{title};
1061
1062 $self->child->configure ($self->border, $self->border, $w, $h); 1134 $self->child->configure ($border, $border, $w, $h);
1063} 1135}
1064 1136
1065sub button_down { 1137sub button_down {
1066 my ($self, $ev, $x, $y) = @_; 1138 my ($self, $ev, $x, $y) = @_;
1067 1139
1083 my ($ev, $x, $y) = @_; 1155 my ($ev, $x, $y) = @_;
1084 1156
1085 my $dx = $ev->{x} - $ox; 1157 my $dx = $ev->{x} - $ox;
1086 my $dy = $ev->{y} - $oy; 1158 my $dy = $ev->{y} - $oy;
1087 1159
1088 $self->{user_x} = $wx + $dx * $mx;
1089 $self->{user_y} = $wy + $dy * $my;
1090 $self->{def_w} = $bw + $dx * ($mx ? -1 : 1); 1160 $self->{force_w} = $bw + $dx * ($mx ? -1 : 1);
1091 $self->{def_h} = $bh + $dy * ($my ? -1 : 1); 1161 $self->{force_h} = $bh + $dy * ($my ? -1 : 1);
1092 $self->move ($self->{user_x}, $self->{user_y}); 1162
1093 $self->realloc; 1163 $self->realloc;
1164 $self->move_abs ($wx + $dx * $mx, $wy + $dy * $my);
1094 }; 1165 };
1095 1166
1096 } elsif ($lr ^ $td) { 1167 } elsif ($lr ^ $td) {
1097 my ($ox, $oy) = ($ev->{x}, $ev->{y}); 1168 my ($ox, $oy) = ($ev->{x}, $ev->{y});
1098 my ($bx, $by) = ($self->{x}, $self->{y}); 1169 my ($bx, $by) = ($self->{x}, $self->{y});
1100 $self->{motion} = sub { 1171 $self->{motion} = sub {
1101 my ($ev, $x, $y) = @_; 1172 my ($ev, $x, $y) = @_;
1102 1173
1103 ($x, $y) = ($ev->{x}, $ev->{y}); 1174 ($x, $y) = ($ev->{x}, $ev->{y});
1104 1175
1105 $self->{user_x} = $bx + $x - $ox; 1176 $self->move_abs ($bx + $x - $ox, $by + $y - $oy);
1106 $self->{user_y} = $by + $y - $oy;
1107
1108 $self->move ($self->{user_x}, $self->{user_y});
1109 $self->realloc;
1110 }; 1177 };
1178 } else {
1179 return 0;
1180 }
1181
1111 } 1182 1
1112} 1183}
1113 1184
1114sub button_up { 1185sub button_up {
1115 my ($self, $ev, $x, $y) = @_; 1186 my ($self, $ev, $x, $y) = @_;
1116 1187
1117 delete $self->{motion}; 1188 !!delete $self->{motion}
1118} 1189}
1119 1190
1120sub mouse_motion { 1191sub mouse_motion {
1121 my ($self, $ev, $x, $y) = @_; 1192 my ($self, $ev, $x, $y) = @_;
1122 1193
1123 $self->{motion}->($ev, $x, $y) if $self->{motion}; 1194 $self->{motion}->($ev, $x, $y) if $self->{motion};
1195
1196 !!$self->{motion}
1124} 1197}
1125 1198
1126sub _draw { 1199sub _draw {
1127 my ($self) = @_; 1200 my ($self) = @_;
1128 1201
1202 my $child = $self->{children}[0];
1203
1129 my ($w, $h ) = ($self->{w}, $self->{h}); 1204 my ($w, $h ) = ($self->{w}, $self->{h});
1130 my ($cw, $ch) = ($self->child->{w}, $self->child->{h}); 1205 my ($cw, $ch) = ($child->{w}, $child->{h});
1131 1206
1132 glEnable GL_TEXTURE_2D; 1207 glEnable GL_TEXTURE_2D;
1133 glTexEnv GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE; 1208 glTexEnv GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE;
1134 1209
1135 my $border = $self->border; 1210 my $border = $self->border;
1136 1211
1137 glColor @{ $self->{border_bg} }; 1212 glColor @{ $self->{border_bg} };
1138 $tex[1]->draw_quad_alpha (0, 0, $w, $border); 1213 $border[0]->draw_quad_alpha (0, 0, $w, $border);
1139 $tex[3]->draw_quad_alpha (0, $border, $border, $ch); 1214 $border[1]->draw_quad_alpha (0, $border, $border, $ch);
1140 $tex[2]->draw_quad_alpha ($w - $border, $border, $border, $ch); 1215 $border[2]->draw_quad_alpha ($w - $border, $border, $border, $ch);
1141 $tex[4]->draw_quad_alpha (0, $h - $border, $w, $border); 1216 $border[3]->draw_quad_alpha (0, $h - $border, $w, $border);
1142 1217
1143 if (@{$self->{bg}} < 4 || $self->{bg}[3]) { 1218 if (@{$self->{bg}} < 4 || $self->{bg}[3]) {
1144 my $bg = $tex[0]; 1219 glColor @{ $self->{bg} };
1145 1220
1146 # TODO: repeat texture not scale 1221 # TODO: repeat texture not scale
1222 # solve this better(?)
1147 my $rep_x = $cw / $bg->{w}; 1223 $bg->{s} = $cw / $bg->{w};
1148 my $rep_y = $ch / $bg->{h}; 1224 $bg->{t} = $ch / $bg->{h};
1149
1150 glColor @{ $self->{bg} };
1151
1152 $bg->{s} = $rep_x;
1153 $bg->{t} = $rep_y;
1154 $bg->{wrap_mode} = 1;
1155 $bg->draw_quad_alpha ($border, $border, $cw, $ch); 1225 $bg->draw_quad_alpha ($border, $border, $cw, $ch);
1156 } 1226 }
1157 1227
1158 glDisable GL_TEXTURE_2D; 1228 glDisable GL_TEXTURE_2D;
1159 1229
1160 $self->{title}->draw if $self->{title};
1161
1162 $self->child->draw; 1230 $child->draw;
1231
1232 if ($self->{title}) {
1233 glTranslate 0, $border - $self->{h};
1234 $self->{title}->_draw;
1235 }
1163} 1236}
1164 1237
1165############################################################################# 1238#############################################################################
1166 1239
1167package CFClient::UI::Table; 1240package CFClient::UI::Table;
1241 (sum @$hs), 1314 (sum @$hs),
1242 ) 1315 )
1243} 1316}
1244 1317
1245sub size_allocate { 1318sub size_allocate {
1246 my ($self, $w, $h, $changed) = @_; 1319 my ($self, $w, $h) = @_;
1247 1320
1248 my ($ws, $hs) = $self->get_wh; 1321 my ($ws, $hs) = $self->get_wh;
1249 1322
1250 my $req_w = (sum @$ws) || 1; 1323 my $req_w = (sum @$ws) || 1;
1251 my $req_h = (sum @$hs) || 1; 1324 my $req_h = (sum @$hs) || 1;
1329 (List::Util::max map $_->{req_h}, @{$self->{children}}), 1402 (List::Util::max map $_->{req_h}, @{$self->{children}}),
1330 ) 1403 )
1331} 1404}
1332 1405
1333sub size_allocate { 1406sub size_allocate {
1334 my ($self, $w, $h, $changed) = @_; 1407 my ($self, $w, $h) = @_;
1335 1408
1336 my $space = $self->{vertical} ? $h : $w; 1409 my $space = $self->{vertical} ? $h : $w;
1337 my $children = $self->{children}; 1410 my $children = $self->{children};
1338 1411
1339 my @req; 1412 my @req;
1422 ellipsise => 3, # end 1495 ellipsise => 3, # end
1423 layout => (new CFClient::Layout), 1496 layout => (new CFClient::Layout),
1424 fontsize => 1, 1497 fontsize => 1,
1425 align => -1, 1498 align => -1,
1426 valign => -1, 1499 valign => -1,
1427 padding => 2, 1500 padding_x => 2,
1501 padding_y => 2,
1428 can_events => 0, 1502 can_events => 0,
1429 %arg 1503 %arg
1430 ); 1504 );
1431 1505
1432 if (exists $self->{template}) { 1506 if (exists $self->{template}) {
1469 1543
1470 $self->{layout} = new CFClient::Layout if $self->{layout}->is_rgba; 1544 $self->{layout} = new CFClient::Layout if $self->{layout}->is_rgba;
1471 $self->{layout}->set_text ($text); 1545 $self->{layout}->set_text ($text);
1472 1546
1473 $self->realloc; 1547 $self->realloc;
1548 $self->update;
1474} 1549}
1475 1550
1476sub set_markup { 1551sub set_markup {
1477 my ($self, $markup) = @_; 1552 my ($self, $markup) = @_;
1478 1553
1483 1558
1484 $self->{layout} = new CFClient::Layout $rgba if $self->{layout}->is_rgba != $rgba; 1559 $self->{layout} = new CFClient::Layout $rgba if $self->{layout}->is_rgba != $rgba;
1485 $self->{layout}->set_markup ($markup); 1560 $self->{layout}->set_markup ($markup);
1486 1561
1487 $self->realloc; 1562 $self->realloc;
1563 $self->update;
1488} 1564}
1489 1565
1490sub size_request { 1566sub size_request {
1491 my ($self) = @_; 1567 my ($self) = @_;
1492 1568
1506 1582
1507 $w = List::Util::max $w, $w2; 1583 $w = List::Util::max $w, $w2;
1508 $h = List::Util::max $h, $h2; 1584 $h = List::Util::max $h, $h2;
1509 } 1585 }
1510 1586
1511 ( 1587 ($w, $h)
1512 $w + $self->{padding} * 2,
1513 $h + $self->{padding} * 2,
1514 )
1515} 1588}
1516 1589
1517sub size_allocate { 1590sub size_allocate {
1518 my ($self, $w, $h, $changed) = @_; 1591 my ($self, $w, $h) = @_;
1592
1593 delete $self->{ox};
1519 1594
1520 delete $self->{texture} 1595 delete $self->{texture}
1521 if $changed; 1596 unless $w >= $self->{req_w} && $self->{old_w} >= $self->{req_w};
1522} 1597}
1523 1598
1524sub set_fontsize { 1599sub set_fontsize {
1525 my ($self, $fontsize) = @_; 1600 my ($self, $fontsize) = @_;
1526 1601
1541 $self->{layout}->set_width ($self->{w}); 1616 $self->{layout}->set_width ($self->{w});
1542 $self->{layout}->set_ellipsise ($self->{ellipsise}); 1617 $self->{layout}->set_ellipsise ($self->{ellipsise});
1543 $self->{layout}->set_single_paragraph_mode ($self->{ellipsise}); 1618 $self->{layout}->set_single_paragraph_mode ($self->{ellipsise});
1544 $self->{layout}->set_height ($self->{fontsize} * $::FONTSIZE); 1619 $self->{layout}->set_height ($self->{fontsize} * $::FONTSIZE);
1545 1620
1546 my $tex = new_from_layout CFClient::Texture $self->{layout}; 1621 new_from_layout CFClient::Texture $self->{layout}
1622 };
1547 1623
1624 unless (exists $self->{ox}) {
1548 $self->{ox} = int ($self->{align} < 0 ? $self->{padding} 1625 $self->{ox} = int ($self->{align} < 0 ? $self->{padding_x}
1549 : $self->{align} > 0 ? $self->{w} - $tex->{w} - $self->{padding} 1626 : $self->{align} > 0 ? $self->{w} - $tex->{w} - $self->{padding_x}
1550 : ($self->{w} - $tex->{w}) * 0.5); 1627 : ($self->{w} - $tex->{w}) * 0.5);
1551 1628
1552 $self->{oy} = int ($self->{valign} < 0 ? $self->{padding} 1629 $self->{oy} = int ($self->{valign} < 0 ? $self->{padding_y}
1553 : $self->{valign} > 0 ? $self->{h} - $tex->{h} - $self->{padding} 1630 : $self->{valign} > 0 ? $self->{h} - $tex->{h} - $self->{padding_y}
1554 : ($self->{h} - $tex->{h}) * 0.5); 1631 : ($self->{h} - $tex->{h}) * 0.5);
1555
1556 $tex
1557 }; 1632 };
1558 1633
1559 glEnable GL_TEXTURE_2D; 1634 glEnable GL_TEXTURE_2D;
1560 glTexEnv GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE; 1635 glTexEnv GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE;
1561 1636
1656 $self->{cursor} = length $text; 1731 $self->{cursor} = length $text;
1657 } elsif ($uni == 27) { 1732 } elsif ($uni == 27) {
1658 $self->_emit ('escape'); 1733 $self->_emit ('escape');
1659 } elsif ($uni) { 1734 } elsif ($uni) {
1660 substr $text, $self->{cursor}++, 0, chr $uni; 1735 substr $text, $self->{cursor}++, 0, chr $uni;
1736 } else {
1737 return 0;
1661 } 1738 }
1662 1739
1663 $self->_set_text ($text); 1740 $self->_set_text ($text);
1664 1741
1665 $self->realloc; 1742 $self->realloc;
1743
1744 1
1666} 1745}
1667 1746
1668sub focus_in { 1747sub focus_in {
1669 my ($self) = @_; 1748 my ($self) = @_;
1670 1749
1685 utf8::encode $text; 1764 utf8::encode $text;
1686 $self->{cursor} = length substr $text, 0, $idx; 1765 $self->{cursor} = length substr $text, 0, $idx;
1687 1766
1688 $self->_set_text ($self->{text}); 1767 $self->_set_text ($self->{text});
1689 $self->update; 1768 $self->update;
1769
1770 1
1690} 1771}
1691 1772
1692sub mouse_motion { 1773sub mouse_motion {
1693 my ($self, $ev, $x, $y) = @_; 1774 my ($self, $ev, $x, $y) = @_;
1694# printf "M %d,%d %d,%d\n", $ev->motion_x, $ev->motion_y, $x, $y;#d# 1775# printf "M %d,%d %d,%d\n", $ev->motion_x, $ev->motion_y, $x, $y;#d#
1776
1777 0
1695} 1778}
1696 1779
1697sub _draw { 1780sub _draw {
1698 my ($self) = @_; 1781 my ($self) = @_;
1699 1782
1776 } else { 1859 } else {
1777 $self->set_text ($self->{history_saveback}); 1860 $self->set_text ($self->{history_saveback});
1778 } 1861 }
1779 1862
1780 } else { 1863 } else {
1781 $self->SUPER::key_down ($ev); 1864 return $self->SUPER::key_down ($ev)
1865 }
1866
1782 } 1867 1
1783
1784} 1868}
1785 1869
1786############################################################################# 1870#############################################################################
1787 1871
1788package CFClient::UI::Button; 1872package CFClient::UI::Button;
1797 1881
1798sub new { 1882sub new {
1799 my $class = shift; 1883 my $class = shift;
1800 1884
1801 $class->SUPER::new ( 1885 $class->SUPER::new (
1802 padding => 4, 1886 padding_x => 4,
1887 padding_y => 4,
1803 fg => [1, 1, 1], 1888 fg => [1, 1, 1],
1804 active_fg => [0, 0, 1], 1889 active_fg => [0, 0, 1],
1805 can_hover => 1, 1890 can_hover => 1,
1806 align => 0, 1891 align => 0,
1807 valign => 0, 1892 valign => 0,
1816 my ($self, $ev, $x, $y) = @_; 1901 my ($self, $ev, $x, $y) = @_;
1817 1902
1818 $self->emit ("activate") 1903 $self->emit ("activate")
1819 if $x >= 0 && $x < $self->{w} 1904 if $x >= 0 && $x < $self->{w}
1820 && $y >= 0 && $y < $self->{h}; 1905 && $y >= 0 && $y < $self->{h};
1906
1907 1
1821} 1908}
1822 1909
1823sub _draw { 1910sub _draw {
1824 my ($self) = @_; 1911 my ($self) = @_;
1825 1912
1854 1941
1855sub new { 1942sub new {
1856 my $class = shift; 1943 my $class = shift;
1857 1944
1858 $class->SUPER::new ( 1945 $class->SUPER::new (
1859 padding => 2, 1946 padding_x => 2,
1947 padding_y => 2,
1860 fg => [1, 1, 1], 1948 fg => [1, 1, 1],
1861 active_fg => [1, 1, 0], 1949 active_fg => [1, 1, 0],
1862 bg => [0, 0, 0, 0.2], 1950 bg => [0, 0, 0, 0.2],
1863 active_bg => [1, 1, 1, 0.5], 1951 active_bg => [1, 1, 1, 0.5],
1864 state => 0, 1952 state => 0,
1868} 1956}
1869 1957
1870sub size_request { 1958sub size_request {
1871 my ($self) = @_; 1959 my ($self) = @_;
1872 1960
1873 ($self->{padding} * 2 + 6) x 2 1961 (6) x 2
1874} 1962}
1875 1963
1876sub button_down { 1964sub button_down {
1877 my ($self, $ev, $x, $y) = @_; 1965 my ($self, $ev, $x, $y) = @_;
1878 1966
1879 if ($x >= $self->{padding} && $x < $self->{w} - $self->{padding} 1967 if ($x >= $self->{padding_x} && $x < $self->{w} - $self->{padding_x}
1880 && $y >= $self->{padding} && $y < $self->{h} - $self->{padding}) { 1968 && $y >= $self->{padding_y} && $y < $self->{h} - $self->{padding_y}) {
1881 $self->{state} = !$self->{state}; 1969 $self->{state} = !$self->{state};
1882 $self->_emit (changed => $self->{state}); 1970 $self->_emit (changed => $self->{state});
1971 } else {
1972 return 0
1973 }
1974
1883 } 1975 1
1884} 1976}
1885 1977
1886sub _draw { 1978sub _draw {
1887 my ($self) = @_; 1979 my ($self) = @_;
1888 1980
1889 $self->SUPER::_draw; 1981 $self->SUPER::_draw;
1890 1982
1891 glTranslate $self->{padding} + 0.375, $self->{padding} + 0.375, 0; 1983 glTranslate $self->{padding_x} + 0.375, $self->{padding_y} + 0.375, 0;
1892 1984
1893 my $s = (List::Util::min @$self{qw(w h)}) - $self->{padding} * 2; 1985 my ($w, $h) = @$self{qw(w h)};
1986
1987 my $s = List::Util::min $w - $self->{padding_x} * 2, $h - $self->{padding_y} * 2;
1894 1988
1895 glColor @{ $FOCUS == $self ? $self->{active_fg} : $self->{fg} }; 1989 glColor @{ $FOCUS == $self ? $self->{active_fg} : $self->{fg} };
1896 1990
1897 my $tex = $self->{state} ? $tex[1] : $tex[0]; 1991 my $tex = $self->{state} ? $tex[1] : $tex[0];
1898 1992
2163 fg => [1, 1, 1], 2257 fg => [1, 1, 1],
2164 active_fg => [0, 0, 0], 2258 active_fg => [0, 0, 0],
2165 bg => [0, 0, 0, 0.2], 2259 bg => [0, 0, 0, 0.2],
2166 active_bg => [1, 1, 1, 0.5], 2260 active_bg => [1, 1, 1, 0.5],
2167 range => [0, 0, 100, 10, 0], 2261 range => [0, 0, 100, 10, 0],
2168 req_w => $::WIDTH / 80, 2262 min_w => $::WIDTH / 80,
2169 req_h => $::WIDTH / 80, 2263 min_h => $::WIDTH / 80,
2170 vertical => 0, 2264 vertical => 0,
2171 can_hover => 1, 2265 can_hover => 1,
2172 inner_pad => 0.02, 2266 inner_pad => 0.02,
2173 @_ 2267 @_
2174 ); 2268 );
2214} 2308}
2215 2309
2216sub size_request { 2310sub size_request {
2217 my ($self) = @_; 2311 my ($self) = @_;
2218 2312
2219 my $w = $self->{req_w}; 2313 ($self->{req_w}, $self->{req_h})
2220 my $h = $self->{req_h};
2221
2222 $self->{vertical} ? ($h, $w) : ($w, $h)
2223} 2314}
2224 2315
2225sub button_down { 2316sub button_down {
2226 my ($self, $ev, $x, $y) = @_; 2317 my ($self, $ev, $x, $y) = @_;
2227 2318
2228 $self->SUPER::button_down ($ev, $x, $y); 2319 $self->SUPER::button_down ($ev, $x, $y);
2229 2320
2230 $self->{click} = [$self->{range}[0], $self->{vertical} ? $y : $x]; 2321 $self->{click} = [$self->{range}[0], $self->{vertical} ? $y : $x];
2231 2322
2232 $self->mouse_motion ($ev, $x, $y); 2323 $self->mouse_motion ($ev, $x, $y)
2233} 2324}
2234 2325
2235sub mouse_motion { 2326sub mouse_motion {
2236 my ($self, $ev, $x, $y) = @_; 2327 my ($self, $ev, $x, $y) = @_;
2237 2328
2241 my (undef, $lo, $hi, $page) = @{$self->{range}}; 2332 my (undef, $lo, $hi, $page) = @{$self->{range}};
2242 2333
2243 $x = ($x - $self->{click}[1]) / ($w * $self->{scale}); 2334 $x = ($x - $self->{click}[1]) / ($w * $self->{scale});
2244 2335
2245 $self->set_value ($self->{click}[0] + $x * ($hi - $page - $lo)); 2336 $self->set_value ($self->{click}[0] + $x * ($hi - $page - $lo));
2337 } else {
2338 return 0;
2339 }
2340
2246 } 2341 1
2247} 2342}
2248 2343
2249sub update { 2344sub update {
2250 my ($self) = @_; 2345 my ($self) = @_;
2251 2346
2377 $self->{fontsize} = $fontsize; 2472 $self->{fontsize} = $fontsize;
2378 $self->reflow; 2473 $self->reflow;
2379} 2474}
2380 2475
2381sub size_allocate { 2476sub size_allocate {
2382 my ($self, $w, $h, $changed) = @_; 2477 my ($self, $w, $h) = @_;
2383 2478
2384 $self->SUPER::size_allocate ($w, $h, $changed); 2479 $self->SUPER::size_allocate ($w, $h);
2385
2386 return unless $changed;
2387 2480
2388 $self->{layout}->set_font ($self->{font}) if $self->{font}; 2481 $self->{layout}->set_font ($self->{font}) if $self->{font};
2389 $self->{layout}->set_height ($self->{fontsize} * $::FONTSIZE); 2482 $self->{layout}->set_height ($self->{fontsize} * $::FONTSIZE);
2390 $self->{layout}->set_width ($self->{children}[0]{w}); 2483 $self->{layout}->set_width ($self->{children}[0]{w});
2391 2484
2614} 2707}
2615 2708
2616sub set_tooltip_from { 2709sub set_tooltip_from {
2617 my ($self, $widget) = @_; 2710 my ($self, $widget) = @_;
2618 2711
2712 my $tooltip = $widget->{tooltip};
2713
2714 if ($ENV{CFPLUS_DEBUG} & 2) {
2715 $tooltip .= "\n\n" . (ref $widget) . "\n"
2716 . "$widget->{x} $widget->{y} $widget->{w} $widget->{h}\n"
2717 . "req $widget->{req_w} $widget->{req_h}\n"
2718 . "visible $widget->{visible}";
2719 }
2720
2619 $self->add (new CFClient::UI::Label 2721 $self->add (new CFClient::UI::Label
2620 markup => $widget->{tooltip}, 2722 markup => $tooltip,
2621 max_w => ($widget->{tooltip_width} || 0.25) * $::WIDTH, 2723 max_w => ($widget->{tooltip_width} || 0.25) * $::WIDTH,
2622 fontsize => 0.8, 2724 fontsize => 0.8,
2623 fg => [0, 0, 0, 1], 2725 fg => [0, 0, 0, 1],
2624 ellipsise => 0, 2726 ellipsise => 0,
2625 font => ($widget->{tooltip_font} || $::FONT_PROP), 2727 font => ($widget->{tooltip_font} || $::FONT_PROP),
2633 2735
2634 ($w + 4, $h + 4) 2736 ($w + 4, $h + 4)
2635} 2737}
2636 2738
2637sub size_allocate { 2739sub size_allocate {
2638 my ($self, $w, $h, $changed) = @_; 2740 my ($self, $w, $h) = @_;
2639 2741
2640 return unless $changed;
2641
2642 $self->SUPER::size_allocate ($w - 4, $h - 4, $changed); 2742 $self->SUPER::size_allocate ($w - 4, $h - 4);
2743}
2744
2745sub visibility_change {
2746 my ($self, $visible) = @_;
2747
2748 return unless $visible;
2749
2750 $self->{root}->on_post_alloc ("move_$self" => sub {
2751 my $widget = $self->{owner}
2752 or return;
2753
2754 my ($x, $y) = $widget->coord2global ($widget->{w}, 0);
2755
2756 ($x, $y) = $widget->coord2global (-$self->{w}, 0)
2757 if $x + $self->{w} > $::WIDTH;
2758
2759 $self->move_abs ($x, $y);
2760 });
2643} 2761}
2644 2762
2645sub _draw { 2763sub _draw {
2646 my ($self) = @_; 2764 my ($self) = @_;
2647 2765
2664 glVertex $w, $h; 2782 glVertex $w, $h;
2665 glVertex $w, 0; 2783 glVertex $w, 0;
2666 glEnd; 2784 glEnd;
2667 2785
2668 glTranslate 2 - 0.375, 2 - 0.375; 2786 glTranslate 2 - 0.375, 2 - 0.375;
2787
2669 $self->SUPER::_draw; 2788 $self->SUPER::_draw;
2670} 2789}
2671 2790
2672############################################################################# 2791#############################################################################
2673 2792
2749 $self->SUPER::DESTROY; 2868 $self->SUPER::DESTROY;
2750} 2869}
2751 2870
2752############################################################################# 2871#############################################################################
2753 2872
2754package CFClient::UI::Inventory; 2873package CFClient::UI::Buttonbar;
2755 2874
2756our @ISA = CFClient::UI::ScrolledWindow::; 2875our @ISA = CFClient::UI::HBox::;
2757 2876
2758sub new { 2877# TODO: should actualyl wrap buttons and other goodies.
2759 my $class = shift;
2760
2761 my $self = $class->SUPER::new (
2762 scrolled => (new CFClient::UI::Table col_expand => [0, 1, 0]),
2763 @_,
2764 );
2765
2766 $self
2767}
2768
2769sub set_items {
2770 my ($self, $items) = @_;
2771
2772 $self->{scrolled}->clear;
2773 return unless $items;
2774
2775 my @items = sort {
2776 ($a->{type} <=> $b->{type})
2777 or ($a->{name} cmp $b->{name})
2778 } @$items;
2779
2780 $self->{real_items} = \@items;
2781
2782 my $row = 0;
2783 for my $item (@items) {
2784 CFClient::Item::update_widgets $item;
2785
2786 $self->{scrolled}->add (0, $row, $item->{face_widget});
2787 $self->{scrolled}->add (1, $row, $item->{desc_widget});
2788 $self->{scrolled}->add (2, $row, $item->{weight_widget});
2789
2790 $row++;
2791 }
2792}
2793 2878
2794############################################################################# 2879#############################################################################
2795 2880
2796package CFClient::UI::Menu; 2881package CFClient::UI::Menu;
2797 2882
2838 # maybe save $GRAB? must be careful about events... 2923 # maybe save $GRAB? must be careful about events...
2839 $GRAB = $self; 2924 $GRAB = $self;
2840 $self->{button} = $ev->{button}; 2925 $self->{button} = $ev->{button};
2841 2926
2842 $self->show; 2927 $self->show;
2843 $self->move ($ev->{x} - $self->{w} * 0.5, $ev->{y} - $self->{h} * 0.5); 2928 $self->move_abs ($ev->{x} - $self->{w} * 0.5, $ev->{y} - $self->{h} * 0.5);
2844} 2929}
2845 2930
2846sub mouse_motion { 2931sub mouse_motion {
2847 my ($self, $ev, $x, $y) = @_; 2932 my ($self, $ev, $x, $y) = @_;
2848 2933
2849 # TODO: should use vbox->find_widget or so 2934 # TODO: should use vbox->find_widget or so
2850 $HOVER = $ROOT->find_widget ($ev->{x}, $ev->{y}); 2935 $HOVER = $ROOT->find_widget ($ev->{x}, $ev->{y});
2851 $self->{hover} = $self->{item}{$HOVER}; 2936 $self->{hover} = $self->{item}{$HOVER};
2937
2938 0
2852} 2939}
2853 2940
2854sub button_up { 2941sub button_up {
2855 my ($self, $ev, $x, $y) = @_; 2942 my ($self, $ev, $x, $y) = @_;
2856 2943
2858 undef $GRAB; 2945 undef $GRAB;
2859 $self->hide; 2946 $self->hide;
2860 2947
2861 $self->_emit ("popdown"); 2948 $self->_emit ("popdown");
2862 $self->{hover}[1]->() if $self->{hover}; 2949 $self->{hover}[1]->() if $self->{hover};
2950 } else {
2951 return 0
2952 }
2953
2954 1
2955}
2956
2957#############################################################################
2958
2959package CFClient::UI::Multiplexer;
2960
2961our @ISA = CFClient::UI::Container::;
2962
2963sub new {
2964 my $class = shift;
2965
2966 my $self = $class->SUPER::new (
2967 @_,
2968 );
2969
2970 $self->{current} = $self->{children}[0]
2971 if @{ $self->{children} };
2972
2973 $self
2974}
2975
2976sub add {
2977 my ($self, @widgets) = @_;
2978
2979 $self->SUPER::add (@widgets);
2980
2981 $self->{current} = $self->{children}[0]
2982 if @{ $self->{children} };
2983}
2984
2985sub set_current_page {
2986 my ($self, $page_or_widget) = @_;
2987
2988 my $widget = ref $page_or_widget
2989 ? $page_or_widget
2990 : $self->{children}[$page_or_widget];
2991
2992 $self->{current} = $widget;
2993 $self->{current}->configure (0, 0, $self->{w}, $self->{h});
2994
2995 $self->_emit (page_changed => $self->{current});
2996
2997 $self->realloc;
2998}
2999
3000sub visible_children {
3001 $_[0]{current}
3002}
3003
3004sub size_request {
3005 my ($self) = @_;
3006
3007 $self->{current}->size_request
3008}
3009
3010sub size_allocate {
3011 my ($self, $w, $h) = @_;
3012
3013 $self->{current}->configure (0, 0, $w, $h);
3014}
3015
3016sub _draw {
3017 my ($self) = @_;
3018
3019 $self->{current}->draw;
3020}
3021
3022#############################################################################
3023
3024package CFClient::UI::Notebook;
3025
3026our @ISA = CFClient::UI::VBox::;
3027
3028sub new {
3029 my $class = shift;
3030
3031 my $self = $class->SUPER::new (
3032 buttonbar => (new CFClient::UI::Buttonbar),
3033 multiplexer => (new CFClient::UI::Multiplexer expand => 1),
3034 # filter => # will be put between multiplexer and $self
3035 @_,
3036 );
2863 } 3037
3038 $self->{filter}->add ($self->{multiplexer}) if $self->{filter};
3039 $self->SUPER::add ($self->{buttonbar}, $self->{filter} || $self->{multiplexer});
3040
3041 $self
3042}
3043
3044sub add {
3045 my ($self, $title, $widget, $tooltip) = @_;
3046
3047 Scalar::Util::weaken $self;
3048
3049 $self->{buttonbar}->add (new CFClient::UI::Button
3050 markup => $title,
3051 tooltip => $tooltip,
3052 on_activate => sub { $self->set_current_page ($widget) },
3053 );
3054
3055 $self->{multiplexer}->add ($widget);
3056}
3057
3058sub set_current_page {
3059 my ($self, $page) = @_;
3060
3061 $self->{multiplexer}->set_current_page ($page);
3062 $self->_emit (page_changed => $self->{multiplexer}{current});
2864} 3063}
2865 3064
2866############################################################################# 3065#############################################################################
2867 3066
2868package CFClient::UI::Statusbox; 3067package CFClient::UI::Statusbox;
2973 $self->SUPER::reconfigure; 3172 $self->SUPER::reconfigure;
2974} 3173}
2975 3174
2976############################################################################# 3175#############################################################################
2977 3176
3177package CFClient::UI::Inventory;
3178
3179our @ISA = CFClient::UI::ScrolledWindow::;
3180
3181sub new {
3182 my $class = shift;
3183
3184 my $self = $class->SUPER::new (
3185 child => (new CFClient::UI::Table col_expand => [0, 1, 0]),
3186 @_,
3187 );
3188
3189 $self
3190}
3191
3192sub set_items {
3193 my ($self, $items) = @_;
3194
3195 $self->{child}->clear;
3196 return unless $items;
3197
3198 my @items = sort {
3199 ($a->{type} <=> $b->{type})
3200 or ($a->{name} cmp $b->{name})
3201 } @$items;
3202
3203 $self->{real_items} = \@items;
3204
3205 my $row = 0;
3206 for my $item (@items) {
3207 CFClient::Item::update_widgets $item;
3208
3209 $self->{child}->add (0, $row, $item->{face_widget});
3210 $self->{child}->add (1, $row, $item->{desc_widget});
3211 $self->{child}->add (2, $row, $item->{weight_widget});
3212
3213 $row++;
3214 }
3215}
3216
3217#############################################################################
3218
3219package CFClient::UI::BindEditor;
3220
3221our @ISA = CFClient::UI::FancyFrame::;
3222
3223sub new {
3224 my $class = shift;
3225
3226 my $self = $class->SUPER::new (binding => [], commands => [], @_);
3227
3228 $self->add (my $vb = new CFClient::UI::VBox);
3229
3230
3231 $vb->add ($self->{rec_btn} = new CFClient::UI::Button
3232 text => "start recording",
3233 tooltip => "Start/Stops recording of actions."
3234 ."All subsequent actions after the recording started will be captured."
3235 ."The actions are displayed after the record was stopped."
3236 ."To bind the action you have to click on the 'Bind' button",
3237 on_activate => sub {
3238 unless ($self->{recording}) {
3239 $self->start;
3240 } else {
3241 $self->stop;
3242 }
3243 });
3244
3245 $vb->add (new CFClient::UI::Label text => "Actions:");
3246 $vb->add ($self->{cmdbox} = new CFClient::UI::VBox);
3247
3248 $vb->add (new CFClient::UI::Label text => "Bound to: ");
3249 $vb->add (my $hb = new CFClient::UI::HBox);
3250 $hb->add ($self->{keylbl} = new CFClient::UI::Label expand => 1);
3251 $hb->add (new CFClient::UI::Button
3252 text => "bind",
3253 tooltip => "This opens a query where you have to press the key combination to bind the recorded actions",
3254 on_activate => sub {
3255 $self->ask_for_bind;
3256 });
3257
3258 $vb->add (my $hb = new CFClient::UI::HBox);
3259 $hb->add (new CFClient::UI::Button
3260 text => "ok",
3261 expand => 1,
3262 tooltip => "This closes the binding editor and saves the binding",
3263 on_activate => sub {
3264 $self->hide;
3265 $self->commit;
3266 });
3267
3268 $hb->add (new CFClient::UI::Button
3269 text => "cancel",
3270 expand => 1,
3271 tooltip => "This closes the binding editor without saving",
3272 on_activate => sub {
3273 $self->hide;
3274 $self->{binding_cancel}->()
3275 if $self->{binding_cancel};
3276 });
3277
3278 $self->update_binding_widgets;
3279
3280 $self
3281}
3282
3283sub commit {
3284 my ($self) = @_;
3285 my ($mod, $sym, $cmds) = $self->get_binding;
3286 if ($sym != 0 && @$cmds > 0) {
3287 $::STATUSBOX->add ("Bound actions to '".CFClient::Binder::keycombo_to_name ($mod, $sym)
3288 ."'. Don't forget 'Save Config'!");
3289 $self->{binding_change}->($mod, $sym, $cmds)
3290 if $self->{binding_change};
3291 } else {
3292 $::STATUSBOX->add ("No action bound, no key or action specified!");
3293 $self->{binding_cancel}->()
3294 if $self->{binding_cancel};
3295 }
3296}
3297
3298sub start {
3299 my ($self) = @_;
3300
3301 $self->{rec_btn}->set_text ("stop recording");
3302 $self->{recording} = 1;
3303 $self->clear_command_list;
3304 $::CONN->start_record if $::CONN;
3305}
3306
3307sub stop {
3308 my ($self) = @_;
3309
3310 $self->{rec_btn}->set_text ("start recording");
3311 $self->{recording} = 0;
3312
3313 my $rec;
3314 $rec = $::CONN->stop_record if $::CONN;
3315 return unless ref $rec eq 'ARRAY';
3316 $self->set_command_list ($rec);
3317}
3318
3319
3320sub ask_for_bind_and_commit {
3321 my ($self) = @_;
3322 $self->ask_for_bind (1);
3323}
3324
3325sub ask_for_bind {
3326 my ($self, $commit) = @_;
3327
3328 CFClient::Binder::open_binding_dialog (sub {
3329 my ($mod, $sym) = @_;
3330 $self->{binding} = [$mod, $sym]; # XXX: how to stop that memleak?
3331 $self->update_binding_widgets;
3332 $self->commit if $commit;
3333 });
3334}
3335
3336# $mod and $sym are the modifiers and key symbol
3337# $cmds is a array ref of strings (the commands)
3338# $cb is the callback that is executed on OK
3339# $ccb is the callback that is executed on CANCEL and
3340# when the binding was unsuccessful on OK
3341sub set_binding {
3342 my ($self, $mod, $sym, $cmds, $cb, $ccb) = @_;
3343
3344 $self->clear_command_list;
3345 $self->{recording} = 0;
3346 $self->{rec_btn}->set_text ("start recording");
3347
3348 $self->{binding} = [$mod, $sym];
3349 $self->{commands} = $cmds;
3350
3351 $self->{binding_change} = $cb;
3352 $self->{binding_cancel} = $ccb;
3353
3354 $self->update_binding_widgets;
3355}
3356
3357# this is a shortcut method that asks for a binding
3358# and then just binds it.
3359sub do_quick_binding {
3360 my ($self, $cmds) = @_;
3361 $self->set_binding (undef, undef, $cmds, sub {
3362 $::CFG->{bindings}->{$_[0]}->{$_[1]} = $_[2];
3363 });
3364 $self->ask_for_bind (1);
3365}
3366
3367sub update_binding_widgets {
3368 my ($self) = @_;
3369 my ($mod, $sym, $cmds) = $self->get_binding;
3370 $self->{keylbl}->set_text (CFClient::Binder::keycombo_to_name ($mod, $sym));
3371 $self->set_command_list ($cmds);
3372}
3373
3374sub get_binding {
3375 my ($self) = @_;
3376 return (
3377 $self->{binding}->[0],
3378 $self->{binding}->[1],
3379 [ grep { defined $_ } @{$self->{commands}} ]
3380 );
3381}
3382
3383sub clear_command_list {
3384 my ($self) = @_;
3385 $self->{cmdbox}->clear ();
3386}
3387
3388sub set_command_list {
3389 my ($self, $cmds) = @_;
3390
3391 $self->{cmdbox}->clear ();
3392 $self->{commands} = $cmds;
3393
3394 my $idx = 0;
3395
3396 for (@$cmds) {
3397 $self->{cmdbox}->add (my $hb = new CFClient::UI::HBox);
3398
3399 my $i = $idx;
3400 $hb->add (new CFClient::UI::Label text => $_);
3401 $hb->add (new CFClient::UI::Button
3402 text => "delete",
3403 tooltip => "Deletes the action from the record",
3404 on_activate => sub {
3405 $self->{cmdbox}->remove ($hb);
3406 $cmds->[$i] = undef;
3407 });
3408
3409
3410 $idx++
3411 }
3412}
3413
3414#############################################################################
3415
3416package CFClient::UI::SpellList;
3417
3418our @ISA = CFClient::UI::Table::;
3419
3420sub new {
3421 my $class = shift;
3422
3423 my $self = $class->SUPER::new (
3424 binding => [],
3425 commands => [],
3426 @_,
3427 )
3428}
3429
3430# XXX: Do sorting? Argl...
3431sub add_spell {
3432 my ($self, $spell) = @_;
3433 $self->{spells}->{$spell->{name}} = $spell;
3434
3435 $self->add (0, $self->{tbl_idx}, new CFClient::UI::Face
3436 face => $spell->{face},
3437 can_hover => 1,
3438 can_events => 1,
3439 tooltip => $spell->{message});
3440
3441 $self->add (1, $self->{tbl_idx}, new CFClient::UI::Label
3442 text => $spell->{name},
3443 can_hover => 1,
3444 can_events => 1,
3445 tooltip => $spell->{message},
3446 expand => 1);
3447
3448 $self->add (2, $self->{tbl_idx}, new CFClient::UI::Label
3449 text => (sprintf "lvl: %2d sp: %2d dmg: %2d",
3450 $spell->{level}, ($spell->{mana} || $spell->{grace}), $spell->{damage}),
3451 expand => 1);
3452
3453 $self->add (3, $self->{tbl_idx}++, new CFClient::UI::Button
3454 text => "bind to key",
3455 on_activate => sub { $::BIND_EDITOR->do_quick_binding (["cast $spell->{name}"]) });
3456}
3457
3458sub rebuild_spell_list {
3459 my ($self) = @_;
3460 $self->{tbl_idx} = 0;
3461 $self->add_spell ($_) for values %{$self->{spells}};
3462}
3463
3464sub remove_spell {
3465 my ($self, $spell) = @_;
3466 delete $self->{spells}->{$spell->{name}};
3467 $self->rebuild_spell_list;
3468}
3469
3470#############################################################################
3471
2978package CFClient::UI::Root; 3472package CFClient::UI::Root;
2979 3473
2980our @ISA = CFClient::UI::Container::; 3474our @ISA = CFClient::UI::Container::;
2981 3475
2982use CFClient::OpenGL; 3476use CFClient::OpenGL;
2992 Scalar::Util::weaken ($self->{root} = $self); 3486 Scalar::Util::weaken ($self->{root} = $self);
2993 3487
2994 $self 3488 $self
2995} 3489}
2996 3490
2997sub configure {
2998 my ($self, $x, $y, $w, $h) = @_;
2999
3000 $self->{w} = $w;
3001 $self->{h} = $h;
3002}
3003
3004sub reconfigure {
3005 my ($self) = @_;
3006
3007 $self->SUPER::reconfigure;
3008
3009 $self->size_allocate ($self->{w}, $self->{h}, 1)
3010 if $self->{w};
3011}
3012
3013sub size_request { 3491sub size_request {
3014 my ($self) = @_; 3492 my ($self) = @_;
3015 3493
3016 ($self->{w}, $self->{h}) 3494 ($self->{w}, $self->{h})
3017} 3495}
3018 3496
3497sub _to_pixel {
3498 my ($coord, $size, $max) = @_;
3499
3500 $coord =
3501 $coord eq "center" ? ($max - $size) * 0.5
3502 : $coord eq "max" ? $max
3503 : $coord;
3504
3505 $coord = 0 if $coord < 0;
3506 $coord = $max - $size if $coord > $max - $size;
3507
3508 int $coord + 0.5
3509}
3510
3019sub size_allocate { 3511sub size_allocate {
3020 my ($self, $w, $h, $changed) = @_; 3512 my ($self, $w, $h) = @_;
3021 3513
3022 for my $child ($self->children) { 3514 for my $child ($self->children) {
3023 my ($X, $Y, $W, $H) = @$child{qw(x y req_w req_h)}; 3515 my ($X, $Y, $W, $H) = @$child{qw(x y req_w req_h)};
3024 3516
3025 $X = $child->{req_x} > 0 ? $child->{req_x} : $w - $W - $child->{req_x} + 1 3517 $X = $child->{force_x} if exists $child->{force_x};
3026 if exists $child->{req_x}; 3518 $Y = $child->{force_y} if exists $child->{force_y};
3027 3519
3028 $Y = $child->{req_y} > 0 ? $child->{req_y} : $h - $H - $child->{req_y} + 1 3520 $X = _to_pixel $X, $W, $self->{w};
3029 if exists $child->{req_y}; 3521 $Y = _to_pixel $Y, $H, $self->{h};
3030
3031 #delete @$child{qw(req_x req_y)};#d# def_x, def_y
3032
3033 $X = List::Util::max 0, List::Util::min $w - $W, int $X + 0.5;
3034 $Y = List::Util::max 0, List::Util::min $h - $H, int $Y + 0.5;
3035 3522
3036 $child->configure ($X, $Y, $W, $H); 3523 $child->configure ($X, $Y, $W, $H);
3037 } 3524 }
3038} 3525}
3039 3526
3056} 3543}
3057 3544
3058sub add { 3545sub add {
3059 my ($self, @children) = @_; 3546 my ($self, @children) = @_;
3060 3547
3061 for my $child (@children) {
3062 $child->{is_toplevel} = 1; 3548 $_->{is_toplevel} = 1
3063 3549 for @children;
3064 # integerise window positions
3065 $child->{x} = int $child->{x};
3066 $child->{y} = int $child->{y};
3067 }
3068 3550
3069 $self->SUPER::add (@children); 3551 $self->SUPER::add (@children);
3070} 3552}
3071 3553
3072sub remove { 3554sub remove {
3073 my ($self, @children) = @_; 3555 my ($self, @children) = @_;
3074 3556
3075 $self->SUPER::remove (@children); 3557 $self->SUPER::remove (@children);
3558
3559 delete $self->{is_toplevel}
3560 for @children;
3076 3561
3077 while (@children) { 3562 while (@children) {
3078 my $w = pop @children; 3563 my $w = pop @children;
3079 push @children, $w->children; 3564 push @children, $w->children;
3080 $w->set_invisible; 3565 $w->set_invisible;
3100 $_->() 3585 $_->()
3101 for values %{delete $self->{refresh_hook}}; 3586 for values %{delete $self->{refresh_hook}};
3102 } 3587 }
3103 3588
3104 if ($self->{realloc}) { 3589 if ($self->{realloc}) {
3590 my %queue;
3105 my @queue; 3591 my @queue;
3592 my $widget;
3106 3593
3594 outer:
3107 while () { 3595 while () {
3108 if ($self->{realloc}) { 3596 if (my $realloc = delete $self->{realloc}) {
3109 #TODO use array-of-depth approach 3597 for $widget (values %$realloc) {
3598 $widget->{visible} or next; # do not resize invisible widgets
3110 3599
3111 @queue = sort { $a->{visible} <=> $b->{visible} } 3600 $queue{$widget+0}++ and next; # duplicates are common
3112 @queue, values %{delete $self->{realloc}}; 3601
3602 push @{ $queue[$widget->{visible}] }, $widget;
3603 }
3113 } 3604 }
3114 3605
3606 while () {
3607 @queue or last outer;
3608
3609 $widget = pop @{ $queue[-1] || [] }
3610 and last;
3611
3612 pop @queue;
3613 }
3614
3615 delete $queue{$widget+0};
3616
3617 my ($w, $h) = $widget->size_request;
3618
3619 $w = List::Util::max $widget->{min_w}, $w + $widget->{padding_x} * 2;
3620 $h = List::Util::max $widget->{min_h}, $h + $widget->{padding_y} * 2;
3621
3622 $w = $widget->{force_w} if exists $widget->{force_w};
3623 $h = $widget->{force_h} if exists $widget->{force_h};
3624
3625 if ($widget->{req_w} != $w || $widget->{req_h} != $h
3626 || delete $widget->{force_realloc}) {
3627 $widget->{req_w} = $w;
3628 $widget->{req_h} = $h;
3629
3630 $self->{size_alloc}{$widget+0} = $widget;
3631
3632 if (my $parent = $widget->{parent}) {
3633 $self->{realloc}{$parent+0} = $parent
3634 unless $queue{$parent+0};
3635
3636 $parent->{force_size_alloc} = 1;
3637 $self->{size_alloc}{$parent+0} = $parent;
3638 }
3639 }
3640
3641 delete $self->{realloc}{$widget+0};
3642 }
3643 }
3644
3645 while (my $size_alloc = delete $self->{size_alloc}) {
3646 my @queue = sort { $b->{visible} <=> $a->{visible} }
3647 values %$size_alloc;
3648
3649 while () {
3115 my $widget = pop @queue || last; 3650 my $widget = pop @queue || last;
3116 3651
3117 $widget->{visible} or last; # do not resize invisible widgets 3652 my ($w, $h) = @$widget{qw(alloc_w alloc_h)};
3118
3119 my ($w, $h) = $widget->{def_w} && $widget->{def_h}
3120 ? @$widget{qw(def_w def_h)}
3121 : $widget->size_request;
3122
3123 Carp::confess "$widget: size_request is negative" if $w < 0 || $h < 0;#d#
3124
3125 $widget->{req_w} = $w;
3126 $widget->{req_h} = $h;
3127
3128 $self->{size_alloc}{$widget} = [$widget, $widget->{w}, $widget->{h}];
3129
3130 push @queue, $widget->{parent}
3131 if $widget->{parent};
3132 }
3133 }
3134
3135 while (my $size_alloc = delete $self->{size_alloc}) {
3136 my @queue = sort $b->[0]{visible} <=> $a->[0]{visible},
3137 values %$size_alloc;
3138
3139 while () {
3140 my ($widget, $w, $h) = @{ pop @queue or last };
3141 3653
3142 $w = 0 if $w < 0; 3654 $w = 0 if $w < 0;
3143 $h = 0 if $h < 0; 3655 $h = 0 if $h < 0;
3144 3656
3657 $w = int $w + 0.5;
3658 $h = int $h + 0.5;
3659
3660 if ($widget->{w} != $w || $widget->{h} != $h || delete $widget->{force_size_alloc}) {
3661 $widget->{old_w} = $widget->{w};
3662 $widget->{old_h} = $widget->{h};
3663
3145 $widget->{w} = $w; 3664 $widget->{w} = $w;
3146 $widget->{h} = $h; 3665 $widget->{h} = $h;
3666
3147 $widget->emit (size_allocate => $w, $h, 1); 3667 $widget->emit (size_allocate => $w, $h);
3668 }
3148 } 3669 }
3149 } 3670 }
3150 3671
3151 while ($self->{post_alloc_hook}) { 3672 while ($self->{post_alloc_hook}) {
3152 $_->() 3673 $_->()
3153 for values %{delete $self->{post_alloc_hook}}; 3674 for values %{delete $self->{post_alloc_hook}};
3154 } 3675 }
3676
3155 3677
3156 glViewport 0, 0, $::WIDTH, $::HEIGHT; 3678 glViewport 0, 0, $::WIDTH, $::HEIGHT;
3157 glClearColor +($::CFG->{fow_intensity}) x 3, 1; 3679 glClearColor +($::CFG->{fow_intensity}) x 3, 1;
3158 glClear GL_COLOR_BUFFER_BIT; 3680 glClear GL_COLOR_BUFFER_BIT;
3159 3681
3161 glLoadIdentity; 3683 glLoadIdentity;
3162 glOrtho 0, $::WIDTH, $::HEIGHT, 0, -10000, 10000; 3684 glOrtho 0, $::WIDTH, $::HEIGHT, 0, -10000, 10000;
3163 glMatrixMode GL_MODELVIEW; 3685 glMatrixMode GL_MODELVIEW;
3164 glLoadIdentity; 3686 glLoadIdentity;
3165 3687
3688 {
3689 package CFClient::UI::Base;
3690
3691 ($draw_x, $draw_y, $draw_w, $draw_h) =
3692 (0, 0, $self->{w}, $self->{h});
3693 }
3694
3166 $self->_draw; 3695 $self->_draw;
3167} 3696}
3168 3697
3169############################################################################# 3698#############################################################################
3170 3699

Diff Legend

Removed lines
+ Added lines
< Changed lines
> Changed lines