--- deliantra/Deliantra-Client/DC/UI.pm 2006/05/03 19:56:05 1.184 +++ deliantra/Deliantra-Client/DC/UI.pm 2006/05/09 22:27:53 1.191 @@ -234,12 +234,7 @@ } if ($self->{w} != $w || $self->{h} != $h) { - $self->{w} = $w; - $self->{h} = $h; - - $self->size_allocate ($w, $h); - $self->update; - $self->emit (size_allocate => $w, $h); + $CFClient::UI::ROOT->{size_alloc}{$self} = [$self, $w, $h]; } } @@ -257,7 +252,9 @@ $_->reconfigure for $self->children; - $_->check_size; + $self->check_size; + $self->size_allocate ($self->{w}, $self->{h}); + $self->update; } sub set_max_size { @@ -267,30 +264,18 @@ delete $self->{max_h}; $self->{max_h} = $h if $h; } -# return top left coordinates -sub _topleft { - my ($self, $x, $y) = @_; - - $self->{parent} - or Carp::confess "no parent widget in _topleft\n";#d# - - $self->{parent}->_topleft ($x + $self->{x}, $y + $self->{y}); -} - # translate global coordinates to local coordinate system sub coord2local { my ($self, $x, $y) = @_; - my ($X, $Y) = $self->_topleft; - ($x - $X, $y - $Y) + $self->{parent}->coord2local ($x - $self->{x}, $y - $self->{y}) } # translate local coordinates to global coordinate system sub coord2global { my ($self, $x, $y) = @_; - my ($X, $Y) = $self->_topleft; - ($x + $X, $y + $Y) + $self->{parent}->coord2global ($x + $self->{x}, $y + $self->{y}) } sub focus_in { @@ -397,33 +382,14 @@ sub set_parent { my ($self, $parent) = @_; + $self->{_tree_depth} = $parent->{_tree_depth} + 1; Scalar::Util::weaken ($self->{parent} = $parent); } sub check_size { my ($self) = @_; - $self->{parent} - or return 1; - - my ($w, $h) = $self->{user_w} && $self->{user_h} - ? @$self{qw(user_w user_h)} - : $self->size_request; - - if ($w != $self->{req_w} || $h != $self->{req_h}) { - $self->{req_w} = $w; - $self->{req_h} = $h; - - $self->{parent}->check_size - or $self->size_allocate ( - (List::Util::max $self->{w}, $w), - (List::Util::max $self->{h}, $h), - ); - - 1 - } else { - 0 - } + $CFClient::UI::ROOT->{check_size}{$self} = $self; } sub update { @@ -530,18 +496,21 @@ } sub add { - my ($self, $child) = @_; + my ($self, @widgets) = @_; - $child->set_parent ($self); + $_->set_parent ($self) + for @widgets; use sort 'stable'; $self->{children} = [ sort { $a->{z} <=> $b->{z} } - @{$self->{children}}, $child + @{$self->{children}}, @widgets ]; - $child->check_size; + $_->check_size + for @widgets; + $self->update; } @@ -741,11 +710,20 @@ $self->update; } -# hmm, this does not work for topleft of $self... but we should not aks for that -sub _topleft { +# hmm, this does not work for topleft of $self... but we should not ask for that +sub coord2local { my ($self, $x, $y) = @_; - $self->SUPER::_topleft ($x - $self->{view_x}, $y - $self->{view_y}) + $self->SUPER::coord2local ($x + $self->{view_x}, $y + $self->{view_y}) +} + +sub coord2global { + my ($self, $x, $y) = @_; + + $x = List::Util::min $self->{w}, $x - $self->{view_x}; + $y = List::Util::min $self->{h}, $y - $self->{view_y}; + + $self->SUPER::coord2global ($x, $y) } sub find_widget { @@ -1324,12 +1302,6 @@ $self->SUPER::update; } -sub reconfigure { - my ($self) = @_; - - delete $self->{texture}; -} - sub set_text { my ($self, $text) = @_; @@ -1338,7 +1310,6 @@ $self->{layout}->set_text ($text); - delete $self->{texture}; $self->update; $self->check_size; } @@ -1351,7 +1322,6 @@ $self->{layout}->set_markup ($markup); - delete $self->{texture}; $self->update; $self->check_size; } @@ -1392,8 +1362,9 @@ $self->{fontsize} = $fontsize; delete $self->{texture}; - $self->check_size; + $self->update; + $self->check_size; } sub _draw { @@ -2485,6 +2456,7 @@ sub _draw { my ($self) = @_; + return unless $::CONN;#d# manage and cache textures differently my $tex = $::CONN->{texture}[$::CONN->{faceid}[$self->{face}]]; # TODO animation @@ -2502,6 +2474,111 @@ ############################################################################# +package CFClient::UI::InventoryItem; + +our @ISA = CFClient::UI::HBox::; + +sub new { + my $class = shift; + + my %args = @_; + + my $item = $args{item}; + + my $desc = $item->{nrof} < 2 + ? $item->{name} + : "$item->{nrof} $item->{name_pl}"; + + + my $self = $class->SUPER::new ( + can_hover => 1, + can_events => 1, + tooltip => (CFClient::UI::Label->escape ($desc) + . "\nleftclick - pick up\nmiddle click - apply\nrightclick - menu"), + connect_button_down => sub { + my ($self, $ev, $x, $y) = @_; + + # todo: maybe put examine on 1? but should just be a tooltip :( + if ($ev->{button} == 1) { + $::CONN->send ("move $::CONN->{player}{tag} $item->{tag} 0"); + } elsif ($ev->{button} == 2) { + $::CONN->send ("apply $item->{tag}"); + } elsif ($ev->{button} == 3) { + CFClient::UI::Menu->new ( + items => [ + ["examine", sub { $::CONN->send ("examine $item->{tag}") }], + [ + $item->{flags} & Crossfire::Protocol::F_LOCKED ? "lock" : "unlock", + sub { $::CONN->send ("lock $item->{tag}") }, + ], + ["mark", sub { $::CONN->send ("mark $item->{tag}") }], + ["apply", sub { $::CONN->send ("apply $item->{tag}") }], + ["drop", sub { $::CONN->send ("move 0 $item->{tag} 0") }], + ], + )->popup ($ev); + } + + 1 + }, + %args + ); + $self->add(new CFClient::UI::Face + can_events => 0, + face => $item->{face}, + anim => $item->{anim}, + animspeed => $item->{animspeed}); + $self->add(new CFClient::UI::Label + can_events => 0, + text => $desc); + + $self +} + +############################################################################# + +package CFClient::UI::Inventory; + +our @ISA = CFClient::UI::ScrolledWindow::; + +sub new { + my $class = shift; + + my $self = $class->SUPER::new ( + scrolled => (new CFClient::UI::VBox), + @_, + ); + + $self +} + +sub set_items { + my ($self, $items) = @_; + + $self->{scrolled}->clear; + return unless $items; + + my @items = sort { $a->{type} <=> $b->{type} } @$items; + + $self->{real_items} = \@items; + + for my $item (@items) { + my $desc = $item->{nrof} < 2 + ? $item->{name} + : "$item->{nrof} $item->{name_pl}"; + + $self->{scrolled}->add (new CFClient::UI::InventoryItem item => $item); + } + +# $range->{range} = [$self->{pos}, 0, $self->{max_pos}, $page]; +} + +sub size_request { + my ($self) = @_; + ($self->{req_w}, $self->{req_h}); +} + +############################################################################# + package CFClient::UI::Menu; our @ISA = CFClient::UI::FancyFrame::; @@ -2580,31 +2657,72 @@ use CFClient::OpenGL; +sub new { + my $class = shift; + + $class->SUPER::new ( + @_, + ) +} + +sub configure { + my ($self, $x, $y, $w, $h) = @_; + + $self->{w} = $w; + $self->{h} = $h; +} + sub check_size { my ($self) = @_; - $self->configure (0, 0, $::WIDTH, $::HEIGHT); + $self->size_allocate ($self->{w}, $self->{h}) + if $self->{w}; } sub size_request { - ($::WIDTH, $::HEIGHT) + my ($self) = @_; + + ($self->{w}, $self->{h}) } -sub configure { - my ($self, $x, $y, $w, $h) = @_; +sub size_allocate { + my ($self, $w, $h) = @_; - $self->SUPER::configure ($x, $y, $w, $h); + my $old_w = $self->{old_w}; + my $old_h = $self->{old_h}; - for my $child (@{$self->{children}}) { + if ($old_w && $old_h) { + for my $child ($self->children) { + $child->{x} = int 0.5 + $child->{x} * $w / $old_w; + $child->{w} = int 0.5 + $child->{w} * $w / $old_w; + $child->{req_w} = int 0.5 + $child->{req_w} * $w / $old_w if exists $child->{req_w}; + $child->{user_w} = int 0.5 + $child->{user_w} * $w / $old_w if exists $child->{user_w}; + $child->{y} = int 0.5 + $child->{y} * $h / $old_h; + $child->{h} = int 0.5 + $child->{h} * $h / $old_h; + $child->{req_h} = int 0.5 + $child->{req_h} * $h / $old_h if exists $child->{req_h}; + $child->{user_h} = int 0.5 + $child->{user_h} * $h / $old_h if exists $child->{user_h}; + } + } + + for my $child ($self->children) { my ($X, $Y, $W, $H) = @$child{qw(x y req_w req_h)}; $X = List::Util::max 0, List::Util::min $w - $W, $X; $Y = List::Util::max 0, List::Util::min $h - $H, $Y; - $child->configure ($X, $Y, $W,$H); + $child->configure ($X, $Y, $W, $H); } + + $self->{old_w} = $w; + $self->{old_h} = $h; } -sub _topleft { +sub coord2local { + my ($self, $x, $y) = @_; + + ($x, $y) +} + +sub coord2global { my ($self, $x, $y) = @_; ($x, $y) @@ -2614,13 +2732,13 @@ my ($self) = @_; $self->check_size; - ::refresh (); + $::WANT_REFRESH++; } sub add { my ($self, $child) = @_; - # integerize window positions + # integerise window positions $child->{x} = int $child->{x}; $child->{y} = int $child->{y}; @@ -2633,129 +2751,64 @@ $self->{refresh_hook}{$id} = $cb; } -sub draw { +sub draw { my ($self) = @_; - while (my $rcb = delete $self->{refresh_hook}) { - $_->() for values %$rcb; - } - - glViewport 0, 0, $::WIDTH, $::HEIGHT; - glClearColor +($::CFG->{fow_intensity}) x 3, 1; - glClear GL_COLOR_BUFFER_BIT; - - glMatrixMode GL_PROJECTION; - glLoadIdentity; - glOrtho 0, $::WIDTH, $::HEIGHT, 0, -10000 , 10000; - glMatrixMode GL_MODELVIEW; - glLoadIdentity; + if ($self->{check_size}) { + my @queue = ([], []); - $self->_draw; -} - -############################################################################# - -package CFClient::UI::InventoryItem; - -our @ISA = CFClient::UI::HBox::; - -sub new { - my $class = shift; - - my %args = @_; - - my $item = $args{item}; - - my $desc = $item->{nrof} < 2 - ? $item->{name} - : "$item->{nrof} $item->{name_pl}"; - - - my $self = $class->SUPER::new ( - can_hover => 1, - can_events => 1, - tooltip => (CFClient::UI::Label->escape ($desc) - . "\nleftclick - pick up\nmiddle click - apply\nrightclick - menu"), - connect_button_down => sub { - my ($self, $ev, $x, $y) = @_; - - # todo: maybe put examine on 1? but should just be a tooltip :( - if ($ev->{button} == 1) { - $::CONN->send ("move $::CONN->{player}{tag} $item->{tag} 0"); - } elsif ($ev->{button} == 2) { - $::CONN->send ("apply $item->{tag}"); - } elsif ($ev->{button} == 3) { - CFClient::UI::Menu->new ( - items => [ - ["examine", sub { $::CONN->send ("examine $item->{tag}") }], - [ - $item->{flags} & Crossfire::Protocol::F_LOCKED ? "lock" : "unlock", - sub { $::CONN->send ("lock $item->{tag}") }, - ], - ["mark", sub { $::CONN->send ("mark $item->{tag}") }], - ["apply", sub { $::CONN->send ("apply $item->{tag}") }], - ["drop", sub { $::CONN->send ("move 0 $item->{tag} 0") }], - ], - )->popup ($ev); + for (;;) { + if ($self->{check_size}) { + # heuristic: check containers last + push @{ $queue[ ! ! $_->isa ("CFClient::UI::Container") ] }, $_ + for values %{delete $self->{check_size}} } - 1 - }, - %args - ); - $self->add(new CFClient::UI::Face - can_events => 0, - face => $item->{face}, - anim => $item->{anim}, - animspeed => $item->{animspeed}); - $self->add(new CFClient::UI::Label - can_events => 0, - text => $desc); - - $self -} - -############################################################################# - -package CFClient::UI::Inventory; - -our @ISA = CFClient::UI::ScrolledWindow::; - -sub new { - my $class = shift; - - my $self = $class->SUPER::new ( - scrolled => (new CFClient::UI::VBox), - @_, - ); + my $widget = (pop @{ $queue[0] }) || (pop @{ $queue[1] }) || last; - $self -} + my ($w, $h) = $widget->{user_w} && $widget->{user_h} + ? @$widget{qw(user_w user_h)} + : $widget->size_request; -sub set_items { - my ($self, $items) = @_; + if ($w != $widget->{req_w} || $h != $widget->{req_h}) { + $widget->{req_w} = $w; + $widget->{req_h} = $h; - $self->{scrolled}->clear; - return unless $items; + $self->{size_alloc}{$widget} = [$widget, $widget->{w}, $widget->{h}]; - my @items = sort { $a->{type} <=> $b->{type} } @$items; + $widget->{parent}->check_size + if $widget->{parent}; + } + } + } - $self->{real_items} = \@items; + while ($self->{size_alloc}) { + for (values %{delete $self->{size_alloc}}) { + my ($widget, $w, $h) = @$_; - for my $item (@items) { - my $desc = $item->{nrof} < 2 - ? $item->{name} - : "$item->{nrof} $item->{name_pl}"; + $widget->{w} = $w; + $widget->{h} = $h; + $widget->size_allocate ($w, $h); + $widget->emit (size_allocate => $w, $h); + } + } - $self->{scrolled}->add (new CFClient::UI::InventoryItem item => $item); + while ($self->{refresh_hook}) { + $_->() + for values %{delete $self->{refresh_hook}}; } -# $range->{range} = [$self->{pos}, 0, $self->{max_pos}, $page]; -} + glViewport 0, 0, $::WIDTH, $::HEIGHT; + glClearColor +($::CFG->{fow_intensity}) x 3, 1; + glClear GL_COLOR_BUFFER_BIT; -sub size_request { - my ($self) = @_; - ($self->{req_w}, $self->{req_h}); + glMatrixMode GL_PROJECTION; + glLoadIdentity; + glOrtho 0, $::WIDTH, $::HEIGHT, 0, -10000 , 10000; + glMatrixMode GL_MODELVIEW; + glLoadIdentity; + + $self->_draw; } #############################################################################