output update
[app-cpan2pkg.git] / lib / App / CPAN2Pkg / Curses.pm
blob7a5f5f4069c2fcacfaae0eae4e817b0de26430ff
2 # This file is part of App::CPAN2Pkg.
3 # Copyright (c) 2009 Jerome Quelin, all rights reserved.
5 # This program is free software; you can redistribute it and/or modify
6 # it under the same terms as Perl itself.
10 package App::CPAN2Pkg::Curses;
12 use strict;
13 use warnings;
15 use App::CPAN2Pkg;
16 use Class::XSAccessor
17 constructor => '_new',
18 accessors => {
19 _current => '_current',
20 _lb => '_listbox',
21 _listbox => '_listbox',
22 _panes => '_panes',
23 _prereqs => '_prereqs',
24 _viewers => '_viewers',
25 _win => '_win',
26 _opts => '_opts',
28 use Curses;
29 use Curses::UI::Common;
30 use Curses::UI::POE;
31 use POE;
34 #--
35 # CONSTRUCTOR
37 sub spawn {
38 my ($class, $opts) = @_;
40 # the userdata object
41 my $self = $class->_new(
42 _opts => $opts,
43 _panes => {},
44 _prereqs => {},
45 _viewers => {},
48 # the curses::ui object
49 my $cui = Curses::UI::POE->new(
50 -color_support => 1,
51 -userdata => $self,
52 inline_states => {
53 # public events
54 append => \&append,
55 module_available => \&module_available,
56 module_spawned => \&module_spawned,
57 prereqs => \&prereqs,
58 # inline states
59 _start => \&_start,
60 _stop => sub { warn "_stop"; },
63 return $cui;
67 #--
68 # SUBS
70 # -- public events
72 sub append {
73 my ($cui, $module, $line) = @_[HEAP, ARG0, ARG1];
74 my $self = $cui->userdata;
76 my $name = $module->name;
77 my $viewer = $self->_viewers->{$name};
78 my $text = $viewer->text;
79 $text .= $line;
80 $viewer->text($text);
82 # forcing redraw if needed
83 $viewer->draw if $self->_current eq $name;
86 sub module_spawned {
87 my ($k, $cui, $module) = @_[KERNEL, HEAP, ARG0];
88 my $self = $cui->userdata;
90 my $name = $module->name;
92 # updating list of modules
93 my $lb = $self->_listbox;
94 my $values = $lb->values;
95 push @$values, $module;
96 $lb->add_labels( { $module => "- $name" } );
97 $lb->values([ sort { $a->name cmp $b->name } @$values ]);
98 $lb->draw;
100 # adding a new pane
101 my $win = $self->_win;
102 my $pane = $win->add(undef, 'Window');
104 # title
105 $pane->add(
106 undef, 'Label',
107 -height => 1,
108 -text => $name,
111 # prereqs
112 my $text = 'Missing prereqs: ';
113 my $a = $pane->add(
114 undef, 'Label',
115 '-y' => 2,
116 -width => length($text),
117 -height => 1,
118 -text => $text,
120 my $prereqs = $pane->add(
121 undef, 'Label',
122 -x => length($text),
123 '-y' => 2,
124 -height => 1,
126 $prereqs->text('unknown');
128 # viewer
129 my $viewer = $pane->add(
130 undef, 'TextViewer',
131 '-y' => 4,
132 -text => '',
133 -vscrollbar => 1,
136 #$self->_set_bindings($pane);
137 #$self->_set_bindings($viewer);
139 # storing the new ui elements
140 $self->_panes->{$name} = $pane;
141 $self->_prereqs->{$name} = $prereqs;
142 $self->_viewers->{$name} = $viewer;
144 # forcing redraw if needed
145 if ( not defined $self->_current ) {
146 $self->_current($name);
147 $win->draw;
148 $viewer->draw;
149 $viewer->focus;
153 sub module_available {
154 my ($k, $cui, $module) = @_[KERNEL, HEAP, ARG0];
155 my $self = $cui->userdata;
157 # update list of modules
158 my $name = $module->name;
159 my $lb = $self->_listbox;
160 $lb->add_labels( { $module => "+ $name" } );
161 $lb->draw;
164 sub prereqs {
165 my ($cui, $module, @prereqs) = @_[HEAP, ARG0..$#_];
166 my $self = $cui->userdata;
168 my $name = $module->name;
169 my $label = $self->_prereqs->{$name};
170 if ( @prereqs ) {
171 $label->set_color_fg('red');
172 $label->text(join ', ', sort @prereqs);
174 } else {
175 $label->set_color_fg('green');
176 $label->text('none');
181 # -- poe inline states
183 sub _start {
184 my ($k, $cui) = @_[KERNEL, HEAP];
185 my $self = $cui->userdata;
187 $k->alias_set('ui');
188 $self->_build_gui($cui);
190 my $opts = $self->_opts;
191 App::CPAN2Pkg->spawn($opts);
197 # METHODS
199 # -- gui events
201 sub _focus_to_listbox {
202 my ($self) = @_;
204 my $lb = $self->_listbox;
205 $lb->focus;
208 sub _focus_to_viewer {
209 my ($self) = @_;
211 #my $lb = $self->_listbox;
212 $self->_win->focus;
216 sub _listbox_item_selected {
217 my ($self) = @_;
219 my $lb = $self->_listbox;
220 my $labels = $lb->labels;
221 my $name = substr $labels->{ $lb->get_active_value }, 2;
222 $self->_current($name);
223 $self->_viewers->{$name}->focus;
226 # -- private methods
228 sub _build_gui {
229 my ($self, $cui) = @_;
231 $self->_build_title($cui);
232 $self->_build_queue($cui);
233 $self->_build_right_window($cui);
234 $self->_set_bindings($cui);
237 sub _build_title {
238 my ($self, $cui) = @_;
239 my $title = 'cpan2pkg - generating native linux packages from cpan';
240 my $tb = $cui->add(undef, 'Window', -height => 1);
241 $tb->add(undef, 'Label', -bold=>1, -text=>$title);
244 sub _build_queue {
245 my ($self, $cui) = @_;
246 my $win = $cui->add(undef, 'Window',
247 qw/ -y 2 -width 40 -vscrollbar 1 -border 1 /,
249 my $list = $win->add(
250 undef, 'Listbox',
251 -onchange => sub { $self->_listbox_item_selected },
253 $list->set_binding( sub {$self->_focus_to_viewer}, CUI_TAB );
254 $self->_listbox($list);
257 sub _build_right_window {
258 my ($self, $cui) = @_;
259 my $win = $cui->add(undef, 'Window',
260 qw/ -x 41 -y 2 -border 1 /,
262 $self->_win($win);
263 #$self->_set_bindings($win);
266 sub _set_bindings {
267 my ($self, $widget) = @_;
268 $widget->set_binding( sub{ die; }, "\cQ" );
269 $widget->set_binding( sub {$self->_focus_to_listbox}, KEY_F(2) );
273 __END__
276 =head1 NAME
278 App::CPAN2Pkg::Curses - curses user interface for cpan2pkg
282 =head1 DESCRIPTION
284 C<App::CPAN2Pkg::Curses> implements a POE session driving a curses
285 interface for C<cpan2pkg>.
287 It is spawned directly by C<cpan2pkg> (since C<Curses::UI::POE> is a bit
288 special regarding the event loop), and is responsible for launching the
289 application controller (see C<App::CPAN2Pkg>).
293 =head1 PUBLIC PACKAGE METHODS
295 =head2 my $cui = App::CPAN2Pkg->spawn( \%params )
297 This method will create a POE session responsible for creating the
298 curses UI and reacting to it.
300 It will return a C<Curses::UI::POE> object.
302 You can tune the session by passing some arguments as a hash
303 reference, where the hash keys are:
305 =over 4
307 =item * modules => \@list_of_modules
309 A list of modules to start packaging.
312 =back
316 =head1 PUBLIC EVENTS ACCEPTED
318 The following events are the module's API.
321 =head2 append( $module, $line )
323 Update the specific part of the ui devoluted to C<$module> with an
324 additional C<$line>.
327 =head2 module_available( $module )
329 Sent when C<$module> is available. Updating list of modules to reflect
330 this new status.
333 =head2 module_spawned( $module )
335 Sent when a new module has been requested to be packaged. The argment
336 C<$module> is a C<App::CPAN2Pkg::Module> object with all the needed
337 information.
340 =head2 prereqs( $module, @prereqs )
342 Update the missing C<@prereqs> of C<$module> in the ui.
345 =head1 SEE ALSO
347 For all related information (bug reporting, source code repository,
348 etc.), refer to C<App::CPAN2Pkg>'s pod, section C<SEE ALSO>.
352 =head1 AUTHOR
354 Jerome Quelin, C<< <jquelin@cpan.org> >>
358 =head1 COPYRIGHT & LICENSE
360 Copyright (c) 2009 Jerome Quelin, all rights reserved.
362 This program is free software; you can redistribute it and/or modify
363 it under the same terms as Perl itself.
365 =cut