+++ /dev/null
-/*
- Copyright (C) 2012 Carl Hetherington <cth@carlh.net>
-
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 2 of the License, or
- (at your option) any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program; if not, write to the Free Software
- Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
-
-*/
-
-#include <iostream>
-#include <gtkmm.h>
-#include <cairomm/cairomm.h>
-#include "alignment.h"
-
-using namespace std;
-
-class AlignmentWidget : public Gtk::DrawingArea
-{
-public:
- void set_text_line (int n, string t)
- {
- if (int(_text.size()) < (n + 1)) {
- _text.resize (n + 1);
- }
-
- _text[n] = t;
- queue_draw ();
- }
-
-private:
- bool on_expose_event (GdkEventExpose* ev)
- {
- if (!get_window ()) {
- return false;
- }
-
- Cairo::RefPtr<Cairo::Context> c = get_window()->create_cairo_context ();
-
- Gtk::Allocation a = get_allocation ();
- int const w = a.get_width ();
- int const h = a.get_height ();
-
- c->rectangle (0, 0, w, h);
- c->set_source_rgb (0, 0, 0);
- c->fill ();
-
- c->set_source_rgb (1, 1, 1);
- c->set_line_width (1);
-
- int const arrow_size = h / 8;
- int const head_size = h / 32;
-
- /* arrow to left edge */
- c->move_to (arrow_size, h / 2);
- c->line_to (0, h / 2);
- c->rel_line_to (head_size, head_size);
- c->move_to (0, h / 2);
- c->rel_line_to (head_size, -head_size);
- c->stroke ();
-
- /* arrow to right edge */
- c->move_to (w - arrow_size, h / 2);
- c->line_to (w, h / 2);
- c->rel_line_to (-head_size, head_size);
- c->move_to (w, h / 2);
- c->rel_line_to (-head_size, -head_size);
- c->stroke ();
-
- /* arrow to top edge */
- c->move_to (w / 2, arrow_size);
- c->line_to (w / 2, 0);
- c->rel_line_to (head_size, head_size);
- c->move_to (w / 2, 0);
- c->rel_line_to (-head_size, head_size);
- c->stroke ();
-
- /* arrow to bottom edge */
- c->move_to (w / 2, h - h / 8);
- c->line_to (w / 2, h);
- c->rel_line_to (head_size, -head_size);
- c->move_to (w / 2, h);
- c->rel_line_to (-head_size, -head_size);
- c->stroke ();
-
- /* arrow to top-left corner */
- c->move_to (arrow_size, arrow_size);
- c->line_to (0, 0);
- c->rel_line_to (head_size, 0);
- c->move_to (0, 0);
- c->rel_line_to (0, head_size);
- c->stroke ();
-
- /* arrow to top-right corner */
- c->move_to (w - arrow_size, arrow_size);
- c->line_to (w, 0);
- c->rel_line_to (0, head_size);
- c->move_to (w, 0);
- c->rel_line_to (-head_size, 0);
- c->stroke ();
-
- /* arrow to bottom-left corner */
- c->move_to (arrow_size, h - arrow_size);
- c->line_to (0, h);
- c->rel_line_to (head_size, 0);
- c->move_to (0, h);
- c->rel_line_to (0, -head_size);
- c->stroke ();
-
- /* arrow to bottom-right corner */
- c->move_to (w - arrow_size, h - arrow_size);
- c->line_to (w, h);
- c->rel_line_to (-head_size, 0);
- c->line_to (w, h);
- c->rel_line_to (0, -head_size);
- c->stroke ();
-
- /* text */
- int max_height = 0;
- for (vector<string>::iterator i = _text.begin(); i != _text.end(); ++i) {
- Cairo::TextExtents e;
- c->get_text_extents (*i, e);
- max_height = max (max_height, int (e.height));
- }
-
- int total_height = max_height * _text.size() * 2;
-
- for (vector<string>::size_type i = 0; i < _text.size(); ++i) {
- Cairo::TextExtents e;
- c->get_text_extents (_text[i], e);
- c->move_to ((w - e.width) / 2, ((h - total_height) / 2) + ((i * 2) + 1) * max_height);
- c->text_path (_text[i]);
- c->stroke ();
- }
-
- return true;
- }
-
- std::vector<std::string> _text;
-};
-
-Alignment::Alignment (Position p, Size s)
-{
- _widget = Gtk::manage (new AlignmentWidget);
- add (*_widget);
- show_all ();
-
- set_decorated (false);
- set_resizable (false);
- set_size_request (s.width, s.height);
- move (p.x, p.y);
-}
-
-void
-Alignment::set_text_line (int n, string t)
-{
- _widget->set_text_line (n, t);
-}
+++ /dev/null
-/*
- Copyright (C) 2012 Carl Hetherington <cth@carlh.net>
-
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 2 of the License, or
- (at your option) any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program; if not, write to the Free Software
- Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
-
-*/
-
-#include <gtkmm.h>
-#include <string>
-#include "lib/util.h"
-
-class AlignmentWidget;
-
-class Alignment : public Gtk::Window
-{
-public:
- Alignment (Position, Size);
-
- void set_text_line (int, std::string);
-
-private:
- AlignmentWidget* _widget;
-};
+++ /dev/null
-/*
- Copyright (C) 2012 Carl Hetherington <cth@carlh.net>
-
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 2 of the License, or
- (at your option) any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program; if not, write to the Free Software
- Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
-
-*/
-
-/** @file src/config_dialog.cc
- * @brief A dialogue to edit DVD-o-matic configuration.
- */
-
-#include <iostream>
-#include <boost/lexical_cast.hpp>
-#include "lib/config.h"
-#include "lib/server.h"
-#include "lib/screen.h"
-#include "lib/format.h"
-#include "lib/scaler.h"
-#include "lib/filter.h"
-#include "config_dialog.h"
-#include "gtk_util.h"
-#include "filter_dialog.h"
-
-using namespace std;
-using namespace boost;
-
-ConfigDialog::ConfigDialog ()
- : Gtk::Dialog ("DVD-o-matic Configuration")
- , _reference_filters_button ("Edit...")
- , _add_server ("Add Server")
- , _remove_server ("Remove Server")
- , _add_screen ("Add Screen")
- , _remove_screen ("Remove Screen")
-{
- Gtk::Table* t = manage (new Gtk::Table);
- t->set_row_spacings (6);
- t->set_col_spacings (6);
- t->set_border_width (6);
-
- Config* config = Config::instance ();
-
- _tms_ip.set_text (config->tms_ip ());
- _tms_ip.signal_changed().connect (sigc::mem_fun (*this, &ConfigDialog::tms_ip_changed));
- _tms_path.set_text (config->tms_path ());
- _tms_path.signal_changed().connect (sigc::mem_fun (*this, &ConfigDialog::tms_path_changed));
- _tms_user.set_text (config->tms_user ());
- _tms_user.signal_changed().connect (sigc::mem_fun (*this, &ConfigDialog::tms_user_changed));
- _tms_password.set_text (config->tms_password ());
- _tms_password.signal_changed().connect (sigc::mem_fun (*this, &ConfigDialog::tms_password_changed));
-
- _num_local_encoding_threads.set_range (1, 128);
- _num_local_encoding_threads.set_increments (1, 4);
- _num_local_encoding_threads.set_value (config->num_local_encoding_threads ());
- _num_local_encoding_threads.signal_changed().connect (sigc::mem_fun (*this, &ConfigDialog::num_local_encoding_threads_changed));
-
- _colour_lut.append_text ("sRGB");
- _colour_lut.append_text ("Rec 709");
- _colour_lut.set_active (config->colour_lut_index ());
- _colour_lut.signal_changed().connect (sigc::mem_fun (*this, &ConfigDialog::colour_lut_changed));
-
- _j2k_bandwidth.set_range (50, 250);
- _j2k_bandwidth.set_increments (10, 50);
- _j2k_bandwidth.set_value (config->j2k_bandwidth() / 1e6);
- _j2k_bandwidth.signal_changed().connect (sigc::mem_fun (*this, &ConfigDialog::j2k_bandwidth_changed));
-
- vector<Scaler const *> const sc = Scaler::all ();
- for (vector<Scaler const *>::const_iterator i = sc.begin(); i != sc.end(); ++i) {
- _reference_scaler.append_text ((*i)->name ());
- }
- _reference_scaler.set_active (Scaler::as_index (config->reference_scaler ()));
- _reference_scaler.signal_changed().connect (sigc::mem_fun (*this, &ConfigDialog::reference_scaler_changed));
-
- _reference_filters.set_alignment (0, 0.5);
- pair<string, string> p = Filter::ffmpeg_strings (config->reference_filters ());
- _reference_filters.set_text (p.first + " " + p.second);
- _reference_filters_button.signal_clicked().connect (sigc::mem_fun (*this, &ConfigDialog::edit_reference_filters_clicked));
-
- _servers_store = Gtk::ListStore::create (_servers_columns);
- vector<Server*> servers = config->servers ();
- for (vector<Server*>::iterator i = servers.begin(); i != servers.end(); ++i) {
- add_server_to_store (*i);
- }
-
- _servers_view.set_model (_servers_store);
- _servers_view.append_column_editable ("Host Name", _servers_columns._host_name);
- _servers_view.append_column_editable ("Threads", _servers_columns._threads);
-
- _add_server.signal_clicked().connect (sigc::mem_fun (*this, &ConfigDialog::add_server_clicked));
- _remove_server.signal_clicked().connect (sigc::mem_fun (*this, &ConfigDialog::remove_server_clicked));
-
- _servers_view.get_selection()->signal_changed().connect (sigc::mem_fun (*this, &ConfigDialog::server_selection_changed));
- server_selection_changed ();
-
- _screens_store = Gtk::TreeStore::create (_screens_columns);
- vector<shared_ptr<Screen> > screens = config->screens ();
- for (vector<shared_ptr<Screen> >::iterator i = screens.begin(); i != screens.end(); ++i) {
- add_screen_to_store (*i);
- }
-
- _screens_view.set_model (_screens_store);
- _screens_view.append_column_editable ("Screen", _screens_columns._name);
- _screens_view.append_column ("Format", _screens_columns._format_name);
- _screens_view.append_column_editable ("x", _screens_columns._x);
- _screens_view.append_column_editable ("y", _screens_columns._y);
- _screens_view.append_column_editable ("Width", _screens_columns._width);
- _screens_view.append_column_editable ("Height", _screens_columns._height);
-
- _add_screen.signal_clicked().connect (sigc::mem_fun (*this, &ConfigDialog::add_screen_clicked));
- _remove_screen.signal_clicked().connect (sigc::mem_fun (*this, &ConfigDialog::remove_screen_clicked));
-
- _screens_view.get_selection()->signal_changed().connect (sigc::mem_fun (*this, &ConfigDialog::screen_selection_changed));
- screen_selection_changed ();
-
- int n = 0;
- t->attach (left_aligned_label ("TMS IP address"), 0, 1, n, n + 1);
- t->attach (_tms_ip, 1, 2, n, n + 1);
- ++n;
- t->attach (left_aligned_label ("TMS target path"), 0, 1, n, n + 1);
- t->attach (_tms_path, 1, 2, n, n + 1);
- ++n;
- t->attach (left_aligned_label ("TMS user name"), 0, 1, n, n + 1);
- t->attach (_tms_user, 1, 2, n, n + 1);
- ++n;
- t->attach (left_aligned_label ("TMS password"), 0, 1, n, n + 1);
- t->attach (_tms_password, 1, 2, n, n + 1);
- ++n;
- t->attach (left_aligned_label ("Threads to use for encoding on this host"), 0, 1, n, n + 1);
- t->attach (_num_local_encoding_threads, 1, 2, n, n + 1);
- ++n;
- t->attach (left_aligned_label ("Colour look-up table"), 0, 1, n, n + 1);
- t->attach (_colour_lut, 1, 2, n, n + 1);
- ++n;
- t->attach (left_aligned_label ("JPEG2000 bandwidth"), 0, 1, n, n + 1);
- t->attach (_j2k_bandwidth, 1, 2, n, n + 1);
- t->attach (left_aligned_label ("MBps"), 2, 3, n, n + 1);
- ++n;
- t->attach (left_aligned_label ("Reference scaler for A/B"), 0, 1, n, n + 1);
- t->attach (_reference_scaler, 1, 2, n, n + 1);
- ++n;
- t->attach (left_aligned_label ("Reference filters for A/B"), 0, 1, n, n + 1);
- Gtk::HBox* fb = Gtk::manage (new Gtk::HBox);
- fb->set_spacing (4);
- fb->pack_start (_reference_filters, true, true);
- fb->pack_start (_reference_filters_button, false, false);
- t->attach (*fb, 1, 2, n, n + 1);
- ++n;
- t->attach (left_aligned_label ("Encoding Servers"), 0, 1, n, n + 1);
- t->attach (_servers_view, 1, 2, n, n + 1);
- Gtk::VBox* b = manage (new Gtk::VBox);
- b->pack_start (_add_server, false, false);
- b->pack_start (_remove_server, false, false);
- t->attach (*b, 2, 3, n, n + 1);
- ++n;
- t->attach (left_aligned_label ("Screens"), 0, 1, n, n + 1);
- t->attach (_screens_view, 1, 2, n, n + 1);
- b = manage (new Gtk::VBox);
- b->pack_start (_add_screen, false, false);
- b->pack_start (_remove_screen, false, false);
- t->attach (*b, 2, 3, n, n + 1);
- ++n;
-
- t->show_all ();
- get_vbox()->pack_start (*t);
-
- get_vbox()->set_border_width (24);
-
- add_button ("Close", Gtk::RESPONSE_CLOSE);
-}
-
-void
-ConfigDialog::tms_ip_changed ()
-{
- Config::instance()->set_tms_ip (_tms_ip.get_text ());
-}
-
-void
-ConfigDialog::tms_path_changed ()
-{
- Config::instance()->set_tms_path (_tms_path.get_text ());
-}
-
-void
-ConfigDialog::tms_user_changed ()
-{
- Config::instance()->set_tms_user (_tms_user.get_text ());
-}
-
-void
-ConfigDialog::tms_password_changed ()
-{
- Config::instance()->set_tms_password (_tms_password.get_text ());
-}
-
-
-void
-ConfigDialog::num_local_encoding_threads_changed ()
-{
- Config::instance()->set_num_local_encoding_threads (_num_local_encoding_threads.get_value ());
-}
-
-void
-ConfigDialog::colour_lut_changed ()
-{
- Config::instance()->set_colour_lut_index (_colour_lut.get_active_row_number ());
-}
-
-void
-ConfigDialog::j2k_bandwidth_changed ()
-{
- Config::instance()->set_j2k_bandwidth (_j2k_bandwidth.get_value() * 1e6);
-}
-
-void
-ConfigDialog::on_response (int r)
-{
- vector<Server*> servers;
-
- Gtk::TreeModel::Children c = _servers_store->children ();
- for (Gtk::TreeModel::Children::iterator i = c.begin(); i != c.end(); ++i) {
- Gtk::TreeModel::Row r = *i;
- Server* s = new Server (r[_servers_columns._host_name], r[_servers_columns._threads]);
- servers.push_back (s);
- }
-
- Config::instance()->set_servers (servers);
-
- vector<shared_ptr<Screen> > screens;
-
- c = _screens_store->children ();
- for (Gtk::TreeModel::Children::iterator i = c.begin(); i != c.end(); ++i) {
-
- Gtk::TreeModel::Row r = *i;
- shared_ptr<Screen> s (new Screen (r[_screens_columns._name]));
-
- Gtk::TreeModel::Children cc = r.children ();
- for (Gtk::TreeModel::Children::iterator j = cc.begin(); j != cc.end(); ++j) {
- Gtk::TreeModel::Row r = *j;
- string const x_ = r[_screens_columns._x];
- string const y_ = r[_screens_columns._y];
- string const width_ = r[_screens_columns._width];
- string const height_ = r[_screens_columns._height];
- s->set_geometry (
- Format::from_nickname (r[_screens_columns._format_nickname]),
- Position (lexical_cast<int> (x_), lexical_cast<int> (y_)),
- Size (lexical_cast<int> (width_), lexical_cast<int> (height_))
- );
- }
-
- screens.push_back (s);
- }
-
- Config::instance()->set_screens (screens);
-
- Gtk::Dialog::on_response (r);
-}
-
-void
-ConfigDialog::add_server_to_store (Server* s)
-{
- Gtk::TreeModel::iterator i = _servers_store->append ();
- Gtk::TreeModel::Row r = *i;
- r[_servers_columns._host_name] = s->host_name ();
- r[_servers_columns._threads] = s->threads ();
-}
-
-void
-ConfigDialog::add_server_clicked ()
-{
- Server s ("localhost", 1);
- add_server_to_store (&s);
-}
-
-void
-ConfigDialog::remove_server_clicked ()
-{
- Gtk::TreeModel::iterator i = _servers_view.get_selection()->get_selected ();
- if (i) {
- _servers_store->erase (i);
- }
-}
-
-void
-ConfigDialog::server_selection_changed ()
-{
- Gtk::TreeModel::iterator i = _servers_view.get_selection()->get_selected ();
- _remove_server.set_sensitive (i);
-}
-
-
-void
-ConfigDialog::add_screen_to_store (shared_ptr<Screen> s)
-{
- Gtk::TreeModel::iterator i = _screens_store->append ();
- Gtk::TreeModel::Row r = *i;
- r[_screens_columns._name] = s->name ();
-
- Screen::GeometryMap geoms = s->geometries ();
- for (Screen::GeometryMap::const_iterator j = geoms.begin(); j != geoms.end(); ++j) {
- i = _screens_store->append (r.children ());
- Gtk::TreeModel::Row c = *i;
- c[_screens_columns._format_name] = j->first->name ();
- c[_screens_columns._format_nickname] = j->first->nickname ();
- c[_screens_columns._x] = lexical_cast<string> (j->second.position.x);
- c[_screens_columns._y] = lexical_cast<string> (j->second.position.y);
- c[_screens_columns._width] = lexical_cast<string> (j->second.size.width);
- c[_screens_columns._height] = lexical_cast<string> (j->second.size.height);
- }
-}
-
-void
-ConfigDialog::add_screen_clicked ()
-{
- shared_ptr<Screen> s (new Screen ("New Screen"));
- add_screen_to_store (s);
-}
-
-void
-ConfigDialog::remove_screen_clicked ()
-{
- Gtk::TreeModel::iterator i = _screens_view.get_selection()->get_selected ();
- if (i) {
- _screens_store->erase (i);
- }
-}
-
-void
-ConfigDialog::screen_selection_changed ()
-{
- Gtk::TreeModel::iterator i = _screens_view.get_selection()->get_selected ();
- _remove_screen.set_sensitive (i);
-}
-
-
-void
-ConfigDialog::reference_scaler_changed ()
-{
- int const n = _reference_scaler.get_active_row_number ();
- if (n >= 0) {
- Config::instance()->set_reference_scaler (Scaler::from_index (n));
- }
-}
-
-void
-ConfigDialog::edit_reference_filters_clicked ()
-{
- FilterDialog d (Config::instance()->reference_filters ());
- d.ActiveChanged.connect (sigc::mem_fun (*this, &ConfigDialog::reference_filters_changed));
- d.run ();
-}
-
-void
-ConfigDialog::reference_filters_changed (vector<Filter const *> f)
-{
- Config::instance()->set_reference_filters (f);
- pair<string, string> p = Filter::ffmpeg_strings (Config::instance()->reference_filters ());
- _reference_filters.set_text (p.first + " " + p.second);
-}
+++ /dev/null
-/*
- Copyright (C) 2012 Carl Hetherington <cth@carlh.net>
-
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 2 of the License, or
- (at your option) any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program; if not, write to the Free Software
- Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
-
-*/
-
-/** @file src/config_dialog.h
- * @brief A dialogue to edit DVD-o-matic configuration.
- */
-
-#include <gtkmm.h>
-
-class Screen;
-class Server;
-
-/** @class ConfigDialog
- * @brief A dialogue to edit DVD-o-matic configuration.
- */
-class ConfigDialog : public Gtk::Dialog
-{
-public:
- ConfigDialog ();
-
-private:
- void on_response (int);
-
- void tms_ip_changed ();
- void tms_path_changed ();
- void tms_user_changed ();
- void tms_password_changed ();
- void num_local_encoding_threads_changed ();
- void colour_lut_changed ();
- void j2k_bandwidth_changed ();
- void add_server_clicked ();
- void remove_server_clicked ();
- void server_selection_changed ();
- void add_screen_clicked ();
- void remove_screen_clicked ();
- void screen_selection_changed ();
- void reference_scaler_changed ();
- void edit_reference_filters_clicked ();
- void reference_filters_changed (std::vector<Filter const *>);
-
- void add_screen_to_store (boost::shared_ptr<Screen>);
- void add_server_to_store (Server *);
-
- struct ServersModelColumns : public Gtk::TreeModelColumnRecord
- {
- ServersModelColumns () {
- add (_host_name);
- add (_threads);
- }
-
- Gtk::TreeModelColumn<std::string> _host_name;
- Gtk::TreeModelColumn<int> _threads;
- };
-
- struct ScreensModelColumns : public Gtk::TreeModelColumnRecord
- {
- ScreensModelColumns () {
- add (_name);
- add (_format_name);
- add (_format_nickname);
- add (_x);
- add (_y);
- add (_width);
- add (_height);
- }
-
- Gtk::TreeModelColumn<std::string> _name;
- Gtk::TreeModelColumn<std::string> _format_name;
- Gtk::TreeModelColumn<std::string> _format_nickname;
- Gtk::TreeModelColumn<std::string> _x;
- Gtk::TreeModelColumn<std::string> _y;
- Gtk::TreeModelColumn<std::string> _width;
- Gtk::TreeModelColumn<std::string> _height;
- };
-
- Gtk::Entry _tms_ip;
- Gtk::Entry _tms_path;
- Gtk::Entry _tms_user;
- Gtk::Entry _tms_password;
- Gtk::SpinButton _num_local_encoding_threads;
- Gtk::ComboBoxText _colour_lut;
- Gtk::SpinButton _j2k_bandwidth;
- Gtk::ComboBoxText _reference_scaler;
- Gtk::Label _reference_filters;
- Gtk::Button _reference_filters_button;
- ServersModelColumns _servers_columns;
- Glib::RefPtr<Gtk::ListStore> _servers_store;
- Gtk::TreeView _servers_view;
- Gtk::Button _add_server;
- Gtk::Button _remove_server;
- ScreensModelColumns _screens_columns;
- Glib::RefPtr<Gtk::TreeStore> _screens_store;
- Gtk::TreeView _screens_view;
- Gtk::Button _add_screen;
- Gtk::Button _remove_screen;
-};
-
+++ /dev/null
-/*
- Copyright (C) 2012 Carl Hetherington <cth@carlh.net>
-
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 2 of the License, or
- (at your option) any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program; if not, write to the Free Software
- Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
-
-*/
-
-#include "dcp_range_dialog.h"
-#include "lib/film.h"
-
-DCPRangeDialog::DCPRangeDialog (Film* f)
- : _film (f)
- , _whole ("Whole film")
- , _first ("First")
- , _cut ("Cut remainder")
- , _black_out ("Black-out remainder")
-{
- set_title ("DCP range");
-
- Gtk::Table* table = Gtk::manage (new Gtk::Table ());
- table->set_border_width (6);
- table->set_row_spacings (6);
- table->set_col_spacings (6);
- table->attach (_whole, 0, 4, 0, 1);
- table->attach (_first, 0, 1, 1, 2);
- table->attach (_n_frames, 1, 2, 1, 2);
- table->attach (*manage (new Gtk::Label ("frames")), 2, 3, 1, 2);
- table->attach (_cut, 1, 2, 2, 3);
- table->attach (_black_out, 1, 2, 3, 4);
-
- Gtk::RadioButtonGroup g = _whole.get_group ();
- _first.set_group (g);
-
- g = _black_out.get_group ();
- _cut.set_group (g);
-
- _n_frames.set_range (1, INT_MAX - 1);
- _n_frames.set_increments (24, 24 * 60);
- if (_film->dcp_frames() > 0) {
- _whole.set_active (false);
- _first.set_active (true);
- _n_frames.set_value (_film->dcp_frames ());
- } else {
- _whole.set_active (true);
- _first.set_active (false);
- _n_frames.set_value (24);
- }
-
- _black_out.set_active (_film->dcp_trim_action() == BLACK_OUT);
- _cut.set_active (_film->dcp_trim_action() == CUT);
-
- _whole.signal_toggled().connect (sigc::mem_fun (*this, &DCPRangeDialog::whole_toggled));
- _cut.signal_toggled().connect (sigc::mem_fun (*this, &DCPRangeDialog::cut_toggled));
- _n_frames.signal_value_changed().connect (sigc::mem_fun (*this, &DCPRangeDialog::n_frames_changed));
-
- get_vbox()->pack_start (*table);
-
- add_button ("Close", Gtk::RESPONSE_CLOSE);
- show_all_children ();
-
- set_sensitivity ();
-}
-
-void
-DCPRangeDialog::whole_toggled ()
-{
- set_sensitivity ();
- emit_changed ();
-}
-
-void
-DCPRangeDialog::set_sensitivity ()
-{
- _n_frames.set_sensitive (_first.get_active ());
- _black_out.set_sensitive (_first.get_active ());
- _cut.set_sensitive (_first.get_active ());
-}
-
-void
-DCPRangeDialog::cut_toggled ()
-{
- emit_changed ();
-}
-
-void
-DCPRangeDialog::n_frames_changed ()
-{
- emit_changed ();
-}
-
-void
-DCPRangeDialog::emit_changed ()
-{
- int frames = 0;
- if (!_whole.get_active ()) {
- frames = _n_frames.get_value_as_int ();
- }
-
- TrimAction action = CUT;
- if (_black_out.get_active ()) {
- action = BLACK_OUT;
- }
-
- Changed (frames, action);
-}
+++ /dev/null
-/*
- Copyright (C) 2012 Carl Hetherington <cth@carlh.net>
-
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 2 of the License, or
- (at your option) any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program; if not, write to the Free Software
- Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
-
-*/
-
-#include <gtkmm.h>
-#include "lib/trim_action.h"
-
-class Film;
-
-class DCPRangeDialog : public Gtk::Dialog
-{
-public:
- DCPRangeDialog (Film *);
-
- sigc::signal2<void, int, TrimAction> Changed;
-
-private:
- void whole_toggled ();
- void cut_toggled ();
- void n_frames_changed ();
-
- void set_sensitivity ();
- void emit_changed ();
-
- Film* _film;
- Gtk::RadioButton _whole;
- Gtk::RadioButton _first;
- Gtk::SpinButton _n_frames;
- Gtk::RadioButton _cut;
- Gtk::RadioButton _black_out;
-};
+++ /dev/null
-/*
- Copyright (C) 2012 Carl Hetherington <cth@carlh.net>
-
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 2 of the License, or
- (at your option) any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program; if not, write to the Free Software
- Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
-
-*/
-
-#include <cassert>
-#include <iostream>
-#include "lib/exceptions.h"
-#include "dvd_title_dialog.h"
-#include "gtk_util.h"
-
-using namespace std;
-
-DVDTitleDialog::DVDTitleDialog ()
-{
- string const dvd = find_dvd ();
- if (dvd.empty ()) {
- throw DVDError ("could not find DVD");
- }
-
- list<DVDTitle> t = dvd_titles (dvd);
- if (t.empty ()) {
- throw DVDError ("no titles found on DVD");
- }
-
- set_title ("Choose DVD title");
- get_vbox()->set_border_width (6);
- get_vbox()->set_spacing (3);
-
- Gtk::RadioButtonGroup g;
- for (list<DVDTitle>::const_iterator i = t.begin(); i != t.end(); ++i) {
- Gtk::RadioButton* b = manage (new Gtk::RadioButton);
- stringstream s;
-#if HAVE_G_FORMAT_SIZE
- s << "Title " << i->number << ": " << g_format_size (i->size);
-#else
- s << "Title " << i->number << ": " << g_format_size_for_display (i->size);
-#endif
- b->set_label (s.str ());
- if (i == t.begin ()) {
- b->set_active ();
- g = b->get_group ();
- } else {
- b->set_group (g);
- }
- get_vbox()->pack_start (*b);
- _buttons[*i] = b;
- }
-
- add_button ("Cancel", Gtk::RESPONSE_CANCEL);
- add_button ("Copy Title", Gtk::RESPONSE_OK);
-
- show_all ();
-}
-
-DVDTitle
-DVDTitleDialog::selected ()
-{
- std::map<DVDTitle, Gtk::RadioButton *>::const_iterator i = _buttons.begin ();
- while (i != _buttons.end() && i->second->get_active() == false) {
- ++i;
- }
-
- assert (i != _buttons.end ());
- return i->first;
-}
+++ /dev/null
-/*
- Copyright (C) 2012 Carl Hetherington <cth@carlh.net>
-
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 2 of the License, or
- (at your option) any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program; if not, write to the Free Software
- Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
-
-*/
-
-#include <gtkmm.h>
-#include "lib/dvd.h"
-
-class DVDTitleDialog : public Gtk::Dialog
-{
-public:
- DVDTitleDialog ();
-
- DVDTitle selected ();
-
-private:
- std::map<DVDTitle, Gtk::RadioButton *> _buttons;
-};
+++ /dev/null
-/*
- Copyright (C) 2012 Carl Hetherington <cth@carlh.net>
-
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 2 of the License, or
- (at your option) any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program; if not, write to the Free Software
- Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
-
-*/
-
-/** @file src/film_editor.cc
- * @brief A GTK widget to edit a film's metadata, and perform various functions.
- */
-
-#include <iostream>
-#include <gtkmm.h>
-#include <boost/thread.hpp>
-#include <boost/filesystem.hpp>
-#include "lib/format.h"
-#include "lib/film.h"
-#include "lib/transcode_job.h"
-#include "lib/exceptions.h"
-#include "lib/ab_transcode_job.h"
-#include "lib/thumbs_job.h"
-#include "lib/job_manager.h"
-#include "lib/filter.h"
-#include "lib/screen.h"
-#include "lib/config.h"
-#include "filter_dialog.h"
-#include "gtk_util.h"
-#include "film_editor.h"
-#include "dcp_range_dialog.h"
-
-using namespace std;
-using namespace boost;
-using namespace Gtk;
-
-/** @param f Film to edit */
-FilmEditor::FilmEditor (Film* f)
- : _film (f)
- , _filters_button ("Edit...")
- , _change_dcp_range_button ("Edit...")
- , _dcp_ab ("A/B")
-{
- _vbox.set_border_width (12);
- _vbox.set_spacing (12);
-
- /* Set up our editing widgets */
- _left_crop.set_range (0, 1024);
- _left_crop.set_increments (1, 16);
- _top_crop.set_range (0, 1024);
- _top_crop.set_increments (1, 16);
- _right_crop.set_range (0, 1024);
- _right_crop.set_increments (1, 16);
- _bottom_crop.set_range (0, 1024);
- _bottom_crop.set_increments (1, 16);
- _filters.set_alignment (0, 0.5);
- _audio_gain.set_range (-60, 60);
- _audio_gain.set_increments (1, 3);
- _audio_delay.set_range (-1000, 1000);
- _audio_delay.set_increments (1, 20);
- _still_duration.set_range (0, 60 * 60);
- _still_duration.set_increments (1, 5);
- _dcp_range.set_alignment (0, 0.5);
-
- vector<Format const *> fmt = Format::all ();
- for (vector<Format const *>::iterator i = fmt.begin(); i != fmt.end(); ++i) {
- _format.append_text ((*i)->name ());
- }
-
- _frames_per_second.set_increments (1, 5);
- _frames_per_second.set_digits (2);
- _frames_per_second.set_range (0, 60);
-
- vector<DCPContentType const *> const ct = DCPContentType::all ();
- for (vector<DCPContentType const *>::const_iterator i = ct.begin(); i != ct.end(); ++i) {
- _dcp_content_type.append_text ((*i)->pretty_name ());
- }
-
- vector<Scaler const *> const sc = Scaler::all ();
- for (vector<Scaler const *>::const_iterator i = sc.begin(); i != sc.end(); ++i) {
- _scaler.append_text ((*i)->name ());
- }
-
- _original_size.set_alignment (0, 0.5);
- _length.set_alignment (0, 0.5);
- _audio.set_alignment (0, 0.5);
-
- /* And set their values from the Film */
- set_film (f);
-
- /* Now connect to them, since initial values are safely set */
- _name.signal_changed().connect (sigc::mem_fun (*this, &FilmEditor::name_changed));
- _frames_per_second.signal_changed().connect (sigc::mem_fun (*this, &FilmEditor::frames_per_second_changed));
- _format.signal_changed().connect (sigc::mem_fun (*this, &FilmEditor::format_changed));
- _content.signal_file_set().connect (sigc::mem_fun (*this, &FilmEditor::content_changed));
- _left_crop.signal_value_changed().connect (sigc::mem_fun (*this, &FilmEditor::left_crop_changed));
- _right_crop.signal_value_changed().connect (sigc::mem_fun (*this, &FilmEditor::right_crop_changed));
- _top_crop.signal_value_changed().connect (sigc::mem_fun (*this, &FilmEditor::top_crop_changed));
- _bottom_crop.signal_value_changed().connect (sigc::mem_fun (*this, &FilmEditor::bottom_crop_changed));
- _filters_button.signal_clicked().connect (sigc::mem_fun (*this, &FilmEditor::edit_filters_clicked));
- _scaler.signal_changed().connect (sigc::mem_fun (*this, &FilmEditor::scaler_changed));
- _dcp_content_type.signal_changed().connect (sigc::mem_fun (*this, &FilmEditor::dcp_content_type_changed));
- _dcp_ab.signal_toggled().connect (sigc::mem_fun (*this, &FilmEditor::dcp_ab_toggled));
- _audio_gain.signal_value_changed().connect (sigc::mem_fun (*this, &FilmEditor::audio_gain_changed));
- _audio_delay.signal_value_changed().connect (sigc::mem_fun (*this, &FilmEditor::audio_delay_changed));
- _still_duration.signal_value_changed().connect (sigc::mem_fun (*this, &FilmEditor::still_duration_changed));
- _change_dcp_range_button.signal_clicked().connect (sigc::mem_fun (*this, &FilmEditor::change_dcp_range_clicked));
-
- /* Set up the table */
-
- Table* t = manage (new Table);
-
- t->set_row_spacings (4);
- t->set_col_spacings (12);
-
- int n = 0;
- t->attach (left_aligned_label ("Name"), 0, 1, n, n + 1);
- t->attach (_name, 1, 2, n, n + 1);
- ++n;
- t->attach (left_aligned_label ("Content"), 0, 1, n, n + 1);
- t->attach (_content, 1, 2, n, n + 1);
- ++n;
- t->attach (left_aligned_label ("Content Type"), 0, 1, n, n + 1);
- t->attach (_dcp_content_type, 1, 2, n, n + 1);
- ++n;
- t->attach (video_widget (left_aligned_label ("Frames Per Second")), 0, 1, n, n + 1);
- t->attach (video_widget (_frames_per_second), 1, 2, n, n + 1);
- ++n;
- t->attach (left_aligned_label ("Format"), 0, 1, n, n + 1);
- t->attach (_format, 1, 2, n, n + 1);
- ++n;
- t->attach (left_aligned_label ("Crop"), 0, 1, n, n + 1);
- HBox* c = manage (new HBox);
- c->set_spacing (4);
- c->pack_start (left_aligned_label ("L"), false, false);
- c->pack_start (_left_crop, true, true);
- c->pack_start (left_aligned_label ("R"), false, false);
- c->pack_start (_right_crop, true, true);
- c->pack_start (left_aligned_label ("T"), false, false);
- c->pack_start (_top_crop, true, true);
- c->pack_start (left_aligned_label ("B"), false, false);
- c->pack_start (_bottom_crop, true, true);
- t->attach (*c, 1, 2, n, n + 1);
- ++n;
-
- int const special = n;
-
- /* VIDEO-only stuff */
- t->attach (video_widget (left_aligned_label ("Filters")), 0, 1, n, n + 1);
- HBox* fb = manage (new HBox);
- fb->set_spacing (4);
- fb->pack_start (video_widget (_filters), true, true);
- fb->pack_start (video_widget (_filters_button), false, false);
- t->attach (*fb, 1, 2, n, n + 1);
- ++n;
- t->attach (video_widget (left_aligned_label ("Scaler")), 0, 1, n, n + 1);
- t->attach (video_widget (_scaler), 1, 2, n, n + 1);
- ++n;
- t->attach (video_widget (left_aligned_label ("Audio Gain")), 0, 1, n, n + 1);
- t->attach (video_widget (_audio_gain), 1, 2, n, n + 1);
- t->attach (video_widget (left_aligned_label ("dB")), 2, 3, n, n + 1);
- ++n;
- t->attach (video_widget (left_aligned_label ("Audio Delay")), 0, 1, n, n + 1);
- t->attach (video_widget (_audio_delay), 1, 2, n, n + 1);
- t->attach (video_widget (left_aligned_label ("ms")), 2, 3, n, n + 1);
- ++n;
- t->attach (video_widget (left_aligned_label ("Original Size")), 0, 1, n, n + 1);
- t->attach (video_widget (_original_size), 1, 2, n, n + 1);
- ++n;
- t->attach (video_widget (left_aligned_label ("Length")), 0, 1, n, n + 1);
- t->attach (video_widget (_length), 1, 2, n, n + 1);
- ++n;
- t->attach (video_widget (left_aligned_label ("Audio")), 0, 1, n, n + 1);
- t->attach (video_widget (_audio), 1, 2, n, n + 1);
- ++n;
- t->attach (video_widget (left_aligned_label ("Range")), 0, 1, n, n + 1);
- Gtk::HBox* db = manage (new Gtk::HBox);
- db->pack_start (_dcp_range, true, true);
- video_widget (_dcp_range);
- db->pack_start (_change_dcp_range_button, false, false);
- video_widget (_change_dcp_range_button);
- t->attach (*db, 1, 2, n, n + 1);
- ++n;
- t->attach (_dcp_ab, 0, 3, n, n + 1);
- video_widget (_dcp_ab);
-
- /* STILL-only stuff */
- n = special;
- t->attach (still_widget (left_aligned_label ("Duration")), 0, 1, n, n + 1);
- t->attach (still_widget (_still_duration), 1, 2, n, n + 1);
- t->attach (still_widget (left_aligned_label ("s")), 2, 3, n, n + 1);
- ++n;
-
- t->show_all ();
- _vbox.pack_start (*t, false, false);
-
- setup_visibility ();
-}
-
-/** @return Our main widget, which contains everything else */
-Widget&
-FilmEditor::widget ()
-{
- return _vbox;
-}
-
-/** Called when the left crop widget has been changed */
-void
-FilmEditor::left_crop_changed ()
-{
- if (_film) {
- _film->set_left_crop (_left_crop.get_value ());
- }
-}
-
-/** Called when the right crop widget has been changed */
-void
-FilmEditor::right_crop_changed ()
-{
- if (_film) {
- _film->set_right_crop (_right_crop.get_value ());
- }
-}
-
-/** Called when the top crop widget has been changed */
-void
-FilmEditor::top_crop_changed ()
-{
- if (_film) {
- _film->set_top_crop (_top_crop.get_value ());
- }
-}
-
-/** Called when the bottom crop value has been changed */
-void
-FilmEditor::bottom_crop_changed ()
-{
- if (_film) {
- _film->set_bottom_crop (_bottom_crop.get_value ());
- }
-}
-
-/** Called when the content filename has been changed */
-void
-FilmEditor::content_changed ()
-{
- if (!_film) {
- return;
- }
-
- try {
- _film->set_content (_content.get_filename ());
- } catch (std::exception& e) {
- _content.set_filename (_film->directory ());
- stringstream m;
- m << "Could not set content: " << e.what() << ".";
- Gtk::MessageDialog d (m.str(), false, MESSAGE_ERROR);
- d.set_title ("DVD-o-matic");
- d.run ();
- }
-}
-
-/** Called when the DCP A/B switch has been toggled */
-void
-FilmEditor::dcp_ab_toggled ()
-{
- if (_film) {
- _film->set_dcp_ab (_dcp_ab.get_active ());
- }
-}
-
-/** Called when the name widget has been changed */
-void
-FilmEditor::name_changed ()
-{
- if (_film) {
- _film->set_name (_name.get_text ());
- }
-}
-
-/** Called when the metadata stored in the Film object has changed;
- * so that we can update the GUI.
- * @param p Property of the Film that has changed.
- */
-void
-FilmEditor::film_changed (Film::Property p)
-{
- if (!_film) {
- return;
- }
-
- stringstream s;
-
- switch (p) {
- case Film::CONTENT:
- _content.set_filename (_film->content ());
- setup_visibility ();
- break;
- case Film::FORMAT:
- _format.set_active (Format::as_index (_film->format ()));
- break;
- case Film::LEFT_CROP:
- _left_crop.set_value (_film->left_crop ());
- break;
- case Film::RIGHT_CROP:
- _right_crop.set_value (_film->right_crop ());
- break;
- case Film::TOP_CROP:
- _top_crop.set_value (_film->top_crop ());
- break;
- case Film::BOTTOM_CROP:
- _bottom_crop.set_value (_film->bottom_crop ());
- break;
- case Film::FILTERS:
- {
- pair<string, string> p = Filter::ffmpeg_strings (_film->filters ());
- _filters.set_text (p.first + " " + p.second);
- break;
- }
- case Film::NAME:
- _name.set_text (_film->name ());
- break;
- case Film::FRAMES_PER_SECOND:
- _frames_per_second.set_value (_film->frames_per_second ());
- break;
- case Film::AUDIO_CHANNELS:
- case Film::AUDIO_SAMPLE_RATE:
- if (_film->audio_channels() == 0 && _film->audio_sample_rate() == 0) {
- _audio.set_text ("");
- } else {
- s << _film->audio_channels () << " channels, " << _film->audio_sample_rate() << "Hz";
- _audio.set_text (s.str ());
- }
- break;
- case Film::SIZE:
- if (_film->size().width == 0 && _film->size().height == 0) {
- _original_size.set_text ("");
- } else {
- s << _film->size().width << " x " << _film->size().height;
- _original_size.set_text (s.str ());
- }
- break;
- case Film::LENGTH:
- if (_film->frames_per_second() > 0 && _film->length() > 0) {
- s << _film->length() << " frames; " << seconds_to_hms (_film->length() / _film->frames_per_second());
- } else if (_film->length() > 0) {
- s << _film->length() << " frames";
- }
- _length.set_text (s.str ());
- break;
- case Film::DCP_CONTENT_TYPE:
- _dcp_content_type.set_active (DCPContentType::as_index (_film->dcp_content_type ()));
- break;
- case Film::THUMBS:
- break;
- case Film::DCP_FRAMES:
- if (_film->dcp_frames() == 0) {
- _dcp_range.set_text ("Whole film");
- } else {
- stringstream s;
- s << "First " << _film->dcp_frames() << " frames";
- _dcp_range.set_text (s.str ());
- }
- break;
- case Film::DCP_TRIM_ACTION:
- break;
- case Film::DCP_AB:
- _dcp_ab.set_active (_film->dcp_ab ());
- break;
- case Film::SCALER:
- _scaler.set_active (Scaler::as_index (_film->scaler ()));
- break;
- case Film::AUDIO_GAIN:
- _audio_gain.set_value (_film->audio_gain ());
- break;
- case Film::AUDIO_DELAY:
- _audio_delay.set_value (_film->audio_delay ());
- break;
- case Film::STILL_DURATION:
- _still_duration.set_value (_film->still_duration ());
- break;
- }
-}
-
-/** Called when the format widget has been changed */
-void
-FilmEditor::format_changed ()
-{
- if (_film) {
- int const n = _format.get_active_row_number ();
- if (n >= 0) {
- _film->set_format (Format::from_index (n));
- }
- }
-}
-
-/** Called when the DCP content type widget has been changed */
-void
-FilmEditor::dcp_content_type_changed ()
-{
- if (_film) {
- int const n = _dcp_content_type.get_active_row_number ();
- if (n >= 0) {
- _film->set_dcp_content_type (DCPContentType::from_index (n));
- }
- }
-}
-
-/** Sets the Film that we are editing */
-void
-FilmEditor::set_film (Film* f)
-{
- _film = f;
-
- set_things_sensitive (_film != 0);
-
- if (_film) {
- _film->Changed.connect (sigc::mem_fun (*this, &FilmEditor::film_changed));
- }
-
- if (_film) {
- FileChanged (_film->directory ());
- } else {
- FileChanged ("");
- }
-
- film_changed (Film::NAME);
- film_changed (Film::CONTENT);
- film_changed (Film::DCP_CONTENT_TYPE);
- film_changed (Film::FORMAT);
- film_changed (Film::LEFT_CROP);
- film_changed (Film::RIGHT_CROP);
- film_changed (Film::TOP_CROP);
- film_changed (Film::BOTTOM_CROP);
- film_changed (Film::FILTERS);
- film_changed (Film::DCP_FRAMES);
- film_changed (Film::DCP_TRIM_ACTION);
- film_changed (Film::DCP_AB);
- film_changed (Film::SIZE);
- film_changed (Film::LENGTH);
- film_changed (Film::FRAMES_PER_SECOND);
- film_changed (Film::AUDIO_CHANNELS);
- film_changed (Film::AUDIO_SAMPLE_RATE);
- film_changed (Film::SCALER);
- film_changed (Film::AUDIO_GAIN);
- film_changed (Film::AUDIO_DELAY);
- film_changed (Film::STILL_DURATION);
-}
-
-/** Updates the sensitivity of lots of widgets to a given value.
- * @param s true to make sensitive, false to make insensitive.
- */
-void
-FilmEditor::set_things_sensitive (bool s)
-{
- _name.set_sensitive (s);
- _frames_per_second.set_sensitive (s);
- _format.set_sensitive (s);
- _content.set_sensitive (s);
- _left_crop.set_sensitive (s);
- _right_crop.set_sensitive (s);
- _top_crop.set_sensitive (s);
- _bottom_crop.set_sensitive (s);
- _filters_button.set_sensitive (s);
- _scaler.set_sensitive (s);
- _dcp_content_type.set_sensitive (s);
- _dcp_range.set_sensitive (s);
- _change_dcp_range_button.set_sensitive (s);
- _dcp_ab.set_sensitive (s);
- _audio_gain.set_sensitive (s);
- _audio_delay.set_sensitive (s);
- _still_duration.set_sensitive (s);
-}
-
-/** Called when the `Edit filters' button has been clicked */
-void
-FilmEditor::edit_filters_clicked ()
-{
- FilterDialog d (_film->filters ());
- d.ActiveChanged.connect (sigc::mem_fun (*_film, &Film::set_filters));
- d.run ();
-}
-
-/** Called when the scaler widget has been changed */
-void
-FilmEditor::scaler_changed ()
-{
- if (_film) {
- int const n = _scaler.get_active_row_number ();
- if (n >= 0) {
- _film->set_scaler (Scaler::from_index (n));
- }
- }
-}
-
-/** Called when the frames per second widget has been changed */
-void
-FilmEditor::frames_per_second_changed ()
-{
- if (_film) {
- _film->set_frames_per_second (_frames_per_second.get_value ());
- }
-}
-
-void
-FilmEditor::audio_gain_changed ()
-{
- if (_film) {
- _film->set_audio_gain (_audio_gain.get_value ());
- }
-}
-
-void
-FilmEditor::audio_delay_changed ()
-{
- if (_film) {
- _film->set_audio_delay (_audio_delay.get_value ());
- }
-}
-
-Widget&
-FilmEditor::video_widget (Widget& w)
-{
- _video_widgets.push_back (&w);
- return w;
-}
-
-Widget&
-FilmEditor::still_widget (Widget& w)
-{
- _still_widgets.push_back (&w);
- return w;
-}
-
-void
-FilmEditor::setup_visibility ()
-{
- ContentType c = VIDEO;
-
- if (_film) {
- c = _film->content_type ();
- }
-
- for (list<Widget *>::iterator i = _video_widgets.begin(); i != _video_widgets.end(); ++i) {
- (*i)->property_visible() = (c == VIDEO);
- }
-
- for (list<Widget *>::iterator i = _still_widgets.begin(); i != _still_widgets.end(); ++i) {
- (*i)->property_visible() = (c == STILL);
- }
-}
-
-void
-FilmEditor::still_duration_changed ()
-{
- if (_film) {
- _film->set_still_duration (_still_duration.get_value ());
- }
-}
-
-void
-FilmEditor::change_dcp_range_clicked ()
-{
- DCPRangeDialog d (_film);
- d.Changed.connect (sigc::mem_fun (*this, &FilmEditor::dcp_range_changed));
- d.run ();
-}
-
-void
-FilmEditor::dcp_range_changed (int frames, TrimAction action)
-{
- _film->set_dcp_frames (frames);
- _film->set_dcp_trim_action (action);
-}
+++ /dev/null
-/*
- Copyright (C) 2012 Carl Hetherington <cth@carlh.net>
-
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 2 of the License, or
- (at your option) any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program; if not, write to the Free Software
- Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
-
-*/
-
-/** @file src/film_editor.h
- * @brief A GTK widget to edit a film's metadata, and perform various functions.
- */
-
-#include <gtkmm.h>
-
-class Film;
-
-/** @class FilmEditor
- * @brief A GTK widget to edit a film's metadata, and perform various functions.
- */
-class FilmEditor
-{
-public:
- FilmEditor (Film *);
-
- Gtk::Widget& widget ();
-
- void set_film (Film *);
- void setup_visibility ();
-
- sigc::signal1<void, std::string> FileChanged;
-
-private:
- /* Handle changes to the view */
- void name_changed ();
- void left_crop_changed ();
- void right_crop_changed ();
- void top_crop_changed ();
- void bottom_crop_changed ();
- void content_changed ();
- void frames_per_second_changed ();
- void format_changed ();
- void dcp_range_changed (int, TrimAction);
- void dcp_content_type_changed ();
- void dcp_ab_toggled ();
- void scaler_changed ();
- void audio_gain_changed ();
- void audio_delay_changed ();
- void still_duration_changed ();
-
- /* Handle changes to the model */
- void film_changed (Film::Property);
-
- /* Button clicks */
- void edit_filters_clicked ();
- void change_dcp_range_clicked ();
-
- void set_things_sensitive (bool);
-
- Gtk::Widget & video_widget (Gtk::Widget &);
- Gtk::Widget & still_widget (Gtk::Widget &);
-
- /** The film we are editing */
- Film* _film;
- /** The overall VBox containing our widget */
- Gtk::VBox _vbox;
- /** The Film's name */
- Gtk::Entry _name;
- /** The Film's frames per second */
- Gtk::SpinButton _frames_per_second;
- /** The Film's format */
- Gtk::ComboBoxText _format;
- /** The Film's content file */
- Gtk::FileChooserButton _content;
- /** The Film's left crop */
- Gtk::SpinButton _left_crop;
- /** The Film's right crop */
- Gtk::SpinButton _right_crop;
- /** The Film's top crop */
- Gtk::SpinButton _top_crop;
- /** The Film's bottom crop */
- Gtk::SpinButton _bottom_crop;
- /** Currently-applied filters */
- Gtk::Label _filters;
- /** Button to open the filters dialogue */
- Gtk::Button _filters_button;
- /** The Film's scaler */
- Gtk::ComboBoxText _scaler;
- /** The Film's audio gain */
- Gtk::SpinButton _audio_gain;
- /** The Film's audio delay */
- Gtk::SpinButton _audio_delay;
- /** The Film's DCP content type */
- Gtk::ComboBoxText _dcp_content_type;
- /** The Film's original size */
- Gtk::Label _original_size;
- /** The Film's length */
- Gtk::Label _length;
- /** The Film's audio details */
- Gtk::Label _audio;
- /** The Film's duration for still sources */
- Gtk::SpinButton _still_duration;
-
- /** Button to start making a DCP from existing J2K and WAV files */
- Gtk::Button _make_dcp_from_existing_button;
- /** Display of the range of frames that will be used */
- Gtk::Label _dcp_range;
- /** Button to change the range */
- Gtk::Button _change_dcp_range_button;
- /** Selector to generate an A/B comparison DCP */
- Gtk::CheckButton _dcp_ab;
-
- std::list<Gtk::Widget*> _video_widgets;
- std::list<Gtk::Widget*> _still_widgets;
-};
+++ /dev/null
-/*
- Copyright (C) 2012 Carl Hetherington <cth@carlh.net>
-
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 2 of the License, or
- (at your option) any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program; if not, write to the Free Software
- Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
-
-*/
-
-#include <boost/filesystem.hpp>
-#include "lib/film.h"
-#include "film_list.h"
-
-using namespace std;
-using namespace boost;
-
-FilmList::FilmList (string d)
- : _directory (d)
- , _list (1)
-{
- for (filesystem::directory_iterator i = filesystem::directory_iterator (_directory); i != filesystem::directory_iterator(); ++i) {
- if (is_directory (*i)) {
- filesystem::path m = filesystem::path (*i) / filesystem::path ("metadata");
- if (is_regular_file (m)) {
- Film* f = new Film (i->path().string());
- _films.push_back (f);
- }
- }
- }
-
- for (vector<Film const *>::iterator i = _films.begin(); i != _films.end(); ++i) {
- _list.append_text ((*i)->name ());
- }
-
- _list.set_headers_visible (false);
- _list.get_selection()->signal_changed().connect (sigc::mem_fun (*this, &FilmList::selection_changed));
-}
-
-Gtk::Widget&
-FilmList::widget ()
-{
- return _list;
-}
-
-void
-FilmList::selection_changed ()
-{
- Gtk::ListViewText::SelectionList s = _list.get_selected ();
- if (s.empty ()) {
- return;
- }
-
- assert (s[0] < int (_films.size ()));
- SelectionChanged (_films[s[0]]);
-}
+++ /dev/null
-/*
- Copyright (C) 2012 Carl Hetherington <cth@carlh.net>
-
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 2 of the License, or
- (at your option) any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program; if not, write to the Free Software
- Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
-
-*/
-
-#include <string>
-#include <vector>
-#include <gtkmm.h>
-
-class Film;
-
-class FilmList
-{
-public:
- FilmList (std::string);
-
- Gtk::Widget& widget ();
-
- sigc::signal<void, Film const *> SelectionChanged;
-
-private:
- void selection_changed ();
-
- std::string _directory;
- std::vector<Film const *> _films;
- Gtk::ListViewText _list;
-};
+++ /dev/null
-/*
- Copyright (C) 2012 Carl Hetherington <cth@carlh.net>
-
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 2 of the License, or
- (at your option) any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program; if not, write to the Free Software
- Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
-
-*/
-
-#include "lib/screen.h"
-#include "lib/config.h"
-#include "lib/player_manager.h"
-#include "lib/film.h"
-#include "film_player.h"
-#include "gtk_util.h"
-
-using namespace std;
-using namespace boost;
-
-FilmPlayer::FilmPlayer (Film const * f)
- : _play ("Play")
- , _pause ("Pause")
- , _stop ("Stop")
- , _ab ("A/B")
- , _ignore_position_changed (false)
-{
- set_film (f);
-
- vector<shared_ptr<Screen> > const scr = Config::instance()->screens ();
- for (vector<shared_ptr<Screen> >::const_iterator i = scr.begin(); i != scr.end(); ++i) {
- _screen.append_text ((*i)->name ());
- }
-
- if (!scr.empty ()) {
- _screen.set_active (0);
- }
-
- _status.set_use_markup (true);
-
- _position.set_digits (0);
-
- _main_vbox.set_spacing (12);
-
- Gtk::HBox* l = manage (new Gtk::HBox);
- l->pack_start (_play);
- l->pack_start (_pause);
- l->pack_start (_stop);
-
- Gtk::VBox* r = manage (new Gtk::VBox);
- r->pack_start (_screen, false, false);
- r->pack_start (_ab, false, false);
- r->pack_start (*manage (new Gtk::Label ("")), true, true);
-
- Gtk::HBox* t = manage (new Gtk::HBox);
- t->pack_start (*l, true, true);
- t->pack_start (*r, false, false);
-
- _main_vbox.pack_start (*t, true, true);
- _main_vbox.pack_start (_position, false, false);
- _main_vbox.pack_start (_status, false, false);
-
- _play.signal_clicked().connect (sigc::mem_fun (*this, &FilmPlayer::play_clicked));
- _pause.signal_clicked().connect (sigc::mem_fun (*this, &FilmPlayer::pause_clicked));
- _stop.signal_clicked().connect (sigc::mem_fun (*this, &FilmPlayer::stop_clicked));
- _position.signal_value_changed().connect (sigc::mem_fun (*this, &FilmPlayer::position_changed));
- _position.signal_format_value().connect (sigc::mem_fun (*this, &FilmPlayer::format_position));
-
- set_button_states ();
- Glib::signal_timeout().connect (sigc::bind_return (sigc::mem_fun (*this, &FilmPlayer::update), true), 1000);
-
- Config::instance()->Changed.connect (sigc::mem_fun (*this, &FilmPlayer::update_screens));
-}
-
-void
-FilmPlayer::set_film (Film const * f)
-{
- _film = f;
-
- if (_film && _film->length() != 0 && _film->frames_per_second() != 0) {
- _position.set_range (0, _film->length() / _film->frames_per_second());
- }
-
- if (_film) {
- _film->Changed.connect (sigc::mem_fun (*this, &FilmPlayer::film_changed));
- }
-}
-
-Gtk::Widget &
-FilmPlayer::widget ()
-{
- return _main_vbox;
-}
-
-void
-FilmPlayer::set_button_states ()
-{
- if (_film == 0) {
- _play.set_sensitive (false);
- _pause.set_sensitive (false);
- _stop.set_sensitive (false);
- _screen.set_sensitive (false);
- _position.set_sensitive (false);
- _ab.set_sensitive (false);
- return;
- }
-
- PlayerManager::State s = PlayerManager::instance()->state ();
-
- switch (s) {
- case PlayerManager::QUIESCENT:
- _play.set_sensitive (true);
- _pause.set_sensitive (false);
- _stop.set_sensitive (false);
- _screen.set_sensitive (true);
- _position.set_sensitive (false);
- _ab.set_sensitive (true);
- break;
- case PlayerManager::PLAYING:
- _play.set_sensitive (false);
- _pause.set_sensitive (true);
- _stop.set_sensitive (true);
- _screen.set_sensitive (false);
- _position.set_sensitive (true);
- _ab.set_sensitive (false);
- break;
- case PlayerManager::PAUSED:
- _play.set_sensitive (true);
- _pause.set_sensitive (false);
- _stop.set_sensitive (true);
- _screen.set_sensitive (false);
- _position.set_sensitive (false);
- _ab.set_sensitive (false);
- break;
- }
-}
-
-void
-FilmPlayer::play_clicked ()
-{
- PlayerManager* p = PlayerManager::instance ();
-
- switch (p->state ()) {
- case PlayerManager::QUIESCENT:
- _last_play_fs = _film->state_copy ();
- if (_ab.get_active ()) {
- shared_ptr<FilmState> fs_a = _film->state_copy ();
- fs_a->filters.clear ();
- /* This is somewhat arbitrary, but hey ho */
- fs_a->scaler = Scaler::from_id ("bicubic");
- p->setup (fs_a, _last_play_fs, screen ());
- } else {
- p->setup (_last_play_fs, screen ());
- }
- p->pause_or_unpause ();
- break;
- case PlayerManager::PLAYING:
- break;
- case PlayerManager::PAUSED:
- p->pause_or_unpause ();
- break;
- }
-}
-
-void
-FilmPlayer::pause_clicked ()
-{
- PlayerManager* p = PlayerManager::instance ();
-
- switch (p->state ()) {
- case PlayerManager::QUIESCENT:
- break;
- case PlayerManager::PLAYING:
- p->pause_or_unpause ();
- break;
- case PlayerManager::PAUSED:
- break;
- }
-}
-
-void
-FilmPlayer::stop_clicked ()
-{
- PlayerManager::instance()->stop ();
-}
-
-shared_ptr<Screen>
-FilmPlayer::screen () const
-{
- vector<shared_ptr<Screen> > const s = Config::instance()->screens ();
- if (s.empty ()) {
- return shared_ptr<Screen> ();
- }
-
- int const r = _screen.get_active_row_number ();
- if (r >= int (s.size ())) {
- return s[0];
- }
-
- return s[r];
-}
-
-void
-FilmPlayer::update ()
-{
- set_button_states ();
- set_status ();
-}
-
-void
-FilmPlayer::set_status ()
-{
- PlayerManager::State s = PlayerManager::instance()->state ();
-
- stringstream m;
- switch (s) {
- case PlayerManager::QUIESCENT:
- m << "Idle";
- break;
- case PlayerManager::PLAYING:
- m << "<span foreground=\"red\" weight=\"bold\">PLAYING</span>";
- break;
- case PlayerManager::PAUSED:
- m << "<b>Paused</b>";
- break;
- }
-
- _ignore_position_changed = true;
-
- if (s != PlayerManager::QUIESCENT) {
- float const p = PlayerManager::instance()->position ();
- if (_last_play_fs->frames_per_second != 0 && _last_play_fs->length != 0) {
- m << " <i>(" << seconds_to_hms (_last_play_fs->length / _last_play_fs->frames_per_second - p) << " remaining)</i>";
- }
-
- _position.set_value (p);
- } else {
- _position.set_value (0);
- }
-
- _ignore_position_changed = false;
-
- _status.set_markup (m.str ());
-}
-
-void
-FilmPlayer::position_changed ()
-{
- if (_ignore_position_changed) {
- return;
- }
-
- PlayerManager::instance()->set_position (_position.get_value ());
-}
-
-string
-FilmPlayer::format_position (double v)
-{
- return seconds_to_hms (v);
-}
-
-void
-FilmPlayer::update_screens ()
-{
- string const c = _screen.get_active_text ();
-
- _screen.clear ();
-
- vector<shared_ptr<Screen> > const scr = Config::instance()->screens ();
- bool have_last_active_text = false;
- for (vector<shared_ptr<Screen> >::const_iterator i = scr.begin(); i != scr.end(); ++i) {
- _screen.append_text ((*i)->name ());
- if ((*i)->name() == c) {
- have_last_active_text = true;
- }
- }
-
- if (have_last_active_text) {
- _screen.set_active_text (c);
- } else if (!scr.empty ()) {
- _screen.set_active (0);
- }
-}
-
-void
-FilmPlayer::film_changed (Film::Property p)
-{
- if (p == Film::CONTENT) {
- setup_visibility ();
- }
-}
-
-void
-FilmPlayer::setup_visibility ()
-{
- if (!_film) {
- return;
- }
-
- widget().property_visible() = (_film->content_type() == VIDEO);
-}
+++ /dev/null
-/*
- Copyright (C) 2012 Carl Hetherington <cth@carlh.net>
-
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 2 of the License, or
- (at your option) any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program; if not, write to the Free Software
- Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
-
-*/
-
-#include <gtkmm.h>
-#include "lib/film.h"
-
-class Film;
-class Screen;
-class FilmState;
-
-class FilmPlayer
-{
-public:
- FilmPlayer (Film const * f = 0);
-
- Gtk::Widget& widget ();
-
- void set_film (Film const *);
- void setup_visibility ();
-
-private:
- void play_clicked ();
- void pause_clicked ();
- void stop_clicked ();
- void position_changed ();
- std::string format_position (double);
- void film_changed (Film::Property);
-
- void set_button_states ();
- boost::shared_ptr<Screen> screen () const;
- void set_status ();
- void update ();
- void update_screens ();
-
- Film const * _film;
- boost::shared_ptr<const FilmState> _last_play_fs;
-
- Gtk::VBox _main_vbox;
- Gtk::Button _play;
- Gtk::Button _pause;
- Gtk::Button _stop;
- Gtk::Label _status;
- Gtk::CheckButton _ab;
- Gtk::ComboBoxText _screen;
- Gtk::HScale _position;
- bool _ignore_position_changed;
-};
+++ /dev/null
-/*
- Copyright (C) 2012 Carl Hetherington <cth@carlh.net>
-
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 2 of the License, or
- (at your option) any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program; if not, write to the Free Software
- Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
-
-*/
-
-/** @file src/film_viewer.cc
- * @brief A GTK widget to view `thumbnails' of a Film.
- */
-
-#include <iostream>
-#include <iomanip>
-#include "lib/film.h"
-#include "lib/format.h"
-#include "lib/util.h"
-#include "lib/thumbs_job.h"
-#include "lib/job_manager.h"
-#include "lib/film_state.h"
-#include "lib/options.h"
-#include "film_viewer.h"
-
-using namespace std;
-using namespace boost;
-
-FilmViewer::FilmViewer (Film* f)
- : _film (f)
-{
- _scroller.add (_image);
-
- Gtk::HBox* controls = manage (new Gtk::HBox);
- controls->set_spacing (6);
- controls->pack_start (_position_slider);
-
- _vbox.pack_start (_scroller, true, true);
- _vbox.pack_start (*controls, false, false);
- _vbox.set_border_width (12);
-
- _position_slider.set_digits (0);
- _position_slider.signal_format_value().connect (sigc::mem_fun (*this, &FilmViewer::format_position_slider_value));
- _position_slider.signal_value_changed().connect (sigc::mem_fun (*this, &FilmViewer::position_slider_changed));
-
- _scroller.signal_size_allocate().connect (sigc::mem_fun (*this, &FilmViewer::scroller_size_allocate));
-
- set_film (_film);
-}
-
-void
-FilmViewer::load_thumbnail (int n)
-{
- if (_film == 0 || _film->num_thumbs() <= n) {
- return;
- }
-
- int const left = _film->left_crop ();
- int const right = _film->right_crop ();
- int const top = _film->top_crop ();
- int const bottom = _film->bottom_crop ();
-
- _pixbuf = Gdk::Pixbuf::create_from_file (_film->thumb_file (n));
-
- int const cw = _film->size().width - left - right;
- int const ch = _film->size().height - top - bottom;
- _cropped_pixbuf = Gdk::Pixbuf::create_subpixbuf (_pixbuf, left, top, cw, ch);
- update_scaled_pixbuf ();
- _image.set (_scaled_pixbuf);
-}
-
-void
-FilmViewer::reload_current_thumbnail ()
-{
- load_thumbnail (_position_slider.get_value ());
-}
-
-void
-FilmViewer::position_slider_changed ()
-{
- reload_current_thumbnail ();
-}
-
-string
-FilmViewer::format_position_slider_value (double v) const
-{
- stringstream s;
-
- if (_film && int (v) < _film->num_thumbs ()) {
- int const f = _film->thumb_frame (int (v));
- s << f << " " << seconds_to_hms (f / _film->frames_per_second ());
- } else {
- s << "-";
- }
-
- return s.str ();
-}
-
-void
-FilmViewer::film_changed (Film::Property p)
-{
- if (p == Film::LEFT_CROP || p == Film::RIGHT_CROP || p == Film::TOP_CROP || p == Film::BOTTOM_CROP) {
- reload_current_thumbnail ();
- } else if (p == Film::THUMBS) {
- if (_film && _film->num_thumbs() > 1) {
- _position_slider.set_range (0, _film->num_thumbs () - 1);
- } else {
- _image.clear ();
- _position_slider.set_range (0, 1);
- }
-
- _position_slider.set_value (0);
- reload_current_thumbnail ();
- } else if (p == Film::FORMAT) {
- reload_current_thumbnail ();
- } else if (p == Film::CONTENT) {
- setup_visibility ();
- _film->examine_content ();
- update_thumbs ();
- }
-}
-
-void
-FilmViewer::set_film (Film* f)
-{
- _film = f;
-
- if (!_film) {
- _image.clear ();
- return;
- }
-
- _film->Changed.connect (sigc::mem_fun (*this, &FilmViewer::film_changed));
-
- film_changed (Film::THUMBS);
-}
-
-pair<int, int>
-FilmViewer::scaled_pixbuf_size () const
-{
- if (_film == 0) {
- return make_pair (0, 0);
- }
-
- int const cw = _film->size().width - _film->left_crop() - _film->right_crop();
- int const ch = _film->size().height - _film->top_crop() - _film->bottom_crop();
-
- float ratio = 1;
- if (_film->format()) {
- ratio = _film->format()->ratio_as_float() * ch / cw;
- }
-
- Gtk::Allocation const a = _scroller.get_allocation ();
- float const zoom = min (float (a.get_width()) / (cw * ratio), float (a.get_height()) / cw);
- return make_pair (cw * zoom * ratio, ch * zoom);
-}
-
-void
-FilmViewer::update_scaled_pixbuf ()
-{
- pair<int, int> const s = scaled_pixbuf_size ();
-
- if (s.first > 0 && s.second > 0 && _cropped_pixbuf) {
- _scaled_pixbuf = _cropped_pixbuf->scale_simple (s.first, s.second, Gdk::INTERP_HYPER);
- _image.set (_scaled_pixbuf);
- }
-}
-
-void
-FilmViewer::update_thumbs ()
-{
- if (!_film) {
- return;
- }
-
- _film->update_thumbs_pre_gui ();
-
- shared_ptr<const FilmState> s = _film->state_copy ();
- shared_ptr<Options> o (new Options (s->dir ("thumbs"), ".tiff", ""));
- o->out_size = _film->size ();
- o->apply_crop = false;
- o->decode_audio = false;
- o->decode_video_frequency = 128;
-
- shared_ptr<Job> j (new ThumbsJob (s, o, _film->log ()));
- j->Finished.connect (sigc::mem_fun (_film, &Film::update_thumbs_post_gui));
- JobManager::instance()->add (j);
-}
-
-void
-FilmViewer::scroller_size_allocate (Gtk::Allocation a)
-{
- if (a.get_width() != _last_scroller_allocation.get_width() || a.get_height() != _last_scroller_allocation.get_height()) {
- update_scaled_pixbuf ();
- }
-
- _last_scroller_allocation = a;
-}
-
-void
-FilmViewer::setup_visibility ()
-{
- if (!_film) {
- return;
- }
-
- ContentType const c = _film->content_type ();
- _position_slider.property_visible() = (c == VIDEO);
-}
+++ /dev/null
-/*
- Copyright (C) 2012 Carl Hetherington <cth@carlh.net>
-
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 2 of the License, or
- (at your option) any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program; if not, write to the Free Software
- Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
-
-*/
-
-/** @file src/film_viewer.h
- * @brief A GTK widget to view `thumbnails' of a Film.
- */
-
-#include <gtkmm.h>
-#include "lib/film.h"
-
-/** @class FilmViewer
- * @brief A GTK widget to view `thumbnails' of a Film.
- */
-class FilmViewer
-{
-public:
- FilmViewer (Film *);
-
- Gtk::Widget& widget () {
- return _vbox;
- }
-
- void set_film (Film *);
- void setup_visibility ();
-
-private:
- void position_slider_changed ();
- void update_thumbs ();
- std::string format_position_slider_value (double) const;
- void load_thumbnail (int);
- void film_changed (Film::Property);
- void reload_current_thumbnail ();
- void update_scaled_pixbuf ();
- std::pair<int, int> scaled_pixbuf_size () const;
- void scroller_size_allocate (Gtk::Allocation);
-
- Film* _film;
- Gtk::VBox _vbox;
- Gtk::ScrolledWindow _scroller;
- Gtk::Image _image;
- Glib::RefPtr<Gdk::Pixbuf> _pixbuf;
- Glib::RefPtr<Gdk::Pixbuf> _cropped_pixbuf;
- Glib::RefPtr<Gdk::Pixbuf> _scaled_pixbuf;
- Gtk::HScale _position_slider;
- Gtk::Allocation _last_scroller_allocation;
-};
+++ /dev/null
-/*
- Copyright (C) 2012 Carl Hetherington <cth@carlh.net>
-
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 2 of the License, or
- (at your option) any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program; if not, write to the Free Software
- Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
-
-*/
-
-/** @file src/filter_dialog.cc
- * @brief A dialog to select FFmpeg filters.
- */
-
-#include "lib/film.h"
-#include "filter_dialog.h"
-
-using namespace std;
-
-FilterDialog::FilterDialog (vector<Filter const *> const & f)
- : Gtk::Dialog ("Filters")
- , _filters (f)
-{
- get_vbox()->pack_start (_filters.widget ());
-
- _filters.ActiveChanged.connect (sigc::mem_fun (*this, &FilterDialog::active_changed));
-
- add_button ("Close", Gtk::RESPONSE_CLOSE);
-
- show_all ();
-}
-
-
-void
-FilterDialog::active_changed ()
-{
- ActiveChanged (_filters.active ());
-}
+++ /dev/null
-/*
- Copyright (C) 2012 Carl Hetherington <cth@carlh.net>
-
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 2 of the License, or
- (at your option) any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program; if not, write to the Free Software
- Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
-
-*/
-
-/** @file src/filter_dialog.h
- * @brief A dialog to select FFmpeg filters.
- */
-
-#include <gtkmm.h>
-#include "filter_view.h"
-
-class Film;
-
-/** @class FilterDialog
- * @brief A dialog to select FFmpeg filters.
- */
-class FilterDialog : public Gtk::Dialog
-{
-public:
- FilterDialog (std::vector<Filter const *> const &);
-
- sigc::signal1<void, std::vector<Filter const *> > ActiveChanged;
-
-private:
- void active_changed ();
-
- FilterView _filters;
-};
+++ /dev/null
-/*
- Copyright (C) 2012 Carl Hetherington <cth@carlh.net>
-
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 2 of the License, or
- (at your option) any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program; if not, write to the Free Software
- Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
-
-*/
-
-/** @file src/filter_view.cc
- * @brief A widget to select FFmpeg filters.
- */
-
-#include <iostream>
-#include "lib/filter.h"
-#include "filter_view.h"
-
-using namespace std;
-
-FilterView::FilterView (vector<Filter const *> const & active)
-{
- _box.set_spacing (4);
-
- vector<Filter const *> filters = Filter::all ();
-
- for (vector<Filter const *>::iterator i = filters.begin(); i != filters.end(); ++i) {
- Gtk::CheckButton* b = Gtk::manage (new Gtk::CheckButton ((*i)->name()));
- bool const a = find (active.begin(), active.end(), *i) != active.end ();
- b->set_active (a);
- _filters[*i] = a;
- b->signal_toggled().connect (sigc::bind (sigc::mem_fun (*this, &FilterView::filter_toggled), *i));
- _box.pack_start (*b, false, false);
- }
-
- _box.show_all ();
-}
-
-Gtk::Widget &
-FilterView::widget ()
-{
- return _box;
-}
-
-void
-FilterView::filter_toggled (Filter const * f)
-{
- _filters[f] = !_filters[f];
- ActiveChanged ();
-}
-
-vector<Filter const*>
-FilterView::active () const
-{
- vector<Filter const *> active;
- for (map<Filter const *, bool>::const_iterator i = _filters.begin(); i != _filters.end(); ++i) {
- if (i->second) {
- active.push_back (i->first);
- }
- }
-
- return active;
-}
+++ /dev/null
-/*
- Copyright (C) 2012 Carl Hetherington <cth@carlh.net>
-
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 2 of the License, or
- (at your option) any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program; if not, write to the Free Software
- Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
-
-*/
-
-/** @file src/filter_view.h
- * @brief A widget to select FFmpeg filters.
- */
-
-#include <gtkmm.h>
-#include <vector>
-
-class Filter;
-
-/** @class FilterView
- * @brief A widget to select FFmpeg filters.
- */
-class FilterView
-{
-public:
- FilterView (std::vector<Filter const *> const &);
-
- Gtk::Widget & widget ();
- std::vector<Filter const *> active () const;
-
- sigc::signal0<void> ActiveChanged;
-
-private:
- void filter_toggled (Filter const *);
-
- Gtk::VBox _box;
- std::map<Filter const *, bool> _filters;
-};
+++ /dev/null
-/*
- Copyright (C) 2012 Carl Hetherington <cth@carlh.net>
-
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 2 of the License, or
- (at your option) any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program; if not, write to the Free Software
- Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
-
-*/
-
-/** @file src/gpl.cc
- * @brief The GPL.
- */
-
-const char* gpl = "\n\
-DVD-o-matic comes with NO WARRANTY. It is free software, and you are \n\
-welcome to redistribute it under the terms of the GNU Public License,\n\
-shown below.\n \
-\n\
- GNU GENERAL PUBLIC LICENSE\n\
- Version 2, June 1991\n\
-\n\
- Copyright (C) 1989, 1991 Free Software Foundation, Inc.\n\
- 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA\n\
- Everyone is permitted to copy and distribute verbatim copies\n\
- of this license document, but changing it is not allowed.\n\
-\n\
- Preamble\n\
-\n\
- The licenses for most software are designed to take away your\n\
-freedom to share and change it. By contrast, the GNU General Public\n\
-License is intended to guarantee your freedom to share and change free\n\
-software--to make sure the software is free for all its users. This\n\
-General Public License applies to most of the Free Software\n\
-Foundation's software and to any other program whose authors commit to\n\
-using it. (Some other Free Software Foundation software is covered by\n\
-the GNU Library General Public License instead.) You can apply it to\n\
-your programs, too.\n\
-\n\
- When we speak of free software, we are referring to freedom, not\n\
-price. Our General Public Licenses are designed to make sure that you\n\
-have the freedom to distribute copies of free software (and charge for\n\
-this service if you wish), that you receive source code or can get it\n\
-if you want it, that you can change the software or use pieces of it\n\
-in new free programs; and that you know you can do these things.\n\
-\n\
- To protect your rights, we need to make restrictions that forbid\n\
-anyone to deny you these rights or to ask you to surrender the rights.\n\
-These restrictions translate to certain responsibilities for you if you\n\
-distribute copies of the software, or if you modify it.\n\
-\n\
- For example, if you distribute copies of such a program, whether\n\
-gratis or for a fee, you must give the recipients all the rights that\n\
-you have. You must make sure that they, too, receive or can get the\n\
-source code. And you must show them these terms so they know their\n\
-rights.\n\
-\n\
- We protect your rights with two steps: (1) copyright the software, and\n\
-(2) offer you this license which gives you legal permission to copy,\n\
-distribute and/or modify the software.\n\
-\n\
- Also, for each author's protection and ours, we want to make certain\n\
-that everyone understands that there is no warranty for this free\n\
-software. If the software is modified by someone else and passed on, we\n\
-want its recipients to know that what they have is not the original, so\n\
-that any problems introduced by others will not reflect on the original\n\
-authors' reputations.\n\
-\n\
- Finally, any free program is threatened constantly by software\n\
-patents. We wish to avoid the danger that redistributors of a free\n\
-program will individually obtain patent licenses, in effect making the\n\
-program proprietary. To prevent this, we have made it clear that any\n\
-patent must be licensed for everyone's free use or not licensed at all.\n\
-\n\
- The precise terms and conditions for copying, distribution and\n\
-modification follow.\n\
-\n\
- GNU GENERAL PUBLIC LICENSE\n\
- TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION\n\
-\n\
- 0. This License applies to any program or other work which contains\n\
-a notice placed by the copyright holder saying it may be distributed\n\
-under the terms of this General Public License. The \"Program\", below,\n\
-refers to any such program or work, and a \"work based on the Program\"\n\
-means either the Program or any derivative work under copyright law:\n\
-that is to say, a work containing the Program or a portion of it,\n\
-either verbatim or with modifications and/or translated into another\n\
-language. (Hereinafter, translation is included without limitation in\n\
-the term \"modification\".) Each licensee is addressed as \"you\".\n\
-\n\
-Activities other than copying, distribution and modification are not\n\
-covered by this License; they are outside its scope. The act of\n\
-running the Program is not restricted, and the output from the Program\n\
-is covered only if its contents constitute a work based on the\n\
-Program (independent of having been made by running the Program).\n\
-Whether that is true depends on what the Program does.\n\
-\n\
- 1. You may copy and distribute verbatim copies of the Program's\n\
-source code as you receive it, in any medium, provided that you\n\
-conspicuously and appropriately publish on each copy an appropriate\n\
-copyright notice and disclaimer of warranty; keep intact all the\n\
-notices that refer to this License and to the absence of any warranty;\n\
-and give any other recipients of the Program a copy of this License\n\
-along with the Program.\n\
-\n\
-You may charge a fee for the physical act of transferring a copy, and\n\
-you may at your option offer warranty protection in exchange for a fee.\n\
-\n\
- 2. You may modify your copy or copies of the Program or any portion\n\
-of it, thus forming a work based on the Program, and copy and\n\
-distribute such modifications or work under the terms of Section 1\n\
-above, provided that you also meet all of these conditions:\n\
-\n\
- a) You must cause the modified files to carry prominent notices\n\
- stating that you changed the files and the date of any change.\n\
-\n\
- b) You must cause any work that you distribute or publish, that in\n\
- whole or in part contains or is derived from the Program or any\n\
- part thereof, to be licensed as a whole at no charge to all third\n\
- parties under the terms of this License.\n\
-\n\
- c) If the modified program normally reads commands interactively\n\
- when run, you must cause it, when started running for such\n\
- interactive use in the most ordinary way, to print or display an\n\
- announcement including an appropriate copyright notice and a\n\
- notice that there is no warranty (or else, saying that you provide\n\
- a warranty) and that users may redistribute the program under\n\
- these conditions, and telling the user how to view a copy of this\n\
- License. (Exception: if the Program itself is interactive but\n\
- does not normally print such an announcement, your work based on\n\
- the Program is not required to print an announcement.)\n\
-\n\
-These requirements apply to the modified work as a whole. If\n\
-identifiable sections of that work are not derived from the Program,\n\
-and can be reasonably considered independent and separate works in\n\
-themselves, then this License, and its terms, do not apply to those\n\
-sections when you distribute them as separate works. But when you\n\
-distribute the same sections as part of a whole which is a work based\n\
-on the Program, the distribution of the whole must be on the terms of\n\
-this License, whose permissions for other licensees extend to the\n\
-entire whole, and thus to each and every part regardless of who wrote it.\n\
-\n\
-Thus, it is not the intent of this section to claim rights or contest\n\
-your rights to work written entirely by you; rather, the intent is to\n\
-exercise the right to control the distribution of derivative or\n\
-collective works based on the Program.\n\
-\n\
-In addition, mere aggregation of another work not based on the Program\n\
-with the Program (or with a work based on the Program) on a volume of\n\
-a storage or distribution medium does not bring the other work under\n\
-the scope of this License.\n\
-\n\
- 3. You may copy and distribute the Program (or a work based on it,\n\
-under Section 2) in object code or executable form under the terms of\n\
-Sections 1 and 2 above provided that you also do one of the following:\n\
-\n\
- a) Accompany it with the complete corresponding machine-readable\n\
- source code, which must be distributed under the terms of Sections\n\
- 1 and 2 above on a medium customarily used for software interchange; or,\n\
-\n\
- b) Accompany it with a written offer, valid for at least three\n\
- years, to give any third party, for a charge no more than your\n\
- cost of physically performing source distribution, a complete\n\
- machine-readable copy of the corresponding source code, to be\n\
- distributed under the terms of Sections 1 and 2 above on a medium\n\
- customarily used for software interchange; or,\n\
-\n\
- c) Accompany it with the information you received as to the offer\n\
- to distribute corresponding source code. (This alternative is\n\
- allowed only for noncommercial distribution and only if you\n\
- received the program in object code or executable form with such\n\
- an offer, in accord with Subsection b above.)\n\
-\n\
-The source code for a work means the preferred form of the work for\n\
-making modifications to it. For an executable work, complete source\n\
-code means all the source code for all modules it contains, plus any\n\
-associated interface definition files, plus the scripts used to\n\
-control compilation and installation of the executable. However, as a\n\
-special exception, the source code distributed need not include\n\
-anything that is normally distributed (in either source or binary\n\
-form) with the major components (compiler, kernel, and so on) of the\n\
-operating system on which the executable runs, unless that component\n\
-itself accompanies the executable.\n\
-\n\
-If distribution of executable or object code is made by offering\n\
-access to copy from a designated place, then offering equivalent\n\
-access to copy the source code from the same place counts as\n\
-distribution of the source code, even though third parties are not\n\
-compelled to copy the source along with the object code.\n\
-\f\n\
- 4. You may not copy, modify, sublicense, or distribute the Program\n\
-except as expressly provided under this License. Any attempt\n\
-otherwise to copy, modify, sublicense or distribute the Program is\n\
-void, and will automatically terminate your rights under this License.\n\
-However, parties who have received copies, or rights, from you under\n\
-this License will not have their licenses terminated so long as such\n\
-parties remain in full compliance.\n\
-\n\
- 5. You are not required to accept this License, since you have not\n\
-signed it. However, nothing else grants you permission to modify or\n\
-distribute the Program or its derivative works. These actions are\n\
-prohibited by law if you do not accept this License. Therefore, by\n\
-modifying or distributing the Program (or any work based on the\n\
-Program), you indicate your acceptance of this License to do so, and\n\
-all its terms and conditions for copying, distributing or modifying\n\
-the Program or works based on it.\n\
-\n\
- 6. Each time you redistribute the Program (or any work based on the\n\
-Program), the recipient automatically receives a license from the\n\
-original licensor to copy, distribute or modify the Program subject to\n\
-these terms and conditions. You may not impose any further\n\
-restrictions on the recipients' exercise of the rights granted herein.\n\
-You are not responsible for enforcing compliance by third parties to\n\
-this License.\n\
-\n\
- 7. If, as a consequence of a court judgment or allegation of patent\n\
-infringement or for any other reason (not limited to patent issues),\n\
-conditions are imposed on you (whether by court order, agreement or\n\
-otherwise) that contradict the conditions of this License, they do not\n\
-excuse you from the conditions of this License. If you cannot\n\
-distribute so as to satisfy simultaneously your obligations under this\n\
-License and any other pertinent obligations, then as a consequence you\n\
-may not distribute the Program at all. For example, if a patent\n\
-license would not permit royalty-free redistribution of the Program by\n\
-all those who receive copies directly or indirectly through you, then\n\
-the only way you could satisfy both it and this License would be to\n\
-refrain entirely from distribution of the Program.\n\
-\n\
-If any portion of this section is held invalid or unenforceable under\n\
-any particular circumstance, the balance of the section is intended to\n\
-apply and the section as a whole is intended to apply in other\n\
-circumstances.\n\
-\n\
-It is not the purpose of this section to induce you to infringe any\n\
-patents or other property right claims or to contest validity of any\n\
-such claims; this section has the sole purpose of protecting the\n\
-integrity of the free software distribution system, which is\n\
-implemented by public license practices. Many people have made\n\
-generous contributions to the wide range of software distributed\n\
-through that system in reliance on consistent application of that\n\
-system; it is up to the author/donor to decide if he or she is willing\n\
-to distribute software through any other system and a licensee cannot\n\
-impose that choice.\n\
-\n\
-This section is intended to make thoroughly clear what is believed to\n\
-be a consequence of the rest of this License.\n\
-\n\
- 8. If the distribution and/or use of the Program is restricted in\n\
-certain countries either by patents or by copyrighted interfaces, the\n\
-original copyright holder who places the Program under this License\n\
-may add an explicit geographical distribution limitation excluding\n\
-those countries, so that distribution is permitted only in or among\n\
-countries not thus excluded. In such case, this License incorporates\n\
-the limitation as if written in the body of this License.\n\
-\n\
- 9. The Free Software Foundation may publish revised and/or new versions\n\
-of the General Public License from time to time. Such new versions will\n\
-be similar in spirit to the present version, but may differ in detail to\n\
-address new problems or concerns.\n\
-\n\
-Each version is given a distinguishing version number. If the Program\n\
-specifies a version number of this License which applies to it and \"any\n\
-later version\", you have the option of following the terms and conditions\n\
-either of that version or of any later version published by the Free\n\
-Software Foundation. If the Program does not specify a version number of\n\
-this License, you may choose any version ever published by the Free Software\n\
-Foundation.\n\
-\n\
- 10. If you wish to incorporate parts of the Program into other free\n\
-programs whose distribution conditions are different, write to the author\n\
-to ask for permission. For software which is copyrighted by the Free\n\
-Software Foundation, write to the Free Software Foundation; we sometimes\n\
-make exceptions for this. Our decision will be guided by the two goals\n\
-of preserving the free status of all derivatives of our free software and\n\
-of promoting the sharing and reuse of software generally.\n\
-\n\
- NO WARRANTY\n\
-\n\
- 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY\n\
-FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN\n\
-OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES\n\
-PROVIDE THE PROGRAM \"AS IS\" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED\n\
-OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF\n\
-MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS\n\
-TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE\n\
-PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,\n\
-REPAIR OR CORRECTION.\n\
-\n\
- 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING\n\
-WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR\n\
-REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,\n\
-INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING\n\
-OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED\n\
-TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY\n\
-YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER\n\
-PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE\n\
-POSSIBILITY OF SUCH DAMAGES.\n\
-\n\
- END OF TERMS AND CONDITIONS\n\
-\n\
- How to Apply These Terms to Your New Programs\n\
-\n\
- If you develop a new program, and you want it to be of the greatest\n\
-possible use to the public, the best way to achieve this is to make it\n\
-free software which everyone can redistribute and change under these terms.\n\
-\n\
- To do so, attach the following notices to the program. It is safest\n\
-to attach them to the start of each source file to most effectively\n\
-convey the exclusion of warranty; and each file should have at least\n\
-the \"copyright\" line and a pointer to where the full notice is found.\n\
-\n\
- <one line to give the program's name and a brief idea of what it does.>\n\
- Copyright (C) <year> <name of author>\n\
-\n\
- This program is free software; you can redistribute it and/or modify\n\
- it under the terms of the GNU General Public License as published by\n\
- the Free Software Foundation; either version 2 of the License, or\n\
- (at your option) any later version.\n\
-\n\
- This program is distributed in the hope that it will be useful,\n\
- but WITHOUT ANY WARRANTY; without even the implied warranty of\n\
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n\
- GNU General Public License for more details.\n\
-\n\
- You should have received a copy of the GNU General Public License\n\
- along with this program; if not, write to the Free Software\n\
- Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA\n\
-\n\
-\n\
-Also add information on how to contact you by electronic and paper mail.\n\
-\n\
-If the program is interactive, make it output a short notice like this\n\
-when it starts in an interactive mode:\n\
-\n\
- Gnomovision version 69, Copyright (C) year name of author\n\
- Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.\n\
- This is free software, and you are welcome to redistribute it\n\
- under certain conditions; type `show c' for details.\n\
-\n\
-The hypothetical commands `show w' and `show c' should show the appropriate\n\
-parts of the General Public License. Of course, the commands you use may\n\
-be called something other than `show w' and `show c'; they could even be\n\
-mouse-clicks or menu items--whatever suits your program.\n\
-\n\
-You should also get your employer (if you work as a programmer) or your\n\
-school, if any, to sign a \"copyright disclaimer\" for the program, if\n\
-necessary. Here is a sample; alter the names:\n\
-\n\
- Yoyodyne, Inc., hereby disclaims all copyright interest in the program\n\
- `Gnomovision' (which makes passes at compilers) written by James Hacker.\n\
-\n\
- <signature of Ty Coon>, 1 April 1989\n\
- Ty Coon, President of Vice\n\
-\n\
-This General Public License does not permit incorporating your program into\n\
-proprietary programs. If your program is a subroutine library, you may\n\
-consider it more useful to permit linking proprietary applications with the\n\
-library. If this is what you want to do, use the GNU Library General\n\
-Public License instead of this License.\n\
-";
-
+++ /dev/null
-/*
- Copyright (C) 2012 Carl Hetherington <cth@carlh.net>
-
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 2 of the License, or
- (at your option) any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program; if not, write to the Free Software
- Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
-
-*/
-
-/** @file src/gpl.h
- * @brief The GPL.
- */
-
-extern const char * gpl;
+++ /dev/null
-/*
- Copyright (C) 2012 Carl Hetherington <cth@carlh.net>
-
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 2 of the License, or
- (at your option) any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program; if not, write to the Free Software
- Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
-
-*/
-
-/** @file src/gtk/util.cc
- * @brief Some utility functions.
- */
-
-#include <gtkmm.h>
-
-using namespace std;
-
-/** @param t Label text.
- * @return GTK label containing t, left-aligned (passed through Gtk::manage)
- */
-Gtk::Label &
-left_aligned_label (string t)
-{
- Gtk::Label* l = Gtk::manage (new Gtk::Label (t));
- l->set_alignment (0, 0.5);
- return *l;
-}
-
-void
-error_dialog (string m)
-{
- Gtk::MessageDialog d (m, false, Gtk::MESSAGE_ERROR, Gtk::BUTTONS_OK, true);
- d.set_title ("DVD-o-matic");
- d.run ();
-}
+++ /dev/null
-/*
- Copyright (C) 2012 Carl Hetherington <cth@carlh.net>
-
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 2 of the License, or
- (at your option) any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program; if not, write to the Free Software
- Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
-
-*/
-
-#include <gtkmm.h>
-
-/** @file src/gtk/util.h
- * @brief Some utility functions.
- */
-
-extern void error_dialog (std::string);
-extern Gtk::Label & left_aligned_label (std::string);
+++ /dev/null
-/*
- Copyright (C) 2012 Carl Hetherington <cth@carlh.net>
-
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 2 of the License, or
- (at your option) any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program; if not, write to the Free Software
- Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
-
-*/
-
-/** @file src/job_manager_view.cc
- * @brief Class generating a GTK widget to show the progress of jobs.
- */
-
-#include "lib/job_manager.h"
-#include "lib/job.h"
-#include "lib/util.h"
-#include "lib/exceptions.h"
-#include "job_manager_view.h"
-#include "gtk_util.h"
-
-using namespace std;
-using namespace boost;
-
-/** Must be called in the GUI thread */
-JobManagerView::JobManagerView ()
-{
- _scroller.set_policy (Gtk::POLICY_NEVER, Gtk::POLICY_ALWAYS);
-
- _store = Gtk::TreeStore::create (_columns);
- _view.set_model (_store);
- _view.append_column ("Name", _columns.name);
-
- Gtk::CellRendererProgress* r = Gtk::manage (new Gtk::CellRendererProgress ());
- int const n = _view.append_column ("Progress", *r);
- Gtk::TreeViewColumn* c = _view.get_column (n - 1);
- c->add_attribute (r->property_value(), _columns.progress);
- c->add_attribute (r->property_pulse(), _columns.progress_unknown);
- c->add_attribute (r->property_text(), _columns.text);
-
- _scroller.add (_view);
- _scroller.set_size_request (-1, 150);
-
- update ();
-}
-
-/** Update the view by examining the state of each jobs.
- * Must be called in the GUI thread.
- */
-void
-JobManagerView::update ()
-{
- list<shared_ptr<Job> > jobs = JobManager::instance()->get ();
-
- for (list<shared_ptr<Job> >::iterator i = jobs.begin(); i != jobs.end(); ++i) {
- Gtk::ListStore::iterator j = _store->children().begin();
- while (j != _store->children().end()) {
- Gtk::TreeRow r = *j;
- shared_ptr<Job> job = r[_columns.job];
- if (job == *i) {
- break;
- }
- ++j;
- }
-
- Gtk::TreeRow r;
- if (j == _store->children().end ()) {
- j = _store->append ();
- r = *j;
- r[_columns.name] = (*i)->name ();
- r[_columns.job] = *i;
- r[_columns.progress_unknown] = -1;
- r[_columns.informed_of_finish] = false;
- } else {
- r = *j;
- }
-
- bool inform_of_finish = false;
- string const st = (*i)->status ();
-
- if (!(*i)->finished ()) {
- float const p = (*i)->overall_progress ();
- if (p >= 0) {
- r[_columns.text] = st;
- r[_columns.progress] = p * 100;
- } else {
- r[_columns.text] = "Running";
- r[_columns.progress_unknown] = r[_columns.progress_unknown] + 1;
- }
- }
-
- /* Hack to work around our lack of cross-thread
- signalling; we tell the job to emit_finished()
- from here (the GUI thread).
- */
-
- if ((*i)->finished_ok ()) {
- bool i = r[_columns.informed_of_finish];
- if (!i) {
- r[_columns.progress_unknown] = -1;
- r[_columns.progress] = 100;
- r[_columns.text] = st;
- inform_of_finish = true;
- }
- } else if ((*i)->finished_in_error ()) {
- bool i = r[_columns.informed_of_finish];
- if (!i) {
- r[_columns.progress_unknown] = -1;
- r[_columns.progress] = 100;
- r[_columns.text] = st;
- inform_of_finish = true;
- }
- }
-
- if (inform_of_finish) {
- try {
- (*i)->emit_finished ();
- } catch (OpenFileError& e) {
- stringstream s;
- s << "Error: " << e.what();
- error_dialog (s.str ());
- }
- r[_columns.informed_of_finish] = true;
- }
- }
-}
+++ /dev/null
-/*
- Copyright (C) 2012 Carl Hetherington <cth@carlh.net>
-
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 2 of the License, or
- (at your option) any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program; if not, write to the Free Software
- Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
-
-*/
-
-/** @file src/job_manager_view.h
- * @brief Class generating a GTK widget to show the progress of jobs.
- */
-
-#include <string>
-#include <boost/shared_ptr.hpp>
-#include <gtkmm.h>
-
-class Job;
-
-/** @class JobManagerView
- * @brief Class generating a GTK widget to show the progress of jobs.
- */
-class JobManagerView
-{
-public:
- JobManagerView ();
-
- /** @return Our main widget, which contains everything else */
- Gtk::Widget& widget () {
- return _scroller;
- }
-
- void update ();
-
-private:
- /** Scroller for all our contents */
- Gtk::ScrolledWindow _scroller;
- /** View for the jobs */
- Gtk::TreeView _view;
- /** Store for the jobs */
- Glib::RefPtr<Gtk::TreeStore> _store;
-
- /** The TreeModelColumnRecord for the store */
- class StoreColumns : public Gtk::TreeModelColumnRecord
- {
- public:
- StoreColumns ()
- {
- add (name);
- add (job);
- add (progress);
- add (progress_unknown);
- add (text);
- add (informed_of_finish);
- }
-
- /** Job name */
- Gtk::TreeModelColumn<std::string> name;
- /** Job */
- Gtk::TreeModelColumn<boost::shared_ptr<Job> > job;
- /** Progress */
- Gtk::TreeModelColumn<float> progress;
- /** An increasing integer number if the progress is unknown */
- Gtk::TreeModelColumn<int> progress_unknown;
- /** Text to write into the progress bar */
- Gtk::TreeModelColumn<std::string> text;
- /** true if the job has been informed of its finish */
- Gtk::TreeModelColumn<bool> informed_of_finish;
- };
-
- /** The columns for the store */
- StoreColumns _columns;
-};
+++ /dev/null
-/*
- Copyright (C) 2012 Carl Hetherington <cth@carlh.net>
-
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 2 of the License, or
- (at your option) any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program; if not, write to the Free Software
- Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
-
-*/
-
-#include <sstream>
-#include "lib/film.h"
-#include "lib/exceptions.h"
-#include "job_wrapper.h"
-#include "gtk_util.h"
-
-using namespace std;
-
-void
-JobWrapper::make_dcp (Film* film, bool transcode)
-{
- if (!film) {
- return;
- }
-
- try {
- film->make_dcp (transcode);
- } catch (BadSettingError& e) {
- stringstream s;
- if (e.setting() == "dcp_long_name") {
- s << "Could not make DCP: long name is invalid (" << e.what() << ")";
- } else {
- s << "Bad setting for " << e.setting() << "(" << e.what() << ")";
- }
- error_dialog (s.str ());
- } catch (std::exception& e) {
- stringstream s;
- s << "Could not make DCP: " << e.what () << ".";
- error_dialog (s.str ());
- }
-}
+++ /dev/null
-/*
- Copyright (C) 2012 Carl Hetherington <cth@carlh.net>
-
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 2 of the License, or
- (at your option) any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program; if not, write to the Free Software
- Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
-
-*/
-
-class Film;
-
-namespace JobWrapper
-{
-
-void make_dcp (Film *, bool);
-
-}
+++ /dev/null
-def configure(conf):
- conf.check_cfg(package = 'glib-2.0', args = '--cflags --libs', uselib_store = 'GLIB', mandatory = True)
- conf.check_cfg(package = 'gtkmm-2.4', args = '--cflags --libs', uselib_store = 'GTKMM', mandatory = True)
- conf.check_cfg(package = 'cairomm-1.0', args = '--cflags --libs', uselib_store = 'CAIROMM', mandatory = True)
-
-def build(bld):
- obj = bld(features = 'cxx cxxshlib')
- obj.name = 'libdvdomatic-gtk'
- obj.includes = [ '..' ]
- obj.export_includes = ['.']
- obj.uselib = 'GLIB GTKMM CAIROMM'
- obj.use = 'libdvdomatic'
- obj.source = """
- alignment.cc
- config_dialog.cc
- dcp_range_dialog.cc
- film_editor.cc
- film_list.cc
- film_viewer.cc
- filter_dialog.cc
- filter_view.cc
- gpl.cc
- job_manager_view.cc
- gtk_util.cc
- job_wrapper.cc
- dvd_title_dialog.cc
- """
-
- if not bld.env.DISABLE_PLAYER:
- obj.source += " film_player.cc"
-
- obj.target = 'dvdomatic-gtk'
+++ /dev/null
-#include <wx/wx.h>
-#include "lib/util.h"
-#include "lib/film.h"
-#include "film_viewer.h"
-#include "film_editor.h"
-
-enum {
- ID_Quit = 1,
-};
-
-class Frame : public wxFrame
-{
-public:
- Frame (wxString const & title, wxPoint const & pos, wxSize const & size)
- : wxFrame (NULL, -1, title, pos, size)
- {
- wxMenuBar* bar = new wxMenuBar;
-
- wxMenu *menu_file = new wxMenu;
- menu_file->Append (ID_Quit, _("&Quit"));
-
- bar->Append (menu_file, _("&File"));
-
- SetMenuBar (bar);
-
- CreateStatusBar ();
- SetStatusText (_("Welcome to DVD-o-matic!"));
- }
-
- void OnQuit (wxCommandEvent& event)
- {
- Close (true);
- }
-};
-
-class App : public wxApp
-{
- bool OnInit ()
- {
- if (!wxApp::OnInit ()) {
- return false;
- }
-
- wxInitAllImageHandlers ();
-
- dvdomatic_setup ();
-
- Film* film = new Film ("/home/carl/DCP/BitHarvest");
-
- Frame* frame = new Frame (_("DVD-o-matic"), wxPoint (50, 50), wxSize(450, 350));
- frame->Show (true);
-
- frame->Connect (
- ID_Quit, wxEVT_COMMAND_MENU_SELECTED,
- (wxObjectEventFunction) &Frame::OnQuit
- );
-
- FilmEditor* editor = new FilmEditor (film, frame);
- editor->Show (true);
- FilmViewer* viewer = new FilmViewer (film, frame);
- viewer->load_thumbnail (22);
-
- wxBoxSizer* main_sizer = new wxBoxSizer (wxHORIZONTAL);
- main_sizer->Add (editor, 0);
- main_sizer->Add (viewer->get_widget (), 1, wxEXPAND);
- frame->SetSizer (main_sizer);
-
-// frame->Add (viewer->get_widget ());
-
- SetTopWindow (frame);
- return true;
- }
-};
-
-IMPLEMENT_APP (App)
-
+/*
+ Copyright (C) 2012 Carl Hetherington <cth@carlh.net>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+*/
+
+/** @file src/film_editor.cc
+ * @brief A GTK widget to edit a film's metadata, and perform various functions.
+ */
+
+#include <iostream>
+#include <gtkmm.h>
+#include <boost/thread.hpp>
+#include <boost/filesystem.hpp>
+#include "lib/format.h"
+#include "lib/film.h"
+#include "lib/transcode_job.h"
+#include "lib/exceptions.h"
+#include "lib/ab_transcode_job.h"
+#include "lib/thumbs_job.h"
+#include "lib/job_manager.h"
+#include "lib/filter.h"
+#include "lib/screen.h"
+#include "lib/config.h"
+#include "filter_dialog.h"
+#include "gtk_util.h"
#include "film_editor.h"
+#include "dcp_range_dialog.h"
+
+using namespace std;
+using namespace boost;
+using namespace Gtk;
+
+/** @param f Film to edit */
+FilmEditor::FilmEditor (Film* f)
+ : _film (f)
+ , _filters_button ("Edit...")
+ , _change_dcp_range_button ("Edit...")
+ , _dcp_ab ("A/B")
+{
+ _vbox.set_border_width (12);
+ _vbox.set_spacing (12);
+
+ /* Set up our editing widgets */
+ _left_crop.set_range (0, 1024);
+ _left_crop.set_increments (1, 16);
+ _top_crop.set_range (0, 1024);
+ _top_crop.set_increments (1, 16);
+ _right_crop.set_range (0, 1024);
+ _right_crop.set_increments (1, 16);
+ _bottom_crop.set_range (0, 1024);
+ _bottom_crop.set_increments (1, 16);
+ _filters.set_alignment (0, 0.5);
+ _audio_gain.set_range (-60, 60);
+ _audio_gain.set_increments (1, 3);
+ _audio_delay.set_range (-1000, 1000);
+ _audio_delay.set_increments (1, 20);
+ _still_duration.set_range (0, 60 * 60);
+ _still_duration.set_increments (1, 5);
+ _dcp_range.set_alignment (0, 0.5);
+
+ vector<Format const *> fmt = Format::all ();
+ for (vector<Format const *>::iterator i = fmt.begin(); i != fmt.end(); ++i) {
+ _format.append_text ((*i)->name ());
+ }
+
+ _frames_per_second.set_increments (1, 5);
+ _frames_per_second.set_digits (2);
+ _frames_per_second.set_range (0, 60);
+
+ vector<DCPContentType const *> const ct = DCPContentType::all ();
+ for (vector<DCPContentType const *>::const_iterator i = ct.begin(); i != ct.end(); ++i) {
+ _dcp_content_type.append_text ((*i)->pretty_name ());
+ }
+
+ vector<Scaler const *> const sc = Scaler::all ();
+ for (vector<Scaler const *>::const_iterator i = sc.begin(); i != sc.end(); ++i) {
+ _scaler.append_text ((*i)->name ());
+ }
+
+ _original_size.set_alignment (0, 0.5);
+ _length.set_alignment (0, 0.5);
+ _audio.set_alignment (0, 0.5);
+
+ /* And set their values from the Film */
+ set_film (f);
+
+ /* Now connect to them, since initial values are safely set */
+ _name.signal_changed().connect (sigc::mem_fun (*this, &FilmEditor::name_changed));
+ _frames_per_second.signal_changed().connect (sigc::mem_fun (*this, &FilmEditor::frames_per_second_changed));
+ _format.signal_changed().connect (sigc::mem_fun (*this, &FilmEditor::format_changed));
+ _content.signal_file_set().connect (sigc::mem_fun (*this, &FilmEditor::content_changed));
+ _left_crop.signal_value_changed().connect (sigc::mem_fun (*this, &FilmEditor::left_crop_changed));
+ _right_crop.signal_value_changed().connect (sigc::mem_fun (*this, &FilmEditor::right_crop_changed));
+ _top_crop.signal_value_changed().connect (sigc::mem_fun (*this, &FilmEditor::top_crop_changed));
+ _bottom_crop.signal_value_changed().connect (sigc::mem_fun (*this, &FilmEditor::bottom_crop_changed));
+ _filters_button.signal_clicked().connect (sigc::mem_fun (*this, &FilmEditor::edit_filters_clicked));
+ _scaler.signal_changed().connect (sigc::mem_fun (*this, &FilmEditor::scaler_changed));
+ _dcp_content_type.signal_changed().connect (sigc::mem_fun (*this, &FilmEditor::dcp_content_type_changed));
+ _dcp_ab.signal_toggled().connect (sigc::mem_fun (*this, &FilmEditor::dcp_ab_toggled));
+ _audio_gain.signal_value_changed().connect (sigc::mem_fun (*this, &FilmEditor::audio_gain_changed));
+ _audio_delay.signal_value_changed().connect (sigc::mem_fun (*this, &FilmEditor::audio_delay_changed));
+ _still_duration.signal_value_changed().connect (sigc::mem_fun (*this, &FilmEditor::still_duration_changed));
+ _change_dcp_range_button.signal_clicked().connect (sigc::mem_fun (*this, &FilmEditor::change_dcp_range_clicked));
+
+ /* Set up the table */
+
+ Table* t = manage (new Table);
+
+ t->set_row_spacings (4);
+ t->set_col_spacings (12);
+
+ int n = 0;
+ t->attach (left_aligned_label ("Name"), 0, 1, n, n + 1);
+ t->attach (_name, 1, 2, n, n + 1);
+ ++n;
+ t->attach (left_aligned_label ("Content"), 0, 1, n, n + 1);
+ t->attach (_content, 1, 2, n, n + 1);
+ ++n;
+ t->attach (left_aligned_label ("Content Type"), 0, 1, n, n + 1);
+ t->attach (_dcp_content_type, 1, 2, n, n + 1);
+ ++n;
+ t->attach (video_widget (left_aligned_label ("Frames Per Second")), 0, 1, n, n + 1);
+ t->attach (video_widget (_frames_per_second), 1, 2, n, n + 1);
+ ++n;
+ t->attach (left_aligned_label ("Format"), 0, 1, n, n + 1);
+ t->attach (_format, 1, 2, n, n + 1);
+ ++n;
+ t->attach (left_aligned_label ("Crop"), 0, 1, n, n + 1);
+ HBox* c = manage (new HBox);
+ c->set_spacing (4);
+ c->pack_start (left_aligned_label ("L"), false, false);
+ c->pack_start (_left_crop, true, true);
+ c->pack_start (left_aligned_label ("R"), false, false);
+ c->pack_start (_right_crop, true, true);
+ c->pack_start (left_aligned_label ("T"), false, false);
+ c->pack_start (_top_crop, true, true);
+ c->pack_start (left_aligned_label ("B"), false, false);
+ c->pack_start (_bottom_crop, true, true);
+ t->attach (*c, 1, 2, n, n + 1);
+ ++n;
+
+ int const special = n;
+
+ /* VIDEO-only stuff */
+ t->attach (video_widget (left_aligned_label ("Filters")), 0, 1, n, n + 1);
+ HBox* fb = manage (new HBox);
+ fb->set_spacing (4);
+ fb->pack_start (video_widget (_filters), true, true);
+ fb->pack_start (video_widget (_filters_button), false, false);
+ t->attach (*fb, 1, 2, n, n + 1);
+ ++n;
+ t->attach (video_widget (left_aligned_label ("Scaler")), 0, 1, n, n + 1);
+ t->attach (video_widget (_scaler), 1, 2, n, n + 1);
+ ++n;
+ t->attach (video_widget (left_aligned_label ("Audio Gain")), 0, 1, n, n + 1);
+ t->attach (video_widget (_audio_gain), 1, 2, n, n + 1);
+ t->attach (video_widget (left_aligned_label ("dB")), 2, 3, n, n + 1);
+ ++n;
+ t->attach (video_widget (left_aligned_label ("Audio Delay")), 0, 1, n, n + 1);
+ t->attach (video_widget (_audio_delay), 1, 2, n, n + 1);
+ t->attach (video_widget (left_aligned_label ("ms")), 2, 3, n, n + 1);
+ ++n;
+ t->attach (video_widget (left_aligned_label ("Original Size")), 0, 1, n, n + 1);
+ t->attach (video_widget (_original_size), 1, 2, n, n + 1);
+ ++n;
+ t->attach (video_widget (left_aligned_label ("Length")), 0, 1, n, n + 1);
+ t->attach (video_widget (_length), 1, 2, n, n + 1);
+ ++n;
+ t->attach (video_widget (left_aligned_label ("Audio")), 0, 1, n, n + 1);
+ t->attach (video_widget (_audio), 1, 2, n, n + 1);
+ ++n;
+ t->attach (video_widget (left_aligned_label ("Range")), 0, 1, n, n + 1);
+ Gtk::HBox* db = manage (new Gtk::HBox);
+ db->pack_start (_dcp_range, true, true);
+ video_widget (_dcp_range);
+ db->pack_start (_change_dcp_range_button, false, false);
+ video_widget (_change_dcp_range_button);
+ t->attach (*db, 1, 2, n, n + 1);
+ ++n;
+ t->attach (_dcp_ab, 0, 3, n, n + 1);
+ video_widget (_dcp_ab);
+
+ /* STILL-only stuff */
+ n = special;
+ t->attach (still_widget (left_aligned_label ("Duration")), 0, 1, n, n + 1);
+ t->attach (still_widget (_still_duration), 1, 2, n, n + 1);
+ t->attach (still_widget (left_aligned_label ("s")), 2, 3, n, n + 1);
+ ++n;
+
+ t->show_all ();
+ _vbox.pack_start (*t, false, false);
+
+ setup_visibility ();
+}
+
+/** @return Our main widget, which contains everything else */
+Widget&
+FilmEditor::widget ()
+{
+ return _vbox;
+}
+
+/** Called when the left crop widget has been changed */
+void
+FilmEditor::left_crop_changed ()
+{
+ if (_film) {
+ _film->set_left_crop (_left_crop.get_value ());
+ }
+}
+
+/** Called when the right crop widget has been changed */
+void
+FilmEditor::right_crop_changed ()
+{
+ if (_film) {
+ _film->set_right_crop (_right_crop.get_value ());
+ }
+}
+
+/** Called when the top crop widget has been changed */
+void
+FilmEditor::top_crop_changed ()
+{
+ if (_film) {
+ _film->set_top_crop (_top_crop.get_value ());
+ }
+}
+
+/** Called when the bottom crop value has been changed */
+void
+FilmEditor::bottom_crop_changed ()
+{
+ if (_film) {
+ _film->set_bottom_crop (_bottom_crop.get_value ());
+ }
+}
+
+/** Called when the content filename has been changed */
+void
+FilmEditor::content_changed ()
+{
+ if (!_film) {
+ return;
+ }
+
+ try {
+ _film->set_content (_content.get_filename ());
+ } catch (std::exception& e) {
+ _content.set_filename (_film->directory ());
+ stringstream m;
+ m << "Could not set content: " << e.what() << ".";
+ Gtk::MessageDialog d (m.str(), false, MESSAGE_ERROR);
+ d.set_title ("DVD-o-matic");
+ d.run ();
+ }
+}
+
+/** Called when the DCP A/B switch has been toggled */
+void
+FilmEditor::dcp_ab_toggled ()
+{
+ if (_film) {
+ _film->set_dcp_ab (_dcp_ab.get_active ());
+ }
+}
+
+/** Called when the name widget has been changed */
+void
+FilmEditor::name_changed ()
+{
+ if (_film) {
+ _film->set_name (_name.get_text ());
+ }
+}
+
+/** Called when the metadata stored in the Film object has changed;
+ * so that we can update the GUI.
+ * @param p Property of the Film that has changed.
+ */
+void
+FilmEditor::film_changed (Film::Property p)
+{
+ if (!_film) {
+ return;
+ }
+
+ stringstream s;
+
+ switch (p) {
+ case Film::CONTENT:
+ _content.set_filename (_film->content ());
+ setup_visibility ();
+ break;
+ case Film::FORMAT:
+ _format.set_active (Format::as_index (_film->format ()));
+ break;
+ case Film::LEFT_CROP:
+ _left_crop.set_value (_film->left_crop ());
+ break;
+ case Film::RIGHT_CROP:
+ _right_crop.set_value (_film->right_crop ());
+ break;
+ case Film::TOP_CROP:
+ _top_crop.set_value (_film->top_crop ());
+ break;
+ case Film::BOTTOM_CROP:
+ _bottom_crop.set_value (_film->bottom_crop ());
+ break;
+ case Film::FILTERS:
+ {
+ pair<string, string> p = Filter::ffmpeg_strings (_film->filters ());
+ _filters.set_text (p.first + " " + p.second);
+ break;
+ }
+ case Film::NAME:
+ _name.set_text (_film->name ());
+ break;
+ case Film::FRAMES_PER_SECOND:
+ _frames_per_second.set_value (_film->frames_per_second ());
+ break;
+ case Film::AUDIO_CHANNELS:
+ case Film::AUDIO_SAMPLE_RATE:
+ if (_film->audio_channels() == 0 && _film->audio_sample_rate() == 0) {
+ _audio.set_text ("");
+ } else {
+ s << _film->audio_channels () << " channels, " << _film->audio_sample_rate() << "Hz";
+ _audio.set_text (s.str ());
+ }
+ break;
+ case Film::SIZE:
+ if (_film->size().width == 0 && _film->size().height == 0) {
+ _original_size.set_text ("");
+ } else {
+ s << _film->size().width << " x " << _film->size().height;
+ _original_size.set_text (s.str ());
+ }
+ break;
+ case Film::LENGTH:
+ if (_film->frames_per_second() > 0 && _film->length() > 0) {
+ s << _film->length() << " frames; " << seconds_to_hms (_film->length() / _film->frames_per_second());
+ } else if (_film->length() > 0) {
+ s << _film->length() << " frames";
+ }
+ _length.set_text (s.str ());
+ break;
+ case Film::DCP_CONTENT_TYPE:
+ _dcp_content_type.set_active (DCPContentType::as_index (_film->dcp_content_type ()));
+ break;
+ case Film::THUMBS:
+ break;
+ case Film::DCP_FRAMES:
+ if (_film->dcp_frames() == 0) {
+ _dcp_range.set_text ("Whole film");
+ } else {
+ stringstream s;
+ s << "First " << _film->dcp_frames() << " frames";
+ _dcp_range.set_text (s.str ());
+ }
+ break;
+ case Film::DCP_TRIM_ACTION:
+ break;
+ case Film::DCP_AB:
+ _dcp_ab.set_active (_film->dcp_ab ());
+ break;
+ case Film::SCALER:
+ _scaler.set_active (Scaler::as_index (_film->scaler ()));
+ break;
+ case Film::AUDIO_GAIN:
+ _audio_gain.set_value (_film->audio_gain ());
+ break;
+ case Film::AUDIO_DELAY:
+ _audio_delay.set_value (_film->audio_delay ());
+ break;
+ case Film::STILL_DURATION:
+ _still_duration.set_value (_film->still_duration ());
+ break;
+ }
+}
+
+/** Called when the format widget has been changed */
+void
+FilmEditor::format_changed ()
+{
+ if (_film) {
+ int const n = _format.get_active_row_number ();
+ if (n >= 0) {
+ _film->set_format (Format::from_index (n));
+ }
+ }
+}
+
+/** Called when the DCP content type widget has been changed */
+void
+FilmEditor::dcp_content_type_changed ()
+{
+ if (_film) {
+ int const n = _dcp_content_type.get_active_row_number ();
+ if (n >= 0) {
+ _film->set_dcp_content_type (DCPContentType::from_index (n));
+ }
+ }
+}
+
+/** Sets the Film that we are editing */
+void
+FilmEditor::set_film (Film* f)
+{
+ _film = f;
+
+ set_things_sensitive (_film != 0);
+
+ if (_film) {
+ _film->Changed.connect (sigc::mem_fun (*this, &FilmEditor::film_changed));
+ }
+
+ if (_film) {
+ FileChanged (_film->directory ());
+ } else {
+ FileChanged ("");
+ }
+
+ film_changed (Film::NAME);
+ film_changed (Film::CONTENT);
+ film_changed (Film::DCP_CONTENT_TYPE);
+ film_changed (Film::FORMAT);
+ film_changed (Film::LEFT_CROP);
+ film_changed (Film::RIGHT_CROP);
+ film_changed (Film::TOP_CROP);
+ film_changed (Film::BOTTOM_CROP);
+ film_changed (Film::FILTERS);
+ film_changed (Film::DCP_FRAMES);
+ film_changed (Film::DCP_TRIM_ACTION);
+ film_changed (Film::DCP_AB);
+ film_changed (Film::SIZE);
+ film_changed (Film::LENGTH);
+ film_changed (Film::FRAMES_PER_SECOND);
+ film_changed (Film::AUDIO_CHANNELS);
+ film_changed (Film::AUDIO_SAMPLE_RATE);
+ film_changed (Film::SCALER);
+ film_changed (Film::AUDIO_GAIN);
+ film_changed (Film::AUDIO_DELAY);
+ film_changed (Film::STILL_DURATION);
+}
+
+/** Updates the sensitivity of lots of widgets to a given value.
+ * @param s true to make sensitive, false to make insensitive.
+ */
+void
+FilmEditor::set_things_sensitive (bool s)
+{
+ _name.set_sensitive (s);
+ _frames_per_second.set_sensitive (s);
+ _format.set_sensitive (s);
+ _content.set_sensitive (s);
+ _left_crop.set_sensitive (s);
+ _right_crop.set_sensitive (s);
+ _top_crop.set_sensitive (s);
+ _bottom_crop.set_sensitive (s);
+ _filters_button.set_sensitive (s);
+ _scaler.set_sensitive (s);
+ _dcp_content_type.set_sensitive (s);
+ _dcp_range.set_sensitive (s);
+ _change_dcp_range_button.set_sensitive (s);
+ _dcp_ab.set_sensitive (s);
+ _audio_gain.set_sensitive (s);
+ _audio_delay.set_sensitive (s);
+ _still_duration.set_sensitive (s);
+}
+
+/** Called when the `Edit filters' button has been clicked */
+void
+FilmEditor::edit_filters_clicked ()
+{
+ FilterDialog d (_film->filters ());
+ d.ActiveChanged.connect (sigc::mem_fun (*_film, &Film::set_filters));
+ d.run ();
+}
+
+/** Called when the scaler widget has been changed */
+void
+FilmEditor::scaler_changed ()
+{
+ if (_film) {
+ int const n = _scaler.get_active_row_number ();
+ if (n >= 0) {
+ _film->set_scaler (Scaler::from_index (n));
+ }
+ }
+}
+
+/** Called when the frames per second widget has been changed */
+void
+FilmEditor::frames_per_second_changed ()
+{
+ if (_film) {
+ _film->set_frames_per_second (_frames_per_second.get_value ());
+ }
+}
+
+void
+FilmEditor::audio_gain_changed ()
+{
+ if (_film) {
+ _film->set_audio_gain (_audio_gain.get_value ());
+ }
+}
+
+void
+FilmEditor::audio_delay_changed ()
+{
+ if (_film) {
+ _film->set_audio_delay (_audio_delay.get_value ());
+ }
+}
+
+Widget&
+FilmEditor::video_widget (Widget& w)
+{
+ _video_widgets.push_back (&w);
+ return w;
+}
+
+Widget&
+FilmEditor::still_widget (Widget& w)
+{
+ _still_widgets.push_back (&w);
+ return w;
+}
+
+void
+FilmEditor::setup_visibility ()
+{
+ ContentType c = VIDEO;
+
+ if (_film) {
+ c = _film->content_type ();
+ }
+
+ for (list<Widget *>::iterator i = _video_widgets.begin(); i != _video_widgets.end(); ++i) {
+ (*i)->property_visible() = (c == VIDEO);
+ }
+
+ for (list<Widget *>::iterator i = _still_widgets.begin(); i != _still_widgets.end(); ++i) {
+ (*i)->property_visible() = (c == STILL);
+ }
+}
+
+void
+FilmEditor::still_duration_changed ()
+{
+ if (_film) {
+ _film->set_still_duration (_still_duration.get_value ());
+ }
+}
+
+void
+FilmEditor::change_dcp_range_clicked ()
+{
+ DCPRangeDialog d (_film);
+ d.Changed.connect (sigc::mem_fun (*this, &FilmEditor::dcp_range_changed));
+ d.run ();
+}
-FilmEditor::FilmEditor (Film* f, wxFrame* p)
- : wxPanel (p)
- , _film (f)
+void
+FilmEditor::dcp_range_changed (int frames, TrimAction action)
{
- new wxButton (this, 0, wxT("FUCK"));
+ _film->set_dcp_frames (frames);
+ _film->set_dcp_trim_action (action);
}
-#include <wx/wx.h>
+/*
+ Copyright (C) 2012 Carl Hetherington <cth@carlh.net>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+*/
+
+/** @file src/film_editor.h
+ * @brief A GTK widget to edit a film's metadata, and perform various functions.
+ */
+
+#include <gtkmm.h>
class Film;
-class FilmEditor : public wxPanel
+/** @class FilmEditor
+ * @brief A GTK widget to edit a film's metadata, and perform various functions.
+ */
+class FilmEditor
{
public:
- FilmEditor (Film* f, wxFrame *);
+ FilmEditor (Film *);
+
+ Gtk::Widget& widget ();
+
+ void set_film (Film *);
+ void setup_visibility ();
+
+ sigc::signal1<void, std::string> FileChanged;
private:
+ /* Handle changes to the view */
+ void name_changed ();
+ void left_crop_changed ();
+ void right_crop_changed ();
+ void top_crop_changed ();
+ void bottom_crop_changed ();
+ void content_changed ();
+ void frames_per_second_changed ();
+ void format_changed ();
+ void dcp_range_changed (int, TrimAction);
+ void dcp_content_type_changed ();
+ void dcp_ab_toggled ();
+ void scaler_changed ();
+ void audio_gain_changed ();
+ void audio_delay_changed ();
+ void still_duration_changed ();
+
+ /* Handle changes to the model */
+ void film_changed (Film::Property);
+
+ /* Button clicks */
+ void edit_filters_clicked ();
+ void change_dcp_range_clicked ();
+
+ void set_things_sensitive (bool);
+
+ Gtk::Widget & video_widget (Gtk::Widget &);
+ Gtk::Widget & still_widget (Gtk::Widget &);
+
+ /** The film we are editing */
Film* _film;
+ /** The overall VBox containing our widget */
+ Gtk::VBox _vbox;
+ /** The Film's name */
+ Gtk::Entry _name;
+ /** The Film's frames per second */
+ Gtk::SpinButton _frames_per_second;
+ /** The Film's format */
+ Gtk::ComboBoxText _format;
+ /** The Film's content file */
+ Gtk::FileChooserButton _content;
+ /** The Film's left crop */
+ Gtk::SpinButton _left_crop;
+ /** The Film's right crop */
+ Gtk::SpinButton _right_crop;
+ /** The Film's top crop */
+ Gtk::SpinButton _top_crop;
+ /** The Film's bottom crop */
+ Gtk::SpinButton _bottom_crop;
+ /** Currently-applied filters */
+ Gtk::Label _filters;
+ /** Button to open the filters dialogue */
+ Gtk::Button _filters_button;
+ /** The Film's scaler */
+ Gtk::ComboBoxText _scaler;
+ /** The Film's audio gain */
+ Gtk::SpinButton _audio_gain;
+ /** The Film's audio delay */
+ Gtk::SpinButton _audio_delay;
+ /** The Film's DCP content type */
+ Gtk::ComboBoxText _dcp_content_type;
+ /** The Film's original size */
+ Gtk::Label _original_size;
+ /** The Film's length */
+ Gtk::Label _length;
+ /** The Film's audio details */
+ Gtk::Label _audio;
+ /** The Film's duration for still sources */
+ Gtk::SpinButton _still_duration;
+
+ /** Button to start making a DCP from existing J2K and WAV files */
+ Gtk::Button _make_dcp_from_existing_button;
+ /** Display of the range of frames that will be used */
+ Gtk::Label _dcp_range;
+ /** Button to change the range */
+ Gtk::Button _change_dcp_range_button;
+ /** Selector to generate an A/B comparison DCP */
+ Gtk::CheckButton _dcp_ab;
+
+ std::list<Gtk::Widget*> _video_widgets;
+ std::list<Gtk::Widget*> _still_widgets;
};
+/*
+ Copyright (C) 2012 Carl Hetherington <cth@carlh.net>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+*/
+
+/** @file src/film_viewer.cc
+ * @brief A GTK widget to view `thumbnails' of a Film.
+ */
+
#include <iostream>
+#include <iomanip>
#include "lib/film.h"
+#include "lib/format.h"
+#include "lib/util.h"
+#include "lib/thumbs_job.h"
+#include "lib/job_manager.h"
+#include "lib/film_state.h"
+#include "lib/options.h"
#include "film_viewer.h"
using namespace std;
+using namespace boost;
+
+FilmViewer::FilmViewer (Film* f)
+ : _film (f)
+{
+ _scroller.add (_image);
+
+ Gtk::HBox* controls = manage (new Gtk::HBox);
+ controls->set_spacing (6);
+ controls->pack_start (_position_slider);
+
+ _vbox.pack_start (_scroller, true, true);
+ _vbox.pack_start (*controls, false, false);
+ _vbox.set_border_width (12);
+
+ _position_slider.set_digits (0);
+ _position_slider.signal_format_value().connect (sigc::mem_fun (*this, &FilmViewer::format_position_slider_value));
+ _position_slider.signal_value_changed().connect (sigc::mem_fun (*this, &FilmViewer::position_slider_changed));
+
+ _scroller.signal_size_allocate().connect (sigc::mem_fun (*this, &FilmViewer::scroller_size_allocate));
-class ThumbPanel : public wxPanel
+ set_film (_film);
+}
+
+void
+FilmViewer::load_thumbnail (int n)
{
-public:
- ThumbPanel (wxFrame* parent)
- : wxPanel (parent)
- , _bitmap (0)
- {
+ if (_film == 0 || _film->num_thumbs() <= n) {
+ return;
}
- void paint_event (wxPaintEvent& ev)
- {
- if (!_bitmap) {
- return;
- }
+ int const left = _film->left_crop ();
+ int const right = _film->right_crop ();
+ int const top = _film->top_crop ();
+ int const bottom = _film->bottom_crop ();
+
+ _pixbuf = Gdk::Pixbuf::create_from_file (_film->thumb_file (n));
+
+ int const cw = _film->size().width - left - right;
+ int const ch = _film->size().height - top - bottom;
+ _cropped_pixbuf = Gdk::Pixbuf::create_subpixbuf (_pixbuf, left, top, cw, ch);
+ update_scaled_pixbuf ();
+ _image.set (_scaled_pixbuf);
+}
+
+void
+FilmViewer::reload_current_thumbnail ()
+{
+ load_thumbnail (_position_slider.get_value ());
+}
+
+void
+FilmViewer::position_slider_changed ()
+{
+ reload_current_thumbnail ();
+}
+
+string
+FilmViewer::format_position_slider_value (double v) const
+{
+ stringstream s;
- cout << "RENDER\n";
+ if (_film && int (v) < _film->num_thumbs ()) {
+ int const f = _film->thumb_frame (int (v));
+ s << f << " " << seconds_to_hms (f / _film->frames_per_second ());
+ } else {
+ s << "-";
+ }
+
+ return s.str ();
+}
+
+void
+FilmViewer::film_changed (Film::Property p)
+{
+ if (p == Film::LEFT_CROP || p == Film::RIGHT_CROP || p == Film::TOP_CROP || p == Film::BOTTOM_CROP) {
+ reload_current_thumbnail ();
+ } else if (p == Film::THUMBS) {
+ if (_film && _film->num_thumbs() > 1) {
+ _position_slider.set_range (0, _film->num_thumbs () - 1);
+ } else {
+ _image.clear ();
+ _position_slider.set_range (0, 1);
+ }
- wxPaintDC dc (this);
- dc.DrawBitmap (*_bitmap, 0, 0, false);
+ _position_slider.set_value (0);
+ reload_current_thumbnail ();
+ } else if (p == Film::FORMAT) {
+ reload_current_thumbnail ();
+ } else if (p == Film::CONTENT) {
+ setup_visibility ();
+ _film->examine_content ();
+ update_thumbs ();
}
+}
+
+void
+FilmViewer::set_film (Film* f)
+{
+ _film = f;
- void set_bitmap (wxBitmap* bitmap)
- {
- _bitmap = bitmap;
+ if (!_film) {
+ _image.clear ();
+ return;
}
- DECLARE_EVENT_TABLE ();
+ _film->Changed.connect (sigc::mem_fun (*this, &FilmViewer::film_changed));
+
+ film_changed (Film::THUMBS);
+}
-private:
- wxBitmap* _bitmap;
-};
+pair<int, int>
+FilmViewer::scaled_pixbuf_size () const
+{
+ if (_film == 0) {
+ return make_pair (0, 0);
+ }
+
+ int const cw = _film->size().width - _film->left_crop() - _film->right_crop();
+ int const ch = _film->size().height - _film->top_crop() - _film->bottom_crop();
-BEGIN_EVENT_TABLE (ThumbPanel, wxPanel)
-EVT_PAINT (ThumbPanel::paint_event)
-END_EVENT_TABLE ()
+ float ratio = 1;
+ if (_film->format()) {
+ ratio = _film->format()->ratio_as_float() * ch / cw;
+ }
-FilmViewer::FilmViewer (Film* f, wxFrame* p)
- : _film (f)
- , _image (0)
- , _scaled_image (0)
- , _bitmap (0)
+ Gtk::Allocation const a = _scroller.get_allocation ();
+ float const zoom = min (float (a.get_width()) / (cw * ratio), float (a.get_height()) / cw);
+ return make_pair (cw * zoom * ratio, ch * zoom);
+}
+
+void
+FilmViewer::update_scaled_pixbuf ()
{
- _thumb_panel = new ThumbPanel (p);
- _thumb_panel->Show (true);
- int x, y;
- _thumb_panel->GetSize (&x, &y);
- cout << x << " " << y << "\n";
+ pair<int, int> const s = scaled_pixbuf_size ();
+
+ if (s.first > 0 && s.second > 0 && _cropped_pixbuf) {
+ _scaled_pixbuf = _cropped_pixbuf->scale_simple (s.first, s.second, Gdk::INTERP_HYPER);
+ _image.set (_scaled_pixbuf);
+ }
}
void
-FilmViewer::load_thumbnail (int n)
+FilmViewer::update_thumbs ()
{
- if (_film == 0 && _film->num_thumbs() <= n) {
+ if (!_film) {
return;
}
- _image = new wxImage (wxString (_film->thumb_file(n).c_str (), wxConvUTF8));
- _scaled_image = new wxImage (_image->Scale (512, 512));
- _bitmap = new wxBitmap (*_scaled_image);
- _thumb_panel->set_bitmap (_bitmap);
+ _film->update_thumbs_pre_gui ();
+
+ shared_ptr<const FilmState> s = _film->state_copy ();
+ shared_ptr<Options> o (new Options (s->dir ("thumbs"), ".tiff", ""));
+ o->out_size = _film->size ();
+ o->apply_crop = false;
+ o->decode_audio = false;
+ o->decode_video_frequency = 128;
+
+ shared_ptr<Job> j (new ThumbsJob (s, o, _film->log ()));
+ j->Finished.connect (sigc::mem_fun (_film, &Film::update_thumbs_post_gui));
+ JobManager::instance()->add (j);
}
-wxPanel *
-FilmViewer::get_widget ()
+void
+FilmViewer::scroller_size_allocate (Gtk::Allocation a)
{
- return _thumb_panel;
+ if (a.get_width() != _last_scroller_allocation.get_width() || a.get_height() != _last_scroller_allocation.get_height()) {
+ update_scaled_pixbuf ();
+ }
+
+ _last_scroller_allocation = a;
+}
+
+void
+FilmViewer::setup_visibility ()
+{
+ if (!_film) {
+ return;
+ }
+
+ ContentType const c = _film->content_type ();
+ _position_slider.property_visible() = (c == VIDEO);
}
-#include <wx/wx.h>
+/*
+ Copyright (C) 2012 Carl Hetherington <cth@carlh.net>
-class Film;
-class ThumbPanel;
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+*/
+
+/** @file src/film_viewer.h
+ * @brief A GTK widget to view `thumbnails' of a Film.
+ */
+
+#include <gtkmm.h>
+#include "lib/film.h"
+
+/** @class FilmViewer
+ * @brief A GTK widget to view `thumbnails' of a Film.
+ */
class FilmViewer
{
public:
- FilmViewer (Film *, wxFrame *);
+ FilmViewer (Film *);
- void load_thumbnail (int);
- wxPanel* get_widget ();
+ Gtk::Widget& widget () {
+ return _vbox;
+ }
+
+ void set_film (Film *);
+ void setup_visibility ();
private:
- Film* _film;
+ void position_slider_changed ();
+ void update_thumbs ();
+ std::string format_position_slider_value (double) const;
+ void load_thumbnail (int);
+ void film_changed (Film::Property);
+ void reload_current_thumbnail ();
+ void update_scaled_pixbuf ();
+ std::pair<int, int> scaled_pixbuf_size () const;
+ void scroller_size_allocate (Gtk::Allocation);
- wxImage* _image;
- wxImage* _scaled_image;
- wxBitmap* _bitmap;
- ThumbPanel* _thumb_panel;
+ Film* _film;
+ Gtk::VBox _vbox;
+ Gtk::ScrolledWindow _scroller;
+ Gtk::Image _image;
+ Glib::RefPtr<Gdk::Pixbuf> _pixbuf;
+ Glib::RefPtr<Gdk::Pixbuf> _cropped_pixbuf;
+ Glib::RefPtr<Gdk::Pixbuf> _scaled_pixbuf;
+ Gtk::HScale _position_slider;
+ Gtk::Allocation _last_scroller_allocation;
};
def configure(conf):
- conf.check_cfg(package = '', path = 'wx-config', args = '--cppflags --cxxflags --libs', uselib_store = 'WXWIDGETS', mandatory = True)
+ conf.check_cfg(package = 'glib-2.0', args = '--cflags --libs', uselib_store = 'GLIB', mandatory = True)
+ conf.check_cfg(package = 'gtkmm-2.4', args = '--cflags --libs', uselib_store = 'GTKMM', mandatory = True)
+ conf.check_cfg(package = 'cairomm-1.0', args = '--cflags --libs', uselib_store = 'CAIROMM', mandatory = True)
def build(bld):
- obj = bld(features = 'cxx cxxprogram')
- obj.name = 'dvdomatic-wx'
+ obj = bld(features = 'cxx cxxshlib')
+ obj.name = 'libdvdomatic-gtk'
obj.includes = [ '..' ]
obj.export_includes = ['.']
- obj.uselib = 'WXWIDGETS'
- obj.use = 'dvdomatic'
+ obj.uselib = 'GLIB GTKMM CAIROMM'
+ obj.use = 'libdvdomatic'
obj.source = """
- dvdomatic.cc
- film_viewer.cc
+ alignment.cc
+ config_dialog.cc
+ dcp_range_dialog.cc
film_editor.cc
+ film_list.cc
+ film_viewer.cc
+ filter_dialog.cc
+ filter_view.cc
+ gpl.cc
+ job_manager_view.cc
+ gtk_util.cc
+ job_wrapper.cc
+ dvd_title_dialog.cc
"""
- obj.target = 'dvdomatic-wx'
+
+ if not bld.env.DISABLE_PLAYER:
+ obj.source += " film_player.cc"
+
+ obj.target = 'dvdomatic-gtk'