--- deliantra/Deliantra-Client/DC/UI.pm 2006/06/05 22:30:35 1.290
+++ deliantra/Deliantra-Client/DC/UI.pm 2006/06/13 11:01:04 1.304
@@ -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;
}
#############################################################################
@@ -3382,13 +3520,14 @@
}
sub ask_for_bind {
- my ($self, $commit) = @_;
+ my ($self, $commit, $end_cb) = @_;
CFClient::Binder::open_binding_dialog (sub {
my ($mod, $sym) = @_;
$self->{binding} = [$mod, $sym]; # XXX: how to stop that memleak?
$self->update_binding_widgets;
$self->commit if $commit;
+ $end_cb->() if $end_cb;
});
}
@@ -3416,11 +3555,11 @@
# this is a shortcut method that asks for a binding
# and then just binds it.
sub do_quick_binding {
- my ($self, $cmds) = @_;
+ my ($self, $cmds, $end_cb) = @_;
$self->set_binding (undef, undef, $cmds, sub {
$::CFG->{bindings}->{$_[0]}->{$_[1]} = $_[2];
});
- $self->ask_for_bind (1);
+ $self->ask_for_bind (1, $end_cb);
}
sub update_binding_widgets {
@@ -3486,12 +3625,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 +3644,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 +3659,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 +3698,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 +3724,13 @@
$self->rebuild_spell_list;
}
+sub clear_spells {
+ my ($self) = @_;
+
+ $self->{spell} = {};
+ $self->rebuild_spell_list;
+}
+
#############################################################################
package CFClient::UI::Root;