Use more ScopeGuards.
[dcpomatic.git] / src / wx / content_panel.cc
index df6308bea548929f1ba50a9dd0ffe366c00693f3..c18520c30b4b677453372736dd78e40f0ba70d70 100644 (file)
@@ -43,6 +43,7 @@
 #include "lib/image_content.h"
 #include "lib/log.h"
 #include "lib/playlist.h"
+#include "lib/scope_guard.h"
 #include "lib/string_text_file.h"
 #include "lib/string_text_file_content.h"
 #include "lib/text_content.h"
@@ -90,22 +91,26 @@ public:
        bool OnSashPositionChange(int new_position) override
        {
                /* Try to stop the top bit of the splitter getting so small that buttons disappear */
-               return new_position > 220;
+               auto const ok = new_position > 220;
+               if (ok) {
+                       Config::instance()->set_main_content_divider_sash_position(new_position);
+               }
+               return ok;
        }
 
        void first_shown(wxWindow* top, wxWindow* bottom)
        {
                int const sn = wxDisplay::GetFromWindow(this);
+               /* Fallback for when GetFromWindow fails for reasons that aren't clear */
+               int pos = -600;
                if (sn >= 0) {
                        wxRect const screen = wxDisplay(sn).GetClientArea();
                        /* This is a hack to try and make the content notebook a sensible size; large on big displays but small
                           enough on small displays to leave space for the content area.
                           */
-                       SplitHorizontally(top, bottom, screen.height > 800 ? -600 : -_top_panel_minimum_size);
-               } else {
-                       /* Fallback for when GetFromWindow fails for reasons that aren't clear */
-                       SplitHorizontally(top, bottom, -600);
+                       pos = screen.height > 800 ? -600 : -_top_panel_minimum_size;
                }
+               SplitHorizontally(top, bottom, Config::instance()->main_content_divider_sash_position().get_value_or(pos));
                _first_shown = true;
        }
 
@@ -117,7 +122,7 @@ private:
                        /* The window is now fairly big but the top panel is small; this happens when the DCP-o-matic window
                         * is shrunk and then made larger again.  Try to set a sensible top panel size in this case (#1839).
                         */
-                       SetSashPosition(_top_panel_minimum_size);
+                       SetSashPosition(Config::instance()->main_content_divider_sash_position().get_value_or(_top_panel_minimum_size));
                }
 
                ev.Skip ();
@@ -175,6 +180,47 @@ private:
 };
 
 
+/** A wxListCtrl that can middle-ellipsize its text */
+class ContentListCtrl : public wxListCtrl
+{
+public:
+       ContentListCtrl(wxWindow* parent)
+               : wxListCtrl(parent, wxID_ANY, wxDefaultPosition, wxSize(320, 160), wxLC_REPORT | wxLC_NO_HEADER | wxLC_VIRTUAL)
+       {
+               _red.SetTextColour(*wxRED);
+       }
+
+       struct Item
+       {
+               wxString text;
+               bool error;
+       };
+
+       void set(vector<Item> const& items)
+       {
+               _items = items;
+               SetItemCount(items.size());
+       }
+
+       wxString OnGetItemText(long item, long) const override
+       {
+               DCPOMATIC_ASSERT(item >= 0 && item < static_cast<long>(_items.size()));
+               wxClientDC dc(const_cast<wxWindow*>(static_cast<wxWindow const*>(this)));
+               return wxControl::Ellipsize(_items[item].text, dc, wxELLIPSIZE_MIDDLE, GetSize().GetWidth());
+       }
+
+       wxListItemAttr* OnGetItemAttr(long item) const override
+       {
+               DCPOMATIC_ASSERT(item >= 0 && item < static_cast<long>(_items.size()));
+               return _items[item].error ? const_cast<wxListItemAttr*>(&_red) : nullptr;
+       }
+
+private:
+       std::vector<Item> _items;
+       wxListItemAttr _red;
+};
+
+
 ContentPanel::ContentPanel(wxNotebook* n, shared_ptr<Film> film, FilmViewer& viewer)
        : _parent (n)
        , _film (film)
@@ -191,12 +237,12 @@ ContentPanel::ContentPanel(wxNotebook* n, shared_ptr<Film> film, FilmViewer& vie
        {
                auto s = new wxBoxSizer (wxHORIZONTAL);
 
-               _content = new wxListCtrl (_top_panel, wxID_ANY, wxDefaultPosition, wxSize (320, 160), wxLC_REPORT | wxLC_NO_HEADER);
+               _content = new ContentListCtrl(_top_panel);
                _content->DragAcceptFiles (true);
                s->Add (_content, 1, wxEXPAND | wxTOP | wxBOTTOM, 6);
 
                _content->InsertColumn (0, wxT(""));
-               _content->SetColumnWidth (0, 512);
+               _content->SetColumnWidth(0, 2048);
 
                auto b = new wxBoxSizer (wxVERTICAL);
 
@@ -533,7 +579,7 @@ ContentPanel::add_file_clicked ()
                return;
        }
 
-       auto path = Config::instance()->add_files_path();
+       auto path = Config::instance()->initial_path("AddFilesPath");
 
        /* The wxFD_CHANGE_DIR here prevents a `could not set working directory' error 123 on Windows when using
           non-Latin filenames or paths.
@@ -563,7 +609,7 @@ ContentPanel::add_file_clicked ()
        add_files (path_list);
 
        if (!path_list.empty()) {
-               Config::instance()->set_add_files_path(path_list[0].parent_path());
+               Config::instance()->set_initial_path("AddFilesPath", path_list[0].parent_path());
        }
 
        d->Destroy ();
@@ -573,15 +619,16 @@ ContentPanel::add_file_clicked ()
 void
 ContentPanel::add_folder_clicked ()
 {
-       auto d = new wxDirDialog (_splitter, _("Choose a folder"), wxT(""), wxDD_DIR_MUST_EXIST);
-       int r = d->ShowModal ();
-       boost::filesystem::path const path (wx_to_std (d->GetPath ()));
-       d->Destroy ();
+       auto const initial_path = Config::instance()->initial_path("AddFilesPath");
 
+       auto d = new wxDirDialog(_splitter, _("Choose a folder"), std_to_wx(initial_path ? initial_path->string() : home_directory().string()), wxDD_DIR_MUST_EXIST);
+       ScopeGuard sg = [d]() { d->Destroy(); };
+       int r = d->ShowModal ();
        if (r != wxID_OK) {
                return;
        }
 
+       boost::filesystem::path const path(wx_to_std(d->GetPath()));
        add_folder(path);
 }
 
@@ -607,15 +654,12 @@ ContentPanel::add_folder(boost::filesystem::path folder)
                auto ic = dynamic_pointer_cast<ImageContent> (i);
                if (ic) {
                        auto e = new ImageSequenceDialog (_splitter);
-                       int const r = e->ShowModal();
-                       auto const frame_rate = e->frame_rate ();
-                       e->Destroy ();
+                       ScopeGuard sg = [e]() { e->Destroy(); };
 
-                       if (r != wxID_OK) {
+                       if (e->ShowModal() != wxID_OK) {
                                return;
                        }
-
-                       ic->set_video_frame_rate (frame_rate);
+                       ic->set_video_frame_rate(_film, e->frame_rate());
                }
 
                _film->examine_and_add_content (i);
@@ -626,15 +670,16 @@ ContentPanel::add_folder(boost::filesystem::path folder)
 void
 ContentPanel::add_dcp_clicked ()
 {
-       auto d = new wxDirDialog (_splitter, _("Choose a DCP folder"), wxT(""), wxDD_DIR_MUST_EXIST);
-       int r = d->ShowModal ();
-       boost::filesystem::path const path (wx_to_std (d->GetPath ()));
-       d->Destroy ();
+       auto const initial_path = Config::instance()->initial_path("AddFilesPath");
 
+       auto d = new wxDirDialog(_splitter, _("Choose a DCP folder"), std_to_wx(initial_path ? initial_path->string() : home_directory().string()), wxDD_DIR_MUST_EXIST);
+       ScopeGuard sg = [d]() { d->Destroy(); };
+       int r = d->ShowModal ();
        if (r != wxID_OK) {
                return;
        }
 
+       boost::filesystem::path const path(wx_to_std(d->GetPath()));
        add_dcp(path);
 }
 
@@ -857,7 +902,7 @@ ContentPanel::setup ()
                selected_content = reinterpret_cast<Content*> (item.GetData ());
        }
 
-       _content->DeleteAllItems ();
+       vector<ContentListCtrl::Item> items;
 
        for (auto i: content) {
                int const t = _content->GetItemCount ();
@@ -881,21 +926,15 @@ ContentPanel::setup ()
                        s = _("NEEDS OV: ") + s;
                }
 
-               wxListItem item;
-               item.SetId (t);
-               item.SetText (s);
-               item.SetData (i.get ());
-               _content->InsertItem (item);
+               items.push_back({s, !valid || needs_kdm || needs_assets});
 
                if (i.get() == selected_content) {
                        set_selected_state(t, true);
                }
-
-               if (!valid || needs_kdm || needs_assets) {
-                       _content->SetItemTextColour (t, *wxRED);
-               }
        }
 
+       _content->set(items);
+
        if (!selected_content && !content.empty ()) {
                /* Select the item of content if none was selected before */
                set_selected_state(0, true);