--- deliantra/Deliantra-Client/DC/UI.pm 2007/07/20 16:32:17 1.385 +++ deliantra/Deliantra-Client/DC/UI.pm 2007/07/22 19:34:59 1.411 @@ -115,8 +115,12 @@ if ($GRAB) { if ($ev->{button} == 4 || $ev->{button} == 5) { # mousewheel - $ev->{dx} = 0; - $ev->{dy} = $ev->{button} * 2 - 9; + my $delta = $ev->{button} * 2 - 9; + my $shift = $ev->{mod} & CFPlus::KMOD_SHIFT; + + $ev->{dx} = $shift ? $delta : 0; + $ev->{dy} = $shift ? 0 : $delta; + $GRAB->emit (mouse_wheel => $ev); } else { $GRAB->emit (button_down => $ev) @@ -549,17 +553,8 @@ $self->{parent} && $self->{parent}->emit ($signal, @args) } -sub find_widget { - my ($self, $x, $y) = @_; - - return () unless $self->{can_events}; - - return $self - if $x >= $self->{x} && $x < $self->{x} + $self->{w} - && $y >= $self->{y} && $y < $self->{y} + $self->{h}; - - () -} +#sub find_widget { +# in .xs sub set_parent { my ($self, $parent) = @_; @@ -600,52 +595,8 @@ # functions seems pointless. our ($draw_x, $draw_y, $draw_w, $draw_h); # screen rectangle being drawn -sub draw { - my ($self) = @_; - - return unless $self->{h} && $self->{w}; - - # update screen rectangle - local $draw_x = $draw_x + $self->{x}; - local $draw_y = $draw_y + $self->{y}; - - # skip widgets that are entirely outside the drawing area - return if ($draw_x + $self->{w} < 0) || ($draw_x >= $draw_w) - || ($draw_y + $self->{h} < 0) || ($draw_y >= $draw_h); - - glPushMatrix; - glTranslate $self->{x}, $self->{y}, 0; - - if ($self == $HOVER && $self->{can_hover}) { - glColor 1*0.2, 0.8*0.2, 0.5*0.2, 0.2; - glEnable GL_BLEND; - glBlendFunc GL_ONE, GL_ONE_MINUS_SRC_ALPHA; - glBegin GL_QUADS; - glVertex 0 , 0; - glVertex $self->{w}, 0; - glVertex $self->{w}, $self->{h}; - glVertex 0 , $self->{h}; - glEnd; - glDisable GL_BLEND; - } - - if ($ENV{CFPLUS_DEBUG} & 1) { - glPushMatrix; - glColor 1, 1, 0, 1; - glTranslate 0.375, 0.375; - glBegin GL_LINE_LOOP; - glVertex 0 , 0; - glVertex $self->{w} - 1, 0; - glVertex $self->{w} - 1, $self->{h} - 1; - glVertex 0 , $self->{h} - 1; - glEnd; - glPopMatrix; - #CFPlus::UI::Label->new (w => $self->{w}, h => $self->{h}, text => $self, fontsize => 0)->_draw; - } - - $self->_draw; - glPopMatrix; -} +#sub draw { +#CFPlus.xs sub _draw { my ($self) = @_; @@ -653,7 +604,6 @@ warn "no draw defined for $self\n"; } -my $cntx;#d# sub DESTROY { my ($self) = @_; @@ -748,7 +698,7 @@ ); $self->add (@$children) - if $children; + if $children && @$children; $self } @@ -767,6 +717,7 @@ $_->set_parent ($self) for @widgets; + # TODO: only do this in widgets that need it, e.g. root, fixed use sort 'stable'; $self->{children} = [ @@ -775,6 +726,8 @@ ]; $self->realloc; + + map $_+0, @widgets } sub children { @@ -795,7 +748,7 @@ sub clear { my ($self) = @_; - my $children = delete $self->{children}; + my $children = $self->{children}; $self->{children} = []; for (@$children) { @@ -965,8 +918,8 @@ my ($w, $h) = @{$self->child}{qw(req_w req_h)}; - $w = 10 if $self->{scroll_x}; - $h = 10 if $self->{scroll_y}; + $w = 1 if $self->{scroll_x}; + $h = 1 if $self->{scroll_y}; ($w, $h) } @@ -1022,7 +975,7 @@ if ( $x >= $self->{x} && $x < $self->{x} + $self->{w} && $y >= $self->{y} && $y < $self->{y} + $self->{h} ) { - $self->child->find_widget ($x + $self->{view_x}, $y + $self->{view_y}) + $self->child->find_widget ($x + $self->{view_x}, $y + $self->{view_y}) } else { $self->CFPlus::UI::Base::find_widget ($x, $y) } @@ -1053,6 +1006,8 @@ my $self; my $hslider = new CFPlus::UI::Slider + col => 0, + row => 1, vertical => 0, range => [0, 0, 1, 0.01], # HACK fix on_changed => sub { @@ -1062,6 +1017,8 @@ ; my $vslider = new CFPlus::UI::Slider + col => 1, + row => 0, vertical => 1, range => [0, 0, 1, 0.01], # HACK fix on_changed => sub { @@ -1082,6 +1039,8 @@ ); $self->{vp} = new CFPlus::UI::ViewPort + col => 0, + row => 0, expand => 1, scroll_x => $self->{scroll_x}, scroll_y => $self->{scroll_y}, @@ -1093,17 +1052,20 @@ 0 }, + on_size_allocate => sub { + my ($vp, $w, $h) = @_; + $vp->{parent}->update_slider; + 0 + }, ; - $self->SUPER::add_at (0, 0, $self->{vp}); + $self->SUPER::add ($self->{vp}); $self->add ($child) if $child; $self } -#TODO# update range on size_allocate depending on child - sub add { my ($self, $widget) = @_; @@ -1115,38 +1077,54 @@ 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]); + if ($self->{scroll_x}) { + my ($w1, $w2) = ($child->{req_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_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]); - - my $visible = $h1 > $h2; - if ($visible != $self->{vslider}{visible}) { - $visible ? $self->SUPER::add_at (1, 0, $self->{vslider}) - : $self->{vslider}->hide; + my $visible = $w1 > $w2; + if ($visible != $self->{hslider_visible}) { + $self->{hslider_visible} = $visible; + $visible ? $self->SUPER::add ($self->{hslider}) + : $self->SUPER::remove ($self->{hslider}); + } + } + + if ($self->{scroll_y}) { + my ($h1, $h2) = ($child->{req_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}) { + $self->{vslider_visible} = $visible; + $visible ? $self->SUPER::add ($self->{vslider}) + : $self->SUPER::remove ($self->{vslider}); + } } } -sub update { - my ($self) = @_; +sub start_dragging { + my ($self, $ev) = @_; - $self->SUPER::update; - $self->update_slider; + $self->grab_focus; + + my $ox = $self->{vp}{view_x}; + my $oy = $self->{vp}{view_y}; + + $self->{motion} = sub { + my ($ev, $x, $y) = @_; + + $ox -= $ev->{xrel}; + $oy -= $ev->{yrel}; + + $self->{vp}->set_offset ($ox, $oy); + }; } sub invoke_mouse_wheel { my ($self, $ev) = @_; - return 0 unless $ev->{dy}; # only vertical movements for now - - $self->{vslider}->emit (mouse_wheel => $ev); + $self->{vslider}->emit (mouse_wheel => $ev) if $self->{vslider_visible}; + $self->{hslider}->emit (mouse_wheel => $ev) if $self->{hslider_visible}; 1 } @@ -1155,18 +1133,7 @@ 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; - }; - + $self->start_dragging ($ev); return 1; } @@ -1586,7 +1553,7 @@ package CFPlus::UI::Table; -our @ISA = CFPlus::UI::Base::; +our @ISA = CFPlus::UI::Container::; use List::Util qw(max sum); @@ -1596,81 +1563,66 @@ my $class = shift; $class->SUPER::new ( - children => [], col_expand => [], row_expand => [], @_, ) } -sub children { - 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, @widgets) = @_; + + for my $child (@widgets) { + $child->{rowspan} ||= 1; + $child->{colspan} ||= 1; + } - Carp::cluck "please use the add_at method instead of calling add, thank you.\n";#d# - $self->add_at (@_); + $self->SUPER::add (@widgets); } sub add_at { my $self = shift; + my @widgets; + while (@_) { my ($col, $row, $child) = splice @_, 0, 3, (); - $child->set_parent ($self); - $self->{children}[$row][$col] = $child; - } - - $self->{force_realloc} = 1; - $self->{force_size_alloc} = 1; - $self->realloc; -} - -sub remove { - my ($self, $child) = @_; + $child->{row} = $row; + $child->{col} = $col; - for (@{ $self->{children} }) { - for (@{ $_ || [] }) { - $_ = undef if $_ == $child; - } + push @widgets, $child; } + + $self->add (@widgets); } -# TODO: move to container class maybe? send children a signal on removal? -sub clear { +sub get_wh { my ($self) = @_; + my (@w, @h); + my @children = $self->children; - delete $self->{children}; - - for (@children) { - delete $_->{parent}; - $_->hide; - } - $self->realloc; -} + # first pass, columns + for my $widget (sort { $a->{colspan} <=> $b->{colspan} } @children) { + my ($c, $w, $cs) = @$widget{qw(col req_w colspan)}; -sub get_wh { - my ($self) = @_; + my $sw = sum @w[$c .. $c + $cs - 1]; - my (@w, @h); + if ($w > $sw) { + $_ += ($w - $sw) / ($sw ? $sw / $_ : $cs) for @w[$c .. $c + $cs - 1]; + } + } - for my $y (0 .. $#{$self->{children}}) { - my $row = $self->{children}[$y] - or next; - - for my $x (0 .. $#$row) { - my $widget = $row->[$x] - or next; - my ($w, $h) = @$widget{qw(req_w req_h)}; + # second pass, rows + for my $widget (sort { $a->{rowspan} <=> $b->{rowspan} } @children) { + my ($r, $h, $rs) = @$widget{qw(row req_h rowspan)}; - $w[$x] = max $w[$x], $w; - $h[$y] = max $h[$y], $h; + my $sh = sum @h[$r .. $r + $rs - 1]; + + if ($h > $sh) { + $_ += ($h - $sh) / ($sh ? $sh / $_ : $rs) for @h[$r .. $r + $rs - 1]; } } @@ -1696,7 +1648,7 @@ my $req_w = (sum @$ws) || 1; my $req_h = (sum @$hs) || 1; - # TODO: nicer code + # now linearly scale the rows/columns to the allocated size my @col_expand = @{$self->{col_expand}}; @col_expand = (1) x @$ws unless @col_expand; my $col_expand = (sum @col_expand) || 1; @@ -1713,55 +1665,21 @@ CFPlus::UI::harmonize $hs; - my $y; - - for my $r (0 .. $#{$self->{children}}) { - my $row = $self->{children}[$r] - or next; + my @x; for (0 .. $#$ws) { $x[$_ + 1] = $x[$_] + $ws->[$_] } + my @y; for (0 .. $#$hs) { $y[$_ + 1] = $y[$_] + $hs->[$_] } - my $x = 0; - my $row_h = $hs->[$r]; - - for my $c (0 .. $#$row) { - my $col_w = $ws->[$c]; - - if (my $widget = $row->[$c]) { - $widget->configure ($x, $y, $col_w, $row_h); - } + for my $widget ($self->children) { + my ($r, $c, $w, $h, $rs, $cs) = @$widget{qw(row col req_w req_h rowspan colspan)}; - $x += $col_w; - } - - $y += $row_h; + $widget->configure ( + $x[$c], $y[$r], + $x[$c + $cs] - $x[$c], $y[$r + $rs] - $y[$r], + ); } 1 } -sub find_widget { - my ($self, $x, $y) = @_; - - $x -= $self->{x}; - $y -= $self->{y}; - - my $res; - - for (grep $_, map @$_, grep $_, @{ $self->{children} }) { - $res = $_->find_widget ($x, $y) - and return $res; - } - - $self->SUPER::find_widget ($x + $self->{x}, $y + $self->{y}) -} - -sub _draw { - my ($self) = @_; - - for (grep $_, @{$self->{children}}) { - $_->draw for grep $_, @$_; - } -} - ############################################################################# package CFPlus::UI::Fixed; @@ -1770,19 +1688,10 @@ 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) = @_; + my ($rel, $val, $max) = @_; - $mode eq "abs" ? $val - : $mode eq "rel" ? $val * $max - : 0 + $rel ? $val * $max : $val } sub size_request { @@ -1792,14 +1701,12 @@ # 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}; + unless ($child->{c_rel}) { + my $x = $child->{c_x}; + my $y = $child->{c_y}; - $x1 = min $x1, $x; $x2 = max $x2, $x + $w; - $y1 = min $y1, $y; $y2 = max $y2, $y + $h; + $x1 = min $x1, $x; $x2 = max $x2, $x + $child->{req_w}; + $y1 = min $y1, $y; $y2 = max $y2, $y + $child->{req_h}; } } @@ -1808,16 +1715,12 @@ # now layout remaining widgets for my $child ($self->visible_children) { - my ($pos, $x, $y, $size, $w, $h) = @{ $child->{_fixed} }; + if ($child->{c_rel}) { + my $x = _scale $child->{c_rel}, $child->{c_x}, $W; + my $y = _scale $child->{c_rel}, $child->{c_y}, $H; - 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; + $x1 = min $x1, $x; $x2 = max $x2, $x + $child->{req_w}; + $y1 = min $y1, $y; $y2 = max $y2, $y + $child->{req_h}; } } @@ -1831,14 +1734,13 @@ my ($self, $W, $H) = @_; for my $child ($self->visible_children) { - my ($pos, $x, $y, $size, $w, $h) = @{ $child->{_fixed} }; + my $x = _scale $child->{c_rel}, $child->{c_x}, $W; + my $y = _scale $child->{c_rel}, $child->{c_y}, $H; - $x = _scale $pos, $x, $W; - $y = _scale $pos, $x, $H; - $w = _scale $size, $w, $child->{req_w}; - $h = _scale $size, $h, $child->{req_h}; + $x += $child->{c_halign} * $child->{req_w}; + $y += $child->{c_valign} * $child->{req_h}; - $child->configure ($x, $y, $w, $h); + $child->configure ($x, $y, $child->{req_w}, $child->{req_h}); } 1 @@ -2111,12 +2013,26 @@ : ($self->{h} - $size->[1]) * 0.5); }; - my $w = List::Util::min $self->{w} + 4, $size->[0]; - my $h = List::Util::min $self->{h} + 2, $size->[1]; +# unless ($self->{list}) { +# $self->{list} = CFPlus::OpenGL::glGenList; +# CFPlus::OpenGL::glNewList $self->{list}; +# $self->{layout}->render ($self->{ox}, $self->{oy}, $self->{style}); +# CFPlus::OpenGL::glEndList; +# } +# +# CFPlus::OpenGL::glCallList $self->{list}; $self->{layout}->render ($self->{ox}, $self->{oy}, $self->{style}); } +#sub destroy { +# my ($self) = @_; +# +# CFPlus::OpenGL::glDeleteList delete $self->{list} if $self->{list}; +# +# $self->SUPER::destroy; +#} + ############################################################################# package CFPlus::UI::EntryBase; @@ -2910,7 +2826,9 @@ $self->{click} = [$self->{range}[0], $self->{vertical} ? $y : $x]; - $self->invoke_mouse_motion ($ev, $x, $y) + $self->invoke_mouse_motion ($ev, $x, $y); + + 1 } sub invoke_mouse_motion { @@ -2940,7 +2858,7 @@ $self->set_value ($self->{range}[0] + $delta * $self->{range}[3] * $pagepart); - ! ! $delta + 1 } sub update { @@ -3523,7 +3441,7 @@ CFPlus::weaken (my $widget = $self); $widget->{animspeed} = List::Util::max 0.05, $widget->{animspeed}; - $widget->{anim_start} = $self->{animspeed} * Event::time / $self->{animspeed}; + $widget->{anim_start} = $self->{animspeed} * int Event::time / $self->{animspeed}; $self->{timer} = Event->timer ( parked => 1, cb => sub { @@ -3570,6 +3488,7 @@ if ($anim && @$anim) { delete $self->{wait_face}; $self->{face} = $anim->[ $self->{frame} % @$anim ]; + $self->{tex} = $::CONN->{texture}[ $::CONN->{faceid}[$self->{face}] ]; } } } @@ -3580,6 +3499,7 @@ if ($::CONN) { if (my $faceid = $::CONN->{faceid}[$self->{face}]) { if (my $tex = $::CONN->{texture}[$faceid]) { + $self->{tex} = $tex; return ($self->{size_w} || $tex->{w}, $self->{size_h} || $tex->{h}); } else { $self->{wait_face} ||= $::CONN->connect_face_update ($faceid, sub { @@ -3611,16 +3531,9 @@ sub _draw { my ($self) = @_; - return unless $::CONN; - $self->SUPER::_draw; - my $faceid = $::CONN->{faceid}[$self->{face}] - or return; - - my $tex = $::CONN->{texture}[$faceid]; - - if ($tex) { + if (my $tex = $self->{tex}) { glEnable GL_TEXTURE_2D; glTexEnv GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE; glColor 0, 0, 0, 1; @@ -3840,11 +3753,15 @@ CFPlus::weaken $self; - $self->{buttonbar}->add (new CFPlus::UI::Button - markup => $title, - tooltip => $tooltip, - on_activate => sub { $self->set_current_page ($widget) }, - ); + unless (ref $title) { + $title = new CFPlus::UI::Button + markup => $title, + tooltip => $tooltip, + ; + } + + $title->connect (activate => sub { $self->set_current_page ($widget) }); + $self->{buttonbar}->add ($title); $self->{multiplexer}->add ($widget); } @@ -4186,7 +4103,7 @@ for values %{delete $self->{refresh_hook}}; } - if ($self->{realloc}) { + while ($self->{realloc}) { my %queue; my @queue; my $widget; @@ -4243,40 +4160,37 @@ delete $self->{realloc}{$widget+0}; } - } - while (my $size_alloc = delete $self->{size_alloc}) { - my @queue = sort { $b->{visible} <=> $a->{visible} } - values %$size_alloc; - - while () { - my $widget = pop @queue || last; + while (my $size_alloc = delete $self->{size_alloc}) { + my @queue = sort { $a->{visible} <=> $b->{visible} } + values %$size_alloc; - my ($w, $h) = @$widget{qw(alloc_w alloc_h)}; + while () { + my $widget = pop @queue || last; - $w = 0 if $w < 0; - $h = 0 if $h < 0; + my ($w, $h) = @$widget{qw(alloc_w alloc_h)}; - $w = max $widget->{min_w}, $w; - $h = max $widget->{min_h}, $h; + $w = max $widget->{min_w}, $w; + $h = max $widget->{min_h}, $h; # $w = min $self->{w} - $widget->{x}, $w if $self->{w}; # $h = min $self->{h} - $widget->{y}, $h if $self->{h}; - $w = min $widget->{max_w}, $w if exists $widget->{max_w}; - $h = min $widget->{max_h}, $h if exists $widget->{max_h}; + $w = min $widget->{max_w}, $w if exists $widget->{max_w}; + $h = min $widget->{max_h}, $h if exists $widget->{max_h}; - $w = int $w + 0.5; - $h = int $h + 0.5; + $w = int $w + 0.5; + $h = int $h + 0.5; - if ($widget->{w} != $w || $widget->{h} != $h || delete $widget->{force_size_alloc}) { - $widget->{old_w} = $widget->{w}; - $widget->{old_h} = $widget->{h}; + if ($widget->{w} != $w || $widget->{h} != $h || delete $widget->{force_size_alloc}) { + $widget->{old_w} = $widget->{w}; + $widget->{old_h} = $widget->{h}; - $widget->{w} = $w; - $widget->{h} = $h; + $widget->{w} = $w; + $widget->{h} = $h; - $widget->emit (size_allocate => $w, $h); + $widget->emit (size_allocate => $w, $h); + } } } }