/usr/local/CPAN/dvdrip/Video/DVDRip/GUI/Project/Subtitle.pm
# $Id: Subtitle.pm 2344 2007-08-09 21:37:41Z joern $
#-----------------------------------------------------------------------
# Copyright (C) 2001-2006 Jörn Reder <joern AT zyn.de>.
# All Rights Reserved. See file COPYRIGHT for details.
#
# This module is part of Video::DVDRip, which is free software; you can
# redistribute it and/or modify it under the same terms as Perl itself.
#-----------------------------------------------------------------------
package Video::DVDRip::GUI::Project::Subtitle;
use base qw( Video::DVDRip::GUI::Base );
use Locale::TextDomain qw (video.dvdrip);
use Carp;
use strict;
use Video::DVDRip::GUI::FormFactory::SubtitlePreviews;
sub new {
my $class = shift;
my $self = $class->SUPER::new(@_);
return $self;
}
sub build_factory {
my $self = shift;
my $context = $self->get_context;
$context->set_object( subtitle_gui => $self );
return Gtk2::Ex::FormFactory::VBox->new(
$self->get_optimum_screen_size_options("page"),
title => '[gtk-underline]'.__ "Subtitles",
object => "title",
active_cond => sub {
$self->selected_title
&& $self->project
&& $self->project->created;
},
active_depends => "project.created",
no_frame => 1,
content => [
Video::DVDRip::GUI::Main->build_selected_title_factory,
Gtk2::Ex::FormFactory::VBox->new(
object => "subtitle",
inactive => "invisible",
expand => 1,
content => [
$self->build_select_box, $self->build_preview_box,
$self->build_render_box, $self->build_vobsub_box,
],
),
Gtk2::Ex::FormFactory::Label->new(
label => "\n<b>" . __("This title has no subtitles") . "</b>",
with_markup => 1,
inactive => "invisible",
active_cond => sub {
!( $self->selected_title && $self->selected_title->has_subtitles )
},
active_depends => "title",
),
],
);
}
sub build_select_box {
my $self = shift;
return Gtk2::Ex::FormFactory::HBox->new(
title => __ "Subtitle selection",
content => [
Gtk2::Ex::FormFactory::Popup->new(
attr => "title.selected_subtitle_id",
label => __ "Select subtitle",
),
Gtk2::Ex::FormFactory::Label->new(
attr => "title.subtitles_activated",
label => __ "Activated:",
),
],
);
}
sub build_preview_box {
my $self = shift;
my $preview_event_box = Gtk2::EventBox->new;
$preview_event_box->modify_bg( "normal",
Gtk2::Gdk::Color->parse("#ffffff") );
return Gtk2::Ex::FormFactory::VBox->new(
title => __ "Preview",
expand => 1,
content => [
Gtk2::Ex::FormFactory::HBox->new(
content => [
Gtk2::Ex::FormFactory::Button->new(
name => "subtitle_grab_button",
object => "subtitle",
label => __ "Grab",
stock => "gtk-copy",
clicked_hook => sub {
$self->grab_subtitle_preview_images;
},
inactive => "invisible",
active_cond => sub {
my ($subtitle) = @_;
return 0 unless $subtitle;
return 0 if $subtitle->is_ripped;
return $self->progress_is_active ?
'insensitive' : 'sensitive';
},
active_depends => ["subtitle.is_ripped", "progress.is_active" ],
),
Gtk2::Ex::FormFactory::Combo->new(
attr => "subtitle.tc_preview_img_cnt",
presets => [ 1, 3, 5, 10, 20, 30, 50, 100 ],
width => 60,
rules => "positive-integer",
),
Gtk2::Ex::FormFactory::Label->new(
label => __ "image(s)",
),
Gtk2::Ex::FormFactory::Entry->new(
attr => "subtitle.tc_preview_timecode",
label => __ "starting at",
width => 60,
rules => sub {
my ($value) = @_;
my $frames = $self->selected_title->frames;
return
if $value =~ /^\d+$/
and $value <= $frames;
return if $value =~ /^\d\d:\d\d:\d\d$/;
return __x( "Movie has only {cnt} frames",
cnt => $frames )
if $value =~ /^\d+$/
and $value > $frames;
return __ "Invalid time/frame number format";
},
),
Gtk2::Ex::FormFactory::Label->new(
label => __ "(timecode nn:nn:nn or frame number)",
),
],
),
Video::DVDRip::GUI::FormFactory::SubtitlePreviews->new(
attr => "subtitle.preview_dir",
attr_image_cnt => "subtitle.tc_preview_img_cnt",
attr_start_time => "subtitle.tc_preview_timecode",
expand => 1,
),
],
);
}
sub build_render_box {
my $self = shift;
my $context = $self->get_context;
return Gtk2::Ex::FormFactory::Table->new(
object => "subtitle",
active_cond =>
sub { $context->get_object_attr("title.subtitle_render_ok") },
active_depends => "subtitle.tc_vobsub",
title => __ "Render subtitle on movie",
layout => "
+--------+------------+>>>+--------+-----------+>>>+-----------+-------+
| ActLab | RendCheckb | S | Colors | ColCheckB | S | PrevImCnt | Entry |
+--------+-------+----+ +--------+-----+-----+ +-----------+-------+
| VOff | Entry | Un | | Gray | Ent | Ent | | PrevWin | Open |
+--------+-------+----+ +--------+-----+-----+ +-----------+-------+
| TimeS | Entry | Un | | Index | Pop | Pop | | |
+--------+-------+----+ +--------+-----+-----+---+-------------------+
| PostPr | Antiaalias | | Suggst | Letterbox | | Full Size Movie |
+--------+-------+----+---+--------+-----------+---+-------------------+
",
content => [
#-- Row #1
Gtk2::Ex::FormFactory::Label->new(
label => __ "Activate this subtitle" . " ",
label_group => "subtitle1",
),
Gtk2::Ex::FormFactory::CheckButton->new(
attr => "subtitle.tc_render",
label => __ "for rendering",
),
Gtk2::Ex::FormFactory::VSeparator->new,
Gtk2::Ex::FormFactory::Label->new(
label => __ "Colors" . " ",
for => "subtitle.tc_color_manip",
),
Gtk2::Ex::FormFactory::CheckButton->new(
attr => "subtitle.tc_color_manip",
label => __ "Enable manipulation",
),
Gtk2::Ex::FormFactory::VSeparator->new,
Gtk2::Ex::FormFactory::Label->new(
label => __ "Preview image count" . " ",
for => "subtitle.tc_test_image_cnt",
),
Gtk2::Ex::FormFactory::Entry->new(
attr => "subtitle.tc_test_image_cnt",
width => 50,
rules => "positive-integer",
),
#-- Row #2
Gtk2::Ex::FormFactory::Label->new(
label => __ "Vertical offset" . " ",
for => "subtitle.tc_vertical_offset",
),
Gtk2::Ex::FormFactory::Entry->new(
attr => "subtitle.tc_vertical_offset",
width => 50,
rules => "integer",
),
Gtk2::Ex::FormFactory::Label->new(
label => __ "rows",
active_cond =>
sub { $context->get_object_attr("subtitle.tc_render") },
),
Gtk2::Ex::FormFactory::Label->new(
label => __ "Gray A/B" . " ",
for => "subtitle.tc_color_a",
),
Gtk2::Ex::FormFactory::Entry->new(
attr => "subtitle.tc_color_a",
width => 50,
rules => sub {
$_[0] =~ /^\d+$/ && $_[0] >= 0 && $_[0] <= 255
? undef
: __ "Value not between 0 and 255";
},
),
Gtk2::Ex::FormFactory::Entry->new(
attr => "subtitle.tc_color_b",
width => 50,
rules => sub {
$_[0] =~ /^\d+$/ && $_[0] >= 0 && $_[0] <= 255
? undef
: __ "Value not between 0 and 255";
},
),
Gtk2::Ex::FormFactory::Label->new(
label => __ "Preview window" . " ",
active_cond => sub {
return 0 unless $context->get_object_attr("subtitle.tc_render");
return !$self->progress_is_active;
},
active_depends => [ "subtitle.tc_render", "progress.is_active" ],
),
Gtk2::Ex::FormFactory::Button->new(
stock => "gtk-media-play",
label => __ "Open",
object => "subtitle",
clicked_hook => sub { $self->subtitle_preview_window },
active_cond => sub {
return 0 unless $context->get_object_attr("subtitle.tc_render");
return !$self->progress_is_active;
},
active_depends => [ "subtitle.tc_render", "progress.is_active" ],
),
#-- Row #3
Gtk2::Ex::FormFactory::Label->new(
label => __ "Time shift" . " ",
for => "subtitle.tc_time_shift",
),
Gtk2::Ex::FormFactory::Entry->new(
attr => "subtitle.tc_time_shift",
width => 50,
rules => "positive-zero-integer",
),
Gtk2::Ex::FormFactory::Label->new(
label => __ "ms",
active_cond =>
sub { $context->get_object_attr("subtitle.tc_render") },
active_depends => "subtitle.tc_render",
),
Gtk2::Ex::FormFactory::Label->new(
label => __ "Index A/B" . " ",
for => "subtitle.tc_assign_color_a",
),
Gtk2::Ex::FormFactory::Popup->new(
attr => "subtitle.tc_assign_color_a",
width => 50,
),
Gtk2::Ex::FormFactory::Popup->new(
attr => "subtitle.tc_assign_color_b",
width => 50,
),
#-- Row #4
Gtk2::Ex::FormFactory::CheckButton->new(
attr => "subtitle.tc_postprocess",
label => __ "Postprocessing" . " ",
),
Gtk2::Ex::FormFactory::CheckButton->new(
attr => "subtitle.tc_antialias",
label => __ "Antialiasing",
),
Gtk2::Ex::FormFactory::Label->new(
label => __ "Suggest" . " ",
active_cond =>
sub { $context->get_object_attr("subtitle.tc_render") },
active_depends => "subtitle.tc_render",
),
Gtk2::Ex::FormFactory::Button->new(
label => __ "Values for letterbox",
object => "subtitle",
active_cond =>
sub { $context->get_object_attr("subtitle.tc_render") },
active_depends => "subtitle.tc_render",
clicked_hook => sub {
$self->suggest_render_black_bars;
},
),
Gtk2::Ex::FormFactory::Button->new(
label => __ "Values for full size movie",
object => "subtitle",
active_cond =>
sub { $context->get_object_attr("subtitle.tc_render") },
active_depends => "subtitle.tc_render",
clicked_hook => sub {
$self->suggest_render_full_size;
},
),
],
);
}
sub build_vobsub_box {
my $self = shift;
my $context = $self->get_context;
return Gtk2::Ex::FormFactory::Table->new(
object => "subtitle",
active_cond =>
sub { !$context->get_object_attr("subtitle.tc_render") },
active_depends => "subtitle.tc_render",
title => __ "Create vobsub file",
layout => "
+---------+---------+---------+---------------+
| Now | Button | Button | Info |
+---------+---------+---------+---------------+
| Later | after transcoding | Info |
+---------+-------------------+---------------+
",
content => [
#-- Row #1
Gtk2::Ex::FormFactory::Label->new(
label => __ "Create now",
label_group => "subtitle1",
),
Gtk2::Ex::FormFactory::Button->new(
label => __ "Create now",
clicked_hook => sub { $self->create_vobsub_now },
active_cond => sub { !$self->progress_is_active },
active_depends => "progress.is_active",
),
Gtk2::Ex::FormFactory::Button->new(
label => __ "View vobsub",
clicked_hook => sub { $self->view_vobsub },
),
Gtk2::Ex::FormFactory::Label->new(
label => " " . __ "Only useful for single-CD-rips or after transcoding",
),
#-- Row #2
Gtk2::Ex::FormFactory::Label->new( label => __ "Create later", ),
Gtk2::Ex::FormFactory::CheckButton->new(
attr => "subtitle.tc_vobsub",
label => __ "after transcoding",
),
Gtk2::Ex::FormFactory::Label->new(
label => " "
. __ "This considers splitted files automaticly",
),
],
);
}
sub suggest_render_black_bars {
my $self = shift;
my $title = $self->selected_title;
return 1 if not $title;
$title->suggest_subtitle_on_black_bars;
$self->get_context->get_object("clip_zoom")->make_previews;
$self->get_context->update_object_widgets("title");
$self->get_context->update_object_widgets("bitrate_calc");
$self->get_context->update_object_attr_widgets(
"subtitle.tc_vertical_offset");
1;
}
sub suggest_render_full_size {
my $self = shift;
my $title = $self->selected_title;
return 1 if not $title;
$title->suggest_subtitle_on_movie;
$self->get_context->get_object("clip_zoom")->make_previews;
$self->get_context->update_object_widgets("title");
$self->get_context->update_object_widgets("bitrate_calc");
$self->get_context->update_object_attr_widgets(
"subtitle.tc_vertical_offset");
1;
}
sub create_vobsub_now {
my $self = shift;
my $title = $self->selected_title;
return 1 if not $title;
my $subtitle = $title->selected_subtitle;
return 1 if not $subtitle;
my $job_planner = $self->get_context->get_object("job_planner");
my $exec_flow_gui = $self->get_context->get_object("exec_flow_gui");
my $job = $job_planner->build_vobsub_job($title, $subtitle);
$exec_flow_gui->start_job($job);
1;
}
sub view_vobsub {
my $self = shift;
my $title = $self->selected_title;
return 1 if not $title;
my $subtitle = $title->selected_subtitle;
return 1 if not $subtitle;
if ( not $self->has("mplayer") ) {
$self->message_window(
message => __ "You need Mplayer to view vobsub files." );
return 1;
}
if ( $title->project->rip_mode ne 'rip' ) {
$self->message_window(
message => __ "This is only supported for ripped movies." );
return 1;
}
if ( not $subtitle->vobsub_file_exists ) {
$self->message_window(
message => __ "What about creating the vobsub file first?" );
return 1;
}
my $command = $title->get_view_vobsub_command( subtitle => $subtitle );
$self->log( __ "Executing command: " . $command );
system("$command &");
1;
}
sub subtitle_preview_window {
my $self = shift;
my $title = $self->selected_title;
my $orig_preview_start_frame = $title->tc_preview_start_frame;
my $orig_preview_end_frame = $title->tc_preview_end_frame;
my ( $from, $to ) = $title->get_subtitle_test_frame_range;
$title->set_tc_preview_start_frame($from);
$title->set_tc_preview_end_frame($to);
my $restore_cb = sub {
$title->set_tc_preview_start_frame($orig_preview_start_frame);
$title->set_tc_preview_end_frame($orig_preview_end_frame);
};
require Video::DVDRip::GUI::Preview;
my $preview = Video::DVDRip::GUI::Preview->new(
form_factory => $self->get_form_factory,
closed_cb => $restore_cb,
eof_cb => $restore_cb,
);
$preview->open;
1;
}
sub grab_subtitle_preview_images {
my $self = shift;
my %par = @_;
my ($force) = @par{'force'};
my $title = $self->selected_title;
return 1 if not $title;
return 1 if $self->progress_is_active;
my $selected_subtitle = $title->selected_subtitle;
return 1 if not $selected_subtitle;
if ( not $title->is_ripped ) {
$self->message_window(
message => __ "You first have to rip this title." );
return 1;
}
if ( not $self->has("subtitle2pgm") ) {
$self->message_window(
message => __ "Sorry, you need subtitle2pgm for this to work." );
return 1;
}
my $job_planner = $self->get_context->get_object("job_planner");
my $exec_flow_gui = $self->get_context->get_object("exec_flow_gui");
my $job = $job_planner->build_grab_subtitle_images_job($title);
$job->get_post_callbacks->add(
sub {
$self->get_context->update_object_attr_widgets(
"title.selected_subtitle_id");
$self->get_context->update_object_attr_widgets(
"subtitle.preview_dir");
}
);
$exec_flow_gui->start_job($job);
1;
}
1;