--- deliantra/Deliantra-Client/DC/UI.pm 2006/04/30 13:10:46 1.183 +++ deliantra/Deliantra-Client/DC/UI.pm 2006/05/10 21:12:26 1.193 @@ -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; + $CFClient::UI::ROOT->{size_alloc}{$self} = [$self, $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 { @@ -398,32 +383,15 @@ my ($self, $parent) = @_; Scalar::Util::weaken ($self->{parent} = $parent); + + $self->check_size + unless exists $self->{req_w}; } 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 +498,19 @@ } 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; + $self->check_size; $self->update; } @@ -741,6 +710,34 @@ $self->update; } +# hmm, this does not work for topleft of $self... but we should not ask for that +sub coord2local { + my ($self, $x, $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 { + my ($self, $x, $y) = @_; + + if ( $x >= $self->{x} && $x < $self->{x} + $self->{w} + && $y >= $self->{y} && $y < $self->{y} + $self->{h} + ) { + $self->child->find_widget ($x + $self->{view_x}, $y + $self->{view_y}) + } else { + $self->CFClient::UI::Base::find_widget ($x, $y) + } +} + sub _render { my ($self) = @_; @@ -1218,6 +1215,8 @@ sub size_allocate { my ($self, $w, $h) = @_; + Carp::confess "negative size" if $w < 0 || $h < 0;#d# + my $children = $self->{children}; my @h = map $_->{req_h}, @$children; @@ -1305,12 +1304,6 @@ $self->SUPER::update; } -sub reconfigure { - my ($self) = @_; - - delete $self->{texture}; -} - sub set_text { my ($self, $text) = @_; @@ -1319,7 +1312,6 @@ $self->{layout}->set_text ($text); - delete $self->{texture}; $self->update; $self->check_size; } @@ -1332,7 +1324,6 @@ $self->{layout}->set_markup ($markup); - delete $self->{texture}; $self->update; $self->check_size; } @@ -1373,8 +1364,9 @@ $self->{fontsize} = $fontsize; delete $self->{texture}; - $self->check_size; + $self->update; + $self->check_size; } sub _draw { @@ -2466,6 +2458,7 @@ sub _draw { my ($self) = @_; + return unless $::CONN;#d# manage and cache textures differently my $tex = $::CONN->{texture}[$::CONN->{faceid}[$self->{face}]]; # TODO animation @@ -2483,6 +2476,115 @@ ############################################################################# +package CFClient::UI::InventoryItem; + +our @ISA = CFClient::UI::HBox::; + +sub new { + my $class = shift; + + my %args = @_; + + my $item = delete $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 ($item->{widget} ||= 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::; @@ -2561,31 +2663,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 coord2local { + my ($self, $x, $y) = @_; + + ($x, $y) } -sub _topleft { +sub coord2global { my ($self, $x, $y) = @_; ($x, $y) @@ -2595,13 +2738,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}; @@ -2614,129 +2757,69 @@ $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 -} + my $widget = (pop @{ $queue[0] }) || (pop @{ $queue[1] }) || last; -############################################################################# + my ($w, $h) = $widget->{user_w} && $widget->{user_h} + ? @$widget{qw(user_w user_h)} + : $widget->size_request; + + if ($w != $widget->{req_w} || $h != $widget->{req_h}) { + Carp::confess "$widget: size_request is negative" if $w < 0 || $h < 0;#d# + + $widget->{req_w} = $w; + $widget->{req_h} = $h; -package CFClient::UI::Inventory; + $self->{size_alloc}{$widget} = [$widget, $widget->{w}, $widget->{h}]; -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; + $widget->{parent}->check_size + if $widget->{parent}; + } + } + } - my @items = sort { $a->{type} <=> $b->{type} } @$items; + while ($self->{size_alloc}) { + for (values %{delete $self->{size_alloc}}) { + my ($widget, $w, $h) = @$_; - $self->{real_items} = \@items; + $w = 0 if $w < 0; + $h = 0 if $h < 0; - 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; } #############################################################################