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.307 by root, Sun Jun 18 19:13:20 2006 UTC vs.
Revision 1.310 by root, Fri Jun 23 20:28:20 2006 UTC

470} 470}
471 471
472sub emit { 472sub emit {
473 my ($self, $signal, @args) = @_; 473 my ($self, $signal, @args) = @_;
474 474
475 #d##TODO# stop propagating at first true, do not use sum
475 (List::Util::sum +(map $_->($self, @args), @{$self->{signal_cb}{$signal} || []}), # before 476 (List::Util::sum map $_->($self, @args), @{$self->{signal_cb}{$signal} || []}) # before
476 ($self->can ("invoke_$signal") || sub { 1 })->($self, @args)) # closure 477 || ($self->can ("invoke_$signal") || sub { 1 })->($self, @args) # closure
477 || ($self->{parent} && $self->{parent}->emit ($signal, @args)) # parent 478 || ($self->{parent} && $self->{parent}->emit ($signal, @args)) # parent
478} 479}
479 480
480sub find_widget { 481sub find_widget {
481 my ($self, $x, $y) = @_; 482 my ($self, $x, $y) = @_;
482 483
1090 if exists $self->{title}; 1091 if exists $self->{title};
1091 1092
1092 if ($self->{has_close_button}) { 1093 if ($self->{has_close_button}) {
1093 $self->{close_button} = 1094 $self->{close_button} =
1094 new CFClient::UI::ImageButton 1095 new CFClient::UI::ImageButton
1095 image => 'x1_close.png', 1096 path => 'x1_close.png',
1096 on_activate => sub { $self->hide }; 1097 on_activate => sub { $self->hide };
1097 1098
1098 $self->CFClient::UI::Container::add ($self->{close_button}); 1099 $self->CFClient::UI::Container::add ($self->{close_button});
1099 } 1100 }
1100 1101
1437 1438
1438sub invoke_size_allocate { 1439sub invoke_size_allocate {
1439 my ($self, $w, $h) = @_; 1440 my ($self, $w, $h) = @_;
1440 1441
1441 my $space = $self->{vertical} ? $h : $w; 1442 my $space = $self->{vertical} ? $h : $w;
1442 my $children = $self->{children}; 1443 my @children = $self->visible_children;
1443 1444
1444 my @req; 1445 my @req;
1445 1446
1446 if ($self->{homogeneous}) { 1447 if ($self->{homogeneous}) {
1447 @req = ($space / (@$children || 1)) x @$children; 1448 @req = ($space / (@children || 1)) x @children;
1448 } else { 1449 } else {
1449 @req = map $_->{$self->{vertical} ? "req_h" : "req_w"}, @$children; 1450 @req = map $_->{$self->{vertical} ? "req_h" : "req_w"}, @children;
1450 my $req = List::Util::sum @req; 1451 my $req = List::Util::sum @req;
1451 1452
1452 if ($req > $space) { 1453 if ($req > $space) {
1453 # ah well, not enough space 1454 # ah well, not enough space
1454 $_ *= $space / $req for @req; 1455 $_ *= $space / $req for @req;
1455 } else { 1456 } else {
1456 my $expand = (List::Util::sum map $_->{expand}, @$children) || 1; 1457 my $expand = (List::Util::sum map $_->{expand}, @children) || 1;
1457 1458
1458 $space = ($space - $req) / $expand; # remaining space to give away 1459 $space = ($space - $req) / $expand; # remaining space to give away
1459 1460
1460 $req[$_] += $space * $children->[$_]{expand} 1461 $req[$_] += $space * $children[$_]{expand}
1461 for 0 .. $#$children; 1462 for 0 .. $#children;
1462 } 1463 }
1463 } 1464 }
1464 1465
1465 CFClient::UI::harmonize \@req; 1466 CFClient::UI::harmonize \@req;
1466 1467
1467 my $pos = 0; 1468 my $pos = 0;
1468 for (0 .. $#$children) { 1469 for (0 .. $#children) {
1469 my $alloc = $req[$_]; 1470 my $alloc = $req[$_];
1470 $children->[$_]->configure ($self->{vertical} ? (0, $pos, $w, $alloc) : ($pos, 0, $alloc, $h)); 1471 $children[$_]->configure ($self->{vertical} ? (0, $pos, $w, $alloc) : ($pos, 0, $alloc, $h));
1471 1472
1472 $pos += $alloc; 1473 $pos += $alloc;
1473 } 1474 }
1474 1475
1475 1 1476 1
2091package CFClient::UI::Image; 2092package CFClient::UI::Image;
2092 2093
2093our @ISA = CFClient::UI::Base::; 2094our @ISA = CFClient::UI::Base::;
2094 2095
2095use CFClient::OpenGL; 2096use CFClient::OpenGL;
2096use Carp qw/confess/;
2097 2097
2098our %loaded_images; 2098our %texture_cache;
2099 2099
2100sub new { 2100sub new {
2101 my $class = shift; 2101 my $class = shift;
2102 2102
2103 my $self = $class->SUPER::new (can_events => 0, @_); 2103 my $self = $class->SUPER::new (
2104 can_events => 0,
2105 @_,
2106 );
2104 2107
2105 $self->{image} or confess "Image has 'image' not set. This is a fatal error!"; 2108 $self->{path}
2109 or Carp::croak "required attribute 'path' not set";
2106 2110
2107 $loaded_images{$self->{image}} ||= 2111 $self->{tex} = $texture_cache{$self->{path}} ||=
2108 new_from_file CFClient::Texture CFClient::find_rcfile $self->{image}, mipmap => 1; 2112 new_from_file CFClient::Texture CFClient::find_rcfile $self->{path}, mipmap => 1;
2109 2113
2110 my $tex = $self->{tex} = $loaded_images{$self->{image}}; 2114 Scalar::Util::weaken $texture_cache{$self->{path}};
2111 2115
2112 Scalar::Util::weaken $loaded_images{$self->{image}}; 2116 $self->{aspect} ||= $self->{tex}{w} / $self->{tex}{h};
2113
2114 $self->{aspect} = $tex->{w} / $tex->{h};
2115 2117
2116 $self 2118 $self
2117} 2119}
2118 2120
2119sub size_request { 2121sub size_request {
2120 my ($self) = @_; 2122 my ($self) = @_;
2121 2123
2122 ($self->{tex}->{w}, $self->{tex}->{h}) 2124 ($self->{tex}{w}, $self->{tex}{h})
2123} 2125}
2124 2126
2125sub _draw { 2127sub _draw {
2126 my ($self) = @_; 2128 my ($self) = @_;
2127 2129
2565 2567
2566 $self->{fontsize} = $fontsize; 2568 $self->{fontsize} = $fontsize;
2567 $self->reflow; 2569 $self->reflow;
2568} 2570}
2569 2571
2572sub visible_children {
2573 my ($self) = @_;
2574
2575 @{$self->{children}}[0,1]
2576}
2577
2570sub invoke_size_allocate { 2578sub invoke_size_allocate {
2571 my ($self, $w, $h) = @_; 2579 my ($self, $w, $h) = @_;
2580
2581 my (undef, undef, @other) = @{ $self->{children} };
2582 $_->configure (@$_{qw(x y req_w req_h)}) for @other;
2572 2583
2573 $self->{layout}->set_font ($self->{font}) if $self->{font}; 2584 $self->{layout}->set_font ($self->{font}) if $self->{font};
2574 $self->{layout}->set_height ($self->{fontsize} * $::FONTSIZE); 2585 $self->{layout}->set_height ($self->{fontsize} * $::FONTSIZE);
2575 $self->{layout}->set_width ($self->{children}[0]{w}); 2586 $self->{layout}->set_width ($self->{children}[0]{w});
2576 $self->{layout}->set_indent ($self->{fontsize} * $::FONTSIZE * $self->{indent}); 2587 $self->{layout}->set_indent ($self->{fontsize} * $::FONTSIZE * $self->{indent});
2578 $self->reflow; 2589 $self->reflow;
2579 2590
2580 $self->SUPER::invoke_size_allocate ($w, $h) 2591 $self->SUPER::invoke_size_allocate ($w, $h)
2581} 2592}
2582 2593
2583sub text_size { 2594sub get_layout {
2584 my ($self, $text, $indent) = @_; 2595 my ($self, $para) = @_;
2585 2596
2586 my $layout = $self->{layout}; 2597 my $layout = $self->{layout};
2587 2598
2599 $layout->set_font ($self->{font}) if $self->{font};
2588 $layout->set_height ($self->{fontsize} * $::FONTSIZE); 2600 $layout->set_height ($self->{fontsize} * $::FONTSIZE);
2589 $layout->set_width ($self->{children}[0]{w} - $indent); 2601 $layout->set_width ($self->{children}[0]{w} - $para->{indent});
2590 $layout->set_indent ($self->{fontsize} * $::FONTSIZE * $self->{indent}); 2602 $layout->set_indent ($self->{fontsize} * $::FONTSIZE * $self->{indent});
2591 $layout->set_markup ($text); 2603 $layout->set_markup ($para->{markup});
2592 2604 $layout->set_shapes (map +($_->{req_w}, $_->{req_h}), @{$para->{widget}});
2605
2593 $layout->size 2606 $layout
2594} 2607}
2595 2608
2596sub reflow { 2609sub reflow {
2597 my ($self) = @_; 2610 my ($self) = @_;
2598 2611
2607 $self->{children}[1]->set_value ($offset); 2620 $self->{children}[1]->set_value ($offset);
2608} 2621}
2609 2622
2610sub clear { 2623sub clear {
2611 my ($self) = @_; 2624 my ($self) = @_;
2625
2626 my (undef, undef, @other) = @{ $self->{children} };
2627 $self->remove ($_) for @other;
2612 2628
2613 $self->{par} = []; 2629 $self->{par} = [];
2614 $self->{height} = 0; 2630 $self->{height} = 0;
2615 $self->{children}[1]->set_range ([0, 0, 0, 1, 1]); 2631 $self->{children}[1]->set_range ([0, 0, 0, 1, 1]);
2616} 2632}
2617 2633
2618sub add_paragraph { 2634sub add_paragraph {
2619 my ($self, $color, $text, $indent) = @_; 2635 my ($self, $color, $para, $indent) = @_;
2620 2636
2621 for my $line (split /\n/, $text) { 2637 my ($text, @w) = ref $para ? @$para : $para;
2622 my ($w, $h) = $self->text_size ($line); 2638
2623 $self->{height} += $h; 2639 $para = {
2624 push @{$self->{par}}, [$w + $indent, $h, $color, $indent, $line]; 2640 w => 1e10,
2641 wrapped => 1,
2642 fg => $color,
2643 indent => $indent,
2644 markup => $text,
2645 widget => \@w,
2625 } 2646 };
2626 2647
2627 $self->{children}[1]->set_range ([$self->{height}, 0, $self->{height}, $self->{h}, 1]); 2648 $self->add (@w) if @w;
2649 push @{$self->{par}}, $para;
2650
2651 $self->{need_reflow}++;
2652 $self->update;
2653}
2654
2655sub scroll_to_bottom {
2656 my ($self) = @_;
2657
2658 $self->{scroll_to_bottom} = 1;
2659 $self->update;
2628} 2660}
2629 2661
2630sub update { 2662sub update {
2631 my ($self) = @_; 2663 my ($self) = @_;
2632 2664
2640 my ($W, $H) = @{$self->{children}[0]}{qw(w h)}; 2672 my ($W, $H) = @{$self->{children}[0]}{qw(w h)};
2641 2673
2642 if (delete $self->{need_reflow}) { 2674 if (delete $self->{need_reflow}) {
2643 my $height = 0; 2675 my $height = 0;
2644 2676
2645 my $layout = $self->{layout};
2646
2647 $layout->set_height ($self->{fontsize} * $::FONTSIZE);
2648
2649 for (@{$self->{par}}) { 2677 for my $para (@{$self->{par}}) {
2650 if (1 || $_->[0] >= $W) { # TODO: works,but needs reconfigure etc. support 2678 if ($para->{w} != $W && ($para->{wrapped} || $para->{w} > $W)) {
2651 $layout->set_width ($W - $_->[3]); 2679 my $layout = $self->get_layout ($para);
2652 $layout->set_indent ($self->{fontsize} * $::FONTSIZE * $self->{indent});
2653 $layout->set_markup ($_->[4]);
2654 my ($w, $h) = $layout->size; 2680 my ($w, $h) = $layout->size;
2655 $_->[0] = $w + $_->[3]; 2681
2682 $para->{w} = $w + $para->{indent};
2656 $_->[1] = $h; 2683 $para->{h} = $h;
2684 $para->{wrapped} = $layout->has_wrapped;
2657 } 2685 }
2658 2686
2659 $height += $_->[1]; 2687 $height += $para->{h};
2660 } 2688 }
2661 2689
2662 $self->{height} = $height; 2690 $self->{height} = $height;
2663 2691
2664 $self->{children}[1]->set_range ([$height, 0, $height, $H, 1]); 2692 $self->{children}[1]->set_range ([$self->{children}[1]{range}[0], 0, $height, $H, 1]);
2665 2693
2666 delete $self->{texture}; 2694 delete $self->{texture};
2695 }
2696
2697 if (delete $self->{scroll_to_bottom}) {
2698 $self->{children}[1]->set_value (1e10);
2667 } 2699 }
2668 2700
2669 $self->{texture} ||= new_from_opengl CFClient::Texture $W, $H, sub { 2701 $self->{texture} ||= new_from_opengl CFClient::Texture $W, $H, sub {
2670 glClearColor 0, 0, 0, 0; 2702 glClearColor 0, 0, 0, 0;
2671 glClear GL_COLOR_BUFFER_BIT; 2703 glClear GL_COLOR_BUFFER_BIT;
2675 my $y0 = $top; 2707 my $y0 = $top;
2676 my $y1 = $top + $H; 2708 my $y1 = $top + $H;
2677 2709
2678 my $y = 0; 2710 my $y = 0;
2679 2711
2680 my $layout = $self->{layout};
2681
2682 $layout->set_font ($self->{font}) if $self->{font};
2683
2684 glEnable GL_BLEND; 2712 glEnable GL_BLEND;
2685 #TODO# not correct in windows where rgba is forced off 2713 #TODO# not correct in windows where rgba is forced off
2686 glBlendFunc GL_ONE, GL_ONE_MINUS_SRC_ALPHA; 2714 glBlendFunc GL_ONE, GL_ONE_MINUS_SRC_ALPHA;
2687 2715
2688 for my $par (@{$self->{par}}) { 2716 for my $para (@{$self->{par}}) {
2689 my $h = $par->[1]; 2717 my $h = $para->{h};
2690 2718
2691 if ($y0 < $y + $h && $y < $y1) { 2719 if ($y0 < $y + $h && $y < $y1) {
2692 $layout->set_foreground (@{ $par->[2] }); 2720
2693 $layout->set_width ($W - $par->[3]); 2721 my $layout = $self->get_layout ($para);
2694 $layout->set_indent ($self->{fontsize} * $::FONTSIZE * $self->{indent});
2695 $layout->set_markup ($par->[4]);
2696 2722
2697 my ($w, $h, $data, $format, $internalformat) = $layout->render; 2723 my ($w, $h, $data, $format, $internalformat) = $layout->render;
2698 2724
2699 glRasterPos $par->[3], $y - $y0; 2725 glRasterPos $para->{indent}, $y - $y0;
2700 glDrawPixels $w, $h, $format, GL_UNSIGNED_BYTE, $data; 2726 glDrawPixels $w, $h, $format, GL_UNSIGNED_BYTE, $data;
2727
2728 if (my @w = @{ $para->{widget} }) {
2729 my @s = $layout->get_shapes;
2730
2731 for (@w) {
2732 my ($dx, $dy) = splice @s, 0, 2, ();
2733
2734 $_->{x} = $dx + $para->{indent};
2735 $_->{y} = $dy + $y - $y0;
2736
2737 $_->draw;
2738 }
2739 }
2701 } 2740 }
2702 2741
2703 $y += $h; 2742 $y += $h;
2704 } 2743 }
2705 2744
2706 glDisable GL_BLEND; 2745 glDisable GL_BLEND;
2707 }; 2746 };
2708 }); 2747 });
2748}
2749
2750sub reconfigure {
2751 my ($self) = @_;
2752
2753 $self->SUPER::reconfigure;
2754
2755 $_->{w} = 1e10 for @{ $self->{par} };
2756 $self->reflow;
2709} 2757}
2710 2758
2711sub _draw { 2759sub _draw {
2712 my ($self) = @_; 2760 my ($self) = @_;
2713 2761
2716 glColor 0, 0, 0, 1; 2764 glColor 0, 0, 0, 1;
2717 $self->{texture}->draw_quad_alpha_premultiplied (0, 0, $self->{children}[0]{w}, $self->{children}[0]{h}); 2765 $self->{texture}->draw_quad_alpha_premultiplied (0, 0, $self->{children}[0]{w}, $self->{children}[0]{h});
2718 glDisable GL_TEXTURE_2D; 2766 glDisable GL_TEXTURE_2D;
2719 2767
2720 $self->{children}[1]->draw; 2768 $self->{children}[1]->draw;
2721
2722} 2769}
2723 2770
2724############################################################################# 2771#############################################################################
2725 2772
2726package CFClient::UI::Animator; 2773package CFClient::UI::Animator;
3471 $self->update_binding_widgets; 3518 $self->update_binding_widgets;
3472 3519
3473 $self 3520 $self
3474} 3521}
3475 3522
3523sub cfg_bind {
3524 my ($self, $mod, $sym, $cmds) = @_;
3525 $::CFG->{profile}{default}{bindings}{$mod}{$sym} = $cmds;
3526 ::update_bindings ();
3527}
3528
3529sub cfg_unbind {
3530 my ($self, $mod, $sym, $cmds) = @_;
3531 delete $::CFG->{profile}{default}{bindings}{$mod}{$sym};
3532 ::update_bindings ();
3533}
3534
3476sub commit { 3535sub commit {
3477 my ($self) = @_; 3536 my ($self) = @_;
3478 my ($mod, $sym, $cmds) = $self->get_binding; 3537 my ($mod, $sym, $cmds) = $self->get_binding;
3479 if ($sym != 0 && @$cmds > 0) { 3538 if ($sym != 0 && @$cmds > 0) {
3480 $::STATUSBOX->add ("Bound actions to '".CFClient::Binder::keycombo_to_name ($mod, $sym) 3539 $::STATUSBOX->add ("Bound actions to '".CFClient::Binder::keycombo_to_name ($mod, $sym)
3550 3609
3551# this is a shortcut method that asks for a binding 3610# this is a shortcut method that asks for a binding
3552# and then just binds it. 3611# and then just binds it.
3553sub do_quick_binding { 3612sub do_quick_binding {
3554 my ($self, $cmds, $end_cb) = @_; 3613 my ($self, $cmds, $end_cb) = @_;
3555 $self->set_binding (undef, undef, $cmds, sub { 3614 $self->set_binding (undef, undef, $cmds, sub { $self->cfg_bind (@_) });
3556 $::CFG->{bindings}->{$_[0]}->{$_[1]} = $_[2];
3557 });
3558 $self->ask_for_bind (1, $end_cb); 3615 $self->ask_for_bind (1, $end_cb);
3559} 3616}
3560 3617
3561sub update_binding_widgets { 3618sub update_binding_widgets {
3562 my ($self) = @_; 3619 my ($self) = @_;

Diff Legend

Removed lines
+ Added lines
< Changed lines
> Changed lines