ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/deliantra/Deliantra-Client/DC/MapWidget.pm
Revision: 1.53
Committed: Sun Jun 11 17:30:53 2006 UTC (17 years, 11 months ago) by root
Branch: MAIN
Changes since 1.52: +2 -1 lines
Log Message:
*** empty log message ***

File Contents

# User Rev Content
1 root 1.1 package CFClient::MapWidget;
2    
3     use strict;
4 root 1.14 use utf8;
5 root 1.1
6     use List::Util qw(min max);
7    
8 root 1.4 use CFClient::OpenGL;
9 root 1.1
10     our @ISA = CFClient::UI::Base::;
11    
12     sub new {
13     my $class = shift;
14    
15 root 1.20 my $self = $class->SUPER::new (
16 root 1.1 z => -1,
17     can_focus => 1,
18 root 1.4 list => glGenList,
19 root 1.51
20     smooth_matrix => [
21     0.05, 0.13, 0.05,
22     0.13, 0.30, 0.13,
23     0.05, 0.13, 0.05,
24     ],
25    
26 root 1.1 @_
27 root 1.20 );
28    
29 root 1.36 $self->{completer} = new CFClient::MapWidget::Command::
30     command => $self->{command},
31     can_focus => 1,
32 root 1.37 tooltip => "<b>The Command Completer</b>\n\n"
33     . "This is your central interface to send text commands to the server. "
34     . "To enter a verbatim command to send to the server, just type the command, "
35     . "followed by a space, and press return. "
36     . "Typing the initial letters of words (or just any letters) displays guesses "
37     . "for commands you might want to use.\n"
38     . "You can use the cursor-up and cursor-down keys to select between those guesses.\n"
39     . "<b>Right-Click</b> opens a menu where you cna select further options, sich as redefining keybindings.",
40 root 1.36 ;
41    
42 root 1.20 $self
43 root 1.1 }
44    
45 root 1.36 sub add_command {
46     my ($self, $command, $tooltip, $widget, $cb) = @_;
47    
48     (my $data = $command) =~ s/\\//g;
49    
50     $tooltip =~ s/^\s+//;
51     $tooltip = "<big>$data</big>\n\n$tooltip";
52     $tooltip =~ s/\s+$//;
53    
54     $self->{completer}{command}{$command} = [$data, $tooltip, $widget, $cb, ++$self->{command_id}];
55     }
56 root 1.4
57 root 1.36 sub clr_commands {
58     my ($self) = @_;
59 root 1.4
60 root 1.36 %{$self->{completer}{command}} = ();
61 root 1.4 }
62    
63 root 1.1 sub button_down {
64     my ($self, $ev, $x, $y) = @_;
65    
66     $self->focus_in;
67    
68 root 1.49 if ($ev->{button} == 1) {
69 root 1.50 my $sw = int $::WIDTH / (32 * $::CFG->{map_scale}) + 0.99;
70     my $sh = int $::HEIGHT / (32 * $::CFG->{map_scale}) + 0.99;
71 root 1.49
72 root 1.50 my $fx = int +($ev->{x} - $::CFG->{map_shift_x}) / (32 * $::CFG->{map_scale}) - 0.5 * $sw + 0.99;
73     my $fy = int +($ev->{y} - $::CFG->{map_shift_y}) / (32 * $::CFG->{map_scale}) - 0.5 * $sh + 0.99;
74 root 1.49
75 root 1.53 $::CONN->send (sprintf "lookat %d %d", $fx, $fy)
76     if $::CONN;
77 root 1.49
78     } elsif ($ev->{button} == 2) {
79 root 1.5 my ($ox, $oy) = ($ev->{x}, $ev->{y});
80 root 1.1 my ($bw, $bh) = ($::CFG->{map_shift_x}, $::CFG->{map_shift_y});
81    
82     $self->{motion} = sub {
83     my ($ev, $x, $y) = @_;
84    
85 root 1.5 ($x, $y) = ($ev->{x}, $ev->{y});
86 root 1.1
87     $::CFG->{map_shift_x} = $bw + $x - $ox;
88     $::CFG->{map_shift_y} = $bh + $y - $oy;
89    
90     $self->update;
91     };
92     }
93 root 1.47
94     1
95 root 1.1 }
96    
97     sub button_up {
98     my ($self, $ev, $x, $y) = @_;
99    
100     delete $self->{motion};
101 root 1.47
102     1
103 root 1.1 }
104    
105     sub mouse_motion {
106     my ($self, $ev, $x, $y) = @_;
107    
108 root 1.47 if ($self->{motion}) {
109     $self->{motion}->($ev, $x, $y);
110     } else {
111     return 0;
112     }
113    
114     1
115 root 1.1 }
116    
117     sub size_request {
118     (
119     1 + 32 * int $::WIDTH / 32,
120     1 + 32 * int $::HEIGHT / 32,
121     )
122     }
123    
124     sub update {
125     my ($self) = @_;
126    
127     $self->{need_update} = 1;
128     $self->SUPER::update;
129     }
130    
131 root 1.36 my %DIR = (
132     CFClient::SDLK_KP8, [1, "north"],
133     CFClient::SDLK_KP9, [2, "northeast"],
134     CFClient::SDLK_KP6, [3, "east"],
135     CFClient::SDLK_KP3, [4, "southeast"],
136     CFClient::SDLK_KP2, [5, "south"],
137     CFClient::SDLK_KP1, [6, "southwest"],
138     CFClient::SDLK_KP4, [7, "west"],
139     CFClient::SDLK_KP7, [8, "northwest"],
140    
141     CFClient::SDLK_UP, [1, "north"],
142     CFClient::SDLK_RIGHT, [3, "east"],
143     CFClient::SDLK_DOWN, [5, "south"],
144     CFClient::SDLK_LEFT, [7, "west"],
145     );
146    
147     sub key_down {
148     my ($self, $ev) = @_;
149    
150 root 1.47 return 0 unless $::CONN;
151 root 1.36
152     my $mod = $ev->{mod};
153     my $sym = $ev->{sym};
154     my $uni = $ev->{unicode};
155    
156     if ($sym == CFClient::SDLK_KP5) {
157     $::CONN->user_send ("stay fire");
158     } elsif ($uni == ord ",") {
159     $::CONN->user_send ("take");
160     } elsif ($uni == ord " ") {
161     $::CONN->user_send ("apply");
162 root 1.37 } elsif ($uni == ord ".") {
163     $::CONN->user_send ($self->{completer}{last_command})
164     if exists $self->{completer}{last_command};
165 root 1.36 } elsif ($uni == ord "\t") {
166 root 1.41 $::INV_WINDOW->toggle_visibility;
167 root 1.36 } elsif ($sym == CFClient::SDLK_KP_PLUS || $uni == ord "+") {
168     $::CONN->user_send ("rotateshoottype +");
169     } elsif ($sym == CFClient::SDLK_KP_MINUS || $uni == ord "-") {
170     $::CONN->user_send ("rotateshoottype -");
171     } elsif ($uni == ord '"') {
172     $self->{completer}->set_prefix ("$::CFG->{say_command} ");
173     $self->{completer}->show;
174     } elsif ($uni == ord "'") {
175     $self->{completer}->set_prefix ("");
176     $self->{completer}->show;
177     } elsif (exists $DIR{$sym}) {
178     if ($mod & CFClient::KMOD_SHIFT) {
179     $self->{shft}++;
180     $::CONN->user_send ("fire $DIR{$sym}[0]");
181     } elsif ($mod & CFClient::KMOD_CTRL) {
182     $self->{ctrl}++;
183     $::CONN->user_send ("run $DIR{$sym}[0]");
184     } else {
185     $::CONN->user_send ("$DIR{$sym}[1]");
186     }
187 elmex 1.43 } elsif ($sym == CFClient::SDLK_INSERT && $mod & CFClient::KMOD_CTRL) {
188 elmex 1.45 $::BIND_EDITOR->set_binding (undef, undef, [],
189     sub {
190     my ($mod, $sym, $cmds) = @_;
191     $::CFG->{bindings}->{$mod}->{$sym} = $cmds;
192     });
193     $::BIND_EDITOR->start;
194     $::BIND_EDITOR->show;
195 elmex 1.43 } elsif ($sym == CFClient::SDLK_INSERT && not ($mod & CFClient::KMOD_CTRL)) {
196 elmex 1.45 $::BIND_EDITOR->stop;
197 elmex 1.46 $::BIND_EDITOR->ask_for_bind_and_commit;
198 elmex 1.45 $::BIND_EDITOR->hide;
199 elmex 1.43 } elsif (my $bind_cmd = $::CFG->{bindings}->{$mod}->{$sym}) {
200     $::CONN->user_send ($_) for @$bind_cmd;
201 root 1.42 } elsif ((ord 'a') <= $uni && $uni <= (ord 'z')) {
202 root 1.36 $self->{completer}->key_down ($ev);
203     $self->{completer}->show;
204 root 1.47 } else {
205     return 0;
206 root 1.36 }
207 root 1.47
208     1
209 root 1.36 }
210    
211     sub key_up {
212     my ($self, $ev) = @_;
213    
214 root 1.47 my $res = 0;
215 root 1.36 my $mod = $ev->{mod};
216     my $sym = $ev->{sym};
217    
218     if (!($mod & CFClient::KMOD_SHIFT) && delete $self->{shft}) {
219     $::CONN->user_send ("fire_stop");
220 root 1.47 $res = 1;
221 root 1.36 }
222 root 1.47
223 root 1.36 if (!($mod & CFClient::KMOD_CTRL ) && delete $self->{ctrl}) {
224     $::CONN->user_send ("run_stop");
225 root 1.47 $res = 1;
226 root 1.36 }
227 root 1.47
228     $res
229 root 1.36 }
230    
231 root 1.1 sub draw {
232     my ($self) = @_;
233    
234 root 1.36 my $focused = $CFClient::UI::FOCUS == $self
235     || $CFClient::UI::FOCUS == $self->{completer}{entry};
236    
237 root 1.26 return
238 root 1.36 unless $focused || !$::FAST;
239 root 1.26
240 root 1.1 if (delete $self->{need_update}) {
241 root 1.4 glNewList $self->{list};
242 root 1.1
243     if ($::MAP) {
244 root 1.17 my $sw = int $::WIDTH / (32 * $::CFG->{map_scale}) + 0.99;
245     my $sh = int $::HEIGHT / (32 * $::CFG->{map_scale}) + 0.99;
246 root 1.1
247 root 1.18 my $sx = $::CFG->{map_shift_x} / $::CFG->{map_scale}; my $sx0 = $sx & 31; $sx = ($sx - $sx0) / 32;
248     my $sy = $::CFG->{map_shift_y} / $::CFG->{map_scale}; my $sy0 = $sy & 31; $sy = ($sy - $sy0) / 32;
249    
250 root 1.16 glPushMatrix;
251 root 1.9 glScale $::CFG->{map_scale}, $::CFG->{map_scale};
252    
253 root 1.1 glTranslate $sx0 - 32, $sy0 - 32, 0;
254    
255     my ($w, $h, $data) = $::MAP->draw ($sx, $sy, 0, 0, $sw + 1, $sh + 1);
256    
257     if ($::CFG->{fow_enable}) {
258 root 1.39 if ($::CFG->{fow_smooth} && $CFClient::OpenGL::GL_VERSION >= 1.2) { # smooth fog of war
259 root 1.1 glConvolutionParameter (GL_CONVOLUTION_2D, GL_CONVOLUTION_BORDER_MODE, GL_CONSTANT_BORDER);
260     glConvolutionFilter2D (
261     GL_CONVOLUTION_2D,
262     GL_ALPHA,
263     3, 3,
264     GL_ALPHA, GL_FLOAT,
265 root 1.51 (pack "f*", @{ $self->{smooth_matrix} }),
266 root 1.1 );
267     glEnable GL_CONVOLUTION_2D;
268     }
269    
270 root 1.35 $self->{fow_texture_name} ||= glGenTexture;
271 root 1.31 # try to re-use the texture name: TODO improve texture class instead
272    
273 root 1.1 $self->{fow_texture} = new CFClient::Texture
274     w => $w,
275     h => $h,
276     data => $data,
277 root 1.35 name => $self->{fow_texture_name},
278 root 1.1 internalformat => GL_ALPHA,
279     format => GL_ALPHA;
280    
281     glDisable GL_CONVOLUTION_2D if $::CFG->{fow_smooth};
282    
283     glEnable GL_TEXTURE_2D;
284     glTexEnv GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE;
285    
286 root 1.7 glColor +($::CFG->{fow_intensity}) x 3, 0.8;
287 root 1.31 $self->{fow_texture}->draw_quad_alpha (0, 0, $w * 32, $h * 32);
288 root 1.1
289     glDisable GL_TEXTURE_2D;
290     }
291    
292 root 1.18 glPopMatrix;
293 root 1.1 }
294    
295     glEndList;
296     }
297    
298     glPushMatrix;
299     glCallList $self->{list};
300     glPopMatrix;
301    
302 root 1.29 # TNT2 emulates logops in software (or worse :)
303 root 1.36 if ($focused) {
304 root 1.32 (delete $self->{out_of_focus})->destroy
305     if $self->{out_of_focus};
306     } else {
307     glColor 0.4, 0.2, 0.2, 0.6;
308 root 1.29 glEnable GL_BLEND;
309     glBlendFunc GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA;
310 root 1.1 glBegin GL_QUADS;
311     glVertex 0, 0;
312     glVertex 0, $::HEIGHT;
313     glVertex $::WIDTH, $::HEIGHT;
314     glVertex $::WIDTH, 0;
315     glEnd;
316 root 1.29 glDisable GL_BLEND;
317 root 1.32
318 root 1.38 # $self->{out_of_focus} ||= do {
319     # my $label = new CFClient::UI::Label
320     # x => 0,
321     # y => 0,
322     # z => 1,
323     # ellipsise => 0,
324     # text => "map out of focus (click map to play)";
325     #
326     # $label->show;
327     # $label->update;
328     #
329     # $CFClient::UI::ROOT->on_post_alloc ("$self$label" => sub {
330 root 1.44 # $label->move_abs (
331 root 1.38 # ($::WIDTH - $label->{w}) * 0.5,
332     # ($::HEIGHT - $label->{h}) * 0.5,
333     # );
334     # });
335     #
336     # $label
337     # };
338 root 1.1 }
339     }
340    
341 root 1.36 sub DESTROY {
342     my $self = shift;
343 root 1.3
344 root 1.36 glDeleteList $self->{list};
345 root 1.1
346 root 1.36 $self->SUPER::DESTROY;
347 root 1.8 }
348    
349 root 1.18 package CFClient::MapWidget::MapMap;
350    
351 root 1.19 our @ISA = CFClient::UI::Base::;
352 root 1.18
353     use Time::HiRes qw(time);
354     use CFClient::OpenGL;
355    
356     sub size_request {
357     ($::HEIGHT * 0.25, $::HEIGHT * 0.25)
358     }
359    
360     sub size_allocate {
361     my ($self, $w, $h) = @_;
362    
363     $self->SUPER::size_allocate ($w, $h);
364     $self->update;
365     }
366    
367     sub update {
368     my ($self) = @_;
369    
370     delete $self->{texture_atime};
371     $self->SUPER::update;
372     }
373    
374     sub _draw {
375     my ($self) = @_;
376    
377     $::MAP or return;
378    
379     my ($w, $h) = @$self{qw(w h)};
380    
381     my $sw = int $::WIDTH / (32 * $::CFG->{map_scale}) + 0.99;
382     my $sh = int $::HEIGHT / (32 * $::CFG->{map_scale}) + 0.99;
383    
384     my $sx = int $::CFG->{map_shift_x} / 32;
385     my $sy = int $::CFG->{map_shift_y} / 32;
386    
387     my $ox = 0.5 * ($w - $sw);
388     my $oy = 0.5 * ($h - $sh);
389    
390     glEnable GL_BLEND;
391     glBlendFunc GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA;
392     glEnable GL_TEXTURE_2D;
393     glTexEnv GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE;
394    
395     if ($self->{texture_atime} < time) {
396     $self->{texture_atime} = time + 1/3;
397    
398     $self->{texture} =
399     new CFClient::Texture
400     w => $w,
401     h => $h,
402     data => $::MAP->mapmap (-$ox, -$oy, $w, $h),
403     type => $CFClient::GL_VERSION >= 1.2 ? GL_UNSIGNED_INT_8_8_8_8_REV : GL_UNSIGNED_BYTE;
404     }
405    
406     $self->{texture}->draw_quad (0, 0);
407    
408     glDisable GL_TEXTURE_2D;
409    
410     glTranslate 0.375, 0.375;
411    
412     #TODO: map scale is completely borked
413    
414     my $x0 = int $ox - $sx + 0.5;
415     my $y0 = int $oy - $sy + 0.5;
416    
417     glColor 1, 1, 0, 1;
418     glBegin GL_LINE_LOOP;
419     glVertex $x0 , $y0 ;
420     glVertex $x0 , $y0 + $sh;
421     glVertex $x0 + $sw, $y0 + $sh;
422     glVertex $x0 + $sw, $y0 ;
423     glEnd;
424    
425     glDisable GL_BLEND;
426     }
427    
428 root 1.8 package CFClient::MapWidget::Command;
429    
430     use strict;
431    
432     use CFClient::OpenGL;
433    
434 root 1.23 our @ISA = CFClient::UI::Frame::;
435 root 1.8
436     sub new {
437     my $class = shift;
438    
439     my $self = $class->SUPER::new (
440 root 1.23 bg => [0, 0, 0, 0.8],
441 root 1.8 @_,
442 root 1.23 );
443    
444     $self->add ($self->{vbox} = new CFClient::UI::VBox);
445    
446     $self->{label} = [
447     map
448 root 1.8 CFClient::UI::Label->new (
449 root 1.25 can_hover => 1,
450     can_events => 1,
451     tooltip_width => 0.33,
452     fontsize => $_,
453 root 1.27 ), (0.8) x 16
454 root 1.23 ];
455    
456     $self->{entry} = new CFClient::UI::Entry
457 root 1.40 on_changed => sub {
458 root 1.23 $self->update_labels;
459 root 1.36 },
460 root 1.40 on_key_down => sub {
461 root 1.36 my ($entry, $ev) = @_;
462    
463     my $self = $entry->{parent}{parent};
464    
465     if ($ev->{sym} == 13) {
466     if (exists $self->{select}) {
467 root 1.37 $self->{last_command} = $self->{select};
468 root 1.36 $::CONN->user_send ($self->{select});
469 elmex 1.52
470     unshift @{$self->{history}}, $self->{select};
471     $self->{hist_ptr} = 0;
472    
473 root 1.36 $self->hide;
474     }
475     } elsif ($ev->{sym} == 27) {
476 elmex 1.52 $self->{hist_ptr} = 0;
477 root 1.36 $self->hide;
478     return;
479     } elsif ($ev->{sym} == CFClient::SDLK_DOWN) {
480 elmex 1.52 if ($self->{hist_ptr} > 1) {
481     $self->{hist_ptr}--;
482     $self->{entry}->set_text ($self->{history}->[$self->{hist_ptr} - 1]);
483     } elsif ($self->{hist_ptr} > 0) {
484     $self->{hist_ptr}--;
485     $self->{entry}->set_text ($self->{hist_saveback});
486     } else {
487     ++$self->{select_offset}
488     if $self->{select_offset} < $#{ $self->{last_match} || [] };
489     }
490 root 1.36 $self->update_labels;
491     } elsif ($ev->{sym} == CFClient::SDLK_UP) {
492 elmex 1.52 if ($self->{select_offset}) {
493     --$self->{select_offset}
494     } else {
495     unless ($self->{hist_ptr}) {
496     $self->{hist_saveback} = $self->{entry}->get_text;
497     }
498     if ($self->{hist_ptr} <= $#{$self->{history}}) {
499     $self->{hist_ptr}++;
500     }
501     $self->{entry}->set_text ($self->{history}->[$self->{hist_ptr} - 1])
502     if exists $self->{history}->[$self->{hist_ptr} - 1];
503     }
504 root 1.36 $self->update_labels;
505     } else {
506     return 0;
507     }
508    
509     1
510     }
511     ;
512 root 1.23
513     $self->{vbox}->add (
514     $self->{entry},
515     @{$self->{label}},
516 root 1.8 );
517    
518     $self
519     }
520    
521 root 1.36 sub set_prefix {
522     my ($self, $prefix) = @_;
523    
524     $self->{entry}->set_text ($prefix);
525     $self->show;
526     }
527    
528 root 1.8 sub size_allocate {
529     my ($self, $w, $h) = @_;
530    
531     $self->SUPER::size_allocate ($w, $h);
532 root 1.44 $self->move_abs (($::WIDTH - $w) * 0.5, ($::HEIGHT - $h) * 0.6, 10);
533 root 1.8 }
534    
535 root 1.36 sub show {
536     my ($self) = @_;
537    
538     $self->SUPER::show;
539     $self->{entry}->focus_in;
540     }
541    
542     sub hide {
543     my ($self) = @_;
544    
545     $self->SUPER::hide;
546     $self->{entry}->set_text ("");
547     }
548    
549 root 1.23 sub key_down {
550     my ($self, $ev) = @_;
551    
552 root 1.47 $self->{entry}->key_down ($ev)
553 root 1.23 }
554    
555 root 1.8 sub update_labels {
556     my ($self) = @_;
557    
558 root 1.23 my $text = $self->{entry}->get_text;
559    
560     length $text
561 root 1.36 or return $self->hide;
562 root 1.23
563     my ($cmd, $arg) = $text =~ /^\s*([^[:space:]]*)(.*)$/;
564    
565 root 1.36 if ($text ne $self->{last_search}) {
566     my @match;
567 root 1.23
568 root 1.36 if ($text =~ /^(.*?)\s+$/) {
569     @match = [$cmd, "(appended whitespace suppresses completion)"];
570     } else {
571     my $regexp = do {
572     my ($beg, @chr) = split //, lc $cmd;
573 root 1.23
574 root 1.36 # the following regex is used to match our "completion entry"
575     # to an actual command - the parentheses match kind of "overhead"
576     # - the more characters the parentheses match, the less attractive
577     # is the match.
578     my $regexp = "^\Q$beg\E"
579     . join "", map "(?:.*?[ \\\\]\Q$_\E|(.*?)\Q$_\E)", @chr;
580     qr<$regexp>
581     };
582    
583     my @penalty;
584    
585     for (keys %{$self->{command}}) {
586     if (@penalty = $_ =~ $regexp) {
587     push @match, [$_, length join "", map "::$_", grep defined, @penalty];
588     }
589 root 1.23 }
590 root 1.36
591     @match = map $self->{command}{$_->[0]},
592     sort {
593     $a->[1] <=> $b->[1]
594     or $self->{command}{$a->[0]}[4] <=> $self->{command}{$b->[0]}[4]
595 root 1.39 or (length $b->[0]) <=> (length $a->[0])
596 root 1.36 } @match;
597 root 1.8 }
598 root 1.23
599 root 1.39 $self->{last_search} = $text;
600 root 1.23 $self->{last_match} = \@match;
601    
602     $self->{select_offset} = 0;
603 root 1.8 }
604    
605 root 1.23 my @labels = @{ $self->{label} };
606     my @matches = @{ $self->{last_match} || [] };
607 root 1.8
608 root 1.23 if ($self->{select_offset}) {
609     splice @matches, 0, $self->{select_offset}, ();
610 root 1.8
611 root 1.23 my $label = shift @labels;
612     $label->set_text ("...");
613     $label->set_tooltip ("Use Cursor-Up to view previous matches");
614 root 1.8 }
615    
616 root 1.23 for my $label (@labels) {
617     $label->{fg} = [1, 1, 1, 1];
618     $label->{bg} = [0, 0, 0, 0];
619     }
620    
621     if (@matches) {
622     $self->{select} = "$matches[0][0]$arg";
623    
624     $labels[0]->{fg} = [0, 0, 0, 1];
625     $labels[0]->{bg} = [1, 1, 1, 0.8];
626     } else {
627 root 1.24 $self->{select} = "$cmd$arg";
628 root 1.23 }
629    
630     for my $match (@matches) {
631     my $label = shift @labels;
632    
633     if (@labels) {
634     $label->set_text ("$match->[0]$arg");
635     $label->set_tooltip ($match->[1]);
636     } else {
637     $label->set_text ("...");
638     $label->set_tooltip ("Use Cursor-Down to view more matches");
639     last;
640     }
641     }
642 root 1.8
643 root 1.23 for my $label (@labels) {
644     $label->set_text ("");
645     $label->set_tooltip ("");
646 root 1.8 }
647    
648 root 1.23 $self->update;
649     ###
650 root 1.8 }
651    
652 root 1.23 sub _draw {
653     my ($self) = @_;
654 root 1.8
655 root 1.23 # hack
656     local $CFClient::UI::FOCUS = $self->{entry};
657 root 1.10
658 root 1.23 $self->SUPER::_draw;
659 root 1.2 }
660    
661 root 1.1 1