1 | package CFPlus::UI; |
1 | package CFPlus::UI; |
2 | |
2 | |
3 | use utf8; |
3 | use utf8; |
4 | use strict; |
4 | use strict; |
5 | |
5 | |
6 | use Scalar::Util (); |
|
|
7 | use List::Util (); |
6 | use List::Util (); |
8 | use Event; |
7 | use Event; |
9 | |
8 | |
10 | use CFPlus; |
9 | use CFPlus; |
11 | use CFPlus::Pod; |
10 | use CFPlus::Pod; |
… | |
… | |
23 | our $TOOLTIP_WATCHER = Event->idle (min => 1/60, cb => sub { |
22 | our $TOOLTIP_WATCHER = Event->idle (min => 1/60, cb => sub { |
24 | if (!$GRAB) { |
23 | if (!$GRAB) { |
25 | for (my $widget = $HOVER; $widget; $widget = $widget->{parent}) { |
24 | for (my $widget = $HOVER; $widget; $widget = $widget->{parent}) { |
26 | if (length $widget->{tooltip}) { |
25 | if (length $widget->{tooltip}) { |
27 | if ($TOOLTIP->{owner} != $widget) { |
26 | if ($TOOLTIP->{owner} != $widget) { |
|
|
27 | $TOOLTIP->{owner}->emit ("tooltip_hide") if $TOOLTIP->{owner}; |
28 | $TOOLTIP->hide; |
28 | $TOOLTIP->hide; |
29 | |
29 | |
30 | $TOOLTIP->{owner} = $widget; |
30 | $TOOLTIP->{owner} = $widget; |
|
|
31 | $TOOLTIP->{owner}->emit ("tooltip_show") if $TOOLTIP->{owner}; |
31 | |
32 | |
32 | return if $ENV{CFPLUS_DEBUG} & 8; |
33 | return if $ENV{CFPLUS_DEBUG} & 8; |
33 | |
34 | |
34 | my $tip = $widget->{tooltip}; |
35 | my $tip = $widget->{tooltip}; |
35 | |
36 | |
… | |
… | |
43 | } |
44 | } |
44 | } |
45 | } |
45 | } |
46 | } |
46 | |
47 | |
47 | $TOOLTIP->hide; |
48 | $TOOLTIP->hide; |
|
|
49 | $TOOLTIP->{owner}->emit ("tooltip_hide") if $TOOLTIP->{owner}; |
48 | delete $TOOLTIP->{owner}; |
50 | delete $TOOLTIP->{owner}; |
49 | }); |
51 | }); |
50 | |
52 | |
51 | sub get_layout { |
53 | sub get_layout { |
52 | my $layout; |
54 | my $layout; |
… | |
… | |
235 | h => undef, |
237 | h => undef, |
236 | can_events => 1, |
238 | can_events => 1, |
237 | @_ |
239 | @_ |
238 | }, $class; |
240 | }, $class; |
239 | |
241 | |
240 | Scalar::Util::weaken ($CFPlus::UI::WIDGET{$self+0} = $self); |
242 | CFPlus::weaken ($CFPlus::UI::WIDGET{$self+0} = $self); |
241 | |
243 | |
242 | for (keys %$self) { |
244 | for (keys %$self) { |
243 | if (/^on_(.*)$/) { |
245 | if (/^on_(.*)$/) { |
244 | $self->connect ($1 => delete $self->{$_}); |
246 | $self->connect ($1 => delete $self->{$_}); |
245 | } |
247 | } |
… | |
… | |
264 | my ($self) = @_; |
266 | my ($self) = @_; |
265 | |
267 | |
266 | $self->hide; |
268 | $self->hide; |
267 | $self->emit ("destroy"); |
269 | $self->emit ("destroy"); |
268 | %$self = (); |
270 | %$self = (); |
|
|
271 | } |
|
|
272 | |
|
|
273 | sub TO_JSON { |
|
|
274 | { __widget_ref__ => $_[0]{s_id} } |
269 | } |
275 | } |
270 | |
276 | |
271 | sub show { |
277 | sub show { |
272 | my ($self) = @_; |
278 | my ($self) = @_; |
273 | |
279 | |
… | |
… | |
530 | ? $args[0]->xy ($self) |
536 | ? $args[0]->xy ($self) |
531 | : (); |
537 | : (); |
532 | |
538 | |
533 | #warn +(caller(1))[3] . "emit $signal on $self (parent $self->{parent})\n";#d# |
539 | #warn +(caller(1))[3] . "emit $signal on $self (parent $self->{parent})\n";#d# |
534 | |
540 | |
535 | #d##TODO# stop propagating at first true, do not use sum |
541 | for my $cb ( |
536 | (List::Util::sum map $_->($self, @args, @append), @{$self->{signal_cb}{$signal} || []}) # before |
542 | @{$self->{signal_cb}{$signal} || []}, # before |
537 | || ($self->can ("invoke_$signal") || sub { 1 })->($self, @args, @append) # closure |
543 | ($self->can ("invoke_$signal") || sub { 1 }), # closure |
|
|
544 | ) { |
|
|
545 | return $cb->($self, @args, @append) || next; |
|
|
546 | } |
|
|
547 | |
|
|
548 | # parent |
538 | || ($self->{parent} && $self->{parent}->emit ($signal, @args)) # parent |
549 | $self->{parent} && $self->{parent}->emit ($signal, @args) |
539 | } |
550 | } |
540 | |
551 | |
541 | sub find_widget { |
552 | sub find_widget { |
542 | my ($self, $x, $y) = @_; |
553 | my ($self, $x, $y) = @_; |
543 | |
554 | |
… | |
… | |
551 | } |
562 | } |
552 | |
563 | |
553 | sub set_parent { |
564 | sub set_parent { |
554 | my ($self, $parent) = @_; |
565 | my ($self, $parent) = @_; |
555 | |
566 | |
556 | Scalar::Util::weaken ($self->{parent} = $parent); |
567 | CFPlus::weaken ($self->{parent} = $parent); |
557 | $self->set_visible if $parent->{visible}; |
568 | $self->set_visible if $parent->{visible}; |
558 | } |
569 | } |
559 | |
570 | |
560 | sub realloc { |
571 | sub realloc { |
561 | my ($self) = @_; |
572 | my ($self) = @_; |
… | |
… | |
640 | my ($self) = @_; |
651 | my ($self) = @_; |
641 | |
652 | |
642 | warn "no draw defined for $self\n"; |
653 | warn "no draw defined for $self\n"; |
643 | } |
654 | } |
644 | |
655 | |
|
|
656 | my $cntx;#d# |
645 | sub DESTROY { |
657 | sub DESTROY { |
646 | my ($self) = @_; |
658 | my ($self) = @_; |
647 | |
659 | |
648 | return if CFPlus::in_destruct; |
660 | return if CFPlus::in_destruct; |
649 | |
661 | |
… | |
… | |
1962 | my $sym = $ev->{sym}; |
1974 | my $sym = $ev->{sym}; |
1963 | my $uni = $ev->{unicode}; |
1975 | my $uni = $ev->{unicode}; |
1964 | |
1976 | |
1965 | my $text = $self->get_text; |
1977 | my $text = $self->get_text; |
1966 | |
1978 | |
|
|
1979 | $self->{cursor} = List::Util::max 0, List::Util::min $self->{cursor}, length $text; |
|
|
1980 | |
1967 | if ($uni == 8) { |
1981 | if ($uni == 8) { |
1968 | substr $text, --$self->{cursor}, 1, "" if $self->{cursor}; |
1982 | substr $text, --$self->{cursor}, 1, "" if $self->{cursor}; |
1969 | } elsif ($uni == 127) { |
1983 | } elsif ($uni == 127) { |
1970 | substr $text, $self->{cursor}, 1, ""; |
1984 | substr $text, $self->{cursor}, 1, ""; |
1971 | } elsif ($sym == CFPlus::SDLK_LEFT) { |
1985 | } elsif ($sym == CFPlus::SDLK_LEFT) { |
1972 | --$self->{cursor} if $self->{cursor}; |
1986 | --$self->{cursor} if $self->{cursor}; |
1973 | } elsif ($sym == CFPlus::SDLK_RIGHT) { |
1987 | } elsif ($sym == CFPlus::SDLK_RIGHT) { |
1974 | ++$self->{cursor} if $self->{cursor} < length $self->{text}; |
1988 | ++$self->{cursor} if $self->{cursor} < length $self->{text}; |
1975 | } elsif ($sym == CFPlus::SDLK_HOME) { |
1989 | } elsif ($sym == CFPlus::SDLK_HOME) { |
|
|
1990 | # what a hack |
1976 | $self->{cursor} = 0; |
1991 | $self->{cursor} = |
|
|
1992 | (substr $self->{text}, 0, $self->{cursor}) =~ /^(.*\012)/ |
|
|
1993 | ? length $1 |
|
|
1994 | : 0; |
1977 | } elsif ($sym == CFPlus::SDLK_END) { |
1995 | } elsif ($sym == CFPlus::SDLK_END) { |
|
|
1996 | # uh, again |
|
|
1997 | $self->{cursor} = |
|
|
1998 | (substr $self->{text}, $self->{cursor}) =~ /^([^\012]*)\012/ |
1978 | $self->{cursor} = length $text; |
1999 | ? $self->{cursor} + length $1 |
|
|
2000 | : length $self->{text}; |
1979 | } elsif ($uni == 21) { # ctrl-u |
2001 | } elsif ($uni == 21) { # ctrl-u |
1980 | $text = ""; |
2002 | $text = ""; |
1981 | $self->{cursor} = 0; |
2003 | $self->{cursor} = 0; |
1982 | } elsif ($uni == 27) { |
2004 | } elsif ($uni == 27) { |
1983 | $self->emit ('escape'); |
2005 | $self->emit ('escape'); |
1984 | } elsif ($uni >= 0x20 || $uni == 0x0d) { |
2006 | } elsif ($uni == 0x0d) { |
|
|
2007 | substr $text, $self->{cursor}++, 0, "\012"; |
|
|
2008 | } elsif ($uni >= 0x20) { |
1985 | substr $text, $self->{cursor}++, 0, chr $uni; |
2009 | substr $text, $self->{cursor}++, 0, chr $uni; |
1986 | } else { |
2010 | } else { |
1987 | return 0; |
2011 | return 0; |
1988 | } |
2012 | } |
1989 | |
2013 | |
… | |
… | |
2310 | or Carp::croak "'path' or 'tex' attributes required"; |
2334 | or Carp::croak "'path' or 'tex' attributes required"; |
2311 | |
2335 | |
2312 | $self->{tex} ||= $texture_cache{$self->{path}} ||= |
2336 | $self->{tex} ||= $texture_cache{$self->{path}} ||= |
2313 | new_from_file CFPlus::Texture CFPlus::find_rcfile $self->{path}, mipmap => 1; |
2337 | new_from_file CFPlus::Texture CFPlus::find_rcfile $self->{path}, mipmap => 1; |
2314 | |
2338 | |
2315 | Scalar::Util::weaken $texture_cache{$self->{path}}; |
2339 | CFPlus::weaken $texture_cache{$self->{path}}; |
2316 | |
2340 | |
2317 | $self->{aspect} ||= $self->{tex}{w} / $self->{tex}{h}; |
2341 | $self->{aspect} ||= $self->{tex}{w} / $self->{tex}{h}; |
2318 | |
2342 | |
2319 | $self |
2343 | $self |
2320 | } |
2344 | } |
… | |
… | |
2693 | sub invoke_mouse_wheel { |
2717 | sub invoke_mouse_wheel { |
2694 | my ($self, $ev) = @_; |
2718 | my ($self, $ev) = @_; |
2695 | |
2719 | |
2696 | my $delta = $self->{vertical} ? $ev->{dy} : $ev->{dx}; |
2720 | my $delta = $self->{vertical} ? $ev->{dy} : $ev->{dx}; |
2697 | |
2721 | |
|
|
2722 | my $pagepart = $ev->{mod} & CFPlus::KMOD_SHIFT ? 1 : 0.2; |
|
|
2723 | |
2698 | $self->set_value ($self->{range}[0] + $delta * $self->{range}[3] * 0.2); |
2724 | $self->set_value ($self->{range}[0] + $delta * $self->{range}[3] * $pagepart); |
2699 | |
2725 | |
2700 | ! ! $delta |
2726 | ! ! $delta |
2701 | } |
2727 | } |
2702 | |
2728 | |
2703 | sub update { |
2729 | sub update { |
… | |
… | |
2813 | #font => default_font |
2839 | #font => default_font |
2814 | @_, |
2840 | @_, |
2815 | |
2841 | |
2816 | layout => (new CFPlus::Layout), |
2842 | layout => (new CFPlus::Layout), |
2817 | par => [], |
2843 | par => [], |
|
|
2844 | max_par => 0, |
2818 | height => 0, |
2845 | height => 0, |
2819 | children => [ |
2846 | children => [ |
2820 | (new CFPlus::UI::Empty expand => 1), |
2847 | (new CFPlus::UI::Empty expand => 1), |
2821 | (new CFPlus::UI::Slider vertical => 1), |
2848 | (new CFPlus::UI::Slider vertical => 1), |
2822 | ], |
2849 | ], |
… | |
… | |
2945 | wrapped => 1, |
2972 | wrapped => 1, |
2946 | }; |
2973 | }; |
2947 | |
2974 | |
2948 | $self->add (@{ $para->{widget} }) if @{ $para->{widget} }; |
2975 | $self->add (@{ $para->{widget} }) if @{ $para->{widget} }; |
2949 | push @{$self->{par}}, $para; |
2976 | push @{$self->{par}}, $para; |
|
|
2977 | } |
|
|
2978 | |
|
|
2979 | if (my $max = $self->{max_par}) { |
|
|
2980 | shift @{$self->{par}} while @{$self->{par}} > $max; |
2950 | } |
2981 | } |
2951 | |
2982 | |
2952 | $self->{need_reflow}++; |
2983 | $self->{need_reflow}++; |
2953 | $self->update; |
2984 | $self->update; |
2954 | } |
2985 | } |
… | |
… | |
3268 | can_events => 0, |
3299 | can_events => 0, |
3269 | @_, |
3300 | @_, |
3270 | ); |
3301 | ); |
3271 | |
3302 | |
3272 | if ($self->{anim} && $self->{animspeed}) { |
3303 | if ($self->{anim} && $self->{animspeed}) { |
3273 | Scalar::Util::weaken (my $widget = $self); |
3304 | CFPlus::weaken (my $widget = $self); |
3274 | |
3305 | |
3275 | $self->{timer} = Event->timer ( |
3306 | $self->{timer} = Event->timer ( |
3276 | at => $self->{animspeed} * int $::NOW / $self->{animspeed}, |
3307 | at => $self->{animspeed} * int $::NOW / $self->{animspeed}, |
3277 | hard => 1, |
3308 | hard => 1, |
3278 | interval => $self->{animspeed}, |
3309 | interval => $self->{animspeed}, |
… | |
… | |
3532 | } |
3563 | } |
3533 | |
3564 | |
3534 | sub add { |
3565 | sub add { |
3535 | my ($self, $title, $widget, $tooltip) = @_; |
3566 | my ($self, $title, $widget, $tooltip) = @_; |
3536 | |
3567 | |
3537 | Scalar::Util::weaken $self; |
3568 | CFPlus::weaken $self; |
3538 | |
3569 | |
3539 | $self->{buttonbar}->add (new CFPlus::UI::Button |
3570 | $self->{buttonbar}->add (new CFPlus::UI::Button |
3540 | markup => $title, |
3571 | markup => $title, |
3541 | tooltip => $tooltip, |
3572 | tooltip => $tooltip, |
3542 | on_activate => sub { $self->set_current_page ($widget) }, |
3573 | on_activate => sub { $self->set_current_page ($widget) }, |
… | |
… | |
3626 | my $self = $class->SUPER::new ( |
3657 | my $self = $class->SUPER::new ( |
3627 | fontsize => 0.8, |
3658 | fontsize => 0.8, |
3628 | @_, |
3659 | @_, |
3629 | ); |
3660 | ); |
3630 | |
3661 | |
3631 | Scalar::Util::weaken (my $this = $self); |
3662 | CFPlus::weaken (my $this = $self); |
3632 | |
3663 | |
3633 | $self->{timer} = Event->timer (after => 1, interval => 1, cb => sub { $this->reorder }); |
3664 | $self->{timer} = Event->timer (after => 1, interval => 1, cb => sub { $this->reorder }); |
3634 | |
3665 | |
3635 | $self |
3666 | $self |
3636 | } |
3667 | } |
… | |
… | |
3775 | my $self = $class->SUPER::new ( |
3806 | my $self = $class->SUPER::new ( |
3776 | visible => 1, |
3807 | visible => 1, |
3777 | @_, |
3808 | @_, |
3778 | ); |
3809 | ); |
3779 | |
3810 | |
3780 | Scalar::Util::weaken ($self->{root} = $self); |
3811 | CFPlus::weaken ($self->{root} = $self); |
3781 | |
3812 | |
3782 | $self |
3813 | $self |
3783 | } |
3814 | } |
3784 | |
3815 | |
3785 | sub size_request { |
3816 | sub size_request { |