#include "lib/kdm_with_metadata.h"
#include "lib/log.h"
#include "lib/make_dcp.h"
+#include "lib/release_notes.h"
#include "lib/screen.h"
#include "lib/send_kdm_email_job.h"
#include "lib/signal_manager.h"
};
+class LimitedFrameSplitter : public wxSplitterWindow
+{
+public:
+ LimitedFrameSplitter(wxWindow* parent)
+ : wxSplitterWindow(parent, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxSP_NOBORDER | wxSP_3DSASH | wxSP_LIVE_UPDATE)
+ {
+ /* This value doesn't really mean much but we just want to stop double-click on the
+ divider from shrinking the left panel.
+ */
+ SetMinimumPaneSize(64);
+
+ Bind(wxEVT_SIZE, boost::bind(&LimitedFrameSplitter::sized, this, _1));
+ }
+
+ bool OnSashPositionChange(int new_position) override
+ {
+ /* Try to stop the left bit of the splitter getting too small */
+ return new_position > _left_panel_minimum_size;
+ }
+
+private:
+ void sized(wxSizeEvent& ev)
+ {
+ if (GetSize().GetWidth() > _left_panel_minimum_size && GetSashPosition() < _left_panel_minimum_size) {
+ /* The window is now fairly big but the left panel is small; this happens when the DCP-o-matic window
+ * is shrunk and then made larger again. Try to set a sensible left panel size in this case.
+ */
+ SetSashPosition(_left_panel_minimum_size);
+ }
+
+ ev.Skip();
+ }
+
+ int const _left_panel_minimum_size = 200;
+};
+
+
class DOMFrame : public wxFrame
{
public:
explicit DOMFrame (wxString const& title)
: wxFrame (nullptr, -1, title)
+ /* Use a panel as the only child of the Frame so that we avoid
+ the dark-grey background on Windows.
+ */
+ , _splitter(new LimitedFrameSplitter(this))
+ , _right_panel(new wxPanel(_splitter, wxID_ANY))
+ , _film_viewer(_right_panel)
{
#if defined(DCPOMATIC_WINDOWS)
if (Config::instance()->win32_console()) {
Bind (wxEVT_CLOSE_WINDOW, boost::bind (&DOMFrame::close, this, _1));
Bind (wxEVT_SHOW, boost::bind (&DOMFrame::show, this, _1));
- /* Use a panel as the only child of the Frame so that we avoid
- the dark-grey background on Windows.
- */
- auto overall_panel = new wxPanel (this, wxID_ANY);
+ auto left_panel = new wxPanel(_splitter, wxID_ANY);
+
+ _film_editor = new FilmEditor(left_panel, _film_viewer);
+
+ auto left_sizer = new wxBoxSizer(wxHORIZONTAL);
+ left_sizer->Add(_film_editor, 1, wxEXPAND);
- _film_viewer.reset (new FilmViewer (overall_panel));
- _controls = new StandardControls (overall_panel, _film_viewer, true);
- _film_editor = new FilmEditor (overall_panel, _film_viewer);
- auto job_manager_view = new JobManagerView (overall_panel, false);
+ left_panel->SetSizerAndFit(left_sizer);
+
+ _controls = new StandardControls(_right_panel, _film_viewer, true);
+ auto job_manager_view = new JobManagerView(_right_panel, false);
auto right_sizer = new wxBoxSizer (wxVERTICAL);
- right_sizer->Add (_film_viewer->panel(), 2, wxEXPAND | wxALL, 6);
+ right_sizer->Add(_film_viewer.panel(), 2, wxEXPAND | wxALL, 6);
right_sizer->Add (_controls, 0, wxEXPAND | wxALL, 6);
right_sizer->Add (job_manager_view, 1, wxEXPAND | wxALL, 6);
- wxBoxSizer* main_sizer = new wxBoxSizer (wxHORIZONTAL);
- main_sizer->Add (_film_editor, 0, wxEXPAND | wxALL, 6);
- main_sizer->Add (right_sizer, 1, wxEXPAND | wxALL, 6);
+ _right_panel->SetSizer(right_sizer);
+
+ _splitter->SplitVertically(left_panel, _right_panel, left_panel->GetSize().GetWidth() + 8);
set_menu_sensitivity ();
_film_editor->content_panel()->SelectionChanged.connect (boost::bind (&DOMFrame::set_menu_sensitivity, this));
set_title ();
- JobManager::instance()->ActiveJobsChanged.connect (boost::bind (&DOMFrame::set_menu_sensitivity, this));
-
- overall_panel->SetSizer (main_sizer);
+ JobManager::instance()->ActiveJobsChanged.connect(boost::bind(&DOMFrame::active_jobs_changed, this));
UpdateChecker::instance()->StateChanged.connect(boost::bind(&DOMFrame::update_checker_state_changed, this));
void set_film (shared_ptr<Film> film)
{
_film = film;
- _film_viewer->set_film (_film);
- _film_editor->set_film (_film);
+ _film_viewer.set_film(_film);
+ _film_editor->set_film(_film);
_controls->set_film (_film);
if (_video_waveform_dialog) {
_video_waveform_dialog->Destroy ();
void view_closed_captions ()
{
- _film_viewer->show_closed_captions ();
+ _film_viewer.show_closed_captions ();
}
void view_video_waveform ()
ev.Skip ();
}
+ void active_jobs_changed()
+ {
+ /* ActiveJobsChanged can be called while JobManager holds a lock on its mutex, making
+ * the call to JobManager::get() in set_menu_sensitivity() deadlock unless we work around
+ * it by using an idle callback. This feels quite unpleasant.
+ */
+ signal_manager->when_idle(boost::bind(&DOMFrame::set_menu_sensitivity, this));
+ }
+
void set_menu_sensitivity ()
{
auto jobs = JobManager::instance()->get ();
void start_stop_pressed ()
{
- if (_film_viewer->playing()) {
- _film_viewer->stop();
+ if (_film_viewer.playing()) {
+ _film_viewer.stop();
} else {
- _film_viewer->start();
+ _film_viewer.start();
}
}
void back_frame ()
{
- _film_viewer->seek_by (-_film_viewer->one_video_frame(), true);
+ _film_viewer.seek_by(-_film_viewer.one_video_frame(), true);
}
void forward_frame ()
{
- _film_viewer->seek_by (_film_viewer->one_video_frame(), true);
+ _film_viewer.seek_by(_film_viewer.one_video_frame(), true);
}
void analytics_message (string title, string html)
}
FilmEditor* _film_editor;
- std::shared_ptr<FilmViewer> _film_viewer;
+ LimitedFrameSplitter* _splitter;
+ wxPanel* _right_panel;
+ FilmViewer _film_viewer;
StandardControls* _controls;
VideoWaveformDialog* _video_waveform_dialog = nullptr;
SystemInformationDialog* _system_information_dialog = nullptr;
try {
wxInitAllImageHandlers ();
- Config::FailedToLoad.connect (boost::bind (&App::config_failed_to_load, this));
+ Config::FailedToLoad.connect(boost::bind(&App::config_failed_to_load, this, _1));
Config::Warning.connect (boost::bind (&App::config_warning, this, _1));
_splash = maybe_show_splash ();
if (Config::instance()->check_for_updates ()) {
UpdateChecker::instance()->run ();
}
+
+ auto release_notes = find_release_notes();
+ if (release_notes) {
+ auto notes = new HTMLDialog(nullptr, _("Release notes"), std_to_wx(*release_notes), true);
+ notes->Centre();
+ notes->ShowModal();
+ notes->Destroy();
+ }
}
catch (exception& e)
{
}
}
- void config_failed_to_load ()
+ void config_failed_to_load (Config::LoadFailure what)
{
- message_dialog (_frame, _("The existing configuration failed to load. Default values will be used instead. These may take a short time to create."));
+ report_config_load_failure(_frame, what);
}
void config_warning (string m)