Implement the hotkey page of the preferences dialog
Originally committed to SVN as r5794.
This commit is contained in:
parent
6c995e7780
commit
f48f17cd0b
13 changed files with 730 additions and 157 deletions
|
@ -1219,22 +1219,6 @@
|
|||
RelativePath="..\..\src\dialog_video_details.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\src\preferences.cpp"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\src\preferences.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\src\preferences_base.cpp"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\src\preferences_base.h"
|
||||
>
|
||||
</File>
|
||||
</Filter>
|
||||
<Filter
|
||||
Name="Core"
|
||||
|
@ -1944,6 +1928,34 @@
|
|||
>
|
||||
</File>
|
||||
</Filter>
|
||||
<Filter
|
||||
Name="Preferences"
|
||||
>
|
||||
<File
|
||||
RelativePath="..\..\src\hotkey_data_view_model.cpp"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\src\hotkey_data_view_model.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\src\preferences.cpp"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\src\preferences.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\src\preferences_base.cpp"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\src\preferences_base.h"
|
||||
>
|
||||
</File>
|
||||
</Filter>
|
||||
</Files>
|
||||
<Globals>
|
||||
</Globals>
|
||||
|
|
|
@ -145,6 +145,7 @@
|
|||
<ClInclude Include="$(SrcDir)gl_wrap.h" />
|
||||
<ClInclude Include="$(SrcDir)help_button.h" />
|
||||
<ClInclude Include="$(SrcDir)hotkeys.h" />
|
||||
<ClInclude Include="$(SrcDir)hotkey_data_view_model.h" />
|
||||
<ClInclude Include="$(SrcDir)kana_table.h" />
|
||||
<ClInclude Include="$(SrcDir)keyframe.h" />
|
||||
<ClInclude Include="$(SrcDir)main.h" />
|
||||
|
@ -332,6 +333,7 @@
|
|||
<ClCompile Include="$(SrcDir)gl_wrap.cpp" />
|
||||
<ClCompile Include="$(SrcDir)help_button.cpp" />
|
||||
<ClCompile Include="$(SrcDir)hotkey.cpp" />
|
||||
<ClCompile Include="$(SrcDir)hotkey_data_view_model.cpp" />
|
||||
<ClCompile Include="$(SrcDir)kana_table.cpp" />
|
||||
<ClCompile Include="$(SrcDir)main.cpp" />
|
||||
<ClCompile Include="$(SrcDir)MatroskaParser.c">
|
||||
|
|
|
@ -558,6 +558,9 @@
|
|||
<ClInclude Include="$(SrcDir)factory_manager.h">
|
||||
<Filter>Utilities</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="$(SrcDir)hotkey_data_view_model.h">
|
||||
<Filter>Preferences</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="$(SrcDir)hotkeys.h">
|
||||
<Filter>Main UI</Filter>
|
||||
</ClInclude>
|
||||
|
@ -1073,6 +1076,9 @@
|
|||
<ClCompile Include="$(SrcDir)compat.cpp">
|
||||
<Filter>Utilities</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="$(SrcDir)hotkey_data_view_model.cpp">
|
||||
<Filter>Preferences</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="$(SrcDir)hotkey.cpp">
|
||||
<Filter>Main UI</Filter>
|
||||
</ClCompile>
|
||||
|
|
|
@ -192,6 +192,7 @@ SRC += \
|
|||
gl_wrap.cpp \
|
||||
help_button.cpp \
|
||||
hotkey.cpp \
|
||||
hotkey_data_view_model.cpp \
|
||||
kana_table.cpp \
|
||||
main.cpp \
|
||||
menu.cpp \
|
||||
|
|
|
@ -115,6 +115,7 @@
|
|||
#include <wx/config.h>
|
||||
#include <wx/control.h>
|
||||
#include <wx/dataobj.h>
|
||||
#include <wx/dataview.h>
|
||||
#include <wx/datetime.h>
|
||||
#include <wx/dc.h>
|
||||
#include <wx/dcbuffer.h>
|
||||
|
@ -169,6 +170,7 @@
|
|||
#include <wx/regex.h>
|
||||
#include <wx/sashwin.h>
|
||||
#include <wx/scrolbar.h>
|
||||
#include <wx/srchctrl.h>
|
||||
#include <wx/settings.h>
|
||||
#include <wx/sizer.h>
|
||||
#include <wx/slider.h>
|
||||
|
|
|
@ -26,10 +26,23 @@
|
|||
|
||||
#include "libresrc/libresrc.h"
|
||||
#include "command/command.h"
|
||||
#include "compat.h"
|
||||
#include "main.h"
|
||||
#include "standard_paths.h"
|
||||
|
||||
namespace hotkey {
|
||||
|
||||
agi::hotkey::Hotkey *inst = 0;
|
||||
void init() {
|
||||
inst = new agi::hotkey::Hotkey(
|
||||
STD_STR(StandardPaths::DecodePath("?user/hotkey.json")),
|
||||
GET_DEFAULT_CONFIG(default_hotkey));
|
||||
}
|
||||
|
||||
void clear() {
|
||||
delete inst;
|
||||
}
|
||||
|
||||
static std::vector<std::string> keycode_names;
|
||||
|
||||
static std::string const& get_keycode_name(int code);
|
||||
|
@ -47,7 +60,7 @@ static std::string const& keycode_name(int code) {
|
|||
return keycode_names[code];
|
||||
}
|
||||
|
||||
bool check(std::string const& context, agi::Context *c, int key_code, wchar_t key_char, int modifier) {
|
||||
std::string keypress_to_str(int key_code, wchar_t key_char, int modifier) {
|
||||
std::string combo;
|
||||
if ((modifier != wxMOD_NONE)) {
|
||||
if ((modifier & wxMOD_CMD) != 0) combo.append("Ctrl-");
|
||||
|
@ -56,10 +69,16 @@ bool check(std::string const& context, agi::Context *c, int key_code, wchar_t ke
|
|||
}
|
||||
|
||||
combo += keycode_name(key_code);
|
||||
|
||||
return combo;
|
||||
}
|
||||
|
||||
bool check(std::string const& context, agi::Context *c, int key_code, wchar_t key_char, int modifier) {
|
||||
std::string combo = keypress_to_str(key_code, key_char, modifier);
|
||||
if (combo.empty()) return false;
|
||||
|
||||
std::string command;
|
||||
if (agi::hotkey::hotkey->Scan(context, combo, OPT_GET("Audio/Medusa Timing Hotkeys")->GetBool(), command)) {
|
||||
if (inst->Scan(context, combo, OPT_GET("Audio/Medusa Timing Hotkeys")->GetBool(), command)) {
|
||||
/// The bottom line should be removed after all the hotkey commands are fixed.
|
||||
/// This is to avoid pointless exceptions.
|
||||
if (command.find("/") != std::string::npos) {
|
||||
|
@ -71,14 +90,13 @@ bool check(std::string const& context, agi::Context *c, int key_code, wchar_t ke
|
|||
}
|
||||
|
||||
std::vector<std::string> get_hotkey_strs(std::string const& context, std::string const& command) {
|
||||
return agi::hotkey::hotkey->GetHotkeys(context, command);
|
||||
return inst->GetHotkeys(context, command);
|
||||
}
|
||||
|
||||
std::string get_hotkey_str_first(std::string const& context, std::string const& command) {
|
||||
return agi::hotkey::hotkey->GetHotkey(context, command);
|
||||
return inst->GetHotkey(context, command);
|
||||
}
|
||||
|
||||
|
||||
static inline void set_kc(std::vector<std::string> &vec, int code, std::string const& str) {
|
||||
if (static_cast<size_t>(code) >= vec.size()) vec.resize(code * 2, "");
|
||||
vec[code] = str;
|
||||
|
@ -176,6 +194,4 @@ static void init_keycode_names() {
|
|||
set_kc(keycode_names, WXK_NUMPAD_DIVIDE, "KP_Divide");
|
||||
}
|
||||
|
||||
|
||||
} // namespace hotkey
|
||||
|
||||
|
|
339
aegisub/src/hotkey_data_view_model.cpp
Normal file
339
aegisub/src/hotkey_data_view_model.cpp
Normal file
|
@ -0,0 +1,339 @@
|
|||
// Copyright (c) 2011, 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/
|
||||
//
|
||||
// $Id$
|
||||
|
||||
/// @file hotkey_data_view_model.cpp
|
||||
/// @see hotkey_data_view_model.h
|
||||
/// @ingroup hotkey configuration_ui
|
||||
///
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include "hotkey_data_view_model.h"
|
||||
|
||||
#include <libaegisub/exception.h>
|
||||
#include <libaegisub/hotkey.h>
|
||||
|
||||
#include "command/command.h"
|
||||
#include "command/icon.h"
|
||||
#include "compat.h"
|
||||
#include "include/aegisub/hotkey.h"
|
||||
#include "preferences.h"
|
||||
|
||||
#ifndef AGI_PRE
|
||||
#include <wx/dataview.h>
|
||||
#include <wx/regex.h>
|
||||
|
||||
#include <set>
|
||||
#endif
|
||||
|
||||
using namespace agi::hotkey;
|
||||
|
||||
/// @class HotkeyModelItem
|
||||
/// @brief A base class for things exposed by HotkeyDataViewModel
|
||||
class HotkeyModelItem {
|
||||
public:
|
||||
virtual unsigned int GetChildren(wxDataViewItemArray &children) const=0;
|
||||
virtual wxDataViewItem GetParent() const=0;
|
||||
virtual void GetValue(wxVariant &variant, unsigned int col) const=0;
|
||||
virtual bool IsContainer() const=0;
|
||||
virtual bool SetValue(wxVariant const& variant, unsigned int col)=0;
|
||||
};
|
||||
|
||||
class HotkeyModelRoot;
|
||||
class HotkeyModelCategory;
|
||||
|
||||
/// @class HotkeyModelCombo
|
||||
/// @brief A single hotkey exposed in the data view
|
||||
///
|
||||
/// All actual mutation of hotkeys happens through this class
|
||||
class HotkeyModelCombo : public HotkeyModelItem {
|
||||
HotkeyModelCategory *parent; ///< The containing category
|
||||
Combo combo; ///< The actual hotkey
|
||||
wxString cmd_name;
|
||||
wxString cmd_str;
|
||||
public:
|
||||
HotkeyModelCombo(HotkeyModelCategory *parent, Combo const& combo)
|
||||
: parent(parent)
|
||||
, combo(combo)
|
||||
, cmd_name(lagi_wxString(combo.CmdName()))
|
||||
, cmd_str(lagi_wxString(combo.Str()))
|
||||
{
|
||||
}
|
||||
|
||||
bool IsVisible(wxRegEx const& filter) const {
|
||||
return filter.Matches(cmd_name) || filter.Matches(cmd_str);
|
||||
}
|
||||
|
||||
void Apply(Hotkey::HotkeyMap *hk_map) {
|
||||
hk_map->insert(make_pair(combo.CmdName(), combo));
|
||||
}
|
||||
|
||||
unsigned int GetChildren(wxDataViewItemArray &children) const { return 0; }
|
||||
wxDataViewItem GetParent() const { return wxDataViewItem(parent); }
|
||||
bool IsContainer() const { return false; }
|
||||
|
||||
void GetValue(wxVariant &variant, unsigned int col) const {
|
||||
if (col == 0)
|
||||
variant = combo.Str();
|
||||
else if (col == 1) {
|
||||
wxIcon icon;
|
||||
icon.CopyFromBitmap(icon::get(combo.CmdName(), 16));
|
||||
variant << wxDataViewIconText(combo.CmdName(), icon);
|
||||
}
|
||||
else if (col == 2) {
|
||||
try {
|
||||
variant = cmd::get(combo.CmdName())->StrHelp();
|
||||
}
|
||||
catch (agi::Exception const& e) {
|
||||
variant = lagi_wxString(e.GetChainedMessage());
|
||||
}
|
||||
}
|
||||
else
|
||||
throw agi::InternalError("HotkeyDataViewModel asked for an invalid column number", 0);
|
||||
}
|
||||
|
||||
bool SetValue(wxVariant const& variant, unsigned int col) {
|
||||
if (col == 0) {
|
||||
wxArrayString toks = wxSplit(variant.GetString(), '-');
|
||||
std::vector<std::string> keys;
|
||||
keys.reserve(toks.size());
|
||||
for (size_t i = 0; i < toks.size(); ++i)
|
||||
keys[i] = STD_STR(toks[i]);
|
||||
combo = Combo(combo.Context(), combo.CmdName(), keys);
|
||||
cmd_str = combo.Str();
|
||||
return true;
|
||||
}
|
||||
else if (col == 1) {
|
||||
wxDataViewIconText text;
|
||||
text << variant;
|
||||
combo = Combo(combo.Context(), STD_STR(text.GetText()), combo.Get());
|
||||
cmd_name = text.GetText();
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
/// A hotkey context exposed in the data view
|
||||
class HotkeyModelCategory : public HotkeyModelItem {
|
||||
std::list<HotkeyModelCombo> children;
|
||||
wxDataViewModel *model;
|
||||
wxString name;
|
||||
wxDataViewItemArray visible_items;
|
||||
public:
|
||||
HotkeyModelCategory(wxDataViewModel *model, wxString const& name)
|
||||
: model(model)
|
||||
, name(name)
|
||||
{
|
||||
}
|
||||
|
||||
void AddChild(Combo const& combo) {
|
||||
children.push_back(HotkeyModelCombo(this, combo));
|
||||
visible_items.push_back(wxDataViewItem(&children.back()));
|
||||
model->ItemAdded(wxDataViewItem(this), wxDataViewItem(&children.back()));
|
||||
}
|
||||
|
||||
void Delete(wxDataViewItem const& item) {
|
||||
for (std::list<HotkeyModelCombo>::iterator it = children.begin(); it != children.end(); ++it) {
|
||||
if (&*it == item.GetID()) {
|
||||
model->ItemDeleted(wxDataViewItem(this), wxDataViewItem((void*)&*it));
|
||||
children.erase(it);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Apply(Hotkey::HotkeyMap *hk_map) {
|
||||
for_each(children.begin(), children.end(),
|
||||
bind(&HotkeyModelCombo::Apply, std::tr1::placeholders::_1, hk_map));
|
||||
}
|
||||
|
||||
void SetFilter(wxRegEx const& new_filter) {
|
||||
std::set<HotkeyModelCombo*> old_visible;
|
||||
for (size_t i = 0; i < visible_items.size(); ++i)
|
||||
old_visible.insert(static_cast<HotkeyModelCombo*>(visible_items[i].GetID()));
|
||||
|
||||
visible_items.clear();
|
||||
|
||||
wxDataViewItemArray added;
|
||||
wxDataViewItemArray removed;
|
||||
|
||||
for (std::list<HotkeyModelCombo>::iterator it = children.begin(); it != children.end(); ++it) {
|
||||
bool was_visible = old_visible.count(&*it) > 0;
|
||||
bool is_visible = it->IsVisible(new_filter);
|
||||
|
||||
if (is_visible)
|
||||
visible_items.push_back(wxDataViewItem(&*it));
|
||||
if (was_visible && !is_visible)
|
||||
removed.push_back(wxDataViewItem(&*it));
|
||||
if (is_visible && !was_visible)
|
||||
added.push_back(wxDataViewItem(&*it));
|
||||
}
|
||||
|
||||
if (!added.empty())
|
||||
model->ItemsAdded(wxDataViewItem(this), added);
|
||||
if (!removed.empty())
|
||||
model->ItemsDeleted(wxDataViewItem(this), removed);
|
||||
}
|
||||
|
||||
|
||||
wxDataViewItem GetParent() const { return wxDataViewItem(0); }
|
||||
bool IsContainer() const { return true; }
|
||||
bool SetValue(wxVariant const& variant, unsigned int col) { return false; }
|
||||
void GetValue(wxVariant &variant, unsigned int col) const {
|
||||
if (col == 1)
|
||||
variant << wxDataViewIconText(name);
|
||||
else
|
||||
variant = name;
|
||||
}
|
||||
|
||||
unsigned int GetChildren(wxDataViewItemArray &out) const {
|
||||
out = visible_items;
|
||||
return out.size();
|
||||
}
|
||||
};
|
||||
|
||||
/// The root containing the hotkey contexts
|
||||
class HotkeyModelRoot : public HotkeyModelItem {
|
||||
std::list<HotkeyModelCategory> categories;
|
||||
public:
|
||||
HotkeyModelRoot(wxDataViewModel *model) {
|
||||
Hotkey::HotkeyMap const& hk_map = hotkey::inst->GetHotkeyMap();
|
||||
std::map<std::string, HotkeyModelCategory*> cat_map;
|
||||
|
||||
for (Hotkey::HotkeyMap::const_iterator it = hk_map.begin(); it != hk_map.end(); ++it) {
|
||||
std::string cat_name = it->second.Context();
|
||||
HotkeyModelCategory *cat;
|
||||
std::map<std::string, HotkeyModelCategory*>::iterator cat_it = cat_map.find(cat_name);
|
||||
if (cat_it != cat_map.end())
|
||||
cat = cat_it->second;
|
||||
else {
|
||||
categories.push_back(HotkeyModelCategory(model, cat_name));
|
||||
cat = cat_map[cat_name] = &categories.back();
|
||||
}
|
||||
|
||||
cat->AddChild(it->second);
|
||||
}
|
||||
}
|
||||
|
||||
void Apply(Hotkey::HotkeyMap *hk_map) {
|
||||
for_each(categories.begin(), categories.end(),
|
||||
bind(&HotkeyModelCategory::Apply, std::tr1::placeholders::_1, hk_map));
|
||||
}
|
||||
|
||||
void SetFilter(wxString filter) {
|
||||
// Escape any regular-expression special characters
|
||||
static wxRegEx escape_meta("[-[\\]{}()*+?.,\\\\^$|#]", wxRE_ADVANCED);
|
||||
escape_meta.Replace(&filter, "\\\\&");
|
||||
|
||||
// Using wxRegEx for case-insensitive contains
|
||||
wxRegEx re(filter, wxRE_ADVANCED | wxRE_ICASE | wxRE_NOSUB);
|
||||
for_each(categories.begin(), categories.end(),
|
||||
bind(&HotkeyModelCategory::SetFilter, std::tr1::placeholders::_1, std::tr1::ref(re)));
|
||||
}
|
||||
|
||||
wxDataViewItem GetParent() const { return wxDataViewItem(0); }
|
||||
bool IsContainer() const { return true; }
|
||||
bool SetValue(wxVariant const& variant, unsigned int col) { return false; }
|
||||
void GetValue(wxVariant &variant, unsigned int col) const { }
|
||||
|
||||
unsigned int GetChildren(wxDataViewItemArray &out) const {
|
||||
out.reserve(categories.size());
|
||||
for (std::list<HotkeyModelCategory>::const_iterator it = categories.begin(); it != categories.end(); ++it)
|
||||
out.push_back(wxDataViewItem((void*)&*it));
|
||||
return out.size();
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
HotkeyDataViewModel::HotkeyDataViewModel(Preferences *parent)
|
||||
: root(new HotkeyModelRoot(this))
|
||||
, parent(parent)
|
||||
, has_pending_changes(false)
|
||||
{
|
||||
}
|
||||
|
||||
const HotkeyModelItem * HotkeyDataViewModel::get(wxDataViewItem const& item) const {
|
||||
if (item.IsOk())
|
||||
return static_cast<HotkeyModelItem*>(item.GetID());
|
||||
return root.get();
|
||||
}
|
||||
|
||||
HotkeyModelItem * HotkeyDataViewModel::get(wxDataViewItem const& item) {
|
||||
if (item.IsOk())
|
||||
return static_cast<HotkeyModelItem*>(item.GetID());
|
||||
return root.get();
|
||||
}
|
||||
|
||||
unsigned int HotkeyDataViewModel::GetChildren(wxDataViewItem const& item, wxDataViewItemArray &children) const {
|
||||
return get(item)->GetChildren(children);
|
||||
}
|
||||
|
||||
wxDataViewItem HotkeyDataViewModel::GetParent(wxDataViewItem const& item) const {
|
||||
return get(item)->GetParent();
|
||||
}
|
||||
|
||||
void HotkeyDataViewModel::GetValue(wxVariant &variant, wxDataViewItem const& item, unsigned int col) const {
|
||||
get(item)->GetValue(variant, col);
|
||||
}
|
||||
|
||||
bool HotkeyDataViewModel::IsContainer(wxDataViewItem const& item) const {
|
||||
return get(item)->IsContainer();
|
||||
}
|
||||
|
||||
bool HotkeyDataViewModel::SetValue(wxVariant const& variant, wxDataViewItem const& item, unsigned int col) {
|
||||
if (!has_pending_changes) {
|
||||
has_pending_changes = true;
|
||||
parent->AddPendingChange(std::tr1::bind(&HotkeyDataViewModel::Apply, this));
|
||||
}
|
||||
return get(item)->SetValue(variant, col);
|
||||
}
|
||||
|
||||
void HotkeyDataViewModel::New(wxDataViewItem item) {
|
||||
if (!item.IsOk()) return;
|
||||
|
||||
if (!IsContainer(item))
|
||||
item = GetParent(item);
|
||||
|
||||
HotkeyModelCategory *ctx = static_cast<HotkeyModelCategory*>(item.GetID());
|
||||
wxVariant name;
|
||||
ctx->GetValue(name, 0);
|
||||
ctx->AddChild(Combo(STD_STR(name.GetString()), "", std::vector<std::string>()));
|
||||
}
|
||||
|
||||
void HotkeyDataViewModel::Delete(wxDataViewItem const& item) {
|
||||
if (!item.IsOk() || IsContainer(item)) return;
|
||||
|
||||
static_cast<HotkeyModelCategory*>(GetParent(item).GetID())->Delete(item);
|
||||
|
||||
if (!has_pending_changes) {
|
||||
has_pending_changes = true;
|
||||
parent->AddPendingChange(std::tr1::bind(&HotkeyDataViewModel::Apply, this));
|
||||
}
|
||||
}
|
||||
|
||||
void HotkeyDataViewModel::Apply() {
|
||||
Hotkey::HotkeyMap hk_map;
|
||||
root->Apply(&hk_map);
|
||||
hotkey::inst->SetHotkeyMap(hk_map);
|
||||
has_pending_changes = false;
|
||||
}
|
||||
|
||||
void HotkeyDataViewModel::SetFilter(wxString const& filter) {
|
||||
root->SetFilter(filter);
|
||||
}
|
66
aegisub/src/hotkey_data_view_model.h
Normal file
66
aegisub/src/hotkey_data_view_model.h
Normal file
|
@ -0,0 +1,66 @@
|
|||
// Copyright (c) 2011, 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/
|
||||
//
|
||||
// $Id$
|
||||
|
||||
/// @file hotkey_data_view_model.h
|
||||
/// @see hotkey_data_view_model.cpp
|
||||
/// @ingroup hotkey configuration_ui
|
||||
///
|
||||
|
||||
#ifndef AGI_PRE
|
||||
#include <wx/dataview.h>
|
||||
#endif
|
||||
|
||||
#include <libaegisub/scoped_ptr.h>
|
||||
|
||||
class HotkeyModelItem;
|
||||
class HotkeyModelRoot;
|
||||
class Preferences;
|
||||
|
||||
/// @class HotkeyDataViewModel
|
||||
/// @brief A wxDataViewModel for hotkeys
|
||||
class HotkeyDataViewModel : public wxDataViewModel {
|
||||
agi::scoped_ptr<HotkeyModelRoot> root;
|
||||
Preferences *parent;
|
||||
bool has_pending_changes;
|
||||
|
||||
/// Get the real item from the wrapper, or root if it's wrapping NULL
|
||||
const HotkeyModelItem *get(wxDataViewItem const& item) const;
|
||||
/// Get the real item from the wrapper, or root if it's wrapping NULL
|
||||
HotkeyModelItem *get(wxDataViewItem const& item);
|
||||
public:
|
||||
HotkeyDataViewModel(Preferences *parent);
|
||||
|
||||
/// Create a new hotkey in the current context
|
||||
void New(wxDataViewItem item);
|
||||
/// Delete the currently selected hotkey
|
||||
void Delete(wxDataViewItem const& item);
|
||||
/// Update the hotkeys with changes made to the model
|
||||
void Apply();
|
||||
|
||||
/// Only display hotkeys containing filter, or all if filter is empty
|
||||
void SetFilter(wxString const& filter);
|
||||
|
||||
unsigned int GetColumnCount() const { return 3; }
|
||||
wxString GetColumnType(unsigned int) const { return "string"; }
|
||||
|
||||
unsigned int GetChildren(wxDataViewItem const& item, wxDataViewItemArray &children) const;
|
||||
wxDataViewItem GetParent(wxDataViewItem const& item) const;
|
||||
void GetValue(wxVariant &variant, wxDataViewItem const& item, unsigned int col) const;
|
||||
bool IsContainer(wxDataViewItem const& item) const;
|
||||
bool SetValue(wxVariant const& variant, wxDataViewItem const& item, unsigned int col);
|
||||
};
|
|
@ -23,12 +23,22 @@
|
|||
#include <vector>
|
||||
#endif
|
||||
|
||||
namespace agi { struct Context; }
|
||||
namespace agi {
|
||||
struct Context;
|
||||
namespace hotkey { class Hotkey; }
|
||||
}
|
||||
|
||||
namespace hotkey {
|
||||
|
||||
extern agi::hotkey::Hotkey *inst;
|
||||
|
||||
void init();
|
||||
void clear();
|
||||
|
||||
bool check(std::string const& context, agi::Context *c, int key_code, wchar_t key_char, int modifier);
|
||||
std::string keypress_to_str(int key_code, wchar_t key_char, int modifier);
|
||||
std::string get_hotkey_str_first(std::string const& context, std::string const& command);
|
||||
std::vector<std::string> get_hotkey_strs(std::string const& context, std::string const& command);
|
||||
|
||||
|
||||
} // namespace hotkey
|
||||
|
|
|
@ -28,6 +28,7 @@
|
|||
#include <wx/event.h>
|
||||
#include <wx/filefn.h>
|
||||
#include <wx/listctrl.h>
|
||||
#include <wx/srchctrl.h>
|
||||
#include <wx/sizer.h>
|
||||
#include <wx/spinctrl.h>
|
||||
#include <wx/stattext.h>
|
||||
|
@ -41,15 +42,53 @@
|
|||
#include "preferences.h"
|
||||
|
||||
#include "colour_button.h"
|
||||
#include "command/command.h"
|
||||
#include "compat.h"
|
||||
#include "hotkey_data_view_model.h"
|
||||
#include "include/aegisub/audio_player.h"
|
||||
#include "include/aegisub/audio_provider.h"
|
||||
#include "include/aegisub/hotkey.h"
|
||||
#include "include/aegisub/subtitles_provider.h"
|
||||
#include "libresrc/libresrc.h"
|
||||
#include "main.h"
|
||||
#include "preferences_base.h"
|
||||
#include "video_provider_manager.h"
|
||||
|
||||
#define CLASS_PAGE(name) \
|
||||
class name: public OptionPage { \
|
||||
public: \
|
||||
name(wxTreebook *book, Preferences *parent); \
|
||||
};
|
||||
|
||||
CLASS_PAGE(General)
|
||||
CLASS_PAGE(Subtitles)
|
||||
CLASS_PAGE(Audio)
|
||||
CLASS_PAGE(Video)
|
||||
CLASS_PAGE(Interface)
|
||||
CLASS_PAGE(Interface_Colours)
|
||||
CLASS_PAGE(Paths)
|
||||
CLASS_PAGE(File_Associations)
|
||||
CLASS_PAGE(Backup)
|
||||
CLASS_PAGE(Automation)
|
||||
CLASS_PAGE(Advanced)
|
||||
CLASS_PAGE(Advanced_Interface)
|
||||
CLASS_PAGE(Advanced_Audio)
|
||||
CLASS_PAGE(Advanced_Video)
|
||||
|
||||
class Interface_Hotkeys : public OptionPage {
|
||||
wxDataViewCtrl *dvc;
|
||||
wxObjectDataPtr<HotkeyDataViewModel> model;
|
||||
wxSearchCtrl *quick_search;
|
||||
|
||||
void OnNewButton(wxCommandEvent&);
|
||||
void OnEditButton(wxCommandEvent&);
|
||||
void OnDeleteButton(wxCommandEvent&);
|
||||
void OnUpdateFilter(wxCommandEvent&);
|
||||
void OnClearFilter(wxCommandEvent&);
|
||||
public:
|
||||
Interface_Hotkeys(wxTreebook *book, Preferences *parent);
|
||||
};
|
||||
|
||||
/// General preferences page
|
||||
General::General(wxTreebook *book, Preferences *parent): OptionPage(book, parent, _("General")) {
|
||||
|
||||
|
@ -213,28 +252,114 @@ Interface_Colours::Interface_Colours(wxTreebook *book, Preferences *parent): Opt
|
|||
SetSizerAndFit(sizer);
|
||||
}
|
||||
|
||||
/// wxDataViewIconTextRenderer with command name autocompletion
|
||||
class CommandRenderer : public wxDataViewIconTextRenderer {
|
||||
wxArrayString autocomplete;
|
||||
public:
|
||||
CommandRenderer()
|
||||
: wxDataViewIconTextRenderer("wxDataViewIconText", wxDATAVIEW_CELL_EDITABLE)
|
||||
{
|
||||
std::vector<std::string> cmd_names = cmd::get_registered_commands();
|
||||
autocomplete.reserve(cmd_names.size());
|
||||
copy(cmd_names.begin(), cmd_names.end(), std::back_inserter(autocomplete));
|
||||
}
|
||||
|
||||
wxWindow *CreateEditorCtrl(wxWindow *parent, wxRect label_rect, wxVariant const& value) {
|
||||
wxTextCtrl *ctrl = static_cast<wxTextCtrl*>(wxDataViewIconTextRenderer::CreateEditorCtrl(parent, label_rect, value));
|
||||
ctrl->AutoComplete(autocomplete);
|
||||
return ctrl;
|
||||
}
|
||||
};
|
||||
|
||||
class HotkeyRenderer : public wxDataViewTextRenderer {
|
||||
wxTextCtrl *ctrl;
|
||||
public:
|
||||
HotkeyRenderer() : wxDataViewTextRenderer("string", wxDATAVIEW_CELL_EDITABLE) { }
|
||||
|
||||
wxWindow *CreateEditorCtrl(wxWindow *parent, wxRect label_rect, wxVariant const& value) {
|
||||
ctrl = static_cast<wxTextCtrl*>(wxDataViewTextRenderer::CreateEditorCtrl(parent, label_rect, value));
|
||||
ctrl->Bind(wxEVT_KEY_DOWN, &HotkeyRenderer::OnKeyDown, this);
|
||||
return ctrl;
|
||||
}
|
||||
|
||||
void OnKeyDown(wxKeyEvent &evt) {
|
||||
ctrl->ChangeValue(lagi_wxString(hotkey::keypress_to_str(evt.GetKeyCode(), evt.GetUnicodeKey(), evt.GetModifiers())));
|
||||
}
|
||||
};
|
||||
|
||||
/// Interface Hotkeys preferences subpage
|
||||
Interface_Hotkeys::Interface_Hotkeys(wxTreebook *book, Preferences *parent): OptionPage(book, parent, _("Hotkeys"), PAGE_SUB) {
|
||||
wxFlexGridSizer *hotkeys = PageSizer(_("Hotkeys"));
|
||||
hotkeys->Add(new wxStaticText(this, wxID_ANY, _T("To be added after hotkey rewrite.")), 0, wxALL, 5);
|
||||
Interface_Hotkeys::Interface_Hotkeys(wxTreebook *book, Preferences *parent)
|
||||
: OptionPage(book, parent, _("Hotkeys"), PAGE_SUB)
|
||||
, model(new HotkeyDataViewModel(parent))
|
||||
{
|
||||
quick_search = new wxSearchCtrl(this, -1);
|
||||
wxButton *new_button = new wxButton(this, -1, _("New"));
|
||||
wxButton *edit_button = new wxButton(this, -1, _("Edit"));
|
||||
wxButton *delete_button = new wxButton(this, -1, _("Delete"));
|
||||
|
||||
new_button->Bind(wxEVT_COMMAND_BUTTON_CLICKED, &Interface_Hotkeys::OnNewButton, this);
|
||||
edit_button->Bind(wxEVT_COMMAND_BUTTON_CLICKED, &Interface_Hotkeys::OnEditButton, this);
|
||||
delete_button->Bind(wxEVT_COMMAND_BUTTON_CLICKED, &Interface_Hotkeys::OnDeleteButton, this);
|
||||
|
||||
quick_search->Bind(wxEVT_COMMAND_TEXT_UPDATED, &Interface_Hotkeys::OnUpdateFilter, this);
|
||||
quick_search->Bind(wxEVT_COMMAND_SEARCHCTRL_CANCEL_BTN, &Interface_Hotkeys::OnClearFilter, this);
|
||||
|
||||
dvc = new wxDataViewCtrl(this, -1);
|
||||
dvc->AssociateModel(model.get());
|
||||
dvc->AppendColumn(new wxDataViewColumn("Hotkey", new HotkeyRenderer, 0, 125, wxALIGN_LEFT, wxCOL_SORTABLE | wxCOL_RESIZABLE));
|
||||
dvc->AppendColumn(new wxDataViewColumn("Command", new CommandRenderer, 1, 250, wxALIGN_LEFT, wxCOL_SORTABLE | wxCOL_RESIZABLE));
|
||||
dvc->AppendTextColumn("Description", 2, wxDATAVIEW_CELL_INERT, 300, wxALIGN_LEFT, wxCOL_SORTABLE | wxCOL_RESIZABLE);
|
||||
|
||||
wxSizer *buttons = new wxBoxSizer(wxHORIZONTAL);
|
||||
buttons->Add(quick_search, wxSizerFlags().Border());
|
||||
buttons->AddStretchSpacer(1);
|
||||
buttons->Add(new_button, wxSizerFlags().Border().Right());
|
||||
buttons->Add(edit_button, wxSizerFlags().Border().Right());
|
||||
buttons->Add(delete_button, wxSizerFlags().Border().Right());
|
||||
|
||||
sizer->Add(buttons, wxSizerFlags().Expand());
|
||||
sizer->Add(dvc, wxSizerFlags(1).Expand().Border(wxLEFT | wxRIGHT));
|
||||
|
||||
SetSizerAndFit(sizer);
|
||||
}
|
||||
|
||||
void Interface_Hotkeys::OnNewButton(wxCommandEvent&) {
|
||||
model->New(dvc->GetSelection());
|
||||
}
|
||||
|
||||
/// Paths preferences page class Paths: public OptionPage { public:
|
||||
void Interface_Hotkeys::OnEditButton(wxCommandEvent&) {
|
||||
dvc->StartEditor(dvc->GetSelection(), 0);
|
||||
}
|
||||
|
||||
void Interface_Hotkeys::OnDeleteButton(wxCommandEvent&) {
|
||||
model->Delete(dvc->GetSelection());
|
||||
}
|
||||
|
||||
void Interface_Hotkeys::OnUpdateFilter(wxCommandEvent&) {
|
||||
model->SetFilter(quick_search->GetValue());
|
||||
|
||||
if (!quick_search->GetValue().empty()) {
|
||||
wxDataViewItemArray contexts;
|
||||
model->GetChildren(wxDataViewItem(0), contexts);
|
||||
for (size_t i = 0; i < contexts.size(); ++i)
|
||||
dvc->Expand(contexts[i]);
|
||||
}
|
||||
}
|
||||
|
||||
void Interface_Hotkeys::OnClearFilter(wxCommandEvent &evt) {
|
||||
quick_search->SetValue("");
|
||||
}
|
||||
|
||||
/// Paths preferences page
|
||||
Paths::Paths(wxTreebook *book, Preferences *parent): OptionPage(book, parent, _("Paths")) {
|
||||
|
||||
wxFlexGridSizer *general = PageSizer(_("General"));
|
||||
general->Add(new wxStaticText(this, wxID_ANY, "TBD..."), 0, wxALL, 5);
|
||||
|
||||
SetSizerAndFit(sizer);
|
||||
}
|
||||
|
||||
|
||||
/// File Associations preferences page
|
||||
File_Associations::File_Associations(wxTreebook *book, Preferences *parent): OptionPage(book, parent, _("File Associations")) {
|
||||
|
||||
wxFlexGridSizer *assoc = PageSizer(_("General"));
|
||||
assoc->Add(new wxStaticText(this, wxID_ANY, "TBD..."), 0, wxALL, 5);
|
||||
|
||||
|
@ -258,8 +383,6 @@ Backup::Backup(wxTreebook *book, Preferences *parent): OptionPage(book, parent,
|
|||
SetSizerAndFit(sizer);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/// Automation preferences page
|
||||
Automation::Automation(wxTreebook *book, Preferences *parent): OptionPage(book, parent, _("Automation")) {
|
||||
wxFlexGridSizer *general = PageSizer(_("General"));
|
||||
|
@ -372,3 +495,110 @@ Advanced_Video::Advanced_Video(wxTreebook *book, Preferences *parent): OptionPag
|
|||
|
||||
SetSizerAndFit(sizer);
|
||||
}
|
||||
|
||||
void Preferences::SetOption(std::string const& name, wxAny value) {
|
||||
pending_changes[name] = value;
|
||||
if (IsEnabled())
|
||||
applyButton->Enable(true);
|
||||
}
|
||||
|
||||
void Preferences::AddPendingChange(Thunk const& callback) {
|
||||
pending_callbacks.push_back(callback);
|
||||
if (IsEnabled())
|
||||
applyButton->Enable(true);
|
||||
}
|
||||
|
||||
void Preferences::OnOK(wxCommandEvent &event) {
|
||||
OnApply(event);
|
||||
EndModal(0);
|
||||
}
|
||||
|
||||
void Preferences::OnApply(wxCommandEvent &event) {
|
||||
for (std::map<std::string, wxAny>::iterator cur = pending_changes.begin(); cur != pending_changes.end(); ++cur) {
|
||||
agi::OptionValue *opt = OPT_SET(cur->first);
|
||||
switch (opt->GetType()) {
|
||||
case agi::OptionValue::Type_Bool:
|
||||
opt->SetBool(cur->second.As<bool>());
|
||||
break;
|
||||
case agi::OptionValue::Type_Colour:
|
||||
opt->SetColour(cur->second.As<agi::Colour>());
|
||||
break;
|
||||
case agi::OptionValue::Type_Double:
|
||||
opt->SetDouble(cur->second.As<double>());
|
||||
break;
|
||||
case agi::OptionValue::Type_Int:
|
||||
opt->SetInt(cur->second.As<int>());
|
||||
break;
|
||||
case agi::OptionValue::Type_String:
|
||||
opt->SetString(cur->second.As<std::string>());
|
||||
break;
|
||||
default:
|
||||
throw PreferenceNotSupported("Unsupported type");
|
||||
}
|
||||
}
|
||||
pending_changes.clear();
|
||||
|
||||
for (std::deque<Thunk>::iterator it = pending_callbacks.begin(); it != pending_callbacks.end(); ++it)
|
||||
(*it)();
|
||||
pending_callbacks.clear();
|
||||
|
||||
applyButton->Enable(false);
|
||||
config::opt->Flush();
|
||||
}
|
||||
|
||||
static void PageChanged(wxBookCtrlEvent& evt) {
|
||||
OPT_SET("Tool/Preferences/Page")->SetInt(evt.GetSelection());
|
||||
}
|
||||
|
||||
Preferences::Preferences(wxWindow *parent): wxDialog(parent, -1, _("Preferences"), wxDefaultPosition, wxSize(-1, 500)) {
|
||||
// SetIcon(BitmapToIcon(GETIMAGE(options_button_24)));
|
||||
|
||||
book = new wxTreebook(this, -1, wxDefaultPosition, wxDefaultSize);
|
||||
new General(book, this);
|
||||
new Subtitles(book, this);
|
||||
new Audio(book, this);
|
||||
new Video(book, this);
|
||||
new Interface(book, this);
|
||||
new Interface_Colours(book, this);
|
||||
new Interface_Hotkeys(book, this);
|
||||
new Paths(book, this);
|
||||
new File_Associations(book, this);
|
||||
new Backup(book, this);
|
||||
new Automation(book, this);
|
||||
new Advanced(book, this);
|
||||
new Advanced_Interface(book, this);
|
||||
new Advanced_Audio(book, this);
|
||||
new Advanced_Video(book, this);
|
||||
|
||||
book->Fit();
|
||||
|
||||
book->ChangeSelection(OPT_GET("Tool/Preferences/Page")->GetInt());
|
||||
book->Bind(wxEVT_COMMAND_TREEBOOK_PAGE_CHANGED, &PageChanged);
|
||||
|
||||
// Bottom Buttons
|
||||
wxStdDialogButtonSizer *stdButtonSizer = CreateStdDialogButtonSizer(wxOK | wxCANCEL | wxAPPLY);
|
||||
applyButton = stdButtonSizer->GetApplyButton();
|
||||
wxSizer *buttonSizer = new wxBoxSizer(wxHORIZONTAL);
|
||||
wxButton *defaultButton = new wxButton(this, -1, _("Restore Defaults"));
|
||||
buttonSizer->Add(defaultButton, wxSizerFlags(0).Expand());
|
||||
buttonSizer->AddStretchSpacer(1);
|
||||
buttonSizer->Add(stdButtonSizer, wxSizerFlags(0).Expand());
|
||||
|
||||
// Main Sizer
|
||||
wxSizer *mainSizer = new wxBoxSizer(wxVERTICAL);
|
||||
mainSizer->Add(book, wxSizerFlags(1).Expand().Border());
|
||||
mainSizer->Add(buttonSizer, wxSizerFlags(0).Expand().Border(wxALL & ~wxTOP));
|
||||
|
||||
SetSizerAndFit(mainSizer);
|
||||
SetMinSize(wxSize(-1, 500));
|
||||
SetMaxSize(wxSize(-1, 500));
|
||||
CenterOnParent();
|
||||
|
||||
applyButton->Enable(false);
|
||||
|
||||
Bind(wxEVT_COMMAND_BUTTON_CLICKED, &Preferences::OnOK, this, wxID_OK);
|
||||
Bind(wxEVT_COMMAND_BUTTON_CLICKED, &Preferences::OnApply, this, wxID_APPLY);
|
||||
}
|
||||
|
||||
Preferences::~Preferences() {
|
||||
}
|
||||
|
|
|
@ -20,20 +20,32 @@
|
|||
/// @ingroup configuration_ui
|
||||
|
||||
#ifndef AGI_PRE
|
||||
#include <deque>
|
||||
#include <tr1/functional>
|
||||
#include <map>
|
||||
|
||||
#include <wx/dialog.h>
|
||||
#endif
|
||||
|
||||
#include <libaegisub/exception.h>
|
||||
|
||||
class wxAny;
|
||||
class wxButton;
|
||||
class wxTreebook;
|
||||
|
||||
DEFINE_BASE_EXCEPTION_NOINNER(PreferencesError, agi::Exception)
|
||||
DEFINE_SIMPLE_EXCEPTION_NOINNER(PreferenceIncorrectType, PreferencesError, "preferences/incorrect_type")
|
||||
DEFINE_SIMPLE_EXCEPTION_NOINNER(PreferenceNotSupported, PreferencesError, "preferences/not_supported")
|
||||
|
||||
class Preferences: public wxDialog {
|
||||
public:
|
||||
typedef std::tr1::function<void ()> Thunk;
|
||||
private:
|
||||
wxTreebook *book;
|
||||
wxButton *applyButton;
|
||||
|
||||
std::map<std::string, wxAny> pending_changes;
|
||||
std::deque<Thunk> pending_callbacks;
|
||||
|
||||
void OnOK(wxCommandEvent &event);
|
||||
void OnCancel(wxCommandEvent &event);
|
||||
|
@ -44,4 +56,5 @@ public:
|
|||
~Preferences();
|
||||
|
||||
void SetOption(std::string const& name, wxAny value);
|
||||
void AddPendingChange(Thunk const& callback);
|
||||
};
|
||||
|
|
|
@ -36,8 +36,6 @@
|
|||
#include <wx/treebook.h>
|
||||
#endif
|
||||
|
||||
#include <libaegisub/exception.h>
|
||||
|
||||
#include "preferences_base.h"
|
||||
|
||||
#include "colour_button.h"
|
||||
|
@ -50,10 +48,6 @@
|
|||
#include "standard_paths.h"
|
||||
#include "video_provider_manager.h"
|
||||
|
||||
DEFINE_BASE_EXCEPTION_NOINNER(PreferencesError, agi::Exception)
|
||||
DEFINE_SIMPLE_EXCEPTION_NOINNER(PreferenceIncorrectType, PreferencesError, "preferences/incorrect_type")
|
||||
DEFINE_SIMPLE_EXCEPTION_NOINNER(PreferenceNotSupported, PreferencesError, "preferences/not_supported")
|
||||
|
||||
#define OPTION_UPDATER(type, evttype, body) \
|
||||
class type { \
|
||||
std::string name; \
|
||||
|
@ -254,99 +248,3 @@ void OptionPage::OptionFont(wxSizer *sizer, std::string opt_prefix) {
|
|||
Add(sizer, _("Font Face"), button_sizer);
|
||||
Add(sizer, _("Font Size"), font_size);
|
||||
}
|
||||
|
||||
void Preferences::SetOption(std::string const& name, wxAny value) {
|
||||
pending_changes[name] = value;
|
||||
if (IsEnabled())
|
||||
applyButton->Enable(true);
|
||||
}
|
||||
|
||||
void Preferences::OnOK(wxCommandEvent &event) {
|
||||
OnApply(event);
|
||||
EndModal(0);
|
||||
}
|
||||
|
||||
void Preferences::OnApply(wxCommandEvent &event) {
|
||||
for (std::map<std::string, wxAny>::iterator cur = pending_changes.begin(); cur != pending_changes.end(); ++cur) {
|
||||
agi::OptionValue *opt = OPT_SET(cur->first);
|
||||
switch (opt->GetType()) {
|
||||
case agi::OptionValue::Type_Bool:
|
||||
opt->SetBool(cur->second.As<bool>());
|
||||
break;
|
||||
case agi::OptionValue::Type_Colour:
|
||||
opt->SetColour(cur->second.As<agi::Colour>());
|
||||
break;
|
||||
case agi::OptionValue::Type_Double:
|
||||
opt->SetDouble(cur->second.As<double>());
|
||||
break;
|
||||
case agi::OptionValue::Type_Int:
|
||||
opt->SetInt(cur->second.As<int>());
|
||||
break;
|
||||
case agi::OptionValue::Type_String:
|
||||
opt->SetString(cur->second.As<std::string>());
|
||||
break;
|
||||
default:
|
||||
throw PreferenceNotSupported("Unsupported type");
|
||||
}
|
||||
}
|
||||
pending_changes.clear();
|
||||
applyButton->Enable(false);
|
||||
config::opt->Flush();
|
||||
}
|
||||
|
||||
static void PageChanged(wxBookCtrlEvent& evt) {
|
||||
OPT_SET("Tool/Preferences/Page")->SetInt(evt.GetSelection());
|
||||
}
|
||||
|
||||
Preferences::Preferences(wxWindow *parent): wxDialog(parent, -1, _("Preferences"), wxDefaultPosition, wxSize(-1, 500)) {
|
||||
// SetIcon(BitmapToIcon(GETIMAGE(options_button_24)));
|
||||
|
||||
book = new wxTreebook(this, -1, wxDefaultPosition, wxDefaultSize);
|
||||
new General(book, this);
|
||||
new Subtitles(book, this);
|
||||
new Audio(book, this);
|
||||
new Video(book, this);
|
||||
new Interface(book, this);
|
||||
new Interface_Colours(book, this);
|
||||
new Interface_Hotkeys(book, this);
|
||||
new Paths(book, this);
|
||||
new File_Associations(book, this);
|
||||
new Backup(book, this);
|
||||
new Automation(book, this);
|
||||
new Advanced(book, this);
|
||||
new Advanced_Interface(book, this);
|
||||
new Advanced_Audio(book, this);
|
||||
new Advanced_Video(book, this);
|
||||
|
||||
book->Fit();
|
||||
|
||||
book->ChangeSelection(OPT_GET("Tool/Preferences/Page")->GetInt());
|
||||
book->Bind(wxEVT_COMMAND_TREEBOOK_PAGE_CHANGED, &PageChanged);
|
||||
|
||||
// Bottom Buttons
|
||||
wxStdDialogButtonSizer *stdButtonSizer = CreateStdDialogButtonSizer(wxOK | wxCANCEL | wxAPPLY);
|
||||
applyButton = stdButtonSizer->GetApplyButton();
|
||||
wxSizer *buttonSizer = new wxBoxSizer(wxHORIZONTAL);
|
||||
wxButton *defaultButton = new wxButton(this, -1, _("Restore Defaults"));
|
||||
buttonSizer->Add(defaultButton, wxSizerFlags(0).Expand());
|
||||
buttonSizer->AddStretchSpacer(1);
|
||||
buttonSizer->Add(stdButtonSizer, wxSizerFlags(0).Expand());
|
||||
|
||||
// Main Sizer
|
||||
wxSizer *mainSizer = new wxBoxSizer(wxVERTICAL);
|
||||
mainSizer->Add(book, wxSizerFlags(1).Expand().Border());
|
||||
mainSizer->Add(buttonSizer, wxSizerFlags(0).Expand().Border(wxALL & ~wxTOP));
|
||||
|
||||
SetSizerAndFit(mainSizer);
|
||||
SetMinSize(wxSize(-1, 500));
|
||||
SetMaxSize(wxSize(-1, 500));
|
||||
CenterOnParent();
|
||||
|
||||
applyButton->Enable(false);
|
||||
|
||||
Bind(wxEVT_COMMAND_BUTTON_CLICKED, &Preferences::OnOK, this, wxID_OK);
|
||||
Bind(wxEVT_COMMAND_BUTTON_CLICKED, &Preferences::OnApply, this, wxID_APPLY);
|
||||
}
|
||||
|
||||
Preferences::~Preferences() {
|
||||
}
|
||||
|
|
|
@ -43,25 +43,3 @@ public:
|
|||
void OptionBrowse(wxFlexGridSizer *flex, const wxString &name, const char *opt_name);
|
||||
void OptionFont(wxSizer *sizer, std::string opt_prefix);
|
||||
};
|
||||
|
||||
#define CLASS_PAGE(name) \
|
||||
class name: public OptionPage { \
|
||||
public: \
|
||||
name(wxTreebook *book, Preferences *parent); \
|
||||
};
|
||||
|
||||
CLASS_PAGE(General)
|
||||
CLASS_PAGE(Subtitles)
|
||||
CLASS_PAGE(Audio)
|
||||
CLASS_PAGE(Video)
|
||||
CLASS_PAGE(Interface)
|
||||
CLASS_PAGE(Interface_Colours)
|
||||
CLASS_PAGE(Interface_Hotkeys)
|
||||
CLASS_PAGE(Paths)
|
||||
CLASS_PAGE(File_Associations)
|
||||
CLASS_PAGE(Backup)
|
||||
CLASS_PAGE(Automation)
|
||||
CLASS_PAGE(Advanced)
|
||||
CLASS_PAGE(Advanced_Interface)
|
||||
CLASS_PAGE(Advanced_Audio)
|
||||
CLASS_PAGE(Advanced_Video)
|
||||
|
|
Loading…
Reference in a new issue