--- deliantra/Deliantra-Client/DC/UI.pm 2007/07/15 22:39:30 1.373 +++ deliantra/Deliantra-Client/DC/UI.pm 2007/07/20 16:32:17 1.385 @@ -946,6 +946,8 @@ package CFPlus::UI::ViewPort; +use List::Util qw(min max); + our @ISA = CFPlus::UI::Window::; sub new { @@ -986,10 +988,16 @@ sub set_offset { my ($self, $x, $y) = @_; - $self->{view_x} = int $x; - $self->{view_y} = int $y; + my $x = max 0, min $self->child->{w} - $self->{w}, int $x; + my $y = max 0, min $self->child->{h} - $self->{h}, int $y; - $self->update; + if ($x != $self->{view_x} or $y != $self->{view_y}) { + $self->{view_x} = $x; + $self->{view_y} = $y; + + $self->emit (changed => $x, $y); + $self->update; + } } # hmm, this does not work for topleft of $self... but we should not ask for that @@ -1074,14 +1082,20 @@ ); $self->{vp} = new CFPlus::UI::ViewPort - expand => 1, - scroll_x => $self->{scroll_x}, - scroll_y => $self->{scroll_y}, + expand => 1, + scroll_x => $self->{scroll_x}, + scroll_y => $self->{scroll_y}, + on_changed => sub { + my ($vp, $x, $y) = @_; + + $vp->{parent}{hslider}->set_value ($x); + $vp->{parent}{vslider}->set_value ($y); + + 0 + }, ; - $self->SUPER::add (0, 0, $self->{vp}); - $self->SUPER::add (1, 0, $self->{vslider}) if $self->{scroll_y}; - $self->SUPER::add (0, 1, $self->{hslider}) if $self->{scroll_x}; + $self->SUPER::add_at (0, 0, $self->{vp}); $self->add ($child) if $child; @@ -1096,16 +1110,6 @@ $self->{vp}->add ($self->{child} = $widget); } -sub invoke_mouse_wheel { - my ($self, $ev) = @_; - - return 0 unless $ev->{dy}; # only vertical movements - - $self->{vslider}->emit (mouse_wheel => $ev); - - 1 -} - sub update_slider { my ($self) = @_; @@ -1113,11 +1117,21 @@ my ($w1, $w2) = ($child->{w}, $self->{vp}{w}); $self->{hslider}->set_range ([$self->{hslider}{range}[0], 0, $w1, $w2, 1]); - #$self->{hslider}->set_visibility ($w1 != $w2); + + my $visible = $w1 > $w2; + if ($visible != $self->{hslider}{visible}) { + $visible ? $self->SUPER::add_at (0, 1, $self->{hslider}) + : $self->{hslider}->hide; + } my ($h1, $h2) = ($child->{h}, $self->{vp}{h}); $self->{vslider}->set_range ([$self->{vslider}{range}[0], 0, $h1, $h2, 1]); - #$self->{vslider}->set_visibility ($h1 != $h2); + + my $visible = $h1 > $h2; + if ($visible != $self->{vslider}{visible}) { + $visible ? $self->SUPER::add_at (1, 0, $self->{vslider}) + : $self->{vslider}->hide; + } } sub update { @@ -1127,6 +1141,59 @@ $self->update_slider; } +sub invoke_mouse_wheel { + my ($self, $ev) = @_; + + return 0 unless $ev->{dy}; # only vertical movements for now + + $self->{vslider}->emit (mouse_wheel => $ev); + + 1 +} + +sub invoke_button_down { + my ($self, $ev, $x, $y) = @_; + + if ($ev->{button} == 2) { + $self->grab_focus; + + my $ox = $self->{vp}{view_x} + $ev->{x}; + my $oy = $self->{vp}{view_y} + $ev->{y}; + + $self->{motion} = sub { + my ($ev, $x, $y) = @_; + + $self->{vp}->set_offset ($ox - $ev->{x}, $oy - $ev->{y}); + $self->update; + }; + + return 1; + } + + 0 +} + +sub invoke_button_up { + my ($self, $ev, $x, $y) = @_; + + if (delete $self->{motion}) { + return 1; + } + + 0 +} + +sub invoke_mouse_motion { + my ($self, $ev, $x, $y) = @_; + + if ($self->{motion}) { + $self->{motion}->($ev, $x, $y); + return 1; + } + + 0 +} + sub invoke_size_allocate { my ($self, $w, $h) = @_; @@ -1290,6 +1357,10 @@ map { new_from_file CFPlus::Texture CFPlus::find_rcfile $_, mipmap => 1 } qw(d1_border_top.png d1_border_right.png d1_border_left.png d1_border_bottom.png); +my @icon = + map { new_from_file CFPlus::Texture CFPlus::find_rcfile $_, mipmap => 1 } + qw(x1_move.png x1_resize.png); + sub new { my ($class, %arg) = @_; @@ -1467,10 +1538,24 @@ my $border = $self->border; glColor @{ $self->{border_bg} }; - $border[0]->draw_quad_alpha (0, 0, $w, $border); - $border[1]->draw_quad_alpha (0, $border, $border, $ch); - $border[2]->draw_quad_alpha ($w - $border, $border, $border, $ch); - $border[3]->draw_quad_alpha (0, $h - $border, $w, $border); + $border[0]->draw_quad_alpha ( 0, 0, $w, $border); + $border[1]->draw_quad_alpha ( 0, $border, $border, $ch); + $border[2]->draw_quad_alpha ($w - $border, $border, $border, $ch); + $border[3]->draw_quad_alpha ( 0, $h - $border, $w, $border); + + # move + my $w2 = ($w - $border) * .5; + my $h2 = ($h - $border) * .5; + $icon[0]->draw_quad_alpha ( 0, $h2, $border, $border); + $icon[0]->draw_quad_alpha ($w - $border, $h2, $border, $border); + $icon[0]->draw_quad_alpha ($w2 , $h - $border, $border, $border); + + # resize + $icon[1]->draw_quad_alpha ( 0, 0, $border, $border); + $icon[1]->draw_quad_alpha ($w - $border, 0, $border, $border) + unless $self->{has_close_button}; + $icon[1]->draw_quad_alpha ( 0, $h - $border, $border, $border); + $icon[1]->draw_quad_alpha ($w - $border, $h - $border, $border, $border); if (@{$self->{bg}} < 4 || $self->{bg}[3]) { glColor @{ $self->{bg} }; @@ -1511,6 +1596,7 @@ my $class = shift; $class->SUPER::new ( + children => [], col_expand => [], row_expand => [], @_, @@ -1521,16 +1607,25 @@ grep $_, map @$_, grep $_, @{ $_[0]{children} } } +# TODO: store row/col info in child widget and use standard add/del sub add { - my ($self) = shift; + my $self = shift; + + Carp::cluck "please use the add_at method instead of calling add, thank you.\n";#d# + $self->add_at (@_); +} + +sub add_at { + my $self = shift; while (@_) { - my ($x, $y, $child) = splice @_, 0, 3, (); + my ($col, $row, $child) = splice @_, 0, 3, (); + $child->set_parent ($self); - $self->{children}[$y][$x] = $child; + $self->{children}[$row][$col] = $child; } - $self->{force_realloc} = 1; + $self->{force_realloc} = 1; $self->{force_size_alloc} = 1; $self->realloc; } @@ -1538,7 +1633,11 @@ sub remove { my ($self, $child) = @_; - # TODO: not yet implemented + for (@{ $self->{children} }) { + for (@{ $_ || [] }) { + $_ = undef if $_ == $child; + } + } } # TODO: move to container class maybe? send children a signal on removal? @@ -1665,6 +1764,88 @@ ############################################################################# +package CFPlus::UI::Fixed; + +use List::Util qw(min max); + +our @ISA = CFPlus::UI::Container::; + +sub add { + my ($self, $child, $posmode, $x, $y, $sizemode, $w, $h) = @_; + + $child->{_fixed} = [$posmode, $x, $y, $sizemode, $w, $h]; + $self->SUPER::add ($child); +} + +sub _scale($$$) { + my ($mode, $val, $max) = @_; + + $mode eq "abs" ? $val + : $mode eq "rel" ? $val * $max + : 0 +} + +sub size_request { + my ($self) = @_; + + my ($x1, $y1, $x2, $y2) = (0, 0, 0, 0); + + # determine overall size by querying abs widgets + for my $child ($self->visible_children) { + my ($pos, $x, $y, $size, $w, $h) = @{ $child->{_fixed} }; + + if ($pos eq "abs") { + $w = _scale $size, $w, $child->{req_w}; + $h = _scale $size, $h, $child->{req_h}; + + $x1 = min $x1, $x; $x2 = max $x2, $x + $w; + $y1 = min $y1, $y; $y2 = max $y2, $y + $h; + } + } + + my $W = $x2 - $x1; + my $H = $y2 - $y1; + + # now layout remaining widgets + for my $child ($self->visible_children) { + my ($pos, $x, $y, $size, $w, $h) = @{ $child->{_fixed} }; + + if ($pos ne "abs") { + $x = _scale $pos, $x, $W; + $y = _scale $pos, $x, $H; + $w = _scale $size, $w, $child->{req_w}; + $h = _scale $size, $h, $child->{req_h}; + + $x1 = min $x1, $x; $x2 = max $x2, $x + $w; + $y1 = min $y1, $y; $y2 = max $y2, $y + $h; + } + } + + my $W = $x2 - $x1; + my $H = $y2 - $y1; + + ($W, $H) +} + +sub invoke_size_allocate { + my ($self, $W, $H) = @_; + + for my $child ($self->visible_children) { + my ($pos, $x, $y, $size, $w, $h) = @{ $child->{_fixed} }; + + $x = _scale $pos, $x, $W; + $y = _scale $pos, $x, $H; + $w = _scale $size, $w, $child->{req_w}; + $h = _scale $size, $h, $child->{req_h}; + + $child->configure ($x, $y, $w, $h); + } + + 1 +} + +############################################################################# + package CFPlus::UI::Box; our @ISA = CFPlus::UI::Container::; @@ -2228,7 +2409,7 @@ my @tex = map { new_from_file CFPlus::Texture CFPlus::find_rcfile $_, mipmap => 1 } - qw(b1_button_active.png); + qw(b1_button_inactive.png b1_button_active.png); sub new { my $class = shift; @@ -2236,8 +2417,8 @@ $class->SUPER::new ( padding_x => 4, padding_y => 4, - fg => [1, 1, 1], - active_fg => [0, 0, 1], + fg => [1.0, 1.0, 1.0], + active_fg => [0.8, 0.8, 0.8], can_hover => 1, align => 0, valign => 0, @@ -2265,7 +2446,8 @@ glTexEnv GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE; glColor 0, 0, 0, 1; - $tex[0]->draw_quad_alpha (0, 0, $self->{w}, $self->{h}); + my $tex = $tex[$GRAB == $self]; + $tex->draw_quad_alpha (0, 0, $self->{w}, $self->{h}); glDisable GL_TEXTURE_2D; @@ -3340,25 +3522,45 @@ if ($self->{anim} && $self->{animspeed}) { CFPlus::weaken (my $widget = $self); + $widget->{animspeed} = List::Util::max 0.05, $widget->{animspeed}; + $widget->{anim_start} = $self->{animspeed} * Event::time / $self->{animspeed}; $self->{timer} = Event->timer ( - at => $self->{animspeed} * int $::NOW / $self->{animspeed}, - hard => 1, - interval => $self->{animspeed}, + parked => 1, cb => sub { - return unless $::CONN; + return unless $::CONN && $widget; ++$widget->{frame}; - $self->update_face; - $self->update; + $widget->update_face; + $widget->update; + + $widget->update_timer; }, ); $self->update_face; + $self->update_timer; } $self } +sub update_timer { + my ($self) = @_; + + return unless $self->{timer}; + + if ($self->{visible}) { + $self->{timer}->at ( + $self->{anim_start} + + $self->{animspeed} + * int 1.5 + (Event::time - $self->{anim_start}) / $self->{animspeed} + ); + $self->{timer}->start; + } else { + $self->{timer}->stop; + } +} + sub update_face { my ($self) = @_; @@ -3398,6 +3600,14 @@ $self->SUPER::update; } +sub invoke_visibility_change { + my ($self) = @_; + + $self->update_timer; + + 0 +} + sub _draw { my ($self) = @_; @@ -3422,7 +3632,7 @@ sub destroy { my ($self) = @_; - $self->{timer}->cancel + (delete $self->{timer})->cancel if $self->{timer}; $self->SUPER::destroy; @@ -4076,7 +4286,6 @@ for values %{delete $self->{post_alloc_hook}}; } - glViewport 0, 0, $::WIDTH, $::HEIGHT; glClearColor +($::CFG->{fow_intensity}) x 3, 1; glClear GL_COLOR_BUFFER_BIT;