1package UI::Dialog::Screen::Menu;
2###############################################################################
3#  Copyright (C) 2004-2016  Kevin C. Krinke <kevin@krinke.ca>
4#
5#  This library is free software; you can redistribute it and/or
6#  modify it under the terms of the GNU Lesser General Public
7#  License as published by the Free Software Foundation; either
8#  version 2.1 of the License, or (at your option) any later version.
9#
10#  This library is distributed in the hope that it will be useful,
11#  but WITHOUT ANY WARRANTY; without even the implied warranty of
12#  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13#  Lesser General Public License for more details.
14#
15#  You should have received a copy of the GNU Lesser General Public
16#  License along with this library; if not, write to the Free Software
17#  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
18###############################################################################
19use 5.006;
20use strict;
21use warnings;
22use constant { TRUE => 1, FALSE => 0 };
23
24BEGIN {
25    use vars qw($VERSION);
26    $VERSION = '1.21';
27}
28
29use UI::Dialog;
30
31# Example Usage
32#
33# my $screen = new UI::Dialog::Screen::Menu ( dialog => $d );
34# $screen->add_menu_item( "Label", \&func );
35# $screen->loop();
36#
37
38sub new {
39    my ($class, %args) = @_;
40    $args{__loop_active} = FALSE;
41    unless (exists $args{dialog}) {
42        $args{dialog} = new UI::Dialog
43         (
44          title => (defined $args{title}) ? $args{title} : '',
45          backtitle => (defined $args{backtitle}) ? $args{backtitle} : '',
46          height => (defined $args{height}) ? $args{height} : 20,
47          width => (defined $args{width}) ? $args{width} : 65,
48          listheight => (defined $args{listheight}) ? $args{listheight} : 5,
49          order => (defined $args{order}) ? $args{order} : undef,
50          PATH => (defined $args{PATH}) ? $args{PATH} : undef,
51          beepbefore => (defined $args{beepbefore}) ? $args{beepbefore} : undef,
52          beepafter => (defined $args{beepafter}) ? $args{beepafter} : undef,
53          'trust-input' => (defined $args{'trust-input'} && $args{'trust-input'} == 1) ? 1 : 0,
54         );
55    }
56    unless (exists $args{menu}) {
57        $args{menu} = [];
58    }
59    return bless { %args }, $class;
60}
61
62#: $screen->add_menu_item( "Label", \&func );
63#: Add an item to the menu with a label and a callback func
64#
65sub add_menu_item {
66    my ($self,$label,$func) = @_;
67    push(@{$self->{menu}},{label=>$label,func=>$func});
68    return @{$self->{menu}} - 1;
69}
70
71#: @list_of_menu_items = $screen->get_menu_items();
72#: Return a list of all the menu items in order. Each item is a hash
73#: with a label and a func reference.
74#
75sub get_menu_items {
76    my ($self) = @_;
77    return @{$self->{menu}};
78}
79
80#: %item = $screen->del_menu_item( $index );
81#: Remove a menu item and return it. The item will no longer show in the
82#: list of avaliable menu items.
83#
84sub del_menu_item {
85    my ($self,$index) = @_;
86    if (defined $index && $index >= 0 && $index < @{$self->{menu}}) {
87        return splice(@{$self->{menu}}, $index, 1);
88    }
89    return undef;
90}
91
92#: $screen->set_menu_item( $index, $label||undef, $func||undef );
93#: Update a menu item's properties. If a field is "undef", no action
94#: is performed on that item's field. Returns the menu_item before
95#: modification.
96#: Note: $index starts from 0.
97#
98sub set_menu_item {
99    my ($self,$index,$label,$func) = @_;
100    if (defined $index && $index >= 0 && $index < @{$self->{menu}}) {
101        my $item = $self->{menu}->[$index];
102        my $orig = { label => $item->{label}, func => $item->{func} };
103        $self->{menu}->[$index]->{label} = $label if defined $label;
104        $self->{menu}->[$index]->{func} = $func if defined $func;
105        return $orig;
106    }
107    return undef;
108}
109
110
111#: $screen->run();
112#: Blocking call, display the menu and react once. Returns 0 if cancelled,
113#: returns 1 if an item was selected and the function called.
114#
115sub run {
116    my ($self) = @_;
117    my @menu_list = ();
118    my $c = 1;
119    foreach my $data (@{$self->{menu}}) {
120        push(@menu_list,$c,$data->{label});
121        $c++;
122    }
123    my $sel = $self->{dialog}->menu
124     (
125      title => (defined $self->{title}) ? $self->{title} : '',
126      text => (defined $self->{text}) ? $self->{text} : '',
127      list => \@menu_list
128     );
129    if ($self->{dialog}->state() eq "OK") {
130        my $data = $self->{menu}->[$sel-1];
131        my $func = $data->{func};
132        &{$func}($self,$self->{dialog},$sel-1) if defined $func and ref($func) eq "CODE";
133        return 1;
134    } else {
135        if (exists $self->{cancel}) {
136            my $func = $self->{cancel};
137            &{$func}($self,$self->{dialog},-1) if defined $func and ref($func) eq "CODE";
138        }
139    }
140    return 0;
141}
142
143#: $screen->loop();
144#: Blocking call, execute $screen->run() indefinitely. If run() was cancelled,
145#: the loop will break.
146sub loop {
147    my ($self) = @_;
148    $self->{__loop_active} = TRUE;
149    while ($self->{__loop_active}) {
150        last unless $self->run();
151    }
152}
153
154#: $screen->break_loop();
155#: Notify loop() to break instead of re-iterate regardless of user input.
156#
157sub break_loop {
158    my ($self) = @_;
159    $self->{__loop_active} = FALSE;
160}
161
162#: $screen->is_looping();
163#: Returns TRUE if currently looping, FALSE otherwise
164#
165sub is_looping {
166    my ($self) = @_;
167    return ($self->{__loop_active}) ? TRUE : FALSE;
168}
169
1701; # END OF UI::Dialog::Screen::Menu
171