More enum class additions.
[dcpomatic.git] / src / wx / text_panel.cc
index 8d404d8c5d5b0d5a5a3b177c7490a00c423668b0..dec58f0cd1fc87b3a5ba49b4bd9ce983864b7622 100644 (file)
 #include "lib/analyse_subtitles_job.h"
 #include "lib/subtitle_analysis.h"
 #include <wx/spinctrl.h>
-#include <boost/foreach.hpp>
 
 using std::vector;
 using std::string;
 using std::list;
 using std::cout;
-using boost::shared_ptr;
+using std::shared_ptr;
 using boost::optional;
-using boost::dynamic_pointer_cast;
+using std::dynamic_pointer_cast;
 using boost::bind;
 
 /** @param t Original text type of the content, if known */
@@ -60,15 +59,13 @@ TextPanel::TextPanel (ContentPanel* p, TextType t)
        , _outline_subtitles (0)
        , _dcp_track_label (0)
        , _dcp_track (0)
-       , _language_label (0)
-       , _language (0)
        , _text_view (0)
        , _fonts_dialog (0)
        , _original_type (t)
        , _loading_analysis (false)
 {
        wxString refer = _("Use this DCP's subtitle as OV and make VF");
-       if (t == TEXT_CLOSED_CAPTION) {
+       if (t == TextType::CLOSED_CAPTION) {
                refer = _("Use this DCP's closed caption as OV and make VF");
        }
 
@@ -87,20 +84,26 @@ TextPanel::TextPanel (ContentPanel* p, TextType t)
 
        _burn = new CheckBox (this, _("Burn subtitles into image"));
 
+#ifdef __WXGTK3__
+       int const spin_width = 118;
+#else
+       int const spin_width = 56;
+#endif
+
        _offset_label = create_label (this, _("Offset"), true);
        _x_offset_label = create_label (this, _("X"), true);
-       _x_offset = new wxSpinCtrl (this, wxID_ANY, wxEmptyString, wxDefaultPosition, wxSize(64, -1));
+       _x_offset = new wxSpinCtrl (this, wxID_ANY, wxEmptyString, wxDefaultPosition, wxSize(spin_width, -1));
        _x_offset_pc_label = new StaticText (this, _("%"));
        _y_offset_label = create_label (this, _("Y"), true);
-       _y_offset = new wxSpinCtrl (this, wxID_ANY, wxEmptyString, wxDefaultPosition, wxSize(64, -1));
+       _y_offset = new wxSpinCtrl (this, wxID_ANY, wxEmptyString, wxDefaultPosition, wxSize(spin_width, -1));
        _y_offset_pc_label = new StaticText (this, _("%"));
 
        _scale_label = create_label (this, _("Scale"), true);
        _x_scale_label = create_label (this, _("X"), true);
-       _x_scale = new wxSpinCtrl (this, wxID_ANY, wxEmptyString, wxDefaultPosition, wxSize(64, -1));
+       _x_scale = new wxSpinCtrl (this, wxID_ANY, wxEmptyString, wxDefaultPosition, wxSize(spin_width, -1));
        _x_scale_pc_label = new StaticText (this, _("%"));
        _y_scale_label = create_label (this, S_("Coord|Y"), true);
-       _y_scale = new wxSpinCtrl (this, wxID_ANY, wxEmptyString, wxDefaultPosition, wxSize(64, -1));
+       _y_scale = new wxSpinCtrl (this, wxID_ANY, wxEmptyString, wxDefaultPosition, wxSize(spin_width, -1));
        _y_scale_pc_label = new StaticText (this, _("%"));
 
        _line_spacing_label = create_label (this, _("Line spacing"), true);
@@ -142,7 +145,7 @@ void
 TextPanel::setup_visibility ()
 {
        switch (current_type()) {
-       case TEXT_OPEN_SUBTITLE:
+       case TextType::OPEN_SUBTITLE:
                if (_dcp_track_label) {
                        _dcp_track_label->Destroy ();
                        _dcp_track_label = 0;
@@ -151,16 +154,6 @@ TextPanel::setup_visibility ()
                        _dcp_track->Destroy ();
                        _dcp_track = 0;
                }
-               if (!_language_label) {
-                       _language_label = create_label (this, _("Language"), true);
-                       add_label_to_sizer (_grid, _language_label, true, wxGBPosition(_language_row, 0));
-               }
-               if (!_language) {
-                       _language = new wxTextCtrl (this, wxID_ANY);
-                       _language->Bind (wxEVT_TEXT, boost::bind(&TextPanel::language_changed, this));
-                       _grid->Add (_language, wxGBPosition(_language_row, 1), wxDefaultSpan, wxEXPAND);
-                       film_content_changed (TextContentProperty::LANGUAGE);
-               }
                if (!_outline_subtitles) {
                        _outline_subtitles = new CheckBox (this, _("Show subtitle area"));
                        _outline_subtitles->Bind (wxEVT_CHECKBOX, boost::bind (&TextPanel::outline_subtitles_changed, this));
@@ -168,23 +161,15 @@ TextPanel::setup_visibility ()
                }
 
                break;
-       case TEXT_CLOSED_CAPTION:
-               if (_language_label) {
-                       _language_label->Destroy ();
-                       _language_label = 0;
-               }
-               if (_language) {
-                       _language->Destroy ();
-                       _language = 0;
-               }
+       case TextType::CLOSED_CAPTION:
                if (!_dcp_track_label) {
                        _dcp_track_label = create_label (this, _("CCAP track"), true);
-                       add_label_to_sizer (_grid, _dcp_track_label, true, wxGBPosition(_language_row, 0));
+                       add_label_to_sizer (_grid, _dcp_track_label, true, wxGBPosition(_ccap_track_row, 0));
                }
                if (!_dcp_track) {
                        _dcp_track = new wxChoice (this, wxID_ANY);
                        _dcp_track->Bind (wxEVT_CHOICE, boost::bind(&TextPanel::dcp_track_changed, this));
-                       _grid->Add (_dcp_track, wxGBPosition(_language_row, 1), wxDefaultSpan, wxEXPAND);
+                       _grid->Add (_dcp_track, wxGBPosition(_ccap_track_row, 1), wxDefaultSpan, wxEXPAND);
                        update_dcp_tracks ();
                        film_content_changed (TextContentProperty::DCP_TRACK);
                }
@@ -204,20 +189,13 @@ TextPanel::setup_visibility ()
 void
 TextPanel::add_to_grid ()
 {
-       Config::Interface const interface = Config::instance()->interface_complexity();
-
        int r = 0;
 
-       _reference->Show (interface == Config::INTERFACE_FULL);
-       _reference_note->Show (interface == Config::INTERFACE_FULL);
-
-       if (interface == Config::INTERFACE_FULL) {
-               wxBoxSizer* reference_sizer = new wxBoxSizer (wxVERTICAL);
-               reference_sizer->Add (_reference, 0);
-               reference_sizer->Add (_reference_note, 0);
-               _grid->Add (reference_sizer, wxGBPosition(r, 0), wxGBSpan(1, 4));
-               ++r;
-       }
+       wxBoxSizer* reference_sizer = new wxBoxSizer (wxVERTICAL);
+       reference_sizer->Add (_reference, 0);
+       reference_sizer->Add (_reference_note, 0);
+       _grid->Add (reference_sizer, wxGBPosition(r, 0), wxGBSpan(1, 4));
+       ++r;
 
        wxBoxSizer* use = new wxBoxSizer (wxHORIZONTAL);
        use->Add (_use, 0, wxEXPAND | wxRIGHT, DCPOMATIC_SIZER_GAP);
@@ -233,23 +211,33 @@ TextPanel::add_to_grid ()
 
        add_label_to_sizer (_grid, _offset_label, true, wxGBPosition (r, 0));
        wxBoxSizer* offset = new wxBoxSizer (wxHORIZONTAL);
-       add_label_to_sizer (offset, _x_offset_label, true);
+       add_label_to_sizer (offset, _x_offset_label, true, 0, wxLEFT | wxRIGHT | wxALIGN_CENTER_VERTICAL);
        offset->Add (_x_offset, 0, wxRIGHT | wxALIGN_CENTER_VERTICAL, DCPOMATIC_SIZER_X_GAP);
        offset->Add (_x_offset_pc_label, 0, wxRIGHT | wxALIGN_CENTER_VERTICAL, DCPOMATIC_SIZER_X_GAP * 2);
-       add_label_to_sizer (offset, _y_offset_label, true);
-       offset->Add (_y_offset, 0);
-       add_label_to_sizer (offset, _y_offset_pc_label, false);
+#ifdef __WXGTK3__
+       _grid->Add (offset, wxGBPosition(r, 1));
+       ++r;
+       offset = new wxBoxSizer (wxHORIZONTAL);
+#endif
+       add_label_to_sizer (offset, _y_offset_label, true, 0, wxLEFT | wxRIGHT | wxALIGN_CENTER_VERTICAL);
+       offset->Add (_y_offset, 0, wxRIGHT | wxALIGN_CENTER_VERTICAL, DCPOMATIC_SIZER_X_GAP);
+       add_label_to_sizer (offset, _y_offset_pc_label, false, 0, wxRIGHT | wxALIGN_CENTER_VERTICAL);
        _grid->Add (offset, wxGBPosition (r, 1));
        ++r;
 
        add_label_to_sizer (_grid, _scale_label, true, wxGBPosition (r, 0));
        wxBoxSizer* scale = new wxBoxSizer (wxHORIZONTAL);
-       add_label_to_sizer (scale, _x_scale_label, true);
+       add_label_to_sizer (scale, _x_scale_label, true, 0, wxLEFT | wxRIGHT | wxALIGN_CENTER_VERTICAL);
        scale->Add (_x_scale, 0, wxRIGHT | wxALIGN_CENTER_VERTICAL, DCPOMATIC_SIZER_X_GAP);
        scale->Add (_x_scale_pc_label, 0, wxRIGHT | wxALIGN_CENTER_VERTICAL, DCPOMATIC_SIZER_X_GAP * 2);
-       add_label_to_sizer (scale, _y_scale_label, true);
-       scale->Add (_y_scale, 0);
-       add_label_to_sizer (scale, _y_scale_pc_label, false);
+#ifdef __WXGTK3__
+       _grid->Add (scale, wxGBPosition(r, 1));
+       ++r;
+       scale = new wxBoxSizer (wxHORIZONTAL);
+#endif
+       add_label_to_sizer (scale, _y_scale_label, true, 0, wxLEFT | wxRIGHT | wxALIGN_CENTER_VERTICAL);
+       scale->Add (_y_scale, 0, wxRIGHT | wxALIGN_CENTER_VERTICAL, DCPOMATIC_SIZER_X_GAP);
+       add_label_to_sizer (scale, _y_scale_pc_label, false, 0, wxRIGHT | wxALIGN_CENTER_VERTICAL);
        _grid->Add (scale, wxGBPosition (r, 1));
        ++r;
 
@@ -257,12 +245,12 @@ TextPanel::add_to_grid ()
                add_label_to_sizer (_grid, _line_spacing_label, true, wxGBPosition (r, 0));
                wxBoxSizer* s = new wxBoxSizer (wxHORIZONTAL);
                s->Add (_line_spacing);
-               add_label_to_sizer (s, _line_spacing_pc_label, false);
+               add_label_to_sizer (s, _line_spacing_pc_label, false, 0, wxLEFT | wxRIGHT | wxALIGN_CENTER_VERTICAL);
                _grid->Add (s, wxGBPosition (r, 1));
                ++r;
        }
 
-       _language_row = r;
+       _ccap_track_row = r;
        ++r;
 
        add_label_to_sizer (_grid, _stream_label, true, wxGBPosition (r, 0));
@@ -290,7 +278,7 @@ TextPanel::update_dcp_track_selection ()
 
        optional<DCPTextTrack> selected;
        bool many = false;
-       BOOST_FOREACH (shared_ptr<Content> i, _parent->selected_text()) {
+       for (auto i: _parent->selected_text()) {
                shared_ptr<TextContent> t = i->text_of_original_type(_original_type);
                if (t) {
                        optional<DCPTextTrack> dt = t->dcp_track();
@@ -303,7 +291,7 @@ TextPanel::update_dcp_track_selection ()
        }
 
        int n = 0;
-       BOOST_FOREACH (DCPTextTrack i, _parent->film()->closed_caption_tracks()) {
+       for (auto i: _parent->film()->closed_caption_tracks()) {
                if (!many && selected && *selected == i) {
                        _dcp_track->SetSelection (n);
                }
@@ -321,7 +309,7 @@ TextPanel::update_dcp_tracks ()
        DCPOMATIC_ASSERT (_dcp_track);
 
        _dcp_track->Clear ();
-       BOOST_FOREACH (DCPTextTrack i, _parent->film()->closed_caption_tracks()) {
+       for (auto i: _parent->film()->closed_caption_tracks()) {
                /* XXX: don't display the "magic" track which has empty name and language;
                   this is a nasty hack (see also Film::closed_caption_tracks)
                */
@@ -350,7 +338,7 @@ TextPanel::dcp_track_changed ()
                d->Destroy ();
        } else {
                /* Find the DCPTextTrack that was selected */
-               BOOST_FOREACH (DCPTextTrack i, _parent->film()->closed_caption_tracks()) {
+               for (auto i: _parent->film()->closed_caption_tracks()) {
                        if (i.summary() == wx_to_std(_dcp_track->GetStringSelection())) {
                                track = i;
                        }
@@ -358,9 +346,9 @@ TextPanel::dcp_track_changed ()
        }
 
        if (track) {
-               BOOST_FOREACH (shared_ptr<Content> i, _parent->selected_text()) {
+               for (auto i: _parent->selected_text()) {
                        shared_ptr<TextContent> t = i->text_of_original_type(_original_type);
-                       if (t && t->type() == TEXT_CLOSED_CAPTION) {
+                       if (t && t->type() == TextType::CLOSED_CAPTION) {
                                t->set_dcp_track(*track);
                        }
                }
@@ -421,10 +409,10 @@ TextPanel::film_content_changed (int property)
        } else if (property == TextContentProperty::TYPE) {
                if (text) {
                        switch (text->type()) {
-                       case TEXT_OPEN_SUBTITLE:
+                       case TextType::OPEN_SUBTITLE:
                                _type->SetSelection (0);
                                break;
-                       case TEXT_CLOSED_CAPTION:
+                       case TextType::CLOSED_CAPTION:
                                _type->SetSelection (1);
                                break;
                        default:
@@ -452,10 +440,6 @@ TextPanel::film_content_changed (int property)
        } else if (property == TextContentProperty::LINE_SPACING) {
                checked_set (_line_spacing, text ? lrint (text->line_spacing() * 100) : 100);
                clear_outline_subtitles ();
-       } else if (property == TextContentProperty::LANGUAGE) {
-               if (_language) {
-                       checked_set (_language, text ? text->language() : "");
-               }
        } else if (property == TextContentProperty::DCP_TRACK) {
                if (_dcp_track) {
                        update_dcp_track_selection ();
@@ -471,13 +455,15 @@ TextPanel::film_content_changed (int property)
                setup_sensitivity ();
        } else if (property == DCPContentProperty::TEXTS) {
                setup_sensitivity ();
+       } else if (property == ContentProperty::TRIM_START) {
+               setup_sensitivity ();
        }
 }
 
 void
 TextPanel::use_toggled ()
 {
-       BOOST_FOREACH (shared_ptr<Content> i, _parent->selected_text()) {
+       for (auto i: _parent->selected_text()) {
                i->text_of_original_type(_original_type)->set_use (_use->GetValue());
        }
 }
@@ -488,18 +474,18 @@ TextPanel::current_type () const
 {
        switch (_type->GetSelection()) {
        case 0:
-               return TEXT_OPEN_SUBTITLE;
+               return TextType::OPEN_SUBTITLE;
        case 1:
-               return TEXT_CLOSED_CAPTION;
+               return TextType::CLOSED_CAPTION;
        }
 
-       return TEXT_UNKNOWN;
+       return TextType::UNKNOWN;
 }
 
 void
 TextPanel::type_changed ()
 {
-       BOOST_FOREACH (shared_ptr<Content> i, _parent->selected_text()) {
+       for (auto i: _parent->selected_text()) {
                i->text_of_original_type(_original_type)->set_type (current_type ());
        }
 
@@ -509,7 +495,7 @@ TextPanel::type_changed ()
 void
 TextPanel::burn_toggled ()
 {
-       BOOST_FOREACH (shared_ptr<Content> i, _parent->selected_text ()) {
+       for (auto i: _parent->selected_text ()) {
                i->text_of_original_type(_original_type)->set_burn (_burn->GetValue());
        }
 }
@@ -523,12 +509,12 @@ TextPanel::setup_sensitivity ()
        /* DCP subs can't have their line spacing changed */
        int dcp_subs = 0;
        ContentList sel = _parent->selected_text ();
-       BOOST_FOREACH (shared_ptr<Content> i, sel) {
+       for (auto i: sel) {
                /* These are the content types that could include subtitles */
-               shared_ptr<const FFmpegContent> fc = boost::dynamic_pointer_cast<const FFmpegContent> (i);
-               shared_ptr<const StringTextFileContent> sc = boost::dynamic_pointer_cast<const StringTextFileContent> (i);
-               shared_ptr<const DCPContent> dc = boost::dynamic_pointer_cast<const DCPContent> (i);
-               shared_ptr<const DCPSubtitleContent> dsc = boost::dynamic_pointer_cast<const DCPSubtitleContent> (i);
+               shared_ptr<const FFmpegContent> fc = std::dynamic_pointer_cast<const FFmpegContent> (i);
+               shared_ptr<const StringTextFileContent> sc = std::dynamic_pointer_cast<const StringTextFileContent> (i);
+               shared_ptr<const DCPContent> dc = std::dynamic_pointer_cast<const DCPContent> (i);
+               shared_ptr<const DCPSubtitleContent> dsc = std::dynamic_pointer_cast<const DCPSubtitleContent> (i);
                if (fc) {
                        if (!fc->text.empty()) {
                                ++ffmpeg_subs;
@@ -572,10 +558,10 @@ TextPanel::setup_sensitivity ()
        }
 
        switch (type) {
-       case TEXT_OPEN_SUBTITLE:
+       case TextType::OPEN_SUBTITLE:
                _type->SetSelection (0);
                break;
-       case TEXT_CLOSED_CAPTION:
+       case TextType::CLOSED_CAPTION:
                if (_type->GetCount() > 1) {
                        _type->SetSelection (1);
                }
@@ -588,35 +574,35 @@ TextPanel::setup_sensitivity ()
        _use->Enable (!reference && any_subs > 0);
        bool const use = _use->GetValue ();
        if (_outline_subtitles) {
-               _outline_subtitles->Enable (!_loading_analysis && any_subs && use && type == TEXT_OPEN_SUBTITLE);
+               _outline_subtitles->Enable (!_loading_analysis && any_subs && use && type == TextType::OPEN_SUBTITLE);
        }
        _type->Enable (!reference && any_subs > 0 && use);
-       _burn->Enable (!reference && any_subs > 0 && use && type == TEXT_OPEN_SUBTITLE);
-       _x_offset->Enable (!reference && any_subs > 0 && use && type == TEXT_OPEN_SUBTITLE);
-       _y_offset->Enable (!reference && any_subs > 0 && use && type == TEXT_OPEN_SUBTITLE);
-       _x_scale->Enable (!reference && any_subs > 0 && use && type == TEXT_OPEN_SUBTITLE);
-       _y_scale->Enable (!reference && any_subs > 0 && use && type == TEXT_OPEN_SUBTITLE);
-       _line_spacing->Enable (!reference && use && type == TEXT_OPEN_SUBTITLE && dcp_subs < any_subs);
+       _burn->Enable (!reference && any_subs > 0 && use && type == TextType::OPEN_SUBTITLE);
+       _x_offset->Enable (!reference && any_subs > 0 && use && type == TextType::OPEN_SUBTITLE);
+       _y_offset->Enable (!reference && any_subs > 0 && use && type == TextType::OPEN_SUBTITLE);
+       _x_scale->Enable (!reference && any_subs > 0 && use && type == TextType::OPEN_SUBTITLE);
+       _y_scale->Enable (!reference && any_subs > 0 && use && type == TextType::OPEN_SUBTITLE);
+       _line_spacing->Enable (!reference && use && type == TextType::OPEN_SUBTITLE && dcp_subs < any_subs);
        _stream->Enable (!reference && ffmpeg_subs == 1);
        /* Ideally we would check here to see if the FFmpeg content has "string" subs (i.e. not bitmaps) */
        _text_view_button->Enable (!reference && any_subs > 0 && ffmpeg_subs == 0);
-       _fonts_dialog_button->Enable (!reference && any_subs > 0 && ffmpeg_subs == 0 && type == TEXT_OPEN_SUBTITLE);
-       _appearance_dialog_button->Enable (!reference && any_subs > 0 && use && type == TEXT_OPEN_SUBTITLE);
+       _fonts_dialog_button->Enable (!reference && any_subs > 0 && ffmpeg_subs == 0 && type == TextType::OPEN_SUBTITLE);
+       _appearance_dialog_button->Enable (!reference && any_subs > 0 && use && type == TextType::OPEN_SUBTITLE);
 }
 
 void
 TextPanel::stream_changed ()
 {
-       FFmpegContentList fc = _parent->selected_ffmpeg ();
+       auto fc = _parent->selected_ffmpeg ();
        if (fc.size() != 1) {
                return;
        }
 
-       shared_ptr<FFmpegContent> fcs = fc.front ();
+       auto fcs = fc.front ();
 
-       vector<shared_ptr<FFmpegSubtitleStream> > a = fcs->subtitle_streams ();
-       vector<shared_ptr<FFmpegSubtitleStream> >::iterator i = a.begin ();
-       string const s = string_client_data (_stream->GetClientObject (_stream->GetSelection ()));
+       auto a = fcs->subtitle_streams ();
+       auto i = a.begin ();
+       auto const s = string_client_data (_stream->GetClientObject (_stream->GetSelection ()));
        while (i != a.end() && (*i)->identifier () != s) {
                ++i;
        }
@@ -629,7 +615,7 @@ TextPanel::stream_changed ()
 void
 TextPanel::x_offset_changed ()
 {
-       BOOST_FOREACH (shared_ptr<Content> i, _parent->selected_text ()) {
+       for (auto i: _parent->selected_text ()) {
                i->text_of_original_type(_original_type)->set_x_offset (_x_offset->GetValue() / 100.0);
        }
 }
@@ -637,7 +623,7 @@ TextPanel::x_offset_changed ()
 void
 TextPanel::y_offset_changed ()
 {
-       BOOST_FOREACH (shared_ptr<Content> i, _parent->selected_text ()) {
+       for (auto i: _parent->selected_text ()) {
                i->text_of_original_type(_original_type)->set_y_offset (_y_offset->GetValue() / 100.0);
        }
 }
@@ -645,7 +631,7 @@ TextPanel::y_offset_changed ()
 void
 TextPanel::x_scale_changed ()
 {
-       ContentList c = _parent->selected_text ();
+       auto c = _parent->selected_text ();
        if (c.size() == 1) {
                c.front()->text_of_original_type(_original_type)->set_x_scale (_x_scale->GetValue() / 100.0);
        }
@@ -654,7 +640,7 @@ TextPanel::x_scale_changed ()
 void
 TextPanel::y_scale_changed ()
 {
-       BOOST_FOREACH (shared_ptr<Content> i, _parent->selected_text ()) {
+       for (auto i: _parent->selected_text ()) {
                i->text_of_original_type(_original_type)->set_y_scale (_y_scale->GetValue() / 100.0);
        }
 }
@@ -662,20 +648,11 @@ TextPanel::y_scale_changed ()
 void
 TextPanel::line_spacing_changed ()
 {
-       BOOST_FOREACH (shared_ptr<Content> i, _parent->selected_text ()) {
+       for (auto i: _parent->selected_text ()) {
                i->text_of_original_type(_original_type)->set_line_spacing (_line_spacing->GetValue() / 100.0);
        }
 }
 
-void
-TextPanel::language_changed ()
-{
-       DCPOMATIC_ASSERT (_language);
-       BOOST_FOREACH (shared_ptr<Content> i, _parent->selected_text ()) {
-               i->text_of_original_type(_original_type)->set_language (wx_to_std (_language->GetValue()));
-       }
-}
-
 void
 TextPanel::content_selection_changed ()
 {
@@ -687,7 +664,6 @@ TextPanel::content_selection_changed ()
        film_content_changed (TextContentProperty::X_SCALE);
        film_content_changed (TextContentProperty::Y_SCALE);
        film_content_changed (TextContentProperty::LINE_SPACING);
-       film_content_changed (TextContentProperty::LANGUAGE);
        film_content_changed (TextContentProperty::FONTS);
        film_content_changed (TextContentProperty::TYPE);
        film_content_changed (TextContentProperty::DCP_TRACK);
@@ -718,10 +694,10 @@ TextPanel::fonts_dialog_clicked ()
 {
        if (_fonts_dialog) {
                _fonts_dialog->Destroy ();
-               _fonts_dialog = 0;
+               _fonts_dialog = nullptr;
        }
 
-       ContentList c = _parent->selected_text ();
+       auto c = _parent->selected_text ();
        DCPOMATIC_ASSERT (c.size() == 1);
 
        _fonts_dialog = new FontsDialog (this, c.front(), c.front()->text_of_original_type(_original_type));
@@ -731,12 +707,12 @@ TextPanel::fonts_dialog_clicked ()
 void
 TextPanel::reference_clicked ()
 {
-       ContentList c = _parent->selected ();
+       auto c = _parent->selected ();
        if (c.size() != 1) {
                return;
        }
 
-       shared_ptr<DCPContent> d = dynamic_pointer_cast<DCPContent> (c.front ());
+       auto d = dynamic_pointer_cast<DCPContent> (c.front ());
        if (!d) {
                return;
        }
@@ -747,10 +723,10 @@ TextPanel::reference_clicked ()
 void
 TextPanel::appearance_dialog_clicked ()
 {
-       ContentList c = _parent->selected_text ();
+       auto c = _parent->selected_text ();
        DCPOMATIC_ASSERT (c.size() == 1);
 
-       SubtitleAppearanceDialog* d = new SubtitleAppearanceDialog (this, _parent->film(), c.front(), c.front()->text_of_original_type(_original_type));
+       auto d = new SubtitleAppearanceDialog (this, _parent->film(), c.front(), c.front()->text_of_original_type(_original_type));
        if (d->ShowModal () == wxID_OK) {
                d->apply ();
        }
@@ -775,21 +751,25 @@ TextPanel::outline_subtitles_changed ()
 void
 TextPanel::try_to_load_analysis ()
 {
+       if (_loading_analysis) {
+               return;
+       }
+
        _loading_analysis = true;
        setup_sensitivity ();
        _analysis.reset ();
 
-       shared_ptr<Content> content = _analysis_content.lock ();
+       auto content = _analysis_content.lock ();
        if (!content) {
                _loading_analysis = false;
                setup_sensitivity ();
                return;
        }
 
-       boost::filesystem::path const path = _parent->film()->subtitle_analysis_path(content);
+       auto const path = _parent->film()->subtitle_analysis_path(content);
 
        if (!boost::filesystem::exists(path)) {
-               BOOST_FOREACH (shared_ptr<Job> i, JobManager::instance()->get()) {
+               for (auto i: JobManager::instance()->get()) {
                        if (dynamic_pointer_cast<AnalyseSubtitlesJob>(i)) {
                                i->cancel ();
                        }
@@ -820,15 +800,15 @@ TextPanel::try_to_load_analysis ()
 void
 TextPanel::update_outline_subtitles_in_viewer ()
 {
-       shared_ptr<FilmViewer> fv = _parent->film_viewer().lock();
+       auto fv = _parent->film_viewer().lock();
        if (!fv) {
                return;
        }
 
        if (_analysis) {
-               optional<dcpomatic::Rect<double> > rect = _analysis->bounding_box ();
+               auto rect = _analysis->bounding_box ();
                if (rect) {
-                       shared_ptr<Content> content = _analysis_content.lock ();
+                       auto content = _analysis_content.lock ();
                        DCPOMATIC_ASSERT (content);
                        rect->x += content->text.front()->x_offset();
                        rect->y += content->text.front()->y_offset();
@@ -855,7 +835,7 @@ TextPanel::clear_outline_subtitles ()
 void
 TextPanel::analysis_finished ()
 {
-       shared_ptr<Content> content = _analysis_content.lock ();
+       auto content = _analysis_content.lock ();
        if (!content) {
                _loading_analysis = false;
                setup_sensitivity ();
@@ -873,6 +853,7 @@ TextPanel::analysis_finished ()
                return;
        }
 
+       _loading_analysis = false;
        try_to_load_analysis ();
 }