--- deliantra/Deliantra-Client/DC/UI.pm 2006/05/15 00:15:08 1.205 +++ deliantra/Deliantra-Client/DC/UI.pm 2006/05/24 03:52:54 1.228 @@ -138,11 +138,22 @@ } } +sub full_refresh { + # make a copy, otherwise for complains about freed values. + my @widgets = values %WIDGET; + + $_->update + for @widgets; +} + # call when resolution changes etc. sub rescale_widgets { my ($sx, $sy) = @_; - for my $widget (values %WIDGET) { + # make a copy, otherwise for complains about freed values. + my @widgets = values %WIDGET; + + for my $widget (@widgets) { if ($widget->{toplevel}) { $widget->{x} = int 0.5 + $widget->{x} * $sx if exists $widget->{x}; $widget->{w} = int 0.5 + $widget->{w} * $sx if exists $widget->{w}; @@ -197,12 +208,24 @@ sub show { my ($self) = @_; - return if $self->{parent}; $CFClient::UI::ROOT->add ($self); } +sub show_centered { + my ($self) = @_; + return if $self->{parent}; + + $self->show; + + $CFClient::UI::ROOT->on_post_alloc ( + "centered $self" => sub { + $self->move (($::WIDTH - $self->{w}) * 0.5, ($::HEIGHT - $self->{h}) * 0.5); + }, + ); +} + sub hide { my ($self) = @_; @@ -284,6 +307,17 @@ delete $self->{max_h}; $self->{max_h} = $h if $h; } +sub set_tooltip { + my ($self, $tooltip) = @_; + + $self->{tooltip} = $tooltip; + + if ($CFClient::UI::TOOLTIP->{owner} == $self) { + delete $CFClient::UI::TOOLTIP->{owner}; + CFClient::UI::check_tooltip; + } +} + # translate global coordinates to local coordinate system sub coord2local { my ($self, $x, $y) = @_; @@ -407,6 +441,8 @@ # TODO: req_w _does_change after ->reconfigure $self->check_size unless exists $self->{req_w}; + + $self->show; } sub check_size { @@ -457,8 +493,8 @@ # range [value, low, high, page] $class->SUPER::new ( - bg => [0, 0, 0, 0.2], - active_bg => [1, 1, 1, 0.5], + #bg => [0, 0, 0, 0.2], + #active_bg => [1, 1, 1, 0.5], @_ ) } @@ -466,20 +502,26 @@ sub _draw { my ($self) = @_; - my ($w, $h) = @$self{qw(w h)}; + my $color = $FOCUS == $self && $self->{active_bg} + ? $self->{active_bg} + : $self->{bg}; - glEnable GL_BLEND; - glBlendFunc GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA; - glColor @{ $FOCUS == $self ? $self->{active_bg} : $self->{bg} }; + if ($color && (@$color < 4 || $color->[3])) { + my ($w, $h) = @$self{qw(w h)}; - glBegin GL_QUADS; - glVertex 0 , 0; - glVertex 0 , $h; - glVertex $w, $h; - glVertex $w, 0; - glEnd; + glEnable GL_BLEND; + glBlendFunc GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA; + glColor @$color; - glDisable GL_BLEND; + glBegin GL_QUADS; + glVertex 0 , 0; + glVertex 0 , $h; + glVertex $w, $h; + glVertex $w, 0; + glEnd; + + glDisable GL_BLEND; + } } ############################################################################# @@ -673,13 +715,6 @@ glClear GL_COLOR_BUFFER_BIT; $self->_render; -# glColorMask 1, 1, 1, 0; -# glEnable GL_BLEND; -# glBlendFunc GL_SRC_ALPHA, GL_ZERO; -# glRasterPos 0, 0; -# glCopyPixels 0, 0, $self->{w}, $self->{h}; -# glDisable GL_BLEND; -# glColorMask 1, 1, 1, 1; }; } @@ -693,7 +728,7 @@ glEnable GL_TEXTURE_2D; glTexEnv GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE; - glColor 0, 0, 0, 1; + glColor 1, 1, 1, 1; $tex->draw_quad_alpha_premultiplied (0, 0, $w, $h); @@ -710,7 +745,6 @@ my ($self) = @_; @$self{qw(child_w child_h)} = @{$self->child}{qw(req_w req_h)}; - $self->child->configure (0, 0, @$self{qw(child_w child_h)}); @$self{qw(child_w child_h)} } @@ -718,6 +752,9 @@ sub size_allocate { my ($self, $w, $h) = @_; + my ($cw, $ch) = @$self{qw(child_w child_h)}; +# $w = $self->{w}; + $self->child->configure (0, 0, $cw, $ch); $self->update; } @@ -786,7 +823,7 @@ ; $self = $class->SUPER::new ( - vp => (new CFClient::UI::ViewPort), + vp => (new CFClient::UI::ViewPort expand => 1), slider => $slider, @_, ); @@ -897,7 +934,7 @@ $h -= List::Util::max 0, $self->border * 2; $w -= List::Util::max 0, $self->border * 2; - $self->{title}->configure ($self->border, $self->border - $::FONTSIZE * 2, $w, $::FONTSIZE * 2) + $self->{title}->configure ($self->border, int $self->border - $::FONTSIZE * 2, $w, int $::FONTSIZE * 2) if $self->{title}; $self->child->configure ($self->border, $self->border, $w, $h); @@ -1268,7 +1305,7 @@ package CFClient::UI::Label; -our @ISA = CFClient::UI::Base::; +our @ISA = CFClient::UI::DrawBG::; use CFClient::OpenGL; @@ -1277,9 +1314,13 @@ my $self = $class->SUPER::new ( fg => [1, 1, 1], + #bg => none + #active_bg => none #font => default_font #text => initial text #markup => initial narkup + #max_w => maximum pixel width + ellipsise => 3, # end layout => (new CFClient::Layout), fontsize => 1, align => -1, @@ -1304,14 +1345,14 @@ $self } -sub escape { - local $_ = $_[1]; +sub escape($) { + local $_ = $_[0]; s/&/&/g; s/>/>/g; s/{layout}->set_font ($self->{font}) if $self->{font}; $self->{layout}->set_width ($self->{max_w} || -1); + $self->{layout}->set_ellipsise ($self->{ellipsise}); + $self->{layout}->set_single_paragraph_mode ($self->{ellipsise}); $self->{layout}->set_height ($self->{fontsize} * $::FONTSIZE); my ($w, $h) = $self->{layout}->size; @@ -1393,21 +1436,25 @@ sub _draw { my ($self) = @_; + $self->SUPER::_draw; # draw background, if applicable + my $tex = $self->{texture} ||= do { $self->{layout}->set_foreground (@{$self->{fg}}); $self->{layout}->set_font ($self->{font}) if $self->{font}; $self->{layout}->set_width ($self->{w}); - $self->{layout}->set_height (List::Util::min $self->{h}, $self->{fontsize} * $::FONTSIZE); + $self->{layout}->set_ellipsise ($self->{ellipsise}); + $self->{layout}->set_single_paragraph_mode ($self->{ellipsise}); + $self->{layout}->set_height ($self->{fontsize} * $::FONTSIZE); my $tex = new_from_layout CFClient::Texture $self->{layout}; - $self->{ox} = int $self->{align} < 0 ? $self->{padding} - : $self->{align} > 0 ? $self->{w} - $tex->{w} - $self->{padding} - : ($self->{w} - $tex->{w}) * 0.5; - - $self->{oy} = int $self->{valign} < 0 ? $self->{padding} - : $self->{valign} > 0 ? $self->{h} - $tex->{h} - $self->{padding} - : ($self->{h} - $tex->{h}) * 0.5; + $self->{ox} = int ($self->{align} < 0 ? $self->{padding} + : $self->{align} > 0 ? $self->{w} - $tex->{w} - $self->{padding} + : ($self->{w} - $tex->{w}) * 0.5); + + $self->{oy} = int ($self->{valign} < 0 ? $self->{padding} + : $self->{valign} > 0 ? $self->{h} - $tex->{h} - $self->{padding} + : ($self->{h} - $tex->{h}) * 0.5); $tex }; @@ -1445,6 +1492,7 @@ can_focus => 1, valign => 0, can_events => 1, + #text => ... @_ ) } @@ -1472,8 +1520,8 @@ $self->{cursor} = length $text; $self->_set_text ($text); - $self->check_size; $self->update; + $self->check_size; } sub get_text { @@ -1523,6 +1571,7 @@ $self->_set_text ($text); $self->update; + $self->check_size; } sub focus_in { @@ -1661,7 +1710,6 @@ $class->SUPER::new ( padding => 4, fg => [1, 1, 1], - bg => [1, 1, 1, 0.2], active_fg => [0, 0, 1], can_hover => 1, align => 0, @@ -1719,6 +1767,8 @@ padding => 2, fg => [1, 1, 1], active_fg => [1, 1, 0], + bg => [0, 0, 0, 0.2], + active_bg => [1, 1, 1, 0.5], state => 0, can_hover => 1, @_ @@ -2012,7 +2062,7 @@ sub new { my $class = shift; - # range [value, low, high, page] + # range [value, low, high, page, unit] # TODO: 0-width page # TODO: req_w/h are wrong with vertical @@ -2020,18 +2070,54 @@ my $self = $class->SUPER::new ( fg => [1, 1, 1], active_fg => [0, 0, 0], - range => [0, 0, 100, 10], + bg => [0, 0, 0, 0.2], + active_bg => [1, 1, 1, 0.5], + range => [0, 0, 100, 10, 0], req_w => $::WIDTH / 80, req_h => $::WIDTH / 80, vertical => 0, can_hover => 1, - inner_pad => 5, + inner_pad => 0.02, @_ ); + $self->set_value ($self->{range}[0]); + $self->update; + $self } +sub set_range { + my ($self, $range) = @_; + + $self->{range} = $range; + + $self->update; +} + +sub set_value { + my ($self, $value) = @_; + + my ($old_value, $lo, $hi, $page, $unit) = @{$self->{range}}; + + $hi = $lo + 1 if $hi <= $lo; + + $page = $hi - $lo if $page > $hi - $lo; + + $value = $lo if $value < $lo; + $value = $hi - $page if $value > $hi - $page; + + $value = $lo + $unit * int +($value - $lo + $unit * 0.5) / $unit + if $unit; + + @{$self->{range}} = ($value, $lo, $hi, $page, $unit); + + if ($value != $old_value) { + $self->emit (changed => $value); + $self->update; + } +} + sub size_request { my ($self) = @_; @@ -2045,6 +2131,9 @@ my ($self, $ev, $x, $y) = @_; $self->SUPER::button_down ($ev, $x, $y); + + $self->{click} = [$self->{range}[0], $self->{vertical} ? $y : $x]; + $self->mouse_motion ($ev, $x, $y); } @@ -2052,30 +2141,38 @@ my ($self, $ev, $x, $y) = @_; if ($GRAB == $self) { - my ($value, $lo, $hi, $page) = @{$self->{range}}; - my ($x, $w) = $self->{vertical} ? ($y, $self->{h}) : ($x, $self->{w}); - my $inner_pad_px = $self->_calc_inner_pad_px ($w); - my $inner_w = $w - $inner_pad_px * 2; # * 2 for left & right + my (undef, $lo, $hi, $page) = @{$self->{range}}; - $x -= $inner_pad_px; # substract the padding - $x = $x * ($hi - $lo) / $inner_w + $lo; - $x = $lo if $x < $lo; - $x = $hi - $page if $x > $hi - $page; - $self->{range}[0] = $x; + $x = ($x - $self->{click}[1]) / ($w * $self->{scale}); - $self->emit (changed => $x); - $self->update; + $self->set_value ($self->{click}[0] + $x * ($hi - $page - $lo)); } } -# the inner_* stuff is for generating a padding for the slider handle, -# so that the handle doesn't leave the texture. This calculation isn't 100% -# correct propably, but it does the job for now -sub _calc_inner_pad_px { - my ($self, $w) = @_; - ($w / 100) * $self->{inner_pad} # % to pixels +sub update { + my ($self) = @_; + + $CFClient::UI::ROOT->on_post_alloc ($self => sub { + $self->set_value ($self->{range}[0]); + + my ($value, $lo, $hi, $page) = @{$self->{range}}; + my $range = ($hi - $page - $lo) || 1e-100; + + my $knob_w = List::Util::min 1, $page / ($hi - $lo) || 0.1; + + $self->{offset} = List::Util::max $self->{inner_pad}, $knob_w * 0.5; + $self->{scale} = 1 - 2 * $self->{offset} || 1e-100; + + $value = ($value - $lo) / $range; + $value = $value * $self->{scale} + $self->{offset}; + + $self->{knob_x} = $value - $knob_w * 0.5; + $self->{knob_w} = $knob_w; + }); + + $self->SUPER::update; } sub _draw { @@ -2083,50 +2180,71 @@ $self->SUPER::_draw (); - my ($w, $h) = @$self{qw(w h)}; + glScale $self->{w}, $self->{h}; if ($self->{vertical}) { # draw a vertical slider like a rotated horizontal slider + glTranslate 1, 0, 0; glRotate 90, 0, 0, 1; - glTranslate 0, -$self->{w}, 0; - - ($w, $h) = ($h, $w); } my $fg = $FOCUS == $self ? $self->{active_fg} : $self->{fg}; my $bg = $FOCUS == $self ? $self->{active_bg} : $self->{bg}; - my ($value, $lo, $hi, $page) = @{$self->{range}}; + glEnable GL_TEXTURE_2D; + glTexEnv GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE; + + # draw background + $tex[1]->draw_quad_alpha (0, 0, 1, 1); + + # draw handle + $tex[0]->draw_quad_alpha ($self->{knob_x}, 0, $self->{knob_w}, 1); - $hi = $value + 1 if $lo == $hi; + glDisable GL_TEXTURE_2D; +} - my $inner_pad_px = $self->_calc_inner_pad_px ($w); - my $inner_w = $w - $inner_pad_px * 2; # * 2 for left & right +############################################################################# - $page = int $page * $inner_w / ($hi - $lo); - $value = int +($value - $lo) * $inner_w / ($hi - $lo); +package CFClient::UI::ValSlider; - $w -= $page; - $page &= ~1; - glTranslate $page * 0.5, 0, 0; - $page ||= 2; +our @ISA = CFClient::UI::HBox::; - my $knob_a = $inner_pad_px + ($value - $page * 0.5); - my $knob_b = $inner_pad_px + ($value + $page * 0.5); +sub new { + my ($class, %arg) = @_; - glEnable GL_TEXTURE_2D; - glTexEnv GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE; + my $range = delete $arg{range}; - # draw background - $tex[1]->draw_quad_alpha (0, 0, $w, $h); + my $self = $class->SUPER::new ( + slider => (new CFClient::UI::Slider expand => 1, range => $range), + entry => (new CFClient::UI::Label text => "", template => delete $arg{template}), + to_value => sub { shift }, + from_value => sub { shift }, + %arg, + ); - # draw handle - $tex[0]->draw_quad_alpha ($knob_a, 0, $knob_b - $knob_a, $h); + $self->{slider}->connect (changed => sub { + my ($self, $value) = @_; + $self->{parent}{entry}->set_text ($self->{parent}{to_value}->($value)); + $self->{parent}->emit (changed => $value); + }); - glDisable GL_TEXTURE_2D; +# $self->{entry}->connect (changed => sub { +# my ($self, $value) = @_; +# $self->{parent}{slider}->set_value ($self->{parent}{from_value}->($value)); +# $self->{parent}->emit (changed => $value); +# }); + + $self->add ($self->{slider}, $self->{entry}); + + $self->{slider}->emit (changed => $self->{slider}{range}[0]); + + $self } +sub set_range { shift->{slider}->set_range (@_) } +sub set_value { shift->{slider}->set_value (@_) } + ############################################################################# package CFClient::UI::TextView; @@ -2165,16 +2283,28 @@ $self->reflow; } -sub text_height { - my ($self, $text) = @_; +sub size_allocate { + my ($self, $w, $h) = @_; + + $self->SUPER::size_allocate ($w, $h); + + $self->{layout}->set_font ($self->{font}) if $self->{font}; + $self->{layout}->set_height ($self->{fontsize} * $::FONTSIZE); + $self->{layout}->set_width ($self->{children}[0]{w}); + + $self->reflow; +} + +sub text_size { + my ($self, $text, $indent) = @_; my $layout = $self->{layout}; $layout->set_height ($self->{fontsize} * $::FONTSIZE); - $layout->set_width ($self->{children}[0]{w}); + $layout->set_width ($self->{children}[0]{w} - $indent); $layout->set_markup ($text); - ($layout->size)[1] + $layout->size } sub reflow { @@ -2184,31 +2314,31 @@ $self->update; } -sub size_allocate { - my ($self, $w, $h) = @_; +sub set_offset { + my ($self, $offset) = @_; - $self->SUPER::size_allocate ($w, $h); + # todo: base offset on lines or so, not on pixels + $self->{children}[1]->set_value ($offset); +} - $self->{layout}->set_font ($self->{font}) if $self->{font}; - $self->{layout}->set_height ($self->{fontsize} * $::FONTSIZE); - $self->{layout}->set_width ($self->{children}[0]{w}); +sub clear { + my ($self) = @_; - $self->reflow; + $self->{par} = []; + $self->{height} = 0; + $self->{children}[1]->set_range ([0, 0, 0, 1, 1]); } sub add_paragraph { - my ($self, $color, $text) = @_; - - #TODO: intelligently "reformat" paragraph + my ($self, $color, $text, $indent) = @_; - my $height = $self->text_height ($text); - - $self->{height} += $height; - - push @{$self->{par}}, [$height, $color, $text]; + for my $line (split /\n/, $text) { + my ($w, $h) = $self->text_size ($line); + $self->{height} += $h; + push @{$self->{par}}, [$w + $indent, $h, $color, $indent, $line]; + } - $self->{children}[1]{range} = [$self->{height} - $self->{h}, 0, $self->{height}, $self->{h}]; - $self->{children}[1]->update; + $self->{children}[1]->set_range ([$self->{height}, 0, $self->{height}, $self->{h}, 1]); } sub update { @@ -2221,30 +2351,42 @@ delete $self->{texture}; $ROOT->on_post_alloc ($self, sub { + my ($W, $H) = @{$self->{children}[0]}{qw(w h)}; + if (delete $self->{need_reflow}) { my $height = 0; - $height += $_->[0] = $self->text_height ($_->[2]) - for @{$self->{par}}; + my $layout = $self->{layout}; + + $layout->set_height ($self->{fontsize} * $::FONTSIZE); + + for (@{$self->{par}}) { + if (1 || $_->[0] >= $W) { # TODO: works,but needs reconfigure etc. support + $layout->set_width ($W - $_->[3]); + $layout->set_markup ($_->[4]); + my ($w, $h) = $layout->size; + $_->[0] = $w + $_->[3]; + $_->[1] = $h; + } + + $height += $_->[1]; + } $self->{height} = $height; - $self->{children}[1]{range} = [$height - $self->{h}, 0, $height, $self->{h}]; + $self->{children}[1]->set_range ([$height, 0, $height, $H, 1]); delete $self->{texture}; } - $self->{texture} ||= new_from_opengl CFClient::Texture $self->{children}[0]{w}, $self->{children}[0]{h}, sub { - glClearColor 0, 0, 0, 0; + $self->{texture} ||= new_from_opengl CFClient::Texture $W, $H, sub { + glClearColor 0.5, 0.5, 0.5, 0; glClear GL_COLOR_BUFFER_BIT; - glEnable GL_TEXTURE_2D; - glTexEnv GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE; - my $top = int $self->{children}[1]{range}[0]; my $y0 = $top; - my $y1 = $top + $self->{h}; + my $y1 = $top + $H; my $y = 0; @@ -2252,21 +2394,28 @@ $layout->set_font ($self->{font}) if $self->{font}; + glEnable GL_BLEND; + #TODO# not correct in windows where rgba is forced off + glBlendFunc GL_ONE, GL_ONE_MINUS_SRC_ALPHA; + for my $par (@{$self->{par}}) { - my $h = $par->[0]; + my $h = $par->[1]; if ($y0 < $y + $h && $y < $y1) { - $layout->set_foreground (@{ $par->[1] }); - $layout->set_markup ($par->[2]); + $layout->set_foreground (@{ $par->[2] }); + $layout->set_width ($W - $par->[3]); + $layout->set_markup ($par->[4]); - my ($W, $H) = $layout->size; - CFClient::Texture->new_from_layout ($layout)->draw_quad_alpha_premultiplied (0, $y - $y0); + my ($w, $h, $data, $format, $internalformat) = $layout->render; + + glRasterPos $par->[3], $y - $y0; + glDrawPixels $w, $h, $format, GL_UNSIGNED_BYTE, $data; } $y += $h; } - glDisable GL_TEXTURE_2D; + glDisable GL_BLEND; }; }); } @@ -2277,7 +2426,7 @@ glEnable GL_TEXTURE_2D; glTexEnv GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE; glColor 1, 1, 1, 1; - $self->{texture}->draw_quad_alpha_premultiplied (0, 0, $self->{children}[0]{w}, $self->{children}[0]{h}); + $self->{texture}->draw_quad_alpha (0, 0, $self->{children}[0]{w}, $self->{children}[0]{h}); glDisable GL_TEXTURE_2D; $self->{children}[1]->draw; @@ -2386,11 +2535,12 @@ my ($self, $widget) = @_; $self->add (new CFClient::UI::Label - markup => $widget->{tooltip}, - max_w => ($widget->{tooltip_width} || 0.25) * $::WIDTH, - fontsize => 0.8, - fg => [0, 0, 0, 1], - font => ($widget->{tooltip_font} || $::FONT_PROP), + markup => $widget->{tooltip}, + max_w => ($widget->{tooltip_width} || 0.25) * $::WIDTH, + fontsize => 0.8, + fg => [0, 0, 0, 1], + ellipsise => 0, + font => ($widget->{tooltip_font} || $::FONT_PROP), ); } @@ -2446,23 +2596,56 @@ sub new { my $class = shift; - $class->SUPER::new ( + my $self = $class->SUPER::new ( aspect => 1, @_, - ) + ); + + if ($self->{anim} && $self->{animspeed}) { + Scalar::Util::weaken (my $widget = $self); + + $self->{timer} = Event->timer ( + at => $self->{animspeed} * int $::NOW / $self->{animspeed}, + hard => 1, + interval => $self->{animspeed}, + cb => sub { + ++$widget->{frame}; + $widget->update; + }, + ); + } + + $self } sub size_request { (32, 8) } +sub update { + my ($self) = @_; + + return unless $self->{visible}; + + $self->SUPER::update; +} + sub _draw { my ($self) = @_; - return unless $::CONN;#d# manage and cache textures differently - my $tex = $::CONN->{texture}[$::CONN->{faceid}[$self->{face}]]; + return unless $::CONN; + + my $face; + + if ($self->{frame}) { + my $anim = $::CONN->{anim}[$self->{anim}]; + + $face = $anim->[ $self->{frame} % @$anim ] + if $anim && @$anim; + } + + my $tex = $::CONN->{texture}[$::CONN->{faceid}[$face || $self->{face}]]; - # TODO animation if ($tex) { glEnable GL_TEXTURE_2D; glTexEnv GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE; @@ -2472,12 +2655,47 @@ } } +sub DESTROY { + my ($self) = @_; + + $self->{timer}->cancel + if $self->{timer}; + + $self->SUPER::DESTROY; +} + ############################################################################# package CFClient::UI::InventoryItem; our @ISA = CFClient::UI::HBox::; +sub _item_to_desc { + my ($item) = @_; + + my $desc = + $item->{nrof} < 2 + ? $item->{name} + : "$item->{nrof} × $item->{name_pl}"; + + $item->{flags} & Crossfire::Protocol::F_OPEN + and $desc .= " (open)"; + $item->{flags} & Crossfire::Protocol::F_APPLIED + and $desc .= " (applied)"; + $item->{flags} & Crossfire::Protocol::F_UNPAID + and $desc .= " (unpaid)"; + $item->{flags} & Crossfire::Protocol::F_MAGIC + and $desc .= " (magic)"; + $item->{flags} & Crossfire::Protocol::F_CURSED + and $desc .= " (cursed)"; + $item->{flags} & Crossfire::Protocol::F_DAMNED + and $desc .= " (damned)"; + $item->{flags} & Crossfire::Protocol::F_LOCKED + and $desc .= " *"; + + $desc +} + sub new { my $class = shift; @@ -2485,37 +2703,47 @@ my $item = delete $args{item}; - my $desc = $item->{nrof} < 2 - ? $item->{name} - : "$item->{nrof} $item->{name_pl}"; - + my $desc = _item_to_desc ($item); my $self = $class->SUPER::new ( - can_hover => 1, + can_hover => 1, can_events => 1, - tooltip => (CFClient::UI::Label->escape ($desc) - . "\nleftclick - pick up\nmiddle click - apply\nrightclick - menu"), + tooltip => ((CFClient::UI::Label::escape $desc) + . "\nleftclick - examine\nshift+leftclick - move/pickup/drop\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"); + if (($ev->{mod} & CFClient::KMOD_SHIFT) && $ev->{button} == 1) { + my $targ = $::CONN->{player}{tag}; + + if ($item->{container} == $::CONN->{player}{tag}) { + $targ = $main::OPENCONT; + } + + $::CONN->send ("move $targ $item->{tag} 0"); + } elsif ($ev->{button} == 1) { + $::CONN->send ("examine $item->{tag}"); } 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); + my @menu_items = ( + ["examine", sub { $::CONN->send ("examine $item->{tag}") }], + ["mark", sub { $::CONN->send ("mark ". pack "N", $item->{tag}) }], + ["apply", sub { $::CONN->send ("apply $item->{tag}") }], + ( + $item->{flags} & Crossfire::Protocol::F_LOCKED + ? ( + ["unlock", sub { $::CONN->send ("lock " . pack "CN", 0, $item->{tag}) }], + ) + : ( + ["lock", sub { $::CONN->send ("lock " . pack "CN", 1, $item->{tag}) }], + ["drop", sub { $::CONN->send ("move $main::OPENCONT $item->{tag} 0") }], + ) + ), + ); + + CFClient::UI::Menu->new (items => \@menu_items)->popup ($ev); } 1 @@ -2523,6 +2751,7 @@ %args ); + $self->add (new CFClient::UI::Face can_events => 0, face => $item->{face}, @@ -2530,14 +2759,23 @@ animspeed => $item->{animspeed}, ); - $self->add (new CFClient::UI::Label - can_events => 0, - text => $desc, - ); + $self->add ($self->{name_lbl} = new CFClient::UI::Label can_events => 0); + + $self->{item} = $item; + + $self->update_item; $self } +sub update_item { + my ($self) = @_; + + my $desc = _item_to_desc ($self->{item}); + + $self->{name_lbl}->set_text ($desc); +} + ############################################################################# package CFClient::UI::Inventory; @@ -2548,7 +2786,7 @@ my $class = shift; my $self = $class->SUPER::new ( - scrolled => (new CFClient::UI::VBox), + scrolled => (new CFClient::UI::Table), @_, ); @@ -2569,14 +2807,17 @@ $self->{real_items} = \@items; for my $item (@items) { - my $desc = $item->{nrof} < 2 - ? $item->{name} - : "$item->{nrof} $item->{name_pl}"; - + $item->{item} = $item; $item = $item->{widget} ||= new CFClient::UI::InventoryItem item => $item; + $item->update_item (); } - $self->{scrolled}->add (@items); + my $i = 0; + for (@items) { + $self->{scrolled}->add (0, $i, $_); + my $nrof = $_->{item}->{nrof} || 1; + $self->{scrolled}->add (1, $i++, new CFClient::UI::Label text => ($_->{item}->{weight} * $nrof) / 1000); + } # $range->{range} = [$self->{pos}, 0, $self->{max_pos}, $page]; } @@ -2664,6 +2905,15 @@ our @ISA = CFClient::UI::VBox::; +sub new { + my $class = shift; + + $class->SUPER::new ( + fontsize => 0.8, + @_, + ) +} + sub reorder { my ($self) = @_; my $NOW = time; @@ -2692,8 +2942,6 @@ for ($short) { s/^\s+//; s/\s+/ /g; - my $len = int 40 / $item->{fontsize}; - substr $_, $len, length, "…" if $len < length; } new CFClient::UI::Label @@ -2701,7 +2949,8 @@ tooltip => $item->{tooltip}, tooltip_font => $::FONT_PROP, tooltip_width => 0.67, - fontsize => $item->{fontsize}, + fontsize => $item->{fontsize} || $self->{fontsize}, + max_w => $::WIDTH * 0.44, fg => $item->{fg}, can_events => 1, can_hover => 1 @@ -2738,7 +2987,6 @@ text => $text, timeout => $timeout, tooltip => $text, - fontsize => 0.8, fg => [0.8, 0.8, 0.8, 0.8], pri => 0, count => 1, @@ -2749,6 +2997,16 @@ $self->reorder; } +sub reconfigure { + my ($self) = @_; + + delete $_->{label} + for values %{ $self->{item} || {} }; + + $self->reorder; + $self->SUPER::reconfigure; +} + ############################################################################# package CFClient::UI::Root; @@ -2841,6 +3099,24 @@ } $self->SUPER::add (@children); + + while (@children) { + my $w = pop @children; + push @children, $w->children; + $w->{visible} = 1; + } +} + +sub remove { + my ($self, @children) = @_; + + $self->SUPER::remove (@children); + + while (@children) { + my $w = pop @children; + push @children, $w->children; + delete $w->{visible}; + } } sub on_refresh { @@ -2919,7 +3195,7 @@ glMatrixMode GL_PROJECTION; glLoadIdentity; - glOrtho 0, $::WIDTH, $::HEIGHT, 0, -10000 , 10000; + glOrtho 0, $::WIDTH, $::HEIGHT, 0, -10000, 10000; glMatrixMode GL_MODELVIEW; glLoadIdentity; @@ -2931,7 +3207,7 @@ package CFClient::UI; $ROOT = new CFClient::UI::Root; -$TOOLTIP = new CFClient::UI::Tooltip; +$TOOLTIP = new CFClient::UI::Tooltip z => 900; 1