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.308 by root, Mon Jun 19 05:18:14 2006 UTC vs.
Revision 1.312 by root, Fri Jun 23 23:54:30 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);
535 return unless $self->{h} && $self->{w}; 539 return unless $self->{h} && $self->{w};
536 540
537 # update screen rectangle 541 # update screen rectangle
538 local $draw_x = $draw_x + $self->{x}; 542 local $draw_x = $draw_x + $self->{x};
539 local $draw_y = $draw_y + $self->{y}; 543 local $draw_y = $draw_y + $self->{y};
540 local $draw_w = $draw_x + $self->{w};
541 local $draw_h = $draw_y + $self->{h};
542 544
543 # skip widgets that are entirely outside the drawing area 545 # skip widgets that are entirely outside the drawing area
544 return if ($draw_x + $self->{w} < 0) || ($draw_x >= $draw_w) 546 return if ($draw_x + $self->{w} < 0) || ($draw_x >= $draw_w)
545 || ($draw_y + $self->{h} < 0) || ($draw_y >= $draw_h); 547 || ($draw_y + $self->{h} < 0) || ($draw_y >= $draw_h);
546 548
1091 if exists $self->{title}; 1093 if exists $self->{title};
1092 1094
1093 if ($self->{has_close_button}) { 1095 if ($self->{has_close_button}) {
1094 $self->{close_button} = 1096 $self->{close_button} =
1095 new CFClient::UI::ImageButton 1097 new CFClient::UI::ImageButton
1096 image => 'x1_close.png', 1098 path => 'x1_close.png',
1097 on_activate => sub { $self->hide }; 1099 on_activate => sub { $self->hide };
1098 1100
1099 $self->CFClient::UI::Container::add ($self->{close_button}); 1101 $self->CFClient::UI::Container::add ($self->{close_button});
1100 } 1102 }
1101 1103
1438 1440
1439sub invoke_size_allocate { 1441sub invoke_size_allocate {
1440 my ($self, $w, $h) = @_; 1442 my ($self, $w, $h) = @_;
1441 1443
1442 my $space = $self->{vertical} ? $h : $w; 1444 my $space = $self->{vertical} ? $h : $w;
1443 my $children = $self->{children}; 1445 my @children = $self->visible_children;
1444 1446
1445 my @req; 1447 my @req;
1446 1448
1447 if ($self->{homogeneous}) { 1449 if ($self->{homogeneous}) {
1448 @req = ($space / (@$children || 1)) x @$children; 1450 @req = ($space / (@children || 1)) x @children;
1449 } else { 1451 } else {
1450 @req = map $_->{$self->{vertical} ? "req_h" : "req_w"}, @$children; 1452 @req = map $_->{$self->{vertical} ? "req_h" : "req_w"}, @children;
1451 my $req = List::Util::sum @req; 1453 my $req = List::Util::sum @req;
1452 1454
1453 if ($req > $space) { 1455 if ($req > $space) {
1454 # ah well, not enough space 1456 # ah well, not enough space
1455 $_ *= $space / $req for @req; 1457 $_ *= $space / $req for @req;
1456 } else { 1458 } else {
1457 my $expand = (List::Util::sum map $_->{expand}, @$children) || 1; 1459 my $expand = (List::Util::sum map $_->{expand}, @children) || 1;
1458 1460
1459 $space = ($space - $req) / $expand; # remaining space to give away 1461 $space = ($space - $req) / $expand; # remaining space to give away
1460 1462
1461 $req[$_] += $space * $children->[$_]{expand} 1463 $req[$_] += $space * $children[$_]{expand}
1462 for 0 .. $#$children; 1464 for 0 .. $#children;
1463 } 1465 }
1464 } 1466 }
1465 1467
1466 CFClient::UI::harmonize \@req; 1468 CFClient::UI::harmonize \@req;
1467 1469
1468 my $pos = 0; 1470 my $pos = 0;
1469 for (0 .. $#$children) { 1471 for (0 .. $#children) {
1470 my $alloc = $req[$_]; 1472 my $alloc = $req[$_];
1471 $children->[$_]->configure ($self->{vertical} ? (0, $pos, $w, $alloc) : ($pos, 0, $alloc, $h)); 1473 $children[$_]->configure ($self->{vertical} ? (0, $pos, $w, $alloc) : ($pos, 0, $alloc, $h));
1472 1474
1473 $pos += $alloc; 1475 $pos += $alloc;
1474 } 1476 }
1475 1477
1476 1 1478 1
1631 }; 1633 };
1632 1634
1633 @{ $self->{size_req} } 1635 @{ $self->{size_req} }
1634} 1636}
1635 1637
1638sub baseline_shift {
1639 $_[0]{layout}->descent
1640}
1641
1636sub invoke_size_allocate { 1642sub invoke_size_allocate {
1637 my ($self, $w, $h) = @_; 1643 my ($self, $w, $h) = @_;
1638 1644
1639 delete $self->{ox}; 1645 delete $self->{ox};
1640 1646
2092package CFClient::UI::Image; 2098package CFClient::UI::Image;
2093 2099
2094our @ISA = CFClient::UI::Base::; 2100our @ISA = CFClient::UI::Base::;
2095 2101
2096use CFClient::OpenGL; 2102use CFClient::OpenGL;
2097use Carp qw/confess/;
2098 2103
2099our %loaded_images; 2104our %texture_cache;
2100 2105
2101sub new { 2106sub new {
2102 my $class = shift; 2107 my $class = shift;
2103 2108
2104 my $self = $class->SUPER::new (can_events => 0, @_); 2109 my $self = $class->SUPER::new (
2110 can_events => 0,
2111 @_,
2112 );
2105 2113
2106 $self->{image} or confess "Image has 'image' not set. This is a fatal error!"; 2114 $self->{path}
2115 or Carp::croak "required attribute 'path' not set";
2107 2116
2108 $loaded_images{$self->{image}} ||= 2117 $self->{tex} = $texture_cache{$self->{path}} ||=
2109 new_from_file CFClient::Texture CFClient::find_rcfile $self->{image}, mipmap => 1; 2118 new_from_file CFClient::Texture CFClient::find_rcfile $self->{path}, mipmap => 1;
2110 2119
2111 my $tex = $self->{tex} = $loaded_images{$self->{image}}; 2120 Scalar::Util::weaken $texture_cache{$self->{path}};
2112 2121
2113 Scalar::Util::weaken $loaded_images{$self->{image}}; 2122 $self->{aspect} ||= $self->{tex}{w} / $self->{tex}{h};
2114
2115 $self->{aspect} = $tex->{w} / $tex->{h};
2116 2123
2117 $self 2124 $self
2118} 2125}
2119 2126
2120sub size_request { 2127sub size_request {
2121 my ($self) = @_; 2128 my ($self) = @_;
2122 2129
2123 ($self->{tex}->{w}, $self->{tex}->{h}) 2130 ($self->{tex}{w}, $self->{tex}{h})
2124} 2131}
2125 2132
2126sub _draw { 2133sub _draw {
2127 my ($self) = @_; 2134 my ($self) = @_;
2128 2135
2566 2573
2567 $self->{fontsize} = $fontsize; 2574 $self->{fontsize} = $fontsize;
2568 $self->reflow; 2575 $self->reflow;
2569} 2576}
2570 2577
2578sub size_request {
2579 my ($self) = @_;
2580
2581 my ($empty, $slider) = @{ $self->{children} };
2582
2583 local $self->{children} = [$empty, $slider];
2584 $self->SUPER::size_request
2585}
2586
2571sub invoke_size_allocate { 2587sub invoke_size_allocate {
2572 my ($self, $w, $h) = @_; 2588 my ($self, $w, $h) = @_;
2573 2589
2590 my ($empty, $slider, @other) = @{ $self->{children} };
2591 $_->configure (@$_{qw(x y req_w req_h)}) for @other;
2592
2574 $self->{layout}->set_font ($self->{font}) if $self->{font}; 2593 $self->{layout}->set_font ($self->{font}) if $self->{font};
2575 $self->{layout}->set_height ($self->{fontsize} * $::FONTSIZE); 2594 $self->{layout}->set_height ($self->{fontsize} * $::FONTSIZE);
2576 $self->{layout}->set_width ($self->{children}[0]{w}); 2595 $self->{layout}->set_width ($empty->{w});
2577 $self->{layout}->set_indent ($self->{fontsize} * $::FONTSIZE * $self->{indent}); 2596 $self->{layout}->set_indent ($self->{fontsize} * $::FONTSIZE * $self->{indent});
2578 2597
2579 $self->reflow; 2598 $self->reflow;
2580 2599
2600 local $self->{children} = [$empty, $slider];
2581 $self->SUPER::invoke_size_allocate ($w, $h) 2601 $self->SUPER::invoke_size_allocate ($w, $h)
2582} 2602}
2583 2603
2584sub text_size { 2604sub get_layout {
2585 my ($self, $text, $indent) = @_; 2605 my ($self, $para) = @_;
2586 2606
2587 my $layout = $self->{layout}; 2607 my $layout = $self->{layout};
2588 2608
2609 $layout->set_font ($self->{font}) if $self->{font};
2610 $layout->set_foreground (@{$para->{fg}});
2589 $layout->set_height ($self->{fontsize} * $::FONTSIZE); 2611 $layout->set_height ($self->{fontsize} * $::FONTSIZE);
2590 $layout->set_width ($self->{children}[0]{w} - $indent); 2612 $layout->set_width ($self->{children}[0]{w} - $para->{indent});
2591 $layout->set_indent ($self->{fontsize} * $::FONTSIZE * $self->{indent}); 2613 $layout->set_indent ($self->{fontsize} * $::FONTSIZE * $self->{indent});
2592 $layout->set_markup ($text); 2614 $layout->set_markup ($para->{markup});
2615
2616 $layout->set_shapes (
2617 map
2618 +(0, $_->baseline_shift +$_->{padding_y} - $_->{h}, $_->{w}, $_->{h}),
2619 @{$para->{widget}}
2593 2620 );
2621
2594 $layout->size 2622 $layout
2595} 2623}
2596 2624
2597sub reflow { 2625sub reflow {
2598 my ($self) = @_; 2626 my ($self) = @_;
2599 2627
2608 $self->{children}[1]->set_value ($offset); 2636 $self->{children}[1]->set_value ($offset);
2609} 2637}
2610 2638
2611sub clear { 2639sub clear {
2612 my ($self) = @_; 2640 my ($self) = @_;
2641
2642 my (undef, undef, @other) = @{ $self->{children} };
2643 $self->remove ($_) for @other;
2613 2644
2614 $self->{par} = []; 2645 $self->{par} = [];
2615 $self->{height} = 0; 2646 $self->{height} = 0;
2616 $self->{children}[1]->set_range ([0, 0, 0, 1, 1]); 2647 $self->{children}[1]->set_range ([0, 0, 0, 1, 1]);
2617} 2648}
2618 2649
2619sub add_paragraph { 2650sub add_paragraph {
2620 my ($self, $color, $text, $indent) = @_; 2651 my ($self, $color, $para, $indent) = @_;
2621 2652
2622 for my $line (split /\n/, $text) { 2653 my ($text, @w) = ref $para ? @$para : $para;
2623 my ($w, $h) = $self->text_size ($line); 2654
2624 $self->{height} += $h; 2655 $para = {
2625 push @{$self->{par}}, [$w + $indent, $h, $color, $indent, $line]; 2656 w => 1e10,
2657 wrapped => 1,
2658 fg => $color,
2659 indent => $indent,
2660 markup => $text,
2661 widget => \@w,
2626 } 2662 };
2627 2663
2628 $self->{children}[1]->set_range ([$self->{height}, 0, $self->{height}, $self->{h}, 1]); 2664 $self->add (@w) if @w;
2665 push @{$self->{par}}, $para;
2666
2667 $self->{need_reflow}++;
2668 $self->update;
2669}
2670
2671sub scroll_to_bottom {
2672 my ($self) = @_;
2673
2674 $self->{scroll_to_bottom} = 1;
2675 $self->update;
2629} 2676}
2630 2677
2631sub update { 2678sub update {
2632 my ($self) = @_; 2679 my ($self) = @_;
2633 2680
2641 my ($W, $H) = @{$self->{children}[0]}{qw(w h)}; 2688 my ($W, $H) = @{$self->{children}[0]}{qw(w h)};
2642 2689
2643 if (delete $self->{need_reflow}) { 2690 if (delete $self->{need_reflow}) {
2644 my $height = 0; 2691 my $height = 0;
2645 2692
2646 my $layout = $self->{layout};
2647
2648 $layout->set_height ($self->{fontsize} * $::FONTSIZE);
2649
2650 for (@{$self->{par}}) { 2693 for my $para (@{$self->{par}}) {
2651 if (1 || $_->[0] >= $W) { # TODO: works,but needs reconfigure etc. support 2694 if ($para->{w} != $W && ($para->{wrapped} || $para->{w} > $W)) {
2652 $layout->set_width ($W - $_->[3]); 2695 my $layout = $self->get_layout ($para);
2653 $layout->set_indent ($self->{fontsize} * $::FONTSIZE * $self->{indent});
2654 $layout->set_markup ($_->[4]);
2655 my ($w, $h) = $layout->size; 2696 my ($w, $h) = $layout->size;
2656 $_->[0] = $w + $_->[3]; 2697
2657 $_->[1] = $h; 2698 $para->{w} = $w + $para->{indent};
2699 $para->{h} = $h;
2700 $para->{wrapped} = $layout->has_wrapped;
2658 } 2701 }
2659 2702
2660 $height += $_->[1]; 2703 $height += $para->{h};
2661 } 2704 }
2662 2705
2663 $self->{height} = $height; 2706 $self->{height} = $height;
2664 2707
2665 $self->{children}[1]->set_range ([$height, 0, $height, $H, 1]); 2708 $self->{children}[1]->set_range ([$self->{children}[1]{range}[0], 0, $height, $H, 1]);
2666 2709
2667 delete $self->{texture}; 2710 delete $self->{texture};
2711 }
2712
2713 if (delete $self->{scroll_to_bottom}) {
2714 $self->{children}[1]->set_value (1e10);
2668 } 2715 }
2669 2716
2670 $self->{texture} ||= new_from_opengl CFClient::Texture $W, $H, sub { 2717 $self->{texture} ||= new_from_opengl CFClient::Texture $W, $H, sub {
2671 glClearColor 0, 0, 0, 0; 2718 glClearColor 0, 0, 0, 0;
2672 glClear GL_COLOR_BUFFER_BIT; 2719 glClear GL_COLOR_BUFFER_BIT;
2676 my $y0 = $top; 2723 my $y0 = $top;
2677 my $y1 = $top + $H; 2724 my $y1 = $top + $H;
2678 2725
2679 my $y = 0; 2726 my $y = 0;
2680 2727
2681 my $layout = $self->{layout};
2682
2683 $layout->set_font ($self->{font}) if $self->{font};
2684
2685 glEnable GL_BLEND; 2728 glEnable GL_BLEND;
2686 #TODO# not correct in windows where rgba is forced off 2729 #TODO# not correct in windows where rgba is forced off
2687 glBlendFunc GL_ONE, GL_ONE_MINUS_SRC_ALPHA; 2730 glBlendFunc GL_ONE, GL_ONE_MINUS_SRC_ALPHA;
2688 2731
2689 for my $par (@{$self->{par}}) { 2732 for my $para (@{$self->{par}}) {
2690 my $h = $par->[1]; 2733 my $h = $para->{h};
2691 2734
2692 if ($y0 < $y + $h && $y < $y1) { 2735 if ($y0 < $y + $h && $y < $y1) {
2693 $layout->set_foreground (@{ $par->[2] }); 2736
2694 $layout->set_width ($W - $par->[3]); 2737 my $layout = $self->get_layout ($para);
2695 $layout->set_indent ($self->{fontsize} * $::FONTSIZE * $self->{indent});
2696 $layout->set_markup ($par->[4]);
2697 2738
2698 my ($w, $h, $data, $format, $internalformat) = $layout->render; 2739 my ($w, $h, $data, $format, $internalformat) = $layout->render;
2699 2740
2700 glRasterPos $par->[3], $y - $y0; 2741 glRasterPos $para->{indent}, $y - $y0;
2701 glDrawPixels $w, $h, $format, GL_UNSIGNED_BYTE, $data; 2742 glDrawPixels $w, $h, $format, GL_UNSIGNED_BYTE, $data;
2743
2744 if (my @w = @{ $para->{widget} }) {
2745 my @s = $layout->get_shapes;
2746
2747 for (@w) {
2748 my ($dx, $dy) = splice @s, 0, 2, ();
2749
2750 $_->{x} = $dx + $para->{indent};
2751 $_->{y} = $dy + $y - $y0;
2752
2753 $_->draw;
2754 }
2755 }
2702 } 2756 }
2703 2757
2704 $y += $h; 2758 $y += $h;
2705 } 2759 }
2706 2760
2707 glDisable GL_BLEND; 2761 glDisable GL_BLEND;
2708 }; 2762 };
2709 }); 2763 });
2764}
2765
2766sub reconfigure {
2767 my ($self) = @_;
2768
2769 $self->SUPER::reconfigure;
2770
2771 $_->{w} = 1e10 for @{ $self->{par} };
2772 $self->reflow;
2710} 2773}
2711 2774
2712sub _draw { 2775sub _draw {
2713 my ($self) = @_; 2776 my ($self) = @_;
2714 2777
2717 glColor 0, 0, 0, 1; 2780 glColor 0, 0, 0, 1;
2718 $self->{texture}->draw_quad_alpha_premultiplied (0, 0, $self->{children}[0]{w}, $self->{children}[0]{h}); 2781 $self->{texture}->draw_quad_alpha_premultiplied (0, 0, $self->{children}[0]{w}, $self->{children}[0]{h});
2719 glDisable GL_TEXTURE_2D; 2782 glDisable GL_TEXTURE_2D;
2720 2783
2721 $self->{children}[1]->draw; 2784 $self->{children}[1]->draw;
2722
2723} 2785}
2724 2786
2725############################################################################# 2787#############################################################################
2726 2788
2727package CFClient::UI::Animator; 2789package CFClient::UI::Animator;
3472 $self->update_binding_widgets; 3534 $self->update_binding_widgets;
3473 3535
3474 $self 3536 $self
3475} 3537}
3476 3538
3539sub cfg_bind {
3540 my ($self, $mod, $sym, $cmds) = @_;
3541 $::CFG->{profile}{default}{bindings}{$mod}{$sym} = $cmds;
3542 ::update_bindings ();
3543}
3544
3545sub cfg_unbind {
3546 my ($self, $mod, $sym, $cmds) = @_;
3547 delete $::CFG->{profile}{default}{bindings}{$mod}{$sym};
3548 ::update_bindings ();
3549}
3550
3477sub commit { 3551sub commit {
3478 my ($self) = @_; 3552 my ($self) = @_;
3479 my ($mod, $sym, $cmds) = $self->get_binding; 3553 my ($mod, $sym, $cmds) = $self->get_binding;
3480 if ($sym != 0 && @$cmds > 0) { 3554 if ($sym != 0 && @$cmds > 0) {
3481 $::STATUSBOX->add ("Bound actions to '".CFClient::Binder::keycombo_to_name ($mod, $sym) 3555 $::STATUSBOX->add ("Bound actions to '".CFClient::Binder::keycombo_to_name ($mod, $sym)
3551 3625
3552# this is a shortcut method that asks for a binding 3626# this is a shortcut method that asks for a binding
3553# and then just binds it. 3627# and then just binds it.
3554sub do_quick_binding { 3628sub do_quick_binding {
3555 my ($self, $cmds, $end_cb) = @_; 3629 my ($self, $cmds, $end_cb) = @_;
3556 $self->set_binding (undef, undef, $cmds, sub { 3630 $self->set_binding (undef, undef, $cmds, sub { $self->cfg_bind (@_) });
3557 $::CFG->{bindings}->{$_[0]}->{$_[1]} = $_[2];
3558 });
3559 $self->ask_for_bind (1, $end_cb); 3631 $self->ask_for_bind (1, $end_cb);
3560} 3632}
3561 3633
3562sub update_binding_widgets { 3634sub update_binding_widgets {
3563 my ($self) = @_; 3635 my ($self) = @_;

Diff Legend

Removed lines
+ Added lines
< Changed lines
> Changed lines