--- deliantra/Deliantra-Client/DC/UI.pm 2006/06/05 22:30:35 1.290 +++ deliantra/Deliantra-Client/DC/UI.pm 2006/06/13 10:28:38 1.303 @@ -274,8 +274,8 @@ $_->set_invisible for $self->children; - delete $self->{root}; delete $self->{visible}; + delete $self->{root}; undef $GRAB if $GRAB == $self; undef $HOVER if $HOVER == $self; @@ -317,8 +317,8 @@ sub move_abs { my ($self, $x, $y, $z) = @_; - $self->{x} = List::Util::max 0, int $x; - $self->{y} = List::Util::max 0, int $y; + $self->{x} = List::Util::max 0, List::Util::min $self->{root}{w} - $self->{w}, int $x; + $self->{y} = List::Util::max 0, List::Util::min $self->{root}{h} - $self->{h}, int $y; $self->{z} = $z if defined $z; $self->update; @@ -595,7 +595,9 @@ my ($self) = @_; delete $WIDGET{$self+0}; - #$self->deactivate; + + eval { $self->destroy }; + warn "exception during widget destruction: $@" if $@ & $@ != /during global destruction/; } ############################################################################# @@ -770,8 +772,7 @@ sub add { my ($self, $child) = @_; - $self->{children} = []; - + $self->SUPER::remove ($_) for @{ $self->{children} }; $self->SUPER::add ($child); } @@ -1074,8 +1075,6 @@ sub new { my ($class, %arg) = @_; - my $title = delete $arg{title}; - my $self = $class->SUPER::new ( bg => [1, 1, 1, 1], border_bg => [1, 1, 1, 1], @@ -1086,12 +1085,21 @@ %arg, ); - $self->{title} = new CFClient::UI::Label + $self->{title_widget} = new CFClient::UI::Label align => 0, valign => 1, - text => $title, - fontsize => $self->{border} - if defined $title; + text => $self->{title}, + fontsize => $self->{border}, + if exists $self->{title}; + + unless ($self->{no_close_button}) { + $self->{close_btn} = + new CFClient::UI::ImageButton + image => 'x1_close.png', + on_activate => sub { $self->hide }; + + $self->CFClient::UI::Container::add ($self->{close_btn}); + } $self } @@ -1100,7 +1108,8 @@ my ($self, @widgets) = @_; $self->SUPER::add (@widgets); - $self->CFClient::UI::Container::add ($self->{title}) if $self->{title}; + $self->CFClient::UI::Container::add ($self->{close_btn}) if $self->{close_btn}; + $self->CFClient::UI::Container::add ($self->{title_widget}) if $self->{title_widget}; } sub border { @@ -1110,8 +1119,11 @@ sub size_request { my ($self) = @_; - $self->{title}->size_request - if $self->{title}; + $self->{title_widget}->size_request + if $self->{title_widget}; + + $self->{close_btn}->size_request + if $self->{close_btn}; my ($w, $h) = $self->SUPER::size_request; @@ -1124,18 +1136,21 @@ sub size_allocate { my ($self, $w, $h) = @_; - if ($self->{title}) { - $self->{title}{w} = $w; - $self->{title}{h} = $h; - $self->{title}->size_allocate ($w, $h); + if ($self->{title_widget}) { + $self->{title_widget}{w} = $w; + $self->{title_widget}{h} = $h; + $self->{title_widget}->size_allocate ($w, $h); } my $border = $self->border; $h -= List::Util::max 0, $border * 2; $w -= List::Util::max 0, $border * 2; - + $self->child->configure ($border, $border, $w, $h); + + $self->{close_btn}->configure ($self->{w} - (2 * $border), 0, $border, $border) + if $self->{close_btn}; } sub button_down { @@ -1191,6 +1206,9 @@ sub button_up { my ($self, $ev, $x, $y) = @_; + $self->{close_btn}->button_up ($ev, $x, $y) + if $self->{close_btn}; + !!delete $self->{motion} } @@ -1235,10 +1253,15 @@ $child->draw; - if ($self->{title}) { + if ($self->{title_widget}) { glTranslate 0, $border - $self->{h}; - $self->{title}->_draw; + $self->{title_widget}->_draw; + + glTranslate 0, - ($border - $self->{h}); } + + $self->{close_btn}->draw + if $self->{close_btn}; } ############################################################################# @@ -1273,6 +1296,12 @@ $self->realloc; } +sub remove { + my ($self, $child) = @_; + + # TODO: not yet implemented +} + # TODO: move to container class maybe? send children a signal on removal? sub clear { my ($self) = @_; @@ -1660,13 +1689,16 @@ glEnable GL_TEXTURE_2D; + my $w = List::Util::min $self->{w} + 4, $tex->{w}; + my $h = List::Util::min $self->{h} + 2, $tex->{h}; + if ($tex->{format} == GL_ALPHA) { glTexEnv GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE; glColor @{$self->{fg}}; - $tex->draw_quad_alpha ($self->{ox}, $self->{oy}); + $tex->draw_quad_alpha ($self->{ox}, $self->{oy}, $w, $h); } else { glTexEnv GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE; - $tex->draw_quad_alpha_premultiplied ($self->{ox}, $self->{oy}); + $tex->draw_quad_alpha_premultiplied ($self->{ox}, $self->{oy}, $w, $h); } glDisable GL_TEXTURE_2D; @@ -1693,6 +1725,7 @@ valign => 0, can_events => 1, #text => ... + #hidden => "*", @_ ) } @@ -1953,6 +1986,44 @@ ############################################################################# +package CFClient::UI::ImageButton; + +our @ISA = CFClient::UI::Image::; + +use CFClient::OpenGL; + +my %textures; + +sub new { + my $class = shift; + + my $self = $class->SUPER::new ( + padding_x => 4, + padding_y => 4, + fg => [1, 1, 1], + active_fg => [0, 0, 1], + can_hover => 1, + align => 0, + valign => 0, + can_events => 1, + @_ + ); +} + +sub activate { } + +sub button_up { + my ($self, $ev, $x, $y) = @_; + + $self->emit ("activate") + if $x >= 0 && $x < $self->{w} + && $y >= 0 && $y < $self->{h}; + + 1 +} + +############################################################################# + package CFClient::UI::CheckBox; our @ISA = CFClient::UI::DrawBG::; @@ -2305,8 +2376,10 @@ ($range, $self->{range}) = ($self->{range}, $range); - $self->update - if "@$range" ne "@{$self->{range}}"; + if ("@$range" ne "@{$self->{range}}") { + $self->update; + $self->set_value ($self->{range}[0]); + } } sub set_value { @@ -2463,7 +2536,7 @@ ############################################################################# -package CFClient::UI::TextView; +package CFClient::UI::TextScroller; our @ISA = CFClient::UI::HBox::; @@ -2475,6 +2548,7 @@ my $self = $class->SUPER::new ( fontsize => 1, can_events => 0, + indent => 0, #font => default_font @_, @@ -2507,6 +2581,7 @@ $self->{layout}->set_font ($self->{font}) if $self->{font}; $self->{layout}->set_height ($self->{fontsize} * $::FONTSIZE); $self->{layout}->set_width ($self->{children}[0]{w}); + $self->{layout}->set_indent ($self->{fontsize} * $::FONTSIZE * $self->{indent}); $self->reflow; } @@ -2518,6 +2593,7 @@ $layout->set_height ($self->{fontsize} * $::FONTSIZE); $layout->set_width ($self->{children}[0]{w} - $indent); + $layout->set_indent ($self->{fontsize} * $::FONTSIZE * $self->{indent}); $layout->set_markup ($text); $layout->size @@ -2566,7 +2642,7 @@ delete $self->{texture}; - $ROOT->on_post_alloc ($self, sub { + $ROOT->on_post_alloc ($self => sub { my ($W, $H) = @{$self->{children}[0]}{qw(w h)}; if (delete $self->{need_reflow}) { @@ -2579,6 +2655,7 @@ for (@{$self->{par}}) { if (1 || $_->[0] >= $W) { # TODO: works,but needs reconfigure etc. support $layout->set_width ($W - $_->[3]); + $layout->set_indent ($self->{fontsize} * $::FONTSIZE * $self->{indent}); $layout->set_markup ($_->[4]); my ($w, $h) = $layout->size; $_->[0] = $w + $_->[3]; @@ -2591,7 +2668,7 @@ $self->{height} = $height; $self->{children}[1]->set_range ([$height, 0, $height, $H, 1]); - + delete $self->{texture}; } @@ -2620,6 +2697,7 @@ if ($y0 < $y + $h && $y < $y1) { $layout->set_foreground (@{ $par->[2] }); $layout->set_width ($W - $par->[3]); + $layout->set_indent ($self->{fontsize} * $::FONTSIZE * $self->{indent}); $layout->set_markup ($par->[4]); my ($w, $h, $data, $format, $internalformat) = $layout->render; @@ -2744,6 +2822,9 @@ . "visible $widget->{visible}"; } + $tooltip =~ s/^\n+//; + $tooltip =~ s/\n+$//; + $self->add (new CFClient::UI::Label markup => $tooltip, max_w => ($widget->{tooltip_width} || 0.25) * $::WIDTH, @@ -2780,7 +2861,7 @@ my ($x, $y) = $widget->coord2global ($widget->{w}, 0); ($x, $y) = $widget->coord2global (-$self->{w}, 0) - if $x + $self->{w} > $::WIDTH; + if $x + $self->{w} > $self->{root}{w}; $self->move_abs ($x, $y); }); @@ -2885,13 +2966,13 @@ } } -sub DESTROY { +sub destroy { my ($self) = @_; $self->{timer}->cancel if $self->{timer}; - $self->SUPER::DESTROY; + $self->SUPER::destroy; } ############################################################################# @@ -2922,14 +3003,15 @@ $self->add ($self->{vbox} = new CFClient::UI::VBox); for my $item (@{ $self->{items} }) { - my ($widget, $cb) = @$item; + my ($widget, $cb, $tooltip) = @$item; # handle various types of items, only text for now if (!ref $widget) { $widget = new CFClient::UI::Label can_hover => 1, can_events => 1, - text => $widget; + markup => $widget, + tooltip => $tooltip } $self->{item}{$widget} = $item; @@ -3090,6 +3172,62 @@ ############################################################################# +package CFClient::UI::Combobox; + +use utf8; + +our @ISA = CFClient::UI::Button::; + +sub new { + my $class = shift; + + my $self = $class->SUPER::new ( + options => [], # [value, title, longdesc], ... + value => undef, + @_, + ); + + $self->_set_value ($self->{value}); + + $self +} + +sub button_down { + my ($self, $ev) = @_; + + my @menu_items; + + for (@{ $self->{options} }) { + my ($value, $title, $tooltip) = @$_; + + push @menu_items, [$tooltip || $title, sub { $self->set_value ($value) }]; + } + + CFClient::UI::Menu->new (items => \@menu_items)->popup ($ev); +} + +sub _set_value { + my ($self, $value) = @_; + + my ($item) = grep $_->[0] eq $value, @{ $self->{options} } + or return; + + $self->{value} = $item->[0]; + $self->set_markup ("$item->[1] ⇓"); + $self->set_tooltip ($item->[2]); +} + +sub set_value { + my ($self, $value) = @_; + + return unless $self->{value} ne $value; + + $self->_set_value ($value); + $self->_emit (changed => $value); +} + +############################################################################# + package CFClient::UI::Statusbox; our @ISA = CFClient::UI::VBox::; @@ -3194,7 +3332,7 @@ $item->{count} = 1; $item->{text} = $item->{tooltip} = $text; } - $item->{id} = ++$self->{id}; + $item->{id} += 0.2;#d# $item->{timeout} = $timeout; delete $item->{label}; } else { @@ -3223,12 +3361,12 @@ $self->SUPER::reconfigure; } -sub DESTROY { +sub destroy { my ($self) = @_; $self->{timer}->cancel; - $self->SUPER::DESTROY; + $self->SUPER::destroy; } ############################################################################# @@ -3486,12 +3624,18 @@ ) } +my $TOOLTIP_ALL = "\n\nLeft click - ready spell\nMiddle click - invoke spell\nRight click - further options"; + +my @TOOLTIP_NAME = (align => -1, can_events => 1, can_hover => 1, tooltip => + "Name. The name of the spell.$TOOLTIP_ALL"); +my @TOOLTIP_SKILL = (align => -1, can_events => 1, can_hover => 1, tooltip => + "Skill. The skill (or magic school) required to be able to attempt casting this spell.$TOOLTIP_ALL"); my @TOOLTIP_LVL = (align => 1, can_events => 1, can_hover => 1, tooltip => - "Level. Minimum level the caster needs in the associated skill to be able to attempt casting this spell."); + "Level. Minimum level the caster needs in the associated skill to be able to attempt casting this spell.$TOOLTIP_ALL"); my @TOOLTIP_SP = (align => 1, can_events => 1, can_hover => 1, tooltip => - "Spell points / Grace points. Amount of spell or grace points used by each invocation."); + "Spell points / Grace points. Amount of spell or grace points used by each invocation.$TOOLTIP_ALL"); my @TOOLTIP_DMG = (align => 1, can_events => 1, can_hover => 1, tooltip => - "Damage. The amount of damage the spell deals when it hits."); + "Damage. The amount of damage the spell deals when it hits.$TOOLTIP_ALL"); sub rebuild_spell_list { my ($self) = @_; @@ -3499,10 +3643,13 @@ $CFClient::UI::ROOT->on_refresh ($self => sub { $self->clear; - $self->add (1, 0, new CFClient::UI::Label text => "Spell Name"); - $self->add (2, 0, new CFClient::UI::Label text => "Lvl" , @TOOLTIP_LVL); - $self->add (3, 0, new CFClient::UI::Label text => "Sp/Gp", @TOOLTIP_SP); - $self->add (4, 0, new CFClient::UI::Label text => "Dmg" , @TOOLTIP_DMG); + return unless $::CONN; + + $self->add (1, 0, new CFClient::UI::Label text => "Spell Name", @TOOLTIP_NAME); + $self->add (2, 0, new CFClient::UI::Label text => "Skill", @TOOLTIP_SKILL); + $self->add (3, 0, new CFClient::UI::Label text => "Lvl" , @TOOLTIP_LVL); + $self->add (4, 0, new CFClient::UI::Label text => "Sp/Gp", @TOOLTIP_SP); + $self->add (5, 0, new CFClient::UI::Label text => "Dmg" , @TOOLTIP_DMG); my $row = 0; @@ -3511,11 +3658,38 @@ $row++; + my $spell_cb = sub { + my ($widget, $ev) = @_; + + if ($ev->{button} == 1) { + $::CONN->user_send ("cast $spell->{name}"); + } elsif ($ev->{button} == 2) { + $::CONN->user_send ("invoke $spell->{name}"); + } elsif ($ev->{button} == 3) { + (new CFClient::UI::Menu + items => [ + ["bind cast $spell->{name} to a key" => sub { $::BIND_EDITOR->do_quick_binding (["cast $spell->{name}"]) }], + ["bind invoke $spell->{name} to a key" => sub { $::BIND_EDITOR->do_quick_binding (["invoke $spell->{name}"]) }], + ], + )->popup ($ev); + } else { + return 0; + } + + 1 + }; + + my $tooltip = "$spell->{message}$TOOLTIP_ALL"; + + #TODO: add path info to tooltip + #$self->add (6, $row, new CFClient::UI::Label text => $spell->{path}); + $self->add (0, $row, new CFClient::UI::Face face => $spell->{face}, can_hover => 1, can_events => 1, - tooltip => $spell->{message}, + tooltip => $tooltip, + on_button_down => $spell_cb, ); $self->add (1, $row, new CFClient::UI::Label @@ -3523,19 +3697,14 @@ text => $spell->{name}, can_hover => 1, can_events => 1, - tooltip => $spell->{message}, + tooltip => $tooltip, + on_button_down => $spell_cb, ); - $self->add (2, $row, new CFClient::UI::Label text => $spell->{level}, @TOOLTIP_LVL); - $self->add (3, $row, new CFClient::UI::Label text => $spell->{mana} || $spell->{grace}, @TOOLTIP_SP); - $self->add (4, $row, new CFClient::UI::Label text => $spell->{damage}, @TOOLTIP_DMG); - - # TODO: should be done via popup - $self->add (5, $row, new CFClient::UI::Button - text => "bind", - tooltip => "bind spell readying (cast command) to key", - on_activate => sub { $::BIND_EDITOR->do_quick_binding (["cast $spell->{name}"]) }, - ); + $self->add (2, $row, new CFClient::UI::Label text => $::CONN->{skill_info}{$spell->{skill}}, @TOOLTIP_SKILL); + $self->add (3, $row, new CFClient::UI::Label text => $spell->{level}, @TOOLTIP_LVL); + $self->add (4, $row, new CFClient::UI::Label text => $spell->{mana} || $spell->{grace}, @TOOLTIP_SP); + $self->add (5, $row, new CFClient::UI::Label text => $spell->{damage}, @TOOLTIP_DMG); } }); } @@ -3554,6 +3723,13 @@ $self->rebuild_spell_list; } +sub clear_spells { + my ($self) = @_; + + $self->{spell} = {}; + $self->rebuild_spell_list; +} + ############################################################################# package CFClient::UI::Root;