+/** Pop up an error dialogue box.
+ * @param parent Parent.
+ * @param m Message.
+ */
+void
+error_dialog (wxWindow* parent, wxString m)
+{
+ wxMessageDialog* d = new wxMessageDialog (parent, m, _("DVD-o-matic"), wxOK);
+ d->ShowModal ();
+ d->Destroy ();
+}
+
+bool
+confirm_dialog (wxWindow* parent, wxString m)
+{
+ wxMessageDialog* d = new wxMessageDialog (parent, m, _("DVD-o-matic"), wxYES_NO | wxICON_QUESTION);
+ int const r = d->ShowModal ();
+ d->Destroy ();
+ return r == wxID_YES;
+}
+
+
+/** @param s wxWidgets string.
+ * @return Corresponding STL string.
+ */
+string
+wx_to_std (wxString s)
+{
+ return string (s.mb_str ());
+}
+
+/** @param s STL string.
+ * @return Corresponding wxWidgets string.
+ */
+wxString
+std_to_wx (string s)
+{
+ return wxString (s.c_str(), wxConvUTF8);
+}
+
+int const ThreadedStaticText::_update_event_id = 10000;
+
+/** @param parent Parent for the wxStaticText.
+ * @param initial Initial text for the wxStaticText while the computation is being run.
+ * @param fn Function which works out what the wxStaticText content should be and returns it.
+ */
+ThreadedStaticText::ThreadedStaticText (wxWindow* parent, wxString initial, function<string ()> fn)
+ : wxStaticText (parent, wxID_ANY, initial)
+{
+ Connect (_update_event_id, wxEVT_COMMAND_TEXT_UPDATED, wxCommandEventHandler (ThreadedStaticText::thread_finished), 0, this);
+ _thread = new thread (bind (&ThreadedStaticText::run, this, fn));
+}
+
+ThreadedStaticText::~ThreadedStaticText ()
+{
+ _thread->interrupt ();
+ _thread->join ();
+ delete _thread;
+}
+
+/** Run our thread and post the result to the GUI thread via AddPendingEvent */
+void
+ThreadedStaticText::run (function<string ()> fn)
+{
+ wxCommandEvent ev (wxEVT_COMMAND_TEXT_UPDATED, _update_event_id);
+ ev.SetString (std_to_wx (fn ()));
+ GetEventHandler()->AddPendingEvent (ev);
+}
+
+/** Called in the GUI thread when our worker thread has finished */
+void
+ThreadedStaticText::thread_finished (wxCommandEvent& ev)
+{
+ SetLabel (ev.GetString ());
+}
+
+string
+string_client_data (wxClientData* o)
+{
+ return wx_to_std (dynamic_cast<wxStringClientData*>(o)->GetData());
+}
+
+void
+checked_set (wxFilePickerCtrl* widget, string value)
+{
+ if (widget->GetPath() != std_to_wx (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));
+ }
+}
+
+void
+checked_set (wxSpinCtrl* widget, int value)
+{
+ if (widget->GetValue() != value) {
+ widget->SetValue (value);
+ }
+}
+