--- deliantra/Deliantra-Client/DC/UI.pm 2006/05/15 00:15:08 1.205 +++ deliantra/Deliantra-Client/DC/UI.pm 2006/05/15 17:45:29 1.206 @@ -2012,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 @@ -2025,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) = @_; @@ -2052,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 { @@ -2083,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; }