--- deliantra/Deliantra-Client/DC/UI.pm 2006/05/13 00:27:09 1.200 +++ deliantra/Deliantra-Client/DC/UI.pm 2006/05/15 18:23:33 1.207 @@ -14,6 +14,8 @@ our $TOOLTIP; our $BUTTON_STATE; +our %WIDGET; # all widgets, weak-referenced + sub check_tooltip { if (!$GRAB) { for (my $widget = $HOVER; $widget; $widget = $widget->{parent}) { @@ -31,9 +33,8 @@ my ($x, $y) = $widget->coord2global ($widget->{w}, 0); - if ($x + $TOOLTIP->{w} > $::WIDTH) { - ($x, $y) = $widget->coord2global (-$TOOLTIP->{w}, 0); - } + ($x, $y) = $widget->coord2global (-$TOOLTIP->{w}, 0) + if $x + $TOOLTIP->{w} > $::WIDTH; $TOOLTIP->move ($x, $y); $TOOLTIP->check_size; @@ -137,6 +138,26 @@ } } +# call when resolution changes etc. +sub rescale_widgets { + my ($sx, $sy) = @_; + + for my $widget (values %WIDGET) { + 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}; + $widget->{req_w} = int 0.5 + $widget->{req_w} * $sx if exists $widget->{req_w}; + $widget->{user_w} = int 0.5 + $widget->{user_w} * $sx if exists $widget->{user_w}; + $widget->{y} = int 0.5 + $widget->{y} * $sy if exists $widget->{y}; + $widget->{h} = int 0.5 + $widget->{h} * $sy if exists $widget->{h}; + $widget->{req_h} = int 0.5 + $widget->{req_h} * $sy if exists $widget->{req_h}; + $widget->{user_h} = int 0.5 + $widget->{user_h} * $sy if exists $widget->{user_h}; + } + + $widget->reconfigure; + } +} + ############################################################################# package CFClient::UI::Base; @@ -162,6 +183,8 @@ } } + Scalar::Util::weaken ($CFClient::UI::WIDGET{$self+0} = $self); + $self } @@ -244,20 +267,16 @@ # nothing to be done } -sub children { -} - -# call when resolution changes etc. sub reconfigure { my ($self) = @_; - $_->reconfigure - for $self->children; - $self->check_size (1); $self->update; } +sub children { +} + sub set_max_size { my ($self, $w, $h) = @_; @@ -358,7 +377,7 @@ glVertex 0 , $self->{h}; glEnd; glPopMatrix; - CFClient::UI::Label->new (w => $self->{w}, h => $self->{h}, text => $self, fontsize => 0)->_draw; + #CFClient::UI::Label->new (w => $self->{w}, h => $self->{h}, text => $self, fontsize => 0)->_draw; } } @@ -419,6 +438,7 @@ sub DESTROY { my ($self) = @_; + delete $WIDGET{$self+0}; #$self->deactivate; } @@ -842,6 +862,7 @@ bg => [1, 1, 1, 1], border_bg => [1, 1, 1, 1], border => 0.6, + toplevel => 1, can_events => 1, @_ ); @@ -1991,7 +2012,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 @@ -2004,13 +2025,39 @@ req_h => $::WIDTH / 80, vertical => 0, can_hover => 1, - inner_pad => 5, + inner_pad => .05, @_ ); + $self->set_value ($self->{range}[0]); + $self->update; + $self } +sub set_value { + my ($self, $value) = @_; + + my ($old_value, $lo, $hi, $page, $unit) = @{$self->{range}}; + + $hi = $lo + 1 if $hi <= $lo; + + $value = $lo if $value < $lo; + $value = $hi if $value > $hi; + + $value = $lo + $unit * int +($value - $lo + $unit * 0.5) / $unit + if $unit; + + $page = $hi - $lo if $page > $hi - $lo; + + @{$self->{range}} = ($value, $lo, $hi, $page, $unit); + + if ($value != $old_value) { + $self->emit (changed => $value); + $self->update; + } +} + sub size_request { my ($self) = @_; @@ -2031,30 +2078,41 @@ 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 / ($w * (1 - 2 * $self->{inner_pad})) - $self->{inner_pad}; - $self->emit (changed => $x); - $self->update; + $self->set_value ($x * ($hi - $lo) + $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 $inner_w = 1 - 2 * $self->{inner_pad}; + + $self->{scale} = ($inner_w / ($hi - $lo)) || 1; + + $page = $self->{scale} * $page || 10 / ($self->{w} || 1); + $value = $self->{scale} * ($value - $lo); + + $value = $self->{inner_pad} + ($value - $page * 0.5); + + $value = 0 if $value < 0; + $page = 1 - $value if $value + $page > 1; + + $self->{knob_x} = $value; + $self->{knob_w} = $page; + }); + + $self->SUPER::update; } sub _draw { @@ -2062,46 +2120,26 @@ $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 glRotate 90, 0, 0, 1; - glTranslate 0, -$self->{w}, 0; - - ($w, $h) = ($h, $w); + glTranslate 0, 1, 0; } 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}}; - - $hi = $value + 1 if $lo == $hi; - - 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); - - $w -= $page; - $page &= ~1; - glTranslate $page * 0.5, 0, 0; - $page ||= 2; - - my $knob_a = $inner_pad_px + ($value - $page * 0.5); - my $knob_b = $inner_pad_px + ($value + $page * 0.5); - glEnable GL_TEXTURE_2D; glTexEnv GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE; # draw background - $tex[1]->draw_quad_alpha (0, 0, $w, $h); + $tex[1]->draw_quad_alpha (0, 0, 1, 1); # draw handle - $tex[0]->draw_quad_alpha ($knob_a, 0, $knob_b - $knob_a, $h); + $tex[0]->draw_quad_alpha ($self->{knob_x}, 0, $self->{knob_w}, 1); glDisable GL_TEXTURE_2D; } @@ -2468,6 +2506,20 @@ ? $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 .= " *"; my $self = $class->SUPER::new ( can_hover => 1, @@ -2483,18 +2535,18 @@ } 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") }], + my @menu_items = ( + ["examine", sub { $::CONN->send ("examine $item->{tag}") }], + ["mark", sub { $::CONN->send ("mark $item->{tag}") }], + ["apply", sub { $::CONN->send ("apply $item->{tag}") }], + ["drop", sub { $::CONN->send ("move $main::OPENCONT $item->{tag} 0") }], + [ + $item->{flags} & Crossfire::Protocol::F_LOCKED ? "lock" : "unlock", + sub { $::CONN->send ("lock ". () ."$item->{tag}") }, ], - )->popup ($ev); + ); + + CFClient::UI::Menu->new (items => \@menu_items)->popup ($ev); } 1 @@ -2540,7 +2592,10 @@ $self->{scrolled}->clear; return unless $items; - my @items = sort { $a->{type} <=> $b->{type} } @$items; + my @items = sort { + ($a->{type} <=> $b->{type}) + or ($a->{name} cmp $b->{name}) + } @$items; $self->{real_items} = \@items; @@ -2549,9 +2604,11 @@ ? $item->{name} : "$item->{nrof} $item->{name_pl}"; - $self->{scrolled}->add ($item->{widget} ||= new CFClient::UI::InventoryItem item => $item); + $item = $item->{widget} ||= new CFClient::UI::InventoryItem item => $item; } + $self->{scrolled}->add (@items); + # $range->{range} = [$self->{pos}, 0, $self->{max_pos}, $page]; } @@ -2665,7 +2722,7 @@ for ($short) { s/^\s+//; - s/\012.*/…/s; + s/\s+/ /g; my $len = int 40 / $item->{fontsize}; substr $_, $len, length, "…" if $len < length; } @@ -2676,7 +2733,7 @@ tooltip_font => $::FONT_PROP, tooltip_width => 0.67, fontsize => $item->{fontsize}, - color => $item->{color}, + fg => $item->{fg}, can_events => 1, can_hover => 1 }; @@ -2713,7 +2770,7 @@ timeout => $timeout, tooltip => $text, fontsize => 0.8, - color => [0.8, 0.8, 0.8, 0.8], + fg => [0.8, 0.8, 0.8, 0.8], pri => 0, count => 1, %arg, @@ -2762,32 +2819,26 @@ sub size_allocate { my ($self, $w, $h) = @_; - my $old_w = $self->{old_w}; - my $old_h = $self->{old_h}; + my $old_w = $self->{old_w}; $self->{old_w} = $w; + my $old_h = $self->{old_h}; $self->{old_h} = $h; - 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}; - } - } + CFClient::UI::rescale_widgets $w / $old_w, $h / $old_h + if $old_w && $old_h && ($old_w != $w || $old_h != $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; + $X = $child->{req_x} > 0 ? $child->{req_x} : $w - $W - $child->{req_x} + 1 + if exists $child->{req_x}; + + $Y = $child->{req_y} > 0 ? $child->{req_y} : $h - $H - $child->{req_y} + 1 + if exists $child->{req_y}; + + $X = List::Util::max 0, List::Util::min $w - $W, int $X + 0.5; + $Y = List::Util::max 0, List::Util::min $h - $H, int $Y + 0.5; + $child->configure ($X, $Y, $W, $H); } - - $self->{old_w} = $w; - $self->{old_h} = $h; } sub coord2local { @@ -2810,13 +2861,17 @@ } sub add { - my ($self, $child) = @_; + my ($self, @children) = @_; - # integerise window positions - $child->{x} = int $child->{x}; - $child->{y} = int $child->{y}; + for my $child (@children) { + $child->{toplevel} = 1; - $self->SUPER::add ($child); + # integerise window positions + $child->{x} = int $child->{x}; + $child->{y} = int $child->{y}; + } + + $self->SUPER::add (@children); } sub on_refresh {