mirror of https://github.com/odrling/Aegisub
Implement the hotkey page of the preferences dialog
Originally committed to SVN as r5794.
This commit is contained in:
parent
6c995e7780
commit
f48f17cd0b
|
@ -1219,22 +1219,6 @@
|
||||||
RelativePath="..\..\src\dialog_video_details.h"
|
RelativePath="..\..\src\dialog_video_details.h"
|
||||||
>
|
>
|
||||||
</File>
|
</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>
|
||||||
<Filter
|
<Filter
|
||||||
Name="Core"
|
Name="Core"
|
||||||
|
@ -1944,6 +1928,34 @@
|
||||||
>
|
>
|
||||||
</File>
|
</File>
|
||||||
</Filter>
|
</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>
|
</Files>
|
||||||
<Globals>
|
<Globals>
|
||||||
</Globals>
|
</Globals>
|
||||||
|
|
|
@ -145,6 +145,7 @@
|
||||||
<ClInclude Include="$(SrcDir)gl_wrap.h" />
|
<ClInclude Include="$(SrcDir)gl_wrap.h" />
|
||||||
<ClInclude Include="$(SrcDir)help_button.h" />
|
<ClInclude Include="$(SrcDir)help_button.h" />
|
||||||
<ClInclude Include="$(SrcDir)hotkeys.h" />
|
<ClInclude Include="$(SrcDir)hotkeys.h" />
|
||||||
|
<ClInclude Include="$(SrcDir)hotkey_data_view_model.h" />
|
||||||
<ClInclude Include="$(SrcDir)kana_table.h" />
|
<ClInclude Include="$(SrcDir)kana_table.h" />
|
||||||
<ClInclude Include="$(SrcDir)keyframe.h" />
|
<ClInclude Include="$(SrcDir)keyframe.h" />
|
||||||
<ClInclude Include="$(SrcDir)main.h" />
|
<ClInclude Include="$(SrcDir)main.h" />
|
||||||
|
@ -332,6 +333,7 @@
|
||||||
<ClCompile Include="$(SrcDir)gl_wrap.cpp" />
|
<ClCompile Include="$(SrcDir)gl_wrap.cpp" />
|
||||||
<ClCompile Include="$(SrcDir)help_button.cpp" />
|
<ClCompile Include="$(SrcDir)help_button.cpp" />
|
||||||
<ClCompile Include="$(SrcDir)hotkey.cpp" />
|
<ClCompile Include="$(SrcDir)hotkey.cpp" />
|
||||||
|
<ClCompile Include="$(SrcDir)hotkey_data_view_model.cpp" />
|
||||||
<ClCompile Include="$(SrcDir)kana_table.cpp" />
|
<ClCompile Include="$(SrcDir)kana_table.cpp" />
|
||||||
<ClCompile Include="$(SrcDir)main.cpp" />
|
<ClCompile Include="$(SrcDir)main.cpp" />
|
||||||
<ClCompile Include="$(SrcDir)MatroskaParser.c">
|
<ClCompile Include="$(SrcDir)MatroskaParser.c">
|
||||||
|
|
|
@ -558,6 +558,9 @@
|
||||||
<ClInclude Include="$(SrcDir)factory_manager.h">
|
<ClInclude Include="$(SrcDir)factory_manager.h">
|
||||||
<Filter>Utilities</Filter>
|
<Filter>Utilities</Filter>
|
||||||
</ClInclude>
|
</ClInclude>
|
||||||
|
<ClInclude Include="$(SrcDir)hotkey_data_view_model.h">
|
||||||
|
<Filter>Preferences</Filter>
|
||||||
|
</ClInclude>
|
||||||
<ClInclude Include="$(SrcDir)hotkeys.h">
|
<ClInclude Include="$(SrcDir)hotkeys.h">
|
||||||
<Filter>Main UI</Filter>
|
<Filter>Main UI</Filter>
|
||||||
</ClInclude>
|
</ClInclude>
|
||||||
|
@ -1073,6 +1076,9 @@
|
||||||
<ClCompile Include="$(SrcDir)compat.cpp">
|
<ClCompile Include="$(SrcDir)compat.cpp">
|
||||||
<Filter>Utilities</Filter>
|
<Filter>Utilities</Filter>
|
||||||
</ClCompile>
|
</ClCompile>
|
||||||
|
<ClCompile Include="$(SrcDir)hotkey_data_view_model.cpp">
|
||||||
|
<Filter>Preferences</Filter>
|
||||||
|
</ClCompile>
|
||||||
<ClCompile Include="$(SrcDir)hotkey.cpp">
|
<ClCompile Include="$(SrcDir)hotkey.cpp">
|
||||||
<Filter>Main UI</Filter>
|
<Filter>Main UI</Filter>
|
||||||
</ClCompile>
|
</ClCompile>
|
||||||
|
|
|
@ -192,6 +192,7 @@ SRC += \
|
||||||
gl_wrap.cpp \
|
gl_wrap.cpp \
|
||||||
help_button.cpp \
|
help_button.cpp \
|
||||||
hotkey.cpp \
|
hotkey.cpp \
|
||||||
|
hotkey_data_view_model.cpp \
|
||||||
kana_table.cpp \
|
kana_table.cpp \
|
||||||
main.cpp \
|
main.cpp \
|
||||||
menu.cpp \
|
menu.cpp \
|
||||||
|
|
|
@ -115,6 +115,7 @@
|
||||||
#include <wx/config.h>
|
#include <wx/config.h>
|
||||||
#include <wx/control.h>
|
#include <wx/control.h>
|
||||||
#include <wx/dataobj.h>
|
#include <wx/dataobj.h>
|
||||||
|
#include <wx/dataview.h>
|
||||||
#include <wx/datetime.h>
|
#include <wx/datetime.h>
|
||||||
#include <wx/dc.h>
|
#include <wx/dc.h>
|
||||||
#include <wx/dcbuffer.h>
|
#include <wx/dcbuffer.h>
|
||||||
|
@ -169,6 +170,7 @@
|
||||||
#include <wx/regex.h>
|
#include <wx/regex.h>
|
||||||
#include <wx/sashwin.h>
|
#include <wx/sashwin.h>
|
||||||
#include <wx/scrolbar.h>
|
#include <wx/scrolbar.h>
|
||||||
|
#include <wx/srchctrl.h>
|
||||||
#include <wx/settings.h>
|
#include <wx/settings.h>
|
||||||
#include <wx/sizer.h>
|
#include <wx/sizer.h>
|
||||||
#include <wx/slider.h>
|
#include <wx/slider.h>
|
||||||
|
|
|
@ -26,10 +26,23 @@
|
||||||
|
|
||||||
#include "libresrc/libresrc.h"
|
#include "libresrc/libresrc.h"
|
||||||
#include "command/command.h"
|
#include "command/command.h"
|
||||||
|
#include "compat.h"
|
||||||
#include "main.h"
|
#include "main.h"
|
||||||
|
#include "standard_paths.h"
|
||||||
|
|
||||||
namespace hotkey {
|
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::vector<std::string> keycode_names;
|
||||||
|
|
||||||
static std::string const& get_keycode_name(int code);
|
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];
|
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;
|
std::string combo;
|
||||||
if ((modifier != wxMOD_NONE)) {
|
if ((modifier != wxMOD_NONE)) {
|
||||||
if ((modifier & wxMOD_CMD) != 0) combo.append("Ctrl-");
|
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);
|
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;
|
if (combo.empty()) return false;
|
||||||
|
|
||||||
std::string command;
|
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.
|
/// The bottom line should be removed after all the hotkey commands are fixed.
|
||||||
/// This is to avoid pointless exceptions.
|
/// This is to avoid pointless exceptions.
|
||||||
if (command.find("/") != std::string::npos) {
|
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) {
|
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) {
|
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) {
|
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, "");
|
if (static_cast<size_t>(code) >= vec.size()) vec.resize(code * 2, "");
|
||||||
vec[code] = str;
|
vec[code] = str;
|
||||||
|
@ -176,6 +194,4 @@ static void init_keycode_names() {
|
||||||
set_kc(keycode_names, WXK_NUMPAD_DIVIDE, "KP_Divide");
|
set_kc(keycode_names, WXK_NUMPAD_DIVIDE, "KP_Divide");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
} // namespace hotkey
|
} // namespace hotkey
|
||||||
|
|
||||||
|
|
|
@ -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);
|
||||||
|
}
|
|
@ -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>
|
#include <vector>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
namespace agi { struct Context; }
|
namespace agi {
|
||||||
|
struct Context;
|
||||||
|
namespace hotkey { class Hotkey; }
|
||||||
|
}
|
||||||
|
|
||||||
namespace 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);
|
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::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);
|
std::vector<std::string> get_hotkey_strs(std::string const& context, std::string const& command);
|
||||||
|
|
||||||
|
|
||||||
} // namespace hotkey
|
} // namespace hotkey
|
||||||
|
|
|
@ -28,6 +28,7 @@
|
||||||
#include <wx/event.h>
|
#include <wx/event.h>
|
||||||
#include <wx/filefn.h>
|
#include <wx/filefn.h>
|
||||||
#include <wx/listctrl.h>
|
#include <wx/listctrl.h>
|
||||||
|
#include <wx/srchctrl.h>
|
||||||
#include <wx/sizer.h>
|
#include <wx/sizer.h>
|
||||||
#include <wx/spinctrl.h>
|
#include <wx/spinctrl.h>
|
||||||
#include <wx/stattext.h>
|
#include <wx/stattext.h>
|
||||||
|
@ -41,15 +42,53 @@
|
||||||
#include "preferences.h"
|
#include "preferences.h"
|
||||||
|
|
||||||
#include "colour_button.h"
|
#include "colour_button.h"
|
||||||
|
#include "command/command.h"
|
||||||
#include "compat.h"
|
#include "compat.h"
|
||||||
|
#include "hotkey_data_view_model.h"
|
||||||
#include "include/aegisub/audio_player.h"
|
#include "include/aegisub/audio_player.h"
|
||||||
#include "include/aegisub/audio_provider.h"
|
#include "include/aegisub/audio_provider.h"
|
||||||
|
#include "include/aegisub/hotkey.h"
|
||||||
#include "include/aegisub/subtitles_provider.h"
|
#include "include/aegisub/subtitles_provider.h"
|
||||||
#include "libresrc/libresrc.h"
|
#include "libresrc/libresrc.h"
|
||||||
#include "main.h"
|
#include "main.h"
|
||||||
#include "preferences_base.h"
|
#include "preferences_base.h"
|
||||||
#include "video_provider_manager.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 preferences page
|
||||||
General::General(wxTreebook *book, Preferences *parent): OptionPage(book, parent, _("General")) {
|
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);
|
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 preferences subpage
|
||||||
Interface_Hotkeys::Interface_Hotkeys(wxTreebook *book, Preferences *parent): OptionPage(book, parent, _("Hotkeys"), PAGE_SUB) {
|
Interface_Hotkeys::Interface_Hotkeys(wxTreebook *book, Preferences *parent)
|
||||||
wxFlexGridSizer *hotkeys = PageSizer(_("Hotkeys"));
|
: OptionPage(book, parent, _("Hotkeys"), PAGE_SUB)
|
||||||
hotkeys->Add(new wxStaticText(this, wxID_ANY, _T("To be added after hotkey rewrite.")), 0, wxALL, 5);
|
, 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);
|
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")) {
|
Paths::Paths(wxTreebook *book, Preferences *parent): OptionPage(book, parent, _("Paths")) {
|
||||||
|
|
||||||
wxFlexGridSizer *general = PageSizer(_("General"));
|
wxFlexGridSizer *general = PageSizer(_("General"));
|
||||||
general->Add(new wxStaticText(this, wxID_ANY, "TBD..."), 0, wxALL, 5);
|
general->Add(new wxStaticText(this, wxID_ANY, "TBD..."), 0, wxALL, 5);
|
||||||
|
|
||||||
SetSizerAndFit(sizer);
|
SetSizerAndFit(sizer);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/// File Associations preferences page
|
/// File Associations preferences page
|
||||||
File_Associations::File_Associations(wxTreebook *book, Preferences *parent): OptionPage(book, parent, _("File Associations")) {
|
File_Associations::File_Associations(wxTreebook *book, Preferences *parent): OptionPage(book, parent, _("File Associations")) {
|
||||||
|
|
||||||
wxFlexGridSizer *assoc = PageSizer(_("General"));
|
wxFlexGridSizer *assoc = PageSizer(_("General"));
|
||||||
assoc->Add(new wxStaticText(this, wxID_ANY, "TBD..."), 0, wxALL, 5);
|
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);
|
SetSizerAndFit(sizer);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/// Automation preferences page
|
/// Automation preferences page
|
||||||
Automation::Automation(wxTreebook *book, Preferences *parent): OptionPage(book, parent, _("Automation")) {
|
Automation::Automation(wxTreebook *book, Preferences *parent): OptionPage(book, parent, _("Automation")) {
|
||||||
wxFlexGridSizer *general = PageSizer(_("General"));
|
wxFlexGridSizer *general = PageSizer(_("General"));
|
||||||
|
@ -372,3 +495,110 @@ Advanced_Video::Advanced_Video(wxTreebook *book, Preferences *parent): OptionPag
|
||||||
|
|
||||||
SetSizerAndFit(sizer);
|
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
|
/// @ingroup configuration_ui
|
||||||
|
|
||||||
#ifndef AGI_PRE
|
#ifndef AGI_PRE
|
||||||
|
#include <deque>
|
||||||
|
#include <tr1/functional>
|
||||||
#include <map>
|
#include <map>
|
||||||
|
|
||||||
#include <wx/dialog.h>
|
#include <wx/dialog.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#include <libaegisub/exception.h>
|
||||||
|
|
||||||
class wxAny;
|
class wxAny;
|
||||||
class wxButton;
|
class wxButton;
|
||||||
class wxTreebook;
|
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 {
|
class Preferences: public wxDialog {
|
||||||
|
public:
|
||||||
|
typedef std::tr1::function<void ()> Thunk;
|
||||||
|
private:
|
||||||
wxTreebook *book;
|
wxTreebook *book;
|
||||||
wxButton *applyButton;
|
wxButton *applyButton;
|
||||||
|
|
||||||
std::map<std::string, wxAny> pending_changes;
|
std::map<std::string, wxAny> pending_changes;
|
||||||
|
std::deque<Thunk> pending_callbacks;
|
||||||
|
|
||||||
void OnOK(wxCommandEvent &event);
|
void OnOK(wxCommandEvent &event);
|
||||||
void OnCancel(wxCommandEvent &event);
|
void OnCancel(wxCommandEvent &event);
|
||||||
|
@ -44,4 +56,5 @@ public:
|
||||||
~Preferences();
|
~Preferences();
|
||||||
|
|
||||||
void SetOption(std::string const& name, wxAny value);
|
void SetOption(std::string const& name, wxAny value);
|
||||||
|
void AddPendingChange(Thunk const& callback);
|
||||||
};
|
};
|
||||||
|
|
|
@ -36,8 +36,6 @@
|
||||||
#include <wx/treebook.h>
|
#include <wx/treebook.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#include <libaegisub/exception.h>
|
|
||||||
|
|
||||||
#include "preferences_base.h"
|
#include "preferences_base.h"
|
||||||
|
|
||||||
#include "colour_button.h"
|
#include "colour_button.h"
|
||||||
|
@ -50,10 +48,6 @@
|
||||||
#include "standard_paths.h"
|
#include "standard_paths.h"
|
||||||
#include "video_provider_manager.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) \
|
#define OPTION_UPDATER(type, evttype, body) \
|
||||||
class type { \
|
class type { \
|
||||||
std::string name; \
|
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 Face"), button_sizer);
|
||||||
Add(sizer, _("Font Size"), font_size);
|
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 OptionBrowse(wxFlexGridSizer *flex, const wxString &name, const char *opt_name);
|
||||||
void OptionFont(wxSizer *sizer, std::string opt_prefix);
|
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 New Issue