X-Git-Url: https://git.carlh.net/gitweb/?a=blobdiff_plain;f=src%2Fwx%2Fwx_util.cc;h=28ac6ab5c5b4bb4bace0bec0020ffd4c82aa1453;hb=b4488bd72fcbcc3fe393724c9f4c65697fa949b6;hp=d20d755cf3a9a571945ae7353e15947ba1f878b6;hpb=bac6ee64d3302977144208a82a8b11824cb328dc;p=dcpomatic.git diff --git a/src/wx/wx_util.cc b/src/wx/wx_util.cc index d20d755cf..28ac6ab5c 100644 --- a/src/wx/wx_util.cc +++ b/src/wx/wx_util.cc @@ -1,5 +1,5 @@ /* - Copyright (C) 2012-2020 Carl Hetherington + Copyright (C) 2012-2021 Carl Hetherington This file is part of DCP-o-matic. @@ -18,30 +18,37 @@ */ + /** @file src/wx/wx_util.cc * @brief Some utility functions and classes. */ -#include "wx_util.h" + #include "file_picker_ctrl.h" -#include "static_text.h" +#include "language_tag_widget.h" #include "password_entry.h" +#include "region_subtag_widget.h" +#include "static_text.h" +#include "wx_ptr.h" +#include "wx_util.h" #include "lib/config.h" -#include "lib/job_manager.h" -#include "lib/util.h" #include "lib/cross.h" #include "lib/job.h" -#include "lib/warnings.h" +#include "lib/job_manager.h" +#include "lib/util.h" +#include "lib/version.h" #include -DCPOMATIC_DISABLE_WARNINGS +#include +LIBDCP_DISABLE_WARNINGS #include #include #include #include #include -DCPOMATIC_ENABLE_WARNINGS +LIBDCP_ENABLE_WARNINGS #include + using std::string; using std::vector; using std::pair; @@ -50,6 +57,7 @@ using boost::optional; using dcp::locale_convert; using namespace dcpomatic; + wxStaticText * #ifdef __WXOSX__ create_label (wxWindow* p, wxString t, bool left) @@ -66,6 +74,7 @@ create_label (wxWindow* p, wxString t, bool) } +#ifdef __WXOSX__ static void setup_osx_flags (wxSizer* s, bool left, int& flags) @@ -77,9 +86,10 @@ setup_osx_flags (wxSizer* s, bool left, int& flags) } } } +#endif -/** Add a wxStaticText to a wxSizer, aligning it at vertical centre. +/** Add a wxStaticText to a wxSizer. * @param s Sizer to add to. * @param p Parent window for the wxStaticText. * @param t Text for the wxStaticText. @@ -94,10 +104,11 @@ add_label_to_sizer (wxSizer* s, wxWindow* p, wxString t, bool left, int prop, in setup_osx_flags (s, left, flags); #endif auto m = create_label (p, t, left); - s->Add (m, prop, flags, 6); + s->Add (m, prop, flags, DCPOMATIC_SIZER_GAP); return m; } + wxStaticText * #ifdef __WXOSX__ add_label_to_sizer (wxSizer* s, wxStaticText* t, bool left, int prop, int flags) @@ -108,22 +119,24 @@ add_label_to_sizer (wxSizer* s, wxStaticText* t, bool, int prop, int flags) #ifdef __WXOSX__ setup_osx_flags (s, left, flags); #endif - s->Add (t, prop, flags, 6); + s->Add (t, prop, flags, DCPOMATIC_SIZER_GAP); return t; } + wxStaticText * -add_label_to_sizer (wxGridBagSizer* s, wxWindow* p, wxString t, bool left, wxGBPosition pos, wxGBSpan span) +add_label_to_sizer(wxGridBagSizer* s, wxWindow* p, wxString t, bool left, wxGBPosition pos, wxGBSpan span, bool indent) { - int flags = wxALIGN_CENTER_VERTICAL | wxLEFT | wxRIGHT; + int flags = wxALIGN_CENTER_VERTICAL | wxLEFT; #ifdef __WXOSX__ setup_osx_flags (s, left, flags); #endif auto m = create_label (p, t, left); - s->Add (m, pos, span, flags); + s->Add(m, pos, span, flags, indent ? DCPOMATIC_SIZER_X_GAP : 0); return m; } + wxStaticText * #ifdef __WXOSX__ add_label_to_sizer (wxGridBagSizer* s, wxStaticText* t, bool left, wxGBPosition pos, wxGBSpan span) @@ -139,6 +152,7 @@ add_label_to_sizer (wxGridBagSizer* s, wxStaticText* t, bool, wxGBPosition pos, return t; } + /** Pop up an error dialogue box. * @param parent Parent. * @param m Message. @@ -147,16 +161,16 @@ add_label_to_sizer (wxGridBagSizer* s, wxStaticText* t, bool, wxGBPosition pos, void error_dialog (wxWindow* parent, wxString m, optional e) { - auto d = new wxMessageDialog (parent, m, _("DCP-o-matic"), wxOK | wxICON_ERROR); + auto d = make_wx(parent, m, _("DCP-o-matic"), wxOK | wxICON_ERROR); if (e) { wxString em = *e; em[0] = wxToupper (em[0]); d->SetExtendedMessage (em); } d->ShowModal (); - d->Destroy (); } + /** Pop up an error dialogue box. * @param parent Parent. * @param m Message. @@ -164,19 +178,17 @@ error_dialog (wxWindow* parent, wxString m, optional e) void message_dialog (wxWindow* parent, wxString m) { - auto d = new wxMessageDialog (parent, m, _("DCP-o-matic"), wxOK | wxICON_INFORMATION); + auto d = make_wx(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); - int const r = d->ShowModal (); - d->Destroy (); - return r == wxID_YES; + auto d = make_wx(parent, m, _("DCP-o-matic"), wxYES_NO | wxICON_QUESTION); + return d->ShowModal() == wxID_YES; } @@ -186,9 +198,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. */ @@ -198,26 +211,29 @@ 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) { - if (widget->GetPath() != std_to_wx (value.string())) { + if (widget->path() != value) { if (value.empty()) { /* Hack to make wxWidgets clear the control when we are passed an empty value. */ value = " "; } - widget->SetPath (std_to_wx (value.string())); + widget->set_path(value); } } + void checked_set (wxDirPickerCtrl* widget, boost::filesystem::path value) { @@ -232,6 +248,7 @@ checked_set (wxDirPickerCtrl* widget, boost::filesystem::path value) } } + void checked_set (wxSpinCtrl* widget, int value) { @@ -240,6 +257,7 @@ checked_set (wxSpinCtrl* widget, int value) } } + void checked_set (wxSpinCtrlDouble* widget, double value) { @@ -249,6 +267,7 @@ checked_set (wxSpinCtrlDouble* widget, double value) } } + void checked_set (wxChoice* widget, int value) { @@ -257,6 +276,7 @@ checked_set (wxChoice* widget, int value) } } + void checked_set (wxChoice* widget, string value) { @@ -274,15 +294,16 @@ checked_set (wxChoice* widget, string value) } } + void -checked_set (wxChoice* widget, vector > items) +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)), + widget->GetClientData() ? string_client_data(widget->GetClientObject(i)) : "" ) ); } @@ -297,6 +318,7 @@ checked_set (wxChoice* widget, vector > items) } } + void checked_set (wxTextCtrl* widget, string value) { @@ -305,6 +327,7 @@ checked_set (wxTextCtrl* widget, string value) } } + void checked_set (PasswordEntry* entry, string value) { @@ -313,6 +336,7 @@ checked_set (PasswordEntry* entry, string value) } } + void checked_set (wxTextCtrl* widget, wxString value) { @@ -321,6 +345,7 @@ checked_set (wxTextCtrl* widget, wxString value) } } + void checked_set (wxStaticText* widget, string value) { @@ -329,6 +354,7 @@ checked_set (wxStaticText* widget, string value) } } + void checked_set (wxStaticText* widget, wxString value) { @@ -337,6 +363,7 @@ checked_set (wxStaticText* widget, wxString value) } } + void checked_set (wxCheckBox* widget, bool value) { @@ -345,6 +372,7 @@ checked_set (wxCheckBox* widget, bool value) } } + void checked_set (wxRadioButton* widget, bool value) { @@ -353,6 +381,34 @@ checked_set (wxRadioButton* widget, bool value) } } + +void +checked_set(LanguageTagWidget* widget, dcp::LanguageTag value) +{ + if (widget->get() != value) { + widget->set(value); + } +} + + +void +checked_set(LanguageTagWidget* widget, optional value) +{ + if (widget->get() != value) { + widget->set(value); + } +} + + +void +checked_set(RegionSubtagWidget* widget, optional value) +{ + if (widget->get() != value) { + widget->set(value); + } +} + + void dcpomatic_setup_i18n () { @@ -387,8 +443,9 @@ dcpomatic_setup_i18n () locale->AddCatalog (wxT ("wxstd3")); #endif - locale->AddCatalog (wxT ("libdcpomatic2-wx")); - locale->AddCatalog (wxT ("dcpomatic2")); + locale->AddCatalog(wxT("wxstd")); + locale->AddCatalog(wxT("libdcpomatic2-wx")); + locale->AddCatalog(wxT("dcpomatic2")); if (!locale->IsOk()) { delete locale; @@ -401,24 +458,28 @@ 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. */ @@ -437,6 +498,7 @@ context_translation (wxString s) return t; } + wxString time_to_timecode (DCPTime t, double fps) { @@ -451,37 +513,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 * + +wxSplashScreen* maybe_show_splash () { wxSplashScreen* splash = nullptr; + try { wxBitmap bitmap; - if (bitmap.LoadFile(bitmap_path("splash"), wxBITMAP_TYPE_PNG)) { - splash = new wxSplashScreen (bitmap, wxSPLASH_CENTRE_ON_SCREEN | wxSPLASH_NO_TIMEOUT, 0, 0, -1); + if (bitmap.LoadFile(bitmap_path("splash.png"), 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, nullptr, -1, wxDefaultPosition, wxDefaultSize, wxBORDER_SIMPLE | wxFRAME_NO_TASKBAR); +#else + splash = new wxSplashScreen(bitmap, wxSPLASH_CENTRE_ON_SCREEN | wxSPLASH_NO_TIMEOUT, 0, nullptr, -1); +#endif wxYield (); } } catch (boost::filesystem::filesystem_error& e) { @@ -491,6 +569,7 @@ maybe_show_splash () return splash; } + double calculate_mark_interval (double mark_interval) { @@ -591,22 +670,97 @@ bitmap_path (string name) } else { base = resources_path(); } + + if (!boost::filesystem::exists(base / name)) { + base = path / boost::filesystem::path("osx/preferences"); + } #else base = resources_path(); #endif - boost::filesystem::path p = base / String::compose("%1.png", name); + auto p = base / name; return std_to_wx (p.string()); } +wxString +icon_path(string name) +{ + return gui_is_dark() ? bitmap_path(String::compose("%1_white.png", name)) : bitmap_path(String::compose("%1_black.png", name)); +} + + wxSize small_button_size (wxWindow* parent, wxString text) { wxClientDC dc (parent); auto size = dc.GetTextExtent (text); size.SetHeight (-1); - size.IncBy (24, 0); + size.IncBy (32, 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 + + + +int +search_ctrl_height () +{ +#ifdef __WXGTK3__ + return 30; +#else + return -1; +#endif +} + + +void +report_config_load_failure(wxWindow* parent, Config::LoadFailure what) +{ + switch (what) { + case Config::LoadFailure::CONFIG: + message_dialog(parent, _("The existing configuration failed to load. Default values will be used instead. These may take a short time to create.")); + break; + case Config::LoadFailure::CINEMAS: + message_dialog( + parent, + _(wxString::Format("The cinemas list for creating KDMs (cinemas.xml) failed to load. Please check the numbered backup files in %s", + std_to_wx(Config::instance()->cinemas_file().parent_path().string()))) + ); + break; + case Config::LoadFailure::DKDM_RECIPIENTS: + message_dialog( + parent, + _(wxString::Format("The recipients list for creating DKDMs (dkdm_recipients.xml) failed to load. Please check the numbered backup files in %s", + std_to_wx(Config::instance()->dkdm_recipients_file().parent_path().string()))) + ); + break; + } +} +