#!/usr/bin/perl use strict; use lib '../lib'; use Data::Dumper; $Data::Dumper::Indent = 1; use Gtk2; use Gtk2::Ex::FormFactory; main: { Gtk2->init; $Gtk2::Ex::FormFactory::DEBUG = 0; my $database = My::Database->new ( discs => [ My::Disc->new( artist => "Michael Oldfield", album => "Tubular Bells", titles => [ "Part I", "Part II", "Part III" ], broken_jewel_case => 0, genre => "instrumental", quality => 2, ), My::Disc->new( artist => "Jamiroquai", album => "A Funk Odyssey", titles => [ "Bla", "Foo", "Baz" ], broken_jewel_case => 1, genre => "soul", quality => 1, cover_filename => "cover.jpg", ), ], selected_discs_idx => [ 1 ], ); my $gui_state = My::GuiState->new( selected_page => 4, ); my $context = Gtk2::Ex::FormFactory::Context->new; $context->add_object ( name => "database", buffered => 0, object => undef, attr_accessors_href => { get_discs => sub { my $self = shift; my (@slist_data); push @slist_data, [ $_->get_artist, $_->get_album ] for @{$self->get_discs}; return \@slist_data; }, }, attr_depends_href => { selected_disc => "selected_discs_idx", } ); $context->add_object ( name => "disc", buffered => 0, aggregated_by => "database.selected_disc", attr_accessors_href => { get_titles => sub { my $self = shift; my (@slist_data, $i); push @slist_data, [ ++$i, $_ ] for @{$self->get_titles}; return \@slist_data; }, set_titles => sub { my $self = shift; my ($slist_data) = @_; my @titles; push @titles, $_->[1] for @{$slist_data}; return $self->set_titles(\@titles); }, }, attr_activity_href => { album => sub { $_[0]->get_artist ne 'Michael Oldfield'; }, }, attr_depends_href => { album => "disc.artist", }, ); $context->add_object ( name => "gui_state", object => $gui_state, ); $context->add_object ( name => "disabled", object => undef, ); $context->set_object( database => $database); my @table_childs; for ( 1..11 ) { push @table_childs, Gtk2::Ex::FormFactory::Button->new ( label => "Child $_", ); } my $ff; push @table_childs, Gtk2::Ex::FormFactory::VBox->new ( expand => 1, title => "Child $_", content => [ Gtk2::Ex::FormFactory::Button->new ( label => "Change Cursor", clicked_hook => sub { $ff->change_mouse_cursor("watch"); sleep 1; $ff->change_mouse_cursor(); 1; }, ), Gtk2::Ex::FormFactory::Button->new ( label => "Extend NB", clicked_hook => sub { extend_nb($ff); }, ), Gtk2::Ex::FormFactory::Button->new ( label => "Reduce NB", clicked_hook => sub { reduce_nb($ff); }, ), ], ); foreach my $nr ( 1 ) { $ff = Gtk2::Ex::FormFactory->new ( context => $context, sync => 1, content => [ Gtk2::Ex::FormFactory::Window->new ( name => "window_$nr", title => "FormFactory Test Application", content => [ menu => { menu_tree => [ _File => { item_type => '', children => [ _New => { item_type => '', extra_data => 'gtk-new', callback => sub { print "new\n" }, accelerator => 'N', }, _Save => { item_type => '', extra_data => 'gtk-save', callback => sub { print "save\n" }, accelerator => 'S', object => "disabled", }, _Quit => { item_type => '', extra_data => 'gtk-quit', callback => sub { print "quit\n"; $ff->close; Gtk2->main_quit; }, accelerator => 'Q', }, ], }, ], }, Gtk2::Ex::FormFactory::Notebook->new ( name => "notebook", attr => "gui_state.selected_page", expand => 1, content => [ Gtk2::Ex::FormFactory::VBox->new ( title => "Select Album", content => [ Gtk2::Ex::FormFactory::VBox->new ( expand => 1, content => [ Gtk2::Ex::FormFactory::List->new ( name => "discs", expand => 1, attr => "database.discs", attr_select => "database.selected_discs_idx", label => "Album Selection", tip => "Select an entry for modification", columns => [ "Artist", "Album" ], types => [ "text", "text" ], selection_mode => "multiple", properties => { 'enable-search' => 1, }, ), ], ), ], ), Gtk2::Ex::FormFactory::VBox->new ( title => "Edit Album", content => [ Gtk2::Ex::FormFactory::Form->new ( content => [ Gtk2::Ex::FormFactory::Entry->new ( attr => "disc.artist", label => "Artist", tip => "Name of the artist", rules => "not-empty", width => 100, ), Gtk2::Ex::FormFactory::Label->new ( attr => "disc.artist", label => "Artist", ), Gtk2::Ex::FormFactory::Combo->new ( attr => "disc.album", label => "Album", tip => "Name of the album, 1st view", rules => "not-empty", ), Gtk2::Ex::FormFactory::Entry->new ( attr => "disc.album", label => "Album 2nd view", tip => "Name of the album, 2nd view", rules => "not-empty", inactive => "invisible", ), Gtk2::Ex::FormFactory::YesNo->new ( attr => "disc.broken_jewel_case", label => "State of jewel case", tip => "Indicates whether the jewel ". "case is broken or not", true_label => "Broken", false_label => "Intact", ), Gtk2::Ex::FormFactory::Expander->new ( label => "Alternative jewel case widgets", content => [ Gtk2::Ex::FormFactory::Form->new ( content => [ Gtk2::Ex::FormFactory::ToggleButton->new ( attr => "disc.broken_jewel_case", label => "State of jewel case", tip => "Indicates whether the jewel ". "case is broken or not", true_label => "Broken", false_label => "Intact", ), Gtk2::Ex::FormFactory::CheckButton->new ( attr => "disc.broken_jewel_case", label => "Jewel case is broken", detach_label => 1, tip => "Indicates whether the jewel ". "case is broken or not", ), Gtk2::Ex::FormFactory::CheckButton->new ( attr => "disc.broken_jewel_case", label => "Broken", tip => "Indicates whether the jewel ". "case is broken or not", ), ], ), ], ), Gtk2::Ex::FormFactory::Popup->new ( attr => "disc.genre", label => "Genre", tip => "Select to which genre this album belongs", ), Gtk2::Ex::FormFactory::Popup->new ( attr => "disc.quality", label => "Quality", tip => "Your opinion about the quality of this album", ), Gtk2::Ex::FormFactory::HBox->new ( label => "Quality again", content => [ Gtk2::Ex::FormFactory::RadioButton->new ( attr => "disc.quality", label => "Bad", value => 0, ), Gtk2::Ex::FormFactory::RadioButton->new ( attr => "disc.quality", label => "Medium", value => 1, ), Gtk2::Ex::FormFactory::RadioButton->new ( attr => "disc.quality", label => "Good", value => 2, ), ], ), Gtk2::Ex::FormFactory::Label->new ( label => "Active for Jamiroquai", active_cond => sub { $context->get_object("disc")->get_artist =~ /Jam/; }, active_depends => "disc.artist", ), ], ), ], ), Gtk2::Ex::FormFactory::VBox->new ( title => "Edit Titles", content => [ Gtk2::Ex::FormFactory::Form->new ( content => [ Gtk2::Ex::FormFactory::List->new ( attr => "disc.titles", label => "Titles", tip => "List of all tracks on this album", columns => [ "Nr", "Title" ], types => [ "int", "text" ], editable => [ 0, 1 ], ), ], ), ], ), Gtk2::Ex::FormFactory::VBox->new ( title => "Disc Cover", content => [ Gtk2::Ex::FormFactory::Form->new ( expand => 1, content => [ Gtk2::Ex::FormFactory::Image->new ( attr => "disc.cover_filename", tip => "Cover of this album", expand_h => 1, expand_v => 1, with_frame => 1, scale_to_fit => 1, max_width => 500, max_height => 500, bgcolor => "#111155", ), ], ), ], ), Gtk2::Ex::FormFactory::VBox->new ( title => "Table Test", content => [ Gtk2::Ex::FormFactory::Table->new ( expand => 1, layout => " +[-------------+>>>>>>>>>>>]+---+ | 1 | | | +[-------------+ 2 | | | ** 4 ** | | | +-------+------+------------+ | | ^ 6 ^ *** | | | ^ ^ ** 7 ** | | | ^ ^ *** | | | ~ +-----%------+ | | ^ ^ * | | | ^ ~ *8* | | _ 5 ^ ^ * | | +-------+------+------------+ | | | ^ ** | | | | ^ ** 10 ** | | | | ^ ** | | ~ 9 | +------------+ | | | | ** 11 ** | | | +------+-----------]+ | | | 12 _ 3 | +-------+-------------------+---+ ", content => \@table_childs, ), ], ), ], ), Gtk2::Ex::FormFactory::DialogButtons->new ( buttons => { ok => 1, apply => 1 }, clicked_hook_before => sub { my ($button) = @_; print "User hit button '$button'\n"; return 1; }, clicked_hook_after => sub { my ($button) = @_; if ( $button eq 'ok' or $button eq 'cancel' ) { print Dumper($database, $gui_state); Gtk2->main_quit; } return 1; }, ), ], ), ], ); $ff->open; $ff->update; } Gtk2->main; } my $added; my @added; sub extend_nb { my ($ff) = @_; my $ff_notebook = $ff->get_widget("notebook"); ++$added; my $new_form = Gtk2::Ex::FormFactory::Form->new ( name => "new_form_$added", title => "Added $added", content => [ Gtk2::Ex::FormFactory::Entry->new ( attr => "disc.artist", label => "A test entry [$added]", ), ], ); $ff_notebook->add_child_widget($new_form); push @added, $new_form; 1; } sub reduce_nb { my ($ff) = @_; return unless $added; my $ff_notebook = $ff->get_widget("notebook"); --$added; $ff_notebook->remove_child_widget(pop @added); 1; } package My::Database; sub get_discs { shift->{discs} } sub get_selected_discs_idx { shift->{selected_discs_idx} } sub set_discs { shift->{discs} = $_[1] } sub set_selected_discs_idx { shift->{selected_discs_idx} = $_[1] } sub new { my $class = shift; my %par = @_; my ($discs, $selected_discs_idx) = @par{'discs','selected_discs_idx'}; $selected_discs_idx ||= []; my $self = bless { discs => $discs, selected_discs_idx => $selected_discs_idx, }, $class; return $self; } sub get_selected_disc { my $self = shift; my $selected_discs_idx = $self->get_selected_discs_idx; return if @{$selected_discs_idx} == 0; return $self->get_discs->[$selected_discs_idx->[0]]; } package My::Disc; sub get_artist { shift->{artist} } sub get_album { shift->{album} } sub get_titles { shift->{titles} } sub get_broken_jewel_case { shift->{broken_jewel_case} } sub get_genre { shift->{genre} } sub get_quality { shift->{quality} } sub get_cover_filename { shift->{cover_filename} } sub set_artist { shift->{artist} = $_[1] } sub set_album { shift->{album} = $_[1] } sub set_titles { shift->{titles} = $_[1] } sub set_broken_jewel_case { shift->{broken_jewel_case} = $_[1] } sub set_genre { shift->{genre} = $_[1] } sub set_quality { shift->{quality} = $_[1] } sub set_cover_filename { shift->{cover_filename} = $_[1] } sub get_album_presets { $_[0]->get_artist =~ /Oldfield/i ? [ "Amarok", "Crisis", "Tubular Bells", "Tubular Bells II", "Tubular Bells III", ]: [ "A Funk Odyssey", "Emergency On Planet Earth", "Synkronized", ]; } sub get_genre_list {{ dance => "Dance", techno => "Techno", country => "Country", soul => "Soul", instrumental => "Instrumental", }} sub get_quality_list {[ "Bad", "Medium", "Good", ]} sub new { my $class = shift; my %par = @_; my ($artist, $album, $titles, $broken_jewel_case, $genre) = @par{'artist','album','titles','broken_jewel_case','genre'}; my ($quality, $cover_filename) = @par{'quality','cover_filename'}; my $self = bless { artist => $artist, album => $album, titles => $titles, broken_jewel_case => $broken_jewel_case, genre => $genre, quality => $quality, cover_filename => $cover_filename, }, $class; return $self; } package My::GuiState; sub get_selected_page { shift->{selected_page} } sub set_selected_page { shift->{selected_page} = $_[1] } sub new { my $class = shift; my %par = @_; my ($selected_page) = $par{'selected_page'}; my $self = bless { selected_page => $selected_page, }, $class; return $self; } 1;