--- deliantra/Deliantra-Client/DC/UI.pm 2006/12/09 21:26:46 1.362 +++ deliantra/Deliantra-Client/DC/UI.pm 2007/07/16 12:36:48 1.374 @@ -24,9 +24,11 @@ for (my $widget = $HOVER; $widget; $widget = $widget->{parent}) { if (length $widget->{tooltip}) { if ($TOOLTIP->{owner} != $widget) { + $TOOLTIP->{owner}->emit ("tooltip_hide") if $TOOLTIP->{owner}; $TOOLTIP->hide; $TOOLTIP->{owner} = $widget; + $TOOLTIP->{owner}->emit ("tooltip_show") if $TOOLTIP->{owner}; return if $ENV{CFPLUS_DEBUG} & 8; @@ -44,6 +46,7 @@ } $TOOLTIP->hide; + $TOOLTIP->{owner}->emit ("tooltip_hide") if $TOOLTIP->{owner}; delete $TOOLTIP->{owner}; }); @@ -267,6 +270,10 @@ %$self = (); } +sub TO_JSON { + { __widget_ref__ => $_[0]{s_id} } +} + sub show { my ($self) = @_; @@ -315,8 +322,8 @@ return if $self->{visible} == $visible; - $visible ? $self->hide - : $self->show; + $visible ? $self->show + : $self->hide; } sub toggle_visibility { @@ -1028,7 +1035,7 @@ package CFPlus::UI::ScrolledWindow; -our @ISA = CFPlus::UI::HBox::; +our @ISA = CFPlus::UI::Table::; sub new { my ($class, %arg) = @_; @@ -1037,22 +1044,43 @@ my $self; - my $slider = new CFPlus::UI::Slider + my $hslider = new CFPlus::UI::Slider + vertical => 0, + range => [0, 0, 1, 0.01], # HACK fix + on_changed => sub { + $self->{hpos} = $_[1]; + $self->{vp}->set_offset ($self->{hpos}, $self->{vpos}); + }, + ; + + my $vslider = new CFPlus::UI::Slider vertical => 1, range => [0, 0, 1, 0.01], # HACK fix on_changed => sub { - $self->{vp}->set_offset (0, $_[1]); + $self->{vpos} = $_[1]; + $self->{vp}->set_offset ($self->{hpos}, $self->{vpos}); }, ; $self = $class->SUPER::new ( - vp => (new CFPlus::UI::ViewPort expand => 1), + scroll_x => 0, + scroll_y => 1, can_events => 1, - slider => $slider, + hslider => $hslider, + vslider => $vslider, + col_expand => [1, 0], + row_expand => [1, 0], %arg, ); - $self->SUPER::add ($self->{vp}, $self->{slider}); + $self->{vp} = new CFPlus::UI::ViewPort + expand => 1, + scroll_x => $self->{scroll_x}, + scroll_y => $self->{scroll_y}, + ; + + $self->SUPER::add (0, 0, $self->{vp}); + $self->add ($child) if $child; $self @@ -1069,9 +1097,9 @@ sub invoke_mouse_wheel { my ($self, $ev) = @_; - return 0 unless $ev->{dy}; # only vertical movements + return 0 unless $ev->{dy}; # only vertical movements for now - $self->{slider}->emit (mouse_wheel => $ev); + $self->{vslider}->emit (mouse_wheel => $ev); 1 } @@ -1079,14 +1107,31 @@ sub update_slider { my ($self) = @_; - $self->{slider}->set_range ([$self->{slider}{range}[0], 0, $self->{vp}->child->{h}, $self->{vp}{h}, 1]); + my $child = ($self->{vp} or return)->child; + + my ($w1, $w2) = ($child->{w}, $self->{vp}{w}); + $self->{hslider}->set_range ([$self->{hslider}{range}[0], 0, $w1, $w2, 1]); + + my $visible = $w1 > $w2; + if ($visible != $self->{hslider}{visible}) { + $visible ? $self->SUPER::add (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]); + + my $visible = $h1 > $h2; + if ($visible != $self->{vslider}{visible}) { + $visible ? $self->SUPER::add (1, 0, $self->{vslider}) + : $self->{vslider}->hide; + } } sub update { my ($self) = @_; $self->SUPER::update; - $self->update_slider; } @@ -1094,7 +1139,6 @@ my ($self, $w, $h) = @_; $self->update_slider; - $self->SUPER::invoke_size_allocate ($w, $h) } @@ -1475,7 +1519,9 @@ my $class = shift; $class->SUPER::new ( + children => [], col_expand => [], + row_expand => [], @_, ) } @@ -1484,6 +1530,7 @@ grep $_, map @$_, grep $_, @{ $_[0]{children} } } +# TODO: store row/col info in child widget and use standard add/del sub add { my ($self) = shift; @@ -1493,7 +1540,7 @@ $self->{children}[$y][$x] = $child; } - $self->{force_realloc} = 1; + $self->{force_realloc} = 1; $self->{force_size_alloc} = 1; $self->realloc; } @@ -1501,7 +1548,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? @@ -1560,16 +1611,21 @@ my $req_w = (sum @$ws) || 1; my $req_h = (sum @$hs) || 1; - # TODO: nicer code && do row_expand + # TODO: nicer code my @col_expand = @{$self->{col_expand}}; @col_expand = (1) x @$ws unless @col_expand; my $col_expand = (sum @col_expand) || 1; - # linearly scale sizes $ws->[$_] += $col_expand[$_] / $col_expand * ($w - $req_w) for 0 .. $#$ws; - $hs->[$_] *= 1 * $h / $req_h for 0 .. $#$hs; CFPlus::UI::harmonize $ws; + + my @row_expand = @{$self->{row_expand}}; + @row_expand = (1) x @$ws unless @row_expand; + my $row_expand = (sum @row_expand) || 1; + + $hs->[$_] += $row_expand[$_] / $row_expand * ($h - $req_h) for 0 .. $#$hs; + CFPlus::UI::harmonize $hs; my $y; @@ -1623,6 +1679,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::; @@ -1969,6 +2107,8 @@ my $text = $self->get_text; + $self->{cursor} = List::Util::max 0, List::Util::min $self->{cursor}, length $text; + if ($uni == 8) { substr $text, --$self->{cursor}, 1, "" if $self->{cursor}; } elsif ($uni == 127) { @@ -1978,15 +2118,25 @@ } elsif ($sym == CFPlus::SDLK_RIGHT) { ++$self->{cursor} if $self->{cursor} < length $self->{text}; } elsif ($sym == CFPlus::SDLK_HOME) { - $self->{cursor} = 0; + # what a hack + $self->{cursor} = + (substr $self->{text}, 0, $self->{cursor}) =~ /^(.*\012)/ + ? length $1 + : 0; } elsif ($sym == CFPlus::SDLK_END) { - $self->{cursor} = length $text; + # uh, again + $self->{cursor} = + (substr $self->{text}, $self->{cursor}) =~ /^([^\012]*)\012/ + ? $self->{cursor} + length $1 + : length $self->{text}; } elsif ($uni == 21) { # ctrl-u $text = ""; $self->{cursor} = 0; } elsif ($uni == 27) { $self->emit ('escape'); - } elsif ($uni >= 0x20 || $uni == 0x0d) { + } elsif ($uni == 0x0d) { + substr $text, $self->{cursor}++, 0, "\012"; + } elsif ($uni >= 0x20) { substr $text, $self->{cursor}++, 0, chr $uni; } else { return 0; @@ -2700,7 +2850,9 @@ my $delta = $self->{vertical} ? $ev->{dy} : $ev->{dx}; - $self->set_value ($self->{range}[0] + $delta * $self->{range}[3] * 0.2); + my $pagepart = $ev->{mod} & CFPlus::KMOD_SHIFT ? 1 : 0.2; + + $self->set_value ($self->{range}[0] + $delta * $self->{range}[3] * $pagepart); ! ! $delta } @@ -2820,6 +2972,7 @@ layout => (new CFPlus::Layout), par => [], + max_par => 0, height => 0, children => [ (new CFPlus::UI::Empty expand => 1), @@ -2954,6 +3107,10 @@ push @{$self->{par}}, $para; } + if (my $max = $self->{max_par}) { + shift @{$self->{par}} while @{$self->{par}} > $max; + } + $self->{need_reflow}++; $self->update; } @@ -3269,6 +3426,8 @@ my $class = shift; my $self = $class->SUPER::new ( + size_w => 32, + size_h => 8, aspect => 1, can_events => 0, @_, @@ -3282,17 +3441,49 @@ hard => 1, interval => $self->{animspeed}, cb => sub { + return unless $::CONN; + ++$widget->{frame}; - $widget->update; + $self->update_face; + $self->update; }, ); + + $self->update_face; } $self } +sub update_face { + my ($self) = @_; + + return unless $::CONN; + + if (my $anim = $::CONN->{anim}[$self->{anim}]) { + if ($anim && @$anim) { + delete $self->{wait_face}; + $self->{face} = $anim->[ $self->{frame} % @$anim ]; + } + } +} + sub size_request { - (32, 8) + my ($self) = @_; + + if ($::CONN) { + if (my $faceid = $::CONN->{faceid}[$self->{face}]) { + if (my $tex = $::CONN->{texture}[$faceid]) { + return ($self->{size_w} || $tex->{w}, $self->{size_h} || $tex->{h}); + } else { + $self->{wait_face} ||= $::CONN->connect_face_update ($faceid, sub { + $self->realloc; + }); + } + } + } + + ($self->{size_w} || 8, $self->{size_h} || 8) } sub update { @@ -3310,16 +3501,10 @@ $self->SUPER::_draw; - my $face; - - if ($self->{frame}) { - my $anim = $::CONN->{anim}[$self->{anim}]; - - $face = $anim->[ $self->{frame} % @$anim ] - if $anim && @$anim; - } + my $faceid = $::CONN->{faceid}[$self->{face}] + or return; - my $tex = $::CONN->{texture}[$::CONN->{faceid}[$face || $self->{face}]]; + my $tex = $::CONN->{texture}[$faceid]; if ($tex) { glEnable GL_TEXTURE_2D;