--- deliantra/Deliantra-Client/DC/UI.pm 2006/05/12 00:16:34 1.196 +++ deliantra/Deliantra-Client/DC/UI.pm 2006/05/14 21:13:11 1.203 @@ -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}) { @@ -36,6 +38,8 @@ } $TOOLTIP->move ($x, $y); + $TOOLTIP->check_size; + $TOOLTIP->update; } return; @@ -135,6 +139,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; @@ -160,6 +184,8 @@ } } + Scalar::Util::weaken ($CFClient::UI::WIDGET{$self+0} = $self); + $self } @@ -242,21 +268,16 @@ # nothing to be done } -sub children { -} - -# call when resolution changes etc. sub reconfigure { my ($self) = @_; - $_->reconfigure - for $self->children; - - $self->check_size; - $CFClient::UI::ROOT->{size_alloc}{$self} = [$self, $self->{w}, $self->{h}]; + $self->check_size (1); $self->update; } +sub children { +} + sub set_max_size { my ($self, $w, $h) = @_; @@ -384,13 +405,15 @@ Scalar::Util::weaken ($self->{parent} = $parent); + # TODO: req_w _does_change after ->reconfigure $self->check_size unless exists $self->{req_w}; } sub check_size { - my ($self) = @_; + my ($self, $forced) = @_; + $self->{force_alloc} = 1 if $forced; $CFClient::UI::ROOT->{check_size}{$self} = $self; } @@ -416,6 +439,7 @@ sub DESTROY { my ($self) = @_; + delete $WIDGET{$self+0}; #$self->deactivate; } @@ -510,7 +534,7 @@ @{$self->{children}}, @widgets ]; - $self->check_size; + $self->check_size (1); $self->update; } @@ -627,7 +651,7 @@ sub update { my ($self) = @_; - $ROOT->on_refresh ($self => sub { $self->render_child }); + $ROOT->on_post_alloc ($self => sub { $self->render_child }); $self->SUPER::update; } @@ -775,7 +799,7 @@ $self } -#TODO# update range on size_allocate depeneing on child +#TODO# update range on size_allocate depending on child # update viewport offset on scroll ############################################################################# @@ -789,38 +813,33 @@ sub new { my $class = shift; - my $self = $class->SUPER::new ( - bg => [1, 1, 1, 1], - border_bg => [1, 1, 1, 1], - border => 0.8, - @_ - ); - - $self + $class->SUPER::new ( + bg => undef, + @_, + ) } sub _draw { my ($self) = @_; - my ($w, $h) = ($self->{w}, $self->{h}); + if ($self->{bg}) { + my ($w, $h) = @$self{qw(w h)}; - glEnable GL_BLEND; - glBlendFunc GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA; - glEnable GL_TEXTURE_2D; - glTexEnv GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE; + glEnable GL_BLEND; + glBlendFunc GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA; + glColor @{ $self->{bg} }; -# glBegin GL_QUADS; -# glColor 0, 0, 0, 0; -# glVertex 0 , 0; -# glVertex 0 , $h; -# glVertex $w, $h; -# glVertex $w, 0; -# glEnd; + glBegin GL_QUADS; + glVertex 0 , 0; + glVertex 0 , $h; + glVertex $w, $h; + glVertex $w, 0; + glEnd; + glDisable GL_BLEND; + } - $self->child->draw; - glDisable GL_BLEND; - glDisable GL_TEXTURE_2D; + $self->SUPER::_draw; } ############################################################################# @@ -844,6 +863,7 @@ bg => [1, 1, 1, 1], border_bg => [1, 1, 1, 1], border => 0.6, + toplevel => 1, can_events => 1, @_ ); @@ -946,18 +966,16 @@ my ($w, $h ) = ($self->{w}, $self->{h}); my ($cw, $ch) = ($self->child->{w}, $self->child->{h}); - glEnable GL_BLEND; - glBlendFunc GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA; glEnable GL_TEXTURE_2D; glTexEnv GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE; my $border = $self->border; glColor @{ $self->{border_bg} }; - $tex[1]->draw_quad (0, 0, $w, $border); - $tex[3]->draw_quad (0, $border, $border, $ch); - $tex[2]->draw_quad ($w - $border, $border, $border, $ch); - $tex[4]->draw_quad (0, $h - $border, $w, $border); + $tex[1]->draw_quad_alpha (0, 0, $w, $border); + $tex[3]->draw_quad_alpha (0, $border, $border, $ch); + $tex[2]->draw_quad_alpha ($w - $border, $border, $border, $ch); + $tex[4]->draw_quad_alpha (0, $h - $border, $w, $border); if (@{$self->{bg}} < 4 || $self->{bg}[3]) { my $bg = $tex[0]; @@ -971,12 +989,11 @@ $bg->{s} = $rep_x; $bg->{t} = $rep_y; $bg->{wrap_mode} = 1; - $bg->draw_quad ($border, $border, $cw, $ch); - - glDisable GL_TEXTURE_2D; - glDisable GL_BLEND; + $bg->draw_quad_alpha ($border, $border, $cw, $ch); } + glDisable GL_TEXTURE_2D; + $self->{title}->draw if $self->{title}; $self->child->draw; @@ -1487,9 +1504,9 @@ my $text = $self->get_text; - if ($sym == 8) { + if ($uni == 8) { substr $text, --$self->{cursor}, 1, "" if $self->{cursor}; - } elsif ($sym == 127) { + } elsif ($uni == 127) { substr $text, $self->{cursor}, 1, ""; } elsif ($sym == CFClient::SDLK_LEFT) { --$self->{cursor} if $self->{cursor}; @@ -1499,7 +1516,7 @@ $self->{cursor} = 0; } elsif ($sym == CFClient::SDLK_END) { $self->{cursor} = length $text; - } elsif ($sym == 27) { + } elsif ($uni == 27) { $self->emit ('escape'); } elsif ($uni) { substr $text, $self->{cursor}++, 0, chr $uni; @@ -1736,12 +1753,10 @@ glColor @{ $FOCUS == $self ? $self->{active_fg} : $self->{fg} }; - glEnable GL_TEXTURE_2D; - my $tex = $self->{state} ? $tex[1] : $tex[0]; + glEnable GL_TEXTURE_2D; $tex->draw_quad_alpha (0, 0, $s, $s); - glDisable GL_TEXTURE_2D; } @@ -2206,7 +2221,7 @@ delete $self->{texture}; - $ROOT->on_refresh ($self, sub { + $ROOT->on_post_alloc ($self, sub { if (delete $self->{need_reflow}) { my $height = 0; @@ -2371,14 +2386,13 @@ sub set_tooltip_from { my ($self, $widget) = @_; - $self->{label} = new CFClient::UI::Label + $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); - - $self->add ($self->{label}); + font => ($widget->{tooltip_font} || $::FONT_PROP), + ); } sub size_request { @@ -2398,7 +2412,6 @@ sub _draw { my ($self) = @_; - glPushMatrix; glTranslate 0.375, 0.375; my ($w, $h) = @$self{qw(w h)}; @@ -2419,9 +2432,7 @@ glVertex $w, 0; glEnd; - glPopMatrix; - - glTranslate 2, 2; + glTranslate 2 - 0.375, 2 - 0.375; $self->SUPER::_draw; } @@ -2551,7 +2562,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; @@ -2560,9 +2574,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]; } @@ -2658,54 +2674,78 @@ } my @widgets; - my @items = sort { $a->{time} <=> $b->{time} } values %{ $self->{item} }; + + my @items = sort { + $a->{pri} <=> $b->{pri} + or $b->{id} <=> $a->{id} + } values %{ $self->{item} }; + my $count = 10 + 1; for my $item (@items) { last unless --$count; push @widgets, $item->{label} ||= do { # TODO: doesn't handle markup well (read as: at all) - my $short = delete $item->{text}; + my $short = $item->{count} > 1 + ? "$item->{count} × $item->{text}" + : $item->{text}; + for ($short) { s/^\s+//; - s/\012.*//s; - my $len = int 30 / $item->{fontsize}; + s/\012.*/…/s; + my $len = int 40 / $item->{fontsize}; substr $_, $len, length, "…" if $len < length; } new CFClient::UI::Label markup => $short, - tooltip => delete $item->{tooltip}, + tooltip => $item->{tooltip}, tooltip_font => $::FONT_PROP, - tooltip_width => 0.75, - fontsize => delete $item->{fontsize}, - color => delete $item->{color}, + tooltip_width => 0.67, + fontsize => $item->{fontsize}, + color => $item->{color}, can_events => 1, - can_hover => 1, + can_hover => 1 }; } $self->clear; - $self->SUPER::add (@widgets); + $self->SUPER::add (reverse @widgets); } sub add { my ($self, $text, %arg) = @_; - my $item = { - time => time, - text => $text, - timeout => 60, - tooltip => $text, - fontsize => 0.8, - color => [0.8, 0.8, 0.8, 0.8], - %arg, - }; + $text =~ s/^\s+//; + $text =~ s/\s+$//; + + my $timeout = time + ((delete $arg{timeout}) || 60); - $item->{timeout} += time; - $item->{group} ||= $item+0; + my $group = exists $arg{group} ? $arg{group} : ++$self->{id}; - $item = $self->{item}{$item->{group}} ||= $item; + if (my $item = $self->{item}{$group}) { + if ($item->{text} eq $text) { + $item->{count}++; + } else { + $item->{count} = 1; + $item->{text} = $item->{tooltip} = $text; + } + $item->{id} = ++$self->{id}; + $item->{timeout} = $timeout; + delete $item->{label}; + } else { + $self->{item}{$group} = { + id => ++$self->{id}, + text => $text, + timeout => $timeout, + tooltip => $text, + fontsize => 0.8, + color => [0.8, 0.8, 0.8, 0.8], + pri => 0, + count => 1, + %arg, + }; + } $self->reorder; } @@ -2749,21 +2789,11 @@ 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)}; @@ -2772,9 +2802,6 @@ $Y = List::Util::max 0, List::Util::min $h - $H, $Y; $child->configure ($X, $Y, $W, $H); } - - $self->{old_w} = $w; - $self->{old_h} = $h; } sub coord2local { @@ -2797,13 +2824,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 { @@ -2812,9 +2843,20 @@ $self->{refresh_hook}{$id} = $cb; } +sub on_post_alloc { + my ($self, $id, $cb) = @_; + + $self->{post_alloc_hook}{$id} = $cb; +} + sub draw { my ($self) = @_; + while ($self->{refresh_hook}) { + $_->() + for values %{delete $self->{refresh_hook}}; + } + if ($self->{check_size}) { my @queue = ([], []); @@ -2831,13 +2873,14 @@ ? @$widget{qw(user_w user_h)} : $widget->size_request; - if ($w != $widget->{req_w} || $h != $widget->{req_h}) { + if (delete $widget->{force_alloc} + or $w != $widget->{req_w} or $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; - $self->{size_alloc}{$widget} = [$widget, $widget->{w}, $widget->{h}]; + $self->{size_alloc}{$widget} = [$widget, $widget->{w} || $w, $widget->{h} || $h]; $widget->{parent}->check_size if $widget->{parent}; @@ -2859,9 +2902,9 @@ } } - while ($self->{refresh_hook}) { + while ($self->{post_alloc_hook}) { $_->() - for values %{delete $self->{refresh_hook}}; + for values %{delete $self->{post_alloc_hook}}; } glViewport 0, 0, $::WIDTH, $::HEIGHT;