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.305 by root, Sun Jun 18 17:13:12 2006 UTC vs.
Revision 1.311 by root, Fri Jun 23 22:35:16 2006 UTC

335sub size_request { 335sub size_request {
336 require Carp; 336 require Carp;
337 Carp::confess "size_request is abstract"; 337 Carp::confess "size_request is abstract";
338} 338}
339 339
340sub baseline_shift {
341 0
342}
343
340sub configure { 344sub configure {
341 my ($self, $x, $y, $w, $h) = @_; 345 my ($self, $x, $y, $w, $h) = @_;
342 346
343 if ($self->{aspect}) { 347 if ($self->{aspect}) {
344 my ($ow, $oh) = ($w, $h); 348 my ($ow, $oh) = ($w, $h);
470} 474}
471 475
472sub emit { 476sub emit {
473 my ($self, $signal, @args) = @_; 477 my ($self, $signal, @args) = @_;
474 478
479 #d##TODO# stop propagating at first true, do not use sum
475 (List::Util::sum +(map $_->($self, @args), @{$self->{signal_cb}{$signal} || []}), # before 480 (List::Util::sum map $_->($self, @args), @{$self->{signal_cb}{$signal} || []}) # before
476 ($self->can ("invoke_$signal") || sub { 1 })->($self, @args)) # closure 481 || ($self->can ("invoke_$signal") || sub { 1 })->($self, @args) # closure
477 || ($self->{parent} && $self->{parent}->emit ($signal, @args)) # parent 482 || ($self->{parent} && $self->{parent}->emit ($signal, @args)) # parent
478} 483}
479 484
480sub find_widget { 485sub find_widget {
481 my ($self, $x, $y) = @_; 486 my ($self, $x, $y) = @_;
482 487
1090 if exists $self->{title}; 1095 if exists $self->{title};
1091 1096
1092 if ($self->{has_close_button}) { 1097 if ($self->{has_close_button}) {
1093 $self->{close_button} = 1098 $self->{close_button} =
1094 new CFClient::UI::ImageButton 1099 new CFClient::UI::ImageButton
1095 image => 'x1_close.png', 1100 path => 'x1_close.png',
1096 on_activate => sub { $self->hide }; 1101 on_activate => sub { $self->hide };
1097 1102
1098 $self->CFClient::UI::Container::add ($self->{close_button}); 1103 $self->CFClient::UI::Container::add ($self->{close_button});
1099 } 1104 }
1100 1105
1437 1442
1438sub invoke_size_allocate { 1443sub invoke_size_allocate {
1439 my ($self, $w, $h) = @_; 1444 my ($self, $w, $h) = @_;
1440 1445
1441 my $space = $self->{vertical} ? $h : $w; 1446 my $space = $self->{vertical} ? $h : $w;
1442 my $children = $self->{children}; 1447 my @children = $self->visible_children;
1443 1448
1444 my @req; 1449 my @req;
1445 1450
1446 if ($self->{homogeneous}) { 1451 if ($self->{homogeneous}) {
1447 @req = ($space / (@$children || 1)) x @$children; 1452 @req = ($space / (@children || 1)) x @children;
1448 } else { 1453 } else {
1449 @req = map $_->{$self->{vertical} ? "req_h" : "req_w"}, @$children; 1454 @req = map $_->{$self->{vertical} ? "req_h" : "req_w"}, @children;
1450 my $req = List::Util::sum @req; 1455 my $req = List::Util::sum @req;
1451 1456
1452 if ($req > $space) { 1457 if ($req > $space) {
1453 # ah well, not enough space 1458 # ah well, not enough space
1454 $_ *= $space / $req for @req; 1459 $_ *= $space / $req for @req;
1455 } else { 1460 } else {
1456 my $expand = (List::Util::sum map $_->{expand}, @$children) || 1; 1461 my $expand = (List::Util::sum map $_->{expand}, @children) || 1;
1457 1462
1458 $space = ($space - $req) / $expand; # remaining space to give away 1463 $space = ($space - $req) / $expand; # remaining space to give away
1459 1464
1460 $req[$_] += $space * $children->[$_]{expand} 1465 $req[$_] += $space * $children[$_]{expand}
1461 for 0 .. $#$children; 1466 for 0 .. $#children;
1462 } 1467 }
1463 } 1468 }
1464 1469
1465 CFClient::UI::harmonize \@req; 1470 CFClient::UI::harmonize \@req;
1466 1471
1467 my $pos = 0; 1472 my $pos = 0;
1468 for (0 .. $#$children) { 1473 for (0 .. $#children) {
1469 my $alloc = $req[$_]; 1474 my $alloc = $req[$_];
1470 $children->[$_]->configure ($self->{vertical} ? (0, $pos, $w, $alloc) : ($pos, 0, $alloc, $h)); 1475 $children[$_]->configure ($self->{vertical} ? (0, $pos, $w, $alloc) : ($pos, 0, $alloc, $h));
1471 1476
1472 $pos += $alloc; 1477 $pos += $alloc;
1473 } 1478 }
1474 1479
1475 1 1480 1
1630 }; 1635 };
1631 1636
1632 @{ $self->{size_req} } 1637 @{ $self->{size_req} }
1633} 1638}
1634 1639
1640sub baseline_shift {
1641 $_[0]{layout}->descent
1642}
1643
1635sub invoke_size_allocate { 1644sub invoke_size_allocate {
1636 my ($self, $w, $h) = @_; 1645 my ($self, $w, $h) = @_;
1637 1646
1638 delete $self->{ox}; 1647 delete $self->{ox};
1639 1648
1891 my $sym = $ev->{sym}; 1900 my $sym = $ev->{sym};
1892 1901
1893 if ($sym == 13) { 1902 if ($sym == 13) {
1894 unshift @{$self->{history}}, 1903 unshift @{$self->{history}},
1895 my $txt = $self->get_text; 1904 my $txt = $self->get_text;
1905
1896 $self->{history_pointer} = -1; 1906 $self->{history_pointer} = -1;
1897 $self->{history_saveback} = ''; 1907 $self->{history_saveback} = '';
1898 $self->emit (activate => $txt); 1908 $self->emit (activate => $txt);
1899 $self->update; 1909 $self->update;
1900 1910
2090package CFClient::UI::Image; 2100package CFClient::UI::Image;
2091 2101
2092our @ISA = CFClient::UI::Base::; 2102our @ISA = CFClient::UI::Base::;
2093 2103
2094use CFClient::OpenGL; 2104use CFClient::OpenGL;
2095use Carp qw/confess/;
2096 2105
2097our %loaded_images; 2106our %texture_cache;
2098 2107
2099sub new { 2108sub new {
2100 my $class = shift; 2109 my $class = shift;
2101 2110
2102 my $self = $class->SUPER::new (can_events => 0, @_); 2111 my $self = $class->SUPER::new (
2112 can_events => 0,
2113 @_,
2114 );
2103 2115
2104 $self->{image} or confess "Image has 'image' not set. This is a fatal error!"; 2116 $self->{path}
2117 or Carp::croak "required attribute 'path' not set";
2105 2118
2106 $loaded_images{$self->{image}} ||= 2119 $self->{tex} = $texture_cache{$self->{path}} ||=
2107 new_from_file CFClient::Texture CFClient::find_rcfile $self->{image}, mipmap => 1; 2120 new_from_file CFClient::Texture CFClient::find_rcfile $self->{path}, mipmap => 1;
2108 2121
2109 my $tex = $self->{tex} = $loaded_images{$self->{image}}; 2122 Scalar::Util::weaken $texture_cache{$self->{path}};
2110 2123
2111 Scalar::Util::weaken $loaded_images{$self->{image}}; 2124 $self->{aspect} ||= $self->{tex}{w} / $self->{tex}{h};
2112
2113 $self->{aspect} = $tex->{w} / $tex->{h};
2114 2125
2115 $self 2126 $self
2116} 2127}
2117 2128
2118sub size_request { 2129sub size_request {
2119 my ($self) = @_; 2130 my ($self) = @_;
2120 2131
2121 ($self->{tex}->{w}, $self->{tex}->{h}) 2132 ($self->{tex}{w}, $self->{tex}{h})
2122} 2133}
2123 2134
2124sub _draw { 2135sub _draw {
2125 my ($self) = @_; 2136 my ($self) = @_;
2126 2137
2409 2420
2410 $self->SUPER::invoke_button_down ($ev, $x, $y); 2421 $self->SUPER::invoke_button_down ($ev, $x, $y);
2411 2422
2412 $self->{click} = [$self->{range}[0], $self->{vertical} ? $y : $x]; 2423 $self->{click} = [$self->{range}[0], $self->{vertical} ? $y : $x];
2413 2424
2414 $self->mouse_motion ($ev, $x, $y) 2425 $self->invoke_mouse_motion ($ev, $x, $y)
2415} 2426}
2416 2427
2417sub invoke_mouse_motion { 2428sub invoke_mouse_motion {
2418 my ($self, $ev, $x, $y) = @_; 2429 my ($self, $ev, $x, $y) = @_;
2419 2430
2564 2575
2565 $self->{fontsize} = $fontsize; 2576 $self->{fontsize} = $fontsize;
2566 $self->reflow; 2577 $self->reflow;
2567} 2578}
2568 2579
2580sub visible_children {
2581 my ($self) = @_;
2582
2583 @{$self->{children}}[0,1]
2584}
2585
2569sub invoke_size_allocate { 2586sub invoke_size_allocate {
2570 my ($self, $w, $h) = @_; 2587 my ($self, $w, $h) = @_;
2571 2588
2589 my ($empty, $slider, @other) = @{ $self->{children} };
2590 $_->configure (@$_{qw(x y req_w req_h)}) for @other;
2591
2572 $self->{layout}->set_font ($self->{font}) if $self->{font}; 2592 $self->{layout}->set_font ($self->{font}) if $self->{font};
2573 $self->{layout}->set_height ($self->{fontsize} * $::FONTSIZE); 2593 $self->{layout}->set_height ($self->{fontsize} * $::FONTSIZE);
2574 $self->{layout}->set_width ($self->{children}[0]{w}); 2594 $self->{layout}->set_width ($empty->{w});
2575 $self->{layout}->set_indent ($self->{fontsize} * $::FONTSIZE * $self->{indent}); 2595 $self->{layout}->set_indent ($self->{fontsize} * $::FONTSIZE * $self->{indent});
2576 2596
2577 $self->reflow; 2597 $self->reflow;
2578 2598
2579 $self->SUPER::invoke_size_allocate ($w, $h) 2599 $self->SUPER::invoke_size_allocate ($w, $h)
2580} 2600}
2581 2601
2582sub text_size { 2602sub get_layout {
2583 my ($self, $text, $indent) = @_; 2603 my ($self, $para) = @_;
2584 2604
2585 my $layout = $self->{layout}; 2605 my $layout = $self->{layout};
2586 2606
2607 $layout->set_font ($self->{font}) if $self->{font};
2608 $layout->set_foreground (@{$para->{fg}});
2587 $layout->set_height ($self->{fontsize} * $::FONTSIZE); 2609 $layout->set_height ($self->{fontsize} * $::FONTSIZE);
2588 $layout->set_width ($self->{children}[0]{w} - $indent); 2610 $layout->set_width ($self->{children}[0]{w} - $para->{indent});
2589 $layout->set_indent ($self->{fontsize} * $::FONTSIZE * $self->{indent}); 2611 $layout->set_indent ($self->{fontsize} * $::FONTSIZE * $self->{indent});
2590 $layout->set_markup ($text); 2612 $layout->set_markup ($para->{markup});
2613
2614 $layout->set_shapes (
2615 map
2616 +(0, $_->baseline_shift +$_->{padding_y} - $_->{h}, $_->{w}, $_->{h}),
2617 @{$para->{widget}}
2591 2618 );
2619
2592 $layout->size 2620 $layout
2593} 2621}
2594 2622
2595sub reflow { 2623sub reflow {
2596 my ($self) = @_; 2624 my ($self) = @_;
2597 2625
2606 $self->{children}[1]->set_value ($offset); 2634 $self->{children}[1]->set_value ($offset);
2607} 2635}
2608 2636
2609sub clear { 2637sub clear {
2610 my ($self) = @_; 2638 my ($self) = @_;
2639
2640 my (undef, undef, @other) = @{ $self->{children} };
2641 $self->remove ($_) for @other;
2611 2642
2612 $self->{par} = []; 2643 $self->{par} = [];
2613 $self->{height} = 0; 2644 $self->{height} = 0;
2614 $self->{children}[1]->set_range ([0, 0, 0, 1, 1]); 2645 $self->{children}[1]->set_range ([0, 0, 0, 1, 1]);
2615} 2646}
2616 2647
2617sub add_paragraph { 2648sub add_paragraph {
2618 my ($self, $color, $text, $indent) = @_; 2649 my ($self, $color, $para, $indent) = @_;
2619 2650
2620 for my $line (split /\n/, $text) { 2651 my ($text, @w) = ref $para ? @$para : $para;
2621 my ($w, $h) = $self->text_size ($line); 2652
2622 $self->{height} += $h; 2653 $para = {
2623 push @{$self->{par}}, [$w + $indent, $h, $color, $indent, $line]; 2654 w => 1e10,
2655 wrapped => 1,
2656 fg => $color,
2657 indent => $indent,
2658 markup => $text,
2659 widget => \@w,
2624 } 2660 };
2625 2661
2626 $self->{children}[1]->set_range ([$self->{height}, 0, $self->{height}, $self->{h}, 1]); 2662 $self->add (@w) if @w;
2663 push @{$self->{par}}, $para;
2664
2665 $self->{need_reflow}++;
2666 $self->update;
2667}
2668
2669sub scroll_to_bottom {
2670 my ($self) = @_;
2671
2672 $self->{scroll_to_bottom} = 1;
2673 $self->update;
2627} 2674}
2628 2675
2629sub update { 2676sub update {
2630 my ($self) = @_; 2677 my ($self) = @_;
2631 2678
2639 my ($W, $H) = @{$self->{children}[0]}{qw(w h)}; 2686 my ($W, $H) = @{$self->{children}[0]}{qw(w h)};
2640 2687
2641 if (delete $self->{need_reflow}) { 2688 if (delete $self->{need_reflow}) {
2642 my $height = 0; 2689 my $height = 0;
2643 2690
2644 my $layout = $self->{layout};
2645
2646 $layout->set_height ($self->{fontsize} * $::FONTSIZE);
2647
2648 for (@{$self->{par}}) { 2691 for my $para (@{$self->{par}}) {
2649 if (1 || $_->[0] >= $W) { # TODO: works,but needs reconfigure etc. support 2692 if ($para->{w} != $W && ($para->{wrapped} || $para->{w} > $W)) {
2650 $layout->set_width ($W - $_->[3]); 2693 my $layout = $self->get_layout ($para);
2651 $layout->set_indent ($self->{fontsize} * $::FONTSIZE * $self->{indent});
2652 $layout->set_markup ($_->[4]);
2653 my ($w, $h) = $layout->size; 2694 my ($w, $h) = $layout->size;
2654 $_->[0] = $w + $_->[3]; 2695
2655 $_->[1] = $h; 2696 $para->{w} = $w + $para->{indent};
2697 $para->{h} = $h;
2698 $para->{wrapped} = $layout->has_wrapped;
2656 } 2699 }
2657 2700
2658 $height += $_->[1]; 2701 $height += $para->{h};
2659 } 2702 }
2660 2703
2661 $self->{height} = $height; 2704 $self->{height} = $height;
2662 2705
2663 $self->{children}[1]->set_range ([$height, 0, $height, $H, 1]); 2706 $self->{children}[1]->set_range ([$self->{children}[1]{range}[0], 0, $height, $H, 1]);
2664 2707
2665 delete $self->{texture}; 2708 delete $self->{texture};
2709 }
2710
2711 if (delete $self->{scroll_to_bottom}) {
2712 $self->{children}[1]->set_value (1e10);
2666 } 2713 }
2667 2714
2668 $self->{texture} ||= new_from_opengl CFClient::Texture $W, $H, sub { 2715 $self->{texture} ||= new_from_opengl CFClient::Texture $W, $H, sub {
2669 glClearColor 0, 0, 0, 0; 2716 glClearColor 0, 0, 0, 0;
2670 glClear GL_COLOR_BUFFER_BIT; 2717 glClear GL_COLOR_BUFFER_BIT;
2674 my $y0 = $top; 2721 my $y0 = $top;
2675 my $y1 = $top + $H; 2722 my $y1 = $top + $H;
2676 2723
2677 my $y = 0; 2724 my $y = 0;
2678 2725
2679 my $layout = $self->{layout};
2680
2681 $layout->set_font ($self->{font}) if $self->{font};
2682
2683 glEnable GL_BLEND; 2726 glEnable GL_BLEND;
2684 #TODO# not correct in windows where rgba is forced off 2727 #TODO# not correct in windows where rgba is forced off
2685 glBlendFunc GL_ONE, GL_ONE_MINUS_SRC_ALPHA; 2728 glBlendFunc GL_ONE, GL_ONE_MINUS_SRC_ALPHA;
2686 2729
2687 for my $par (@{$self->{par}}) { 2730 for my $para (@{$self->{par}}) {
2688 my $h = $par->[1]; 2731 my $h = $para->{h};
2689 2732
2690 if ($y0 < $y + $h && $y < $y1) { 2733 if ($y0 < $y + $h && $y < $y1) {
2691 $layout->set_foreground (@{ $par->[2] }); 2734
2692 $layout->set_width ($W - $par->[3]); 2735 my $layout = $self->get_layout ($para);
2693 $layout->set_indent ($self->{fontsize} * $::FONTSIZE * $self->{indent});
2694 $layout->set_markup ($par->[4]);
2695 2736
2696 my ($w, $h, $data, $format, $internalformat) = $layout->render; 2737 my ($w, $h, $data, $format, $internalformat) = $layout->render;
2697 2738
2698 glRasterPos $par->[3], $y - $y0; 2739 glRasterPos $para->{indent}, $y - $y0;
2699 glDrawPixels $w, $h, $format, GL_UNSIGNED_BYTE, $data; 2740 glDrawPixels $w, $h, $format, GL_UNSIGNED_BYTE, $data;
2741
2742 if (my @w = @{ $para->{widget} }) {
2743 my @s = $layout->get_shapes;
2744
2745 for (@w) {
2746 my ($dx, $dy) = splice @s, 0, 2, ();
2747
2748 $_->{x} = $dx + $para->{indent};
2749 $_->{y} = $dy + $y - $y0;
2750
2751 $_->draw;
2752 }
2753 }
2700 } 2754 }
2701 2755
2702 $y += $h; 2756 $y += $h;
2703 } 2757 }
2704 2758
2705 glDisable GL_BLEND; 2759 glDisable GL_BLEND;
2706 }; 2760 };
2707 }); 2761 });
2762}
2763
2764sub reconfigure {
2765 my ($self) = @_;
2766
2767 $self->SUPER::reconfigure;
2768
2769 $_->{w} = 1e10 for @{ $self->{par} };
2770 $self->reflow;
2708} 2771}
2709 2772
2710sub _draw { 2773sub _draw {
2711 my ($self) = @_; 2774 my ($self) = @_;
2712 2775
2715 glColor 0, 0, 0, 1; 2778 glColor 0, 0, 0, 1;
2716 $self->{texture}->draw_quad_alpha_premultiplied (0, 0, $self->{children}[0]{w}, $self->{children}[0]{h}); 2779 $self->{texture}->draw_quad_alpha_premultiplied (0, 0, $self->{children}[0]{w}, $self->{children}[0]{h});
2717 glDisable GL_TEXTURE_2D; 2780 glDisable GL_TEXTURE_2D;
2718 2781
2719 $self->{children}[1]->draw; 2782 $self->{children}[1]->draw;
2720
2721} 2783}
2722 2784
2723############################################################################# 2785#############################################################################
2724 2786
2725package CFClient::UI::Animator; 2787package CFClient::UI::Animator;
3470 $self->update_binding_widgets; 3532 $self->update_binding_widgets;
3471 3533
3472 $self 3534 $self
3473} 3535}
3474 3536
3537sub cfg_bind {
3538 my ($self, $mod, $sym, $cmds) = @_;
3539 $::CFG->{profile}{default}{bindings}{$mod}{$sym} = $cmds;
3540 ::update_bindings ();
3541}
3542
3543sub cfg_unbind {
3544 my ($self, $mod, $sym, $cmds) = @_;
3545 delete $::CFG->{profile}{default}{bindings}{$mod}{$sym};
3546 ::update_bindings ();
3547}
3548
3475sub commit { 3549sub commit {
3476 my ($self) = @_; 3550 my ($self) = @_;
3477 my ($mod, $sym, $cmds) = $self->get_binding; 3551 my ($mod, $sym, $cmds) = $self->get_binding;
3478 if ($sym != 0 && @$cmds > 0) { 3552 if ($sym != 0 && @$cmds > 0) {
3479 $::STATUSBOX->add ("Bound actions to '".CFClient::Binder::keycombo_to_name ($mod, $sym) 3553 $::STATUSBOX->add ("Bound actions to '".CFClient::Binder::keycombo_to_name ($mod, $sym)
3549 3623
3550# this is a shortcut method that asks for a binding 3624# this is a shortcut method that asks for a binding
3551# and then just binds it. 3625# and then just binds it.
3552sub do_quick_binding { 3626sub do_quick_binding {
3553 my ($self, $cmds, $end_cb) = @_; 3627 my ($self, $cmds, $end_cb) = @_;
3554 $self->set_binding (undef, undef, $cmds, sub { 3628 $self->set_binding (undef, undef, $cmds, sub { $self->cfg_bind (@_) });
3555 $::CFG->{bindings}->{$_[0]}->{$_[1]} = $_[2];
3556 });
3557 $self->ask_for_bind (1, $end_cb); 3629 $self->ask_for_bind (1, $end_cb);
3558} 3630}
3559 3631
3560sub update_binding_widgets { 3632sub update_binding_widgets {
3561 my ($self) = @_; 3633 my ($self) = @_;

Diff Legend

Removed lines
+ Added lines
< Changed lines
> Changed lines