X-Git-Url: https://main.carlh.net/gitweb/?p=dcpomatic.git;a=blobdiff_plain;f=src%2Fwx%2Fwx_util.cc;h=47a6bd5b05141a704ed08a86b3df64c39b9d3d57;hp=c9185ec973df9565413acc25414b3951bfd01016;hb=2d2af972a53a2c11b95469058803b4eaed2d3c01;hpb=44b78ba0e1bd215fb307a0d5f557c0d4c48f0981 diff --git a/src/wx/wx_util.cc b/src/wx/wx_util.cc index c9185ec97..47a6bd5b0 100644 --- a/src/wx/wx_util.cc +++ b/src/wx/wx_util.cc @@ -1,5 +1,5 @@ /* - Copyright (C) 2012-2016 Carl Hetherington + Copyright (C) 2012-2021 Carl Hetherington This file is part of DCP-o-matic. @@ -18,24 +18,42 @@ */ + /** @file src/wx/wx_util.cc * @brief Some utility functions and classes. */ -#include "wx_util.h" + #include "file_picker_ctrl.h" +#include "password_entry.h" +#include "static_text.h" +#include "wx_util.h" #include "lib/config.h" -#include "lib/util.h" #include "lib/cross.h" +#include "lib/job.h" +#include "lib/job_manager.h" +#include "lib/util.h" +#include "lib/version.h" +#include "lib/warnings.h" #include +DCPOMATIC_DISABLE_WARNINGS #include #include +#include #include +#include +DCPOMATIC_ENABLE_WARNINGS #include -using namespace std; -using namespace boost; + +using std::string; +using std::vector; +using std::pair; +using std::shared_ptr; +using boost::optional; using dcp::locale_convert; +using namespace dcpomatic; + wxStaticText * #ifdef __WXOSX__ @@ -49,9 +67,25 @@ create_label (wxWindow* p, wxString t, bool) t += wxT (":"); } #endif - return new wxStaticText (p, wxID_ANY, t); + return new StaticText (p, t); } + +#ifdef __WXOSX__ +static +void +setup_osx_flags (wxSizer* s, bool left, int& flags) +{ + if (left) { + auto box = dynamic_cast(s); + if (!box || box->GetOrientation() != wxHORIZONTAL) { + flags |= wxALIGN_RIGHT; + } + } +} +#endif + + /** Add a wxStaticText to a wxSizer, aligning it at vertical centre. * @param s Sizer to add to. * @param p Parent window for the wxStaticText. @@ -64,15 +98,14 @@ wxStaticText * add_label_to_sizer (wxSizer* s, wxWindow* p, wxString t, bool left, int prop, int flags) { #ifdef __WXOSX__ - if (left) { - flags |= wxALIGN_RIGHT; - } + setup_osx_flags (s, left, flags); #endif - wxStaticText* m = create_label (p, t, left); + auto m = create_label (p, t, left); s->Add (m, prop, flags, 6); return m; } + wxStaticText * #ifdef __WXOSX__ add_label_to_sizer (wxSizer* s, wxStaticText* t, bool left, int prop, int flags) @@ -81,28 +114,26 @@ add_label_to_sizer (wxSizer* s, wxStaticText* t, bool, int prop, int flags) #endif { #ifdef __WXOSX__ - if (left) { - flags |= wxALIGN_RIGHT; - } + setup_osx_flags (s, left, flags); #endif s->Add (t, prop, flags, 6); return t; } + wxStaticText * add_label_to_sizer (wxGridBagSizer* s, wxWindow* p, wxString t, bool left, wxGBPosition pos, wxGBSpan span) { int flags = wxALIGN_CENTER_VERTICAL | wxLEFT | wxRIGHT; #ifdef __WXOSX__ - if (left) { - flags |= wxALIGN_RIGHT; - } + setup_osx_flags (s, left, flags); #endif - wxStaticText* m = create_label (p, t, left); + auto m = create_label (p, t, left); s->Add (m, pos, span, flags); return m; } + wxStaticText * #ifdef __WXOSX__ add_label_to_sizer (wxGridBagSizer* s, wxStaticText* t, bool left, wxGBPosition pos, wxGBSpan span) @@ -112,14 +143,13 @@ add_label_to_sizer (wxGridBagSizer* s, wxStaticText* t, bool, wxGBPosition pos, { int flags = wxALIGN_CENTER_VERTICAL | wxLEFT | wxRIGHT; #ifdef __WXOSX__ - if (left) { - flags |= wxALIGN_RIGHT; - } + setup_osx_flags (s, left, flags); #endif s->Add (t, pos, span, flags); return t; } + /** Pop up an error dialogue box. * @param parent Parent. * @param m Message. @@ -128,7 +158,7 @@ add_label_to_sizer (wxGridBagSizer* s, wxStaticText* t, bool, wxGBPosition pos, void error_dialog (wxWindow* parent, wxString m, optional e) { - wxMessageDialog* d = new wxMessageDialog (parent, m, _("DCP-o-matic"), wxOK | wxICON_ERROR); + auto d = new wxMessageDialog (parent, m, _("DCP-o-matic"), wxOK | wxICON_ERROR); if (e) { wxString em = *e; em[0] = wxToupper (em[0]); @@ -138,6 +168,7 @@ error_dialog (wxWindow* parent, wxString m, optional e) d->Destroy (); } + /** Pop up an error dialogue box. * @param parent Parent. * @param m Message. @@ -145,15 +176,17 @@ error_dialog (wxWindow* parent, wxString m, optional e) void message_dialog (wxWindow* parent, wxString m) { - wxMessageDialog* d = new wxMessageDialog (parent, m, _("DCP-o-matic"), wxOK | wxICON_INFORMATION); + auto d = new wxMessageDialog (parent, m, _("DCP-o-matic"), wxOK | wxICON_INFORMATION); d->ShowModal (); d->Destroy (); } + +/** @return true if the user answered "yes" */ bool confirm_dialog (wxWindow* parent, wxString m) { - wxMessageDialog* d = new wxMessageDialog (parent, m, _("DCP-o-matic"), wxYES_NO | wxICON_QUESTION); + auto d = new wxMessageDialog (parent, m, _("DCP-o-matic"), wxYES_NO | wxICON_QUESTION); int const r = d->ShowModal (); d->Destroy (); return r == wxID_YES; @@ -166,9 +199,10 @@ confirm_dialog (wxWindow* parent, wxString m) string wx_to_std (wxString s) { - return string (s.ToUTF8 ()); + return string (s.ToUTF8()); } + /** @param s STL string. * @return Corresponding wxWidgets string. */ @@ -178,12 +212,14 @@ std_to_wx (string s) return wxString (s.c_str(), wxConvUTF8); } + string string_client_data (wxClientData* o) { return wx_to_std (dynamic_cast(o)->GetData()); } + void checked_set (FilePickerCtrl* widget, boost::filesystem::path value) { @@ -198,6 +234,7 @@ checked_set (FilePickerCtrl* widget, boost::filesystem::path value) } } + void checked_set (wxDirPickerCtrl* widget, boost::filesystem::path value) { @@ -212,6 +249,7 @@ checked_set (wxDirPickerCtrl* widget, boost::filesystem::path value) } } + void checked_set (wxSpinCtrl* widget, int value) { @@ -220,6 +258,7 @@ checked_set (wxSpinCtrl* widget, int value) } } + void checked_set (wxSpinCtrlDouble* widget, double value) { @@ -229,6 +268,7 @@ checked_set (wxSpinCtrlDouble* widget, double value) } } + void checked_set (wxChoice* widget, int value) { @@ -237,10 +277,11 @@ checked_set (wxChoice* widget, int value) } } + void checked_set (wxChoice* widget, string value) { - wxClientData* o = 0; + wxClientData* o = nullptr; if (widget->GetSelection() != -1) { o = widget->GetClientObject (widget->GetSelection ()); } @@ -254,15 +295,16 @@ checked_set (wxChoice* widget, string value) } } + void checked_set (wxChoice* widget, vector > items) { - vector > current; + vector> current; for (unsigned int i = 0; i < widget->GetCount(); ++i) { current.push_back ( - make_pair ( - wx_to_std (widget->GetString (i)), - string_client_data (widget->GetClientObject (i)) + make_pair( + wx_to_std(widget->GetString(i)), + string_client_data(widget->GetClientObject(i)) ) ); } @@ -272,11 +314,12 @@ checked_set (wxChoice* widget, vector > items) } widget->Clear (); - for (vector >::const_iterator i = items.begin(); i != items.end(); ++i) { - widget->Append (std_to_wx (i->first), new wxStringClientData (std_to_wx (i->second))); + for (auto i: items) { + widget->Append (std_to_wx(i.first), new wxStringClientData(std_to_wx(i.second))); } } + void checked_set (wxTextCtrl* widget, string value) { @@ -285,6 +328,16 @@ checked_set (wxTextCtrl* widget, string value) } } + +void +checked_set (PasswordEntry* entry, string value) +{ + if (entry->get() != value) { + entry->set(value); + } +} + + void checked_set (wxTextCtrl* widget, wxString value) { @@ -293,6 +346,7 @@ checked_set (wxTextCtrl* widget, wxString value) } } + void checked_set (wxStaticText* widget, string value) { @@ -301,6 +355,7 @@ checked_set (wxStaticText* widget, string value) } } + void checked_set (wxStaticText* widget, wxString value) { @@ -309,6 +364,7 @@ checked_set (wxStaticText* widget, wxString value) } } + void checked_set (wxCheckBox* widget, bool value) { @@ -317,6 +373,7 @@ checked_set (wxCheckBox* widget, bool value) } } + void checked_set (wxRadioButton* widget, bool value) { @@ -325,20 +382,21 @@ checked_set (wxRadioButton* widget, bool value) } } + void dcpomatic_setup_i18n () { int language = wxLANGUAGE_DEFAULT; - boost::optional config_lang = Config::instance()->language (); + auto config_lang = Config::instance()->language (); if (config_lang && !config_lang->empty ()) { - wxLanguageInfo const * li = wxLocale::FindLanguageInfo (std_to_wx (config_lang.get ())); + auto const li = wxLocale::FindLanguageInfo (std_to_wx (config_lang.get ())); if (li) { language = li->Language; } } - wxLocale* locale = 0; + wxLocale* locale = nullptr; if (wxLocale::IsAvailable (language)) { locale = new wxLocale (language, wxLOCALE_LOAD_DEFAULT); @@ -354,6 +412,9 @@ dcpomatic_setup_i18n () of wxWidgets. */ locale->AddCatalog (wxT ("dcpomatic2-wxstd")); + + /* Fedora 29 (at least) installs wxstd3.mo instead of wxstd.mo */ + locale->AddCatalog (wxT ("wxstd3")); #endif locale->AddCatalog (wxT ("libdcpomatic2-wx")); @@ -370,31 +431,35 @@ dcpomatic_setup_i18n () } } + int wx_get (wxSpinCtrl* w) { return w->GetValue (); } + int wx_get (wxChoice* w) { return w->GetSelection (); } + double wx_get (wxSpinCtrlDouble* w) { return w->GetValue (); } + /** @param s String of the form Context|String * @return translation, or String if no translation is available. */ wxString context_translation (wxString s) { - wxString t = wxGetTranslation (s); + auto t = wxGetTranslation (s); if (t == s) { /* No translation; strip the context */ int c = t.Find (wxT ("|")); @@ -406,10 +471,11 @@ context_translation (wxString s) return t; } + wxString time_to_timecode (DCPTime t, double fps) { - double w = t.seconds (); + auto w = t.seconds (); int const h = (w / 3600); w -= h * 3600; int const m = (w / 60); @@ -420,41 +486,53 @@ time_to_timecode (DCPTime t, double fps) return wxString::Format (wxT("%02d:%02d:%02d.%02d"), h, m, s, f); } + void setup_audio_channels_choice (wxChoice* choice, int minimum) { - vector > items; + vector> items; for (int i = minimum; i <= 16; i += 2) { if (i == 2) { - items.push_back (make_pair (wx_to_std (_("2 - stereo")), locale_convert (i))); + items.push_back (make_pair(wx_to_std(_("2 - stereo")), locale_convert(i))); } else if (i == 4) { - items.push_back (make_pair (wx_to_std (_("4 - L/C/R/Lfe")), locale_convert (i))); + items.push_back (make_pair(wx_to_std(_("4 - L/C/R/Lfe")), locale_convert(i))); } else if (i == 6) { - items.push_back (make_pair (wx_to_std (_("6 - 5.1")), locale_convert (i))); + items.push_back (make_pair(wx_to_std(_("6 - 5.1")), locale_convert(i))); } else if (i == 8) { - items.push_back (make_pair (wx_to_std (_("8 - 5.1/HI/VI")), locale_convert (i))); + items.push_back (make_pair(wx_to_std(_("8 - 5.1/HI/VI")), locale_convert(i))); } else if (i == 12) { - items.push_back (make_pair (wx_to_std (_("12 - 7.1/HI/VI")), locale_convert (i))); + items.push_back (make_pair(wx_to_std(_("12 - 7.1/HI/VI")), locale_convert(i))); } else { - items.push_back (make_pair (locale_convert (i), locale_convert (i))); + items.push_back (make_pair(locale_convert (i), locale_convert(i))); } } checked_set (choice, items); } + wxSplashScreen * maybe_show_splash () { - wxSplashScreen* splash = 0; + wxSplashScreen* splash = nullptr; try { - if (!Config::have_existing ("config.xml")) { - wxBitmap bitmap; - boost::filesystem::path p = shared_path () / "splash.png"; - if (bitmap.LoadFile (std_to_wx (p.string ()), wxBITMAP_TYPE_PNG)) { - splash = new wxSplashScreen (bitmap, wxSPLASH_CENTRE_ON_SCREEN | wxSPLASH_NO_TIMEOUT, 0, 0, -1); - wxYield (); + wxBitmap bitmap; + if (bitmap.LoadFile(bitmap_path("splash"), wxBITMAP_TYPE_PNG)) { + { + /* This wxMemoryDC must be destroyed before bitmap can be used elsewhere */ + wxMemoryDC dc(bitmap); + auto const version = wxString::Format("%s (%s)", dcpomatic_version, dcpomatic_git_commit); + auto screen_size = dc.GetSize(); + auto text_size = dc.GetTextExtent(version); + dc.DrawText(version, (screen_size.GetWidth() - text_size.GetWidth()) / 2, 236); } +#ifdef DCPOMATIC_WINDOWS + /* Having wxSTAY_ON_TOP means error dialogues hide behind the splash screen on Windows, no matter what I try */ + splash = new wxSplashScreen (bitmap, wxSPLASH_CENTRE_ON_SCREEN | wxSPLASH_NO_TIMEOUT, 0, 0, -1, wxDefaultPosition, wxDefaultSize, wxBORDER_SIMPLE | wxFRAME_NO_TASKBAR); +#else + splash = new wxSplashScreen (bitmap, wxSPLASH_CENTRE_ON_SCREEN | wxSPLASH_NO_TIMEOUT, 0, 0, -1); +#endif + wxYield (); } } catch (boost::filesystem::filesystem_error& e) { /* Maybe we couldn't find the splash image; never mind */ @@ -463,11 +541,6 @@ maybe_show_splash () return splash; } -boost::filesystem::path -path_from_file_dialog (wxFileDialog* dialog, string extension) -{ - return boost::filesystem::path(wx_to_std(dialog->GetPath())).replace_extension(extension); -} double calculate_mark_interval (double mark_interval) @@ -491,3 +564,127 @@ calculate_mark_interval (double mark_interval) return mark_interval; } + + +/** @return false if the task was cancelled */ +bool +display_progress (wxString title, wxString task) +{ + auto jm = JobManager::instance (); + + wxProgressDialog progress (title, task, 100, 0, wxPD_CAN_ABORT); + + bool ok = true; + + while (jm->work_to_do()) { + dcpomatic_sleep_seconds (1); + if (!progress.Pulse()) { + /* user pressed cancel */ + for (auto i: jm->get()) { + i->cancel(); + } + ok = false; + break; + } + } + + return ok; +} + + +int +get_offsets (vector& offsets) +{ + offsets.push_back (Offset(_("UTC-11"), -11, 0)); + offsets.push_back (Offset(_("UTC-10"), -10, 0)); + offsets.push_back (Offset(_("UTC-9"), -9, 0)); + offsets.push_back (Offset(_("UTC-8"), -8, 0)); + offsets.push_back (Offset(_("UTC-7"), -7, 0)); + offsets.push_back (Offset(_("UTC-6"), -6, 0)); + offsets.push_back (Offset(_("UTC-5"), -5, 0)); + offsets.push_back (Offset(_("UTC-4:30"), -4, 30)); + offsets.push_back (Offset(_("UTC-4"), -4, 0)); + offsets.push_back (Offset(_("UTC-3:30"), -3, 30)); + offsets.push_back (Offset(_("UTC-3"), -3, 0)); + offsets.push_back (Offset(_("UTC-2"), -2, 0)); + offsets.push_back (Offset(_("UTC-1"), -1, 0)); + int utc = offsets.size(); + offsets.push_back (Offset(_("UTC") , 0, 0)); + offsets.push_back (Offset(_("UTC+1"), 1, 0)); + offsets.push_back (Offset(_("UTC+2"), 2, 0)); + offsets.push_back (Offset(_("UTC+3"), 3, 0)); + offsets.push_back (Offset(_("UTC+4"), 4, 0)); + offsets.push_back (Offset(_("UTC+5"), 5, 0)); + offsets.push_back (Offset(_("UTC+5:30"), 5, 30)); + offsets.push_back (Offset(_("UTC+6"), 6, 0)); + offsets.push_back (Offset(_("UTC+7"), 7, 0)); + offsets.push_back (Offset(_("UTC+8"), 8, 0)); + offsets.push_back (Offset(_("UTC+9"), 9, 0)); + offsets.push_back (Offset(_("UTC+9:30"), 9, 30)); + offsets.push_back (Offset(_("UTC+10"), 10, 0)); + offsets.push_back (Offset(_("UTC+11"), 11, 0)); + offsets.push_back (Offset(_("UTC+12"), 12, 0)); + + return utc; +} + + +wxString +bitmap_path (string name) +{ + boost::filesystem::path base; + +#ifdef DCPOMATIC_DEBUG + /* Hack to allow Linux and OS X to find icons when running from the source tree */ + char* path = getenv ("DCPOMATIC_GRAPHICS"); + if (path) { + base = path; + } else { + base = resources_path(); + } +#else + base = resources_path(); +#endif + + auto p = base / String::compose("%1.png", name); + return std_to_wx (p.string()); +} + + +wxSize +small_button_size (wxWindow* parent, wxString text) +{ + wxClientDC dc (parent); + auto size = dc.GetTextExtent (text); + size.SetHeight (-1); + size.IncBy (24, 0); + return size; +} + + +bool +gui_is_dark () +{ +#if defined(DCPOMATIC_OSX) && wxCHECK_VERSION(3, 1, 0) + auto appearance = wxSystemSettings::GetAppearance(); + return appearance.IsDark(); +#else + return false; +#endif +} + + +#if wxCHECK_VERSION(3,1,0) +double +dpi_scale_factor (wxWindow* window) +{ + return window->GetDPIScaleFactor(); +} +#else +double +dpi_scale_factor (wxWindow*) +{ + return 1; +} +#endif +