forked from mia/Aegisub
e924db1fda
Even if every dialog in the program was open at once, linearly searching a vector is quite fast enough.
117 lines
3.8 KiB
C++
117 lines
3.8 KiB
C++
// Copyright (c) 2012, Thomas Goyne <plorkyeran@aegisub.org>
|
|
//
|
|
// Permission to use, copy, modify, and distribute this software for any
|
|
// purpose with or without fee is hereby granted, provided that the above
|
|
// copyright notice and this permission notice appear in all copies.
|
|
//
|
|
// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
|
// WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
|
// MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
|
// ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
|
// WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
|
// ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
|
// OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
|
//
|
|
// Aegisub Project http://www.aegisub.org/
|
|
|
|
#include "utils.h"
|
|
|
|
#include <libaegisub/exception.h>
|
|
|
|
#include <vector>
|
|
#include <typeinfo>
|
|
#include <wx/dialog.h>
|
|
|
|
namespace agi { struct Context; }
|
|
|
|
/// @brief A manager for dialogs
|
|
///
|
|
/// DialogManager keeps track of modal and modeless dialogs which have been
|
|
/// created, so that commands can be send to the appropriate places and so that
|
|
/// the same dialog can't be opened twice at once.
|
|
class DialogManager {
|
|
using dialog_pair = std::pair<const std::type_info *, wxDialog *>;
|
|
/// Dialogs which currently exist
|
|
std::vector<dialog_pair> created_dialogs;
|
|
|
|
/// Close handler which deletes and unregisters closed modeless dialogs
|
|
template<typename Event>
|
|
void OnClose(Event &evt) {
|
|
evt.Skip();
|
|
auto dialog = static_cast<wxWindow *>(evt.GetEventObject());
|
|
while (!dialog->IsTopLevel()) dialog = dialog->GetParent();
|
|
dialog->Destroy();
|
|
|
|
for (auto it = created_dialogs.begin(); it != created_dialogs.end(); ++it) {
|
|
if (it->second == dialog) {
|
|
created_dialogs.erase(it);
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
|
|
template<typename T>
|
|
std::vector<dialog_pair>::iterator Find() {
|
|
for (auto it = begin(created_dialogs); it != end(created_dialogs); ++it) {
|
|
if (*it->first == typeid(T))
|
|
return it;
|
|
}
|
|
return end(created_dialogs);
|
|
}
|
|
|
|
public:
|
|
/// Show a modeless dialog of the given type, creating it if needed
|
|
/// @tparam DialogType Type of dialog to show
|
|
template<class DialogType>
|
|
void Show(agi::Context *c) {
|
|
for (auto const& diag : created_dialogs) {
|
|
if (*diag.first == typeid(DialogType)) {
|
|
diag.second->Show();
|
|
diag.second->SetFocus();
|
|
}
|
|
}
|
|
|
|
try {
|
|
wxDialog *d = new DialogType(c);
|
|
created_dialogs.emplace_back(&typeid(DialogType), d);
|
|
d->Bind(wxEVT_CLOSE_WINDOW, &DialogManager::OnClose<wxCloseEvent>, this);
|
|
d->Bind(wxEVT_BUTTON, &DialogManager::OnClose<wxCommandEvent>, this, wxID_CANCEL);
|
|
d->Show();
|
|
SetFloatOnParent(d);
|
|
}
|
|
catch (agi::UserCancelException const&) { }
|
|
}
|
|
|
|
/// Show a modal dialog of the given type, creating it if needed
|
|
/// @tparam DialogType Type of dialog to show
|
|
template<class DialogType>
|
|
void ShowModal(agi::Context *c) {
|
|
DialogType diag(c);
|
|
created_dialogs.emplace_back(&typeid(DialogType), &diag);
|
|
try {
|
|
diag.ShowModal();
|
|
}
|
|
catch (...) {
|
|
created_dialogs.erase(Find<DialogType>());
|
|
throw;
|
|
}
|
|
created_dialogs.erase(Find<DialogType>());
|
|
}
|
|
|
|
/// Get the dialog of the given type
|
|
/// @tparam DialogType Type of dialog to get
|
|
/// @return A pointer to a DialogType or nullptr if no dialog of the given type has been created
|
|
template<class DialogType>
|
|
DialogType *Get() const {
|
|
auto it = const_cast<DialogManager *>(this)->Find<DialogType>();
|
|
return it != created_dialogs.end() ? static_cast<DialogType*>(it->second) : nullptr;
|
|
}
|
|
|
|
~DialogManager() {
|
|
for (auto const& it : created_dialogs) {
|
|
it.second->Unbind(wxEVT_CLOSE_WINDOW, &DialogManager::OnClose<wxCloseEvent>, this);
|
|
it.second->Unbind(wxEVT_BUTTON, &DialogManager::OnClose<wxCommandEvent>, this, wxID_CANCEL);
|
|
it.second->Destroy();
|
|
}
|
|
}
|
|
};
|