diff --git a/aegisub/Makefile.am b/aegisub/Makefile.am index 5c400f5a9..59c9ca837 100644 --- a/aegisub/Makefile.am +++ b/aegisub/Makefile.am @@ -14,6 +14,7 @@ ffmpegsource = libffms endif SUBDIRS = \ + libaegisub \ $(ffmpegsource) \ $(libass) \ $(univchardet) \ diff --git a/aegisub/build/aegisub_vs2008/aegisub_vs2008.vcproj b/aegisub/build/aegisub_vs2008/aegisub_vs2008.vcproj index ec670775a..b610ce8c7 100644 --- a/aegisub/build/aegisub_vs2008/aegisub_vs2008.vcproj +++ b/aegisub/build/aegisub_vs2008/aegisub_vs2008.vcproj @@ -22,7 +22,7 @@ @@ -223,7 +223,7 @@ @@ -1103,14 +1103,6 @@ RelativePath="..\..\src\dialog_kara_timing_copy.h" > - - - - @@ -1255,10 +1247,62 @@ RelativePath="..\..\src\dialog_video_details.h" > + + + + + + + + + + + + + + + + + + + + + + @@ -1307,46 +1351,6 @@ RelativePath="..\..\src\setup.cpp" > - - - - - - - - - - - - - - - - diff --git a/aegisub/build/aegisub_vs2008/libaegisub_include_dir.vsprops b/aegisub/build/aegisub_vs2008/libaegisub_include_dir.vsprops new file mode 100644 index 000000000..04bbc734c --- /dev/null +++ b/aegisub/build/aegisub_vs2008/libaegisub_include_dir.vsprops @@ -0,0 +1,11 @@ + + + + diff --git a/aegisub/build/libaegisub_vs2008/compiler_options.vsprops b/aegisub/build/libaegisub_vs2008/compiler_options.vsprops new file mode 100644 index 000000000..da57a9c7a --- /dev/null +++ b/aegisub/build/libaegisub_vs2008/compiler_options.vsprops @@ -0,0 +1,26 @@ + + + + + diff --git a/aegisub/build/libaegisub_vs2008/compiler_options_debug.vsprops b/aegisub/build/libaegisub_vs2008/compiler_options_debug.vsprops new file mode 100644 index 000000000..fe1663f67 --- /dev/null +++ b/aegisub/build/libaegisub_vs2008/compiler_options_debug.vsprops @@ -0,0 +1,26 @@ + + + + + diff --git a/aegisub/build/libaegisub_vs2008/libaegisub_vs2008.vcproj b/aegisub/build/libaegisub_vs2008/libaegisub_vs2008.vcproj new file mode 100644 index 000000000..083430e21 --- /dev/null +++ b/aegisub/build/libaegisub_vs2008/libaegisub_vs2008.vcproj @@ -0,0 +1,226 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/aegisub/build/libaegisub_vs2008/libraries_outdirs.vsprops b/aegisub/build/libaegisub_vs2008/libraries_outdirs.vsprops new file mode 100644 index 000000000..f012a6c1f --- /dev/null +++ b/aegisub/build/libaegisub_vs2008/libraries_outdirs.vsprops @@ -0,0 +1,27 @@ + + + + + + + diff --git a/aegisub/build/libaegisub_vs2008/precomp_header.vsprops b/aegisub/build/libaegisub_vs2008/precomp_header.vsprops new file mode 100644 index 000000000..5da6833a5 --- /dev/null +++ b/aegisub/build/libaegisub_vs2008/precomp_header.vsprops @@ -0,0 +1,13 @@ + + + + diff --git a/aegisub/build/libaegisub_vs2008/src_msvc_include_dir.vsprops b/aegisub/build/libaegisub_vs2008/src_msvc_include_dir.vsprops new file mode 100644 index 000000000..adc9c6cd6 --- /dev/null +++ b/aegisub/build/libaegisub_vs2008/src_msvc_include_dir.vsprops @@ -0,0 +1,11 @@ + + + + diff --git a/aegisub/build/libaegisub_vs2008/wxlib_include.vsprops b/aegisub/build/libaegisub_vs2008/wxlib_include.vsprops new file mode 100644 index 000000000..5029d0eae --- /dev/null +++ b/aegisub/build/libaegisub_vs2008/wxlib_include.vsprops @@ -0,0 +1,15 @@ + + + + + diff --git a/aegisub/configure.in b/aegisub/configure.in index a164b575c..0036a4808 100644 --- a/aegisub/configure.in +++ b/aegisub/configure.in @@ -1204,6 +1204,7 @@ AC_CONFIG_FILES([ Makefile automation/Makefile desktop/Makefile +libaegisub/Makefile libass/Makefile libffms/Makefile po/Makefile.in @@ -1214,6 +1215,7 @@ src/libosxutil/Makefile src/libresrc/Makefile tools/Makefile universalchardet/Makefile +tests/Makefile ]) # Files that need substitution. diff --git a/aegisub/docs/doxygen/doxyfile_libaegisub b/aegisub/docs/doxygen/doxyfile_libaegisub new file mode 100644 index 000000000..cc97d8124 --- /dev/null +++ b/aegisub/docs/doxygen/doxyfile_libaegisub @@ -0,0 +1,12 @@ +@INCLUDE = doxyfile_base + +PROJECT_NAME = "libaegisub" + +INPUT = ../../libaegisub/ ./pages_libaegisub + +EXCLUDE_PATTERNS = */.svn* */.deps* */.libs* + +PREDEFINED += \ + __WINDOWS__ \ + __UNIX__ \ + __OSX__ diff --git a/aegisub/docs/doxygen/gen.sh b/aegisub/docs/doxygen/gen.sh index dc84baadb..a980b4e09 100755 --- a/aegisub/docs/doxygen/gen.sh +++ b/aegisub/docs/doxygen/gen.sh @@ -17,6 +17,9 @@ case "$1" in "reporter") TRIM="${SRC_PWD}/reporter/" ;; + "libaegisub") + TRIM="${SRC_PWD}/libaegisub/" + ;; esac export OUTPUT_DIR="$2" diff --git a/aegisub/docs/doxygen/pages_libaegisub/groups.dox b/aegisub/docs/doxygen/pages_libaegisub/groups.dox new file mode 100644 index 000000000..13172d4be --- /dev/null +++ b/aegisub/docs/doxygen/pages_libaegisub/groups.dox @@ -0,0 +1,7 @@ +/** +@defgroup base Base +@defgroup unix Unix +@defgroup windows Windows +@defgroup osx OS X +@defgroup io File I/O +*/ diff --git a/aegisub/docs/doxygen/pages_libaegisub/index.dox b/aegisub/docs/doxygen/pages_libaegisub/index.dox new file mode 100644 index 000000000..c47304e82 --- /dev/null +++ b/aegisub/docs/doxygen/pages_libaegisub/index.dox @@ -0,0 +1,11 @@ +/** @mainpage + +Main + - @ref base + +Library + - @ref unix + - @ref windows + - @ref osx + - @ref io +*/ diff --git a/aegisub/docs/doxygen/pages_libaegisub/license.dox b/aegisub/docs/doxygen/pages_libaegisub/license.dox new file mode 100644 index 000000000..903d32cb6 --- /dev/null +++ b/aegisub/docs/doxygen/pages_libaegisub/license.dox @@ -0,0 +1,5 @@ +/** @page License libaegisub License + +@verbinclude "LICENCE" + +*/ diff --git a/aegisub/libaegisub/Makefile.am b/aegisub/libaegisub/Makefile.am new file mode 100644 index 000000000..af8c1cb15 --- /dev/null +++ b/aegisub/libaegisub/Makefile.am @@ -0,0 +1,32 @@ +# $Id$ +AUTOMAKE_OPTIONS = subdir-objects +AM_CXXFLAGS= +DISTCLEANFILES= + +lib_LTLIBRARIES = libaegisub-2.2.la +libaegisub_2_2_la_CPPFLAGS = -I../src/include -Iinclude -I. @WX_CPPFLAGS@ + +if PRECOMPILED_HEADER +BUILT_SOURCES = lagi_pre.h.gch +AM_CXXFLAGS += -include lagi_pre.h -Winvalid-pch -fpch-deps -fpch-preprocess +nodist_libaegisub_2_2_la_SOURCES = lagi_pre.h.gch +endif + +if PRECOMPILED_HEADER +# This doesn't depend on Makefile on purpose, you should already know what you're doing when using this. +lagi_pre.h.gch: lagi_pre.h + @CXX@ $(libaegisub_2_2_la_CPPFLAGS) @CXXFLAGS@ @DEBUG_FLAGS@ -fPIC -DPIC lagi_pre.h +DISTCLEANFILES += lagi_pre.h.gch +endif + +libaegisub_2_2_la_SOURCES = \ + common/mru.cpp \ + common/option.cpp \ + common/option_visit.cpp \ + common/validator.cpp \ + unix/util.cpp \ + unix/io.cpp \ + unix/access.cpp + +noinst_HEADERS = *.h + diff --git a/aegisub/libaegisub/common/mru.cpp b/aegisub/libaegisub/common/mru.cpp new file mode 100644 index 000000000..6cbe9e739 --- /dev/null +++ b/aegisub/libaegisub/common/mru.cpp @@ -0,0 +1,203 @@ +// Copyright (c) 2010, Amar Takhar +// +// 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. +// +// $Id$ + +/// @file mru.cpp +/// @brief Most Recently Used (MRU) Lists +/// @ingroup libaegisub + +#ifndef LAGI_PRE +#include +#include +#endif + +#include "libaegisub/access.h" +#include "libaegisub/mru.h" +#include "libaegisub/io.h" + +namespace agi { + +MRUManager::MRUManager(const std::string &config, const std::string &default_config): config_name(config) { + + json::UnknownElement root; + std::istream *stream; + + try { + stream = io::Open(config); + } catch (const acs::AcsNotFound&) { + stream = new std::istringstream(default_config); + } + + try { + json::Reader::Read(root, *stream); + } catch (const json::Exception&) { + /// @todo Do something better here, maybe print the exact error +// std::cout << "json::Exception: " << e.what() << std::endl; + + stream = new std::istringstream(default_config); + json::Reader::Read(root, *stream); + } + + const json::Object& root_new = (json::Object)root; + + json::Object::const_iterator index_object(root_new.Begin()), index_objectEnd(root_new.End()); + + for (; index_object != index_objectEnd; ++index_object) { + const json::Object::Member& member = *index_object; + const std::string &member_name = member.name; + const json::UnknownElement& element = member.element; + + Load(member_name, (json::Array)element); + } + + delete stream; +} + + +MRUManager::~MRUManager() { + Flush(); +} + + +void MRUManager::Add(const std::string &key, const std::string &entry) { + + MRUMap::iterator index; + + if ((index = mru.find(key)) != mru.end()) { + MRUListMap &map = *index->second; + + // Remove the file before adding it. + Remove(key, entry); + + map.insert(std::pair(time(NULL), entry)); + + Prune(map); + + } else { + throw MRUErrorInvalidKey("Invalid key value"); + } +} + + +void MRUManager::Remove(const std::string &key, const std::string &entry) { + + MRUMap::iterator index; + + if ((index = mru.find(key)) != mru.end()) { + MRUListMap map = *index->second; + for (MRUListMap::iterator map_idx = map.begin(); map_idx != map.end();) { + if (map_idx->second == entry) + map.erase(map_idx++); + else + ++map_idx; + } + } else { + throw MRUErrorInvalidKey("Invalid key value"); + } + +} + + +const MRUManager::MRUListMap* MRUManager::Get(const std::string &key) { + + MRUMap::iterator index; + + if ((index = mru.find(key)) != mru.end()) { + return index->second; + } else { + throw MRUErrorInvalidKey("Invalid key value"); + } +} + + +const std::string MRUManager::GetEntry(const std::string &key, const int entry) { + + const MRUManager::MRUListMap *map = Get(key); + + MRUListMap::const_iterator index = map->begin();; + + if ((unsigned int)entry > map->size()) + throw MRUErrorIndexOutOfRange("Requested element index is out of range."); + + std::advance(index, entry); + + return index->second; +} + + +void MRUManager::Flush() { + + json::Object out; + + for (MRUMap::const_iterator i = mru.begin(); i != mru.end(); ++i) { + json::Array array; + MRUListMap *map_list = i->second; + + for (MRUListMap::const_iterator i_lst = map_list->begin(); i_lst != map_list->end(); ++i_lst) { + json::Object obj; + obj["time"] = json::Number((double)i_lst->first); + obj["entry"] = json::String(i_lst->second); + array.Insert(obj); + } + + out[i->first] = array; + } + + io::Save file(config_name); + std::ofstream& ofp = file.Get(); + json::Writer::Write(out, ofp); + +} + + +/// @brief Prune MRUListMap to the desired length. +/// This uses the user-set values for MRU list length. +inline void MRUManager::Prune(MRUListMap& map) { + unsigned int size = 16; + + MRUListMap::iterator index = map.begin();; + + if (map.size() >= size) { + std::advance(index, size); + + // Use a range incase the storage number shrinks. + map.erase(index, map.end()); + } +} + +/// @brief Load MRU Lists. +/// @param key List name. +/// @param array json::Array of values. +void MRUManager::Load(const std::string &key, const json::Array& array) { + + json::Array::const_iterator index(array.Begin()), indexEnd(array.End()); + + MRUListMap *map = new MRUListMap(); + + for (; index != indexEnd; ++index) { + const json::Object& obj = *index; + + time_t time = (time_t)(json::Number)obj["time"]; + std::string entry = (json::String)obj["entry"]; + + map->insert(std::pair(time, entry)); + } + + mru.insert(std::pair(key, map)); + Prune(*map); +} + + +} diff --git a/aegisub/libaegisub/common/option.cpp b/aegisub/libaegisub/common/option.cpp new file mode 100644 index 000000000..e61e1e6cb --- /dev/null +++ b/aegisub/libaegisub/common/option.cpp @@ -0,0 +1,237 @@ +// Copyright (c) 2010, Amar Takhar +// +// 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. +// +// $Id$ + +/// @file option.cpp +/// @brief Option interface. +/// @ingroup libaegisub + +#ifndef LAGI_PRE +#include +#include +#include +#endif + +#include "libaegisub/io.h" +#include "option_visit.h" + +namespace agi { + +Options::Options(const std::string &file, const std::string& default_config): + config_file(file), config_default(default_config), config_loaded(false) { + std::istringstream stream(default_config); + LoadConfig(stream); +} + +Options::~Options() { + Flush(); +} + +void Options::ConfigNext(std::istream& stream) { + LoadConfig(stream); +} + +void Options::ConfigUser() { + std::istream *stream = agi::io::Open(config_file); + LoadConfig(*stream); + config_loaded = true; + delete stream; +} + + +void Options::LoadConfig(std::istream& stream) { + /// @todo Store all previously loaded configs in an array for bug report purposes, + /// this is just a temp stub. + json::UnknownElement config_root; + + try { + json::Reader::Read(config_root, stream); + } catch (json::Reader::ParseException& e) { + std::cout << "json::ParseException: " << e.what() << ", Line/offset: " << e.m_locTokenBegin.m_nLine + 1 << '/' << e.m_locTokenBegin.m_nLineOffset + 1 << std::endl << std::endl; + } catch (json::Exception& e) { + /// @todo Do something better here, maybe print the exact error + std::cout << "json::Exception: " << e.what() << std::endl; + } + + ConfigVisitor config_visitor(values, std::string("")); + config_root.Accept(config_visitor); +} + + + + +OptionValue* Options::Get(const std::string &name) { + + OptionValueMap::iterator index; + + if ((index = values.find(name)) != values.end()) + return index->second; + + std::cout << "agi::Options::Get Option not found: (" << name << ")" << std::endl; + throw OptionErrorNotFound("Option value not found"); +} + + + +void Options::Flush() { + + json::Object obj_out; + + bool ok; + + for (OptionValueMap::const_iterator i = values.begin(); i != values.end(); ++i) { + + std::string key = i->first.substr(i->first.rfind("/")+1, i->first.size()); + + int type = i->second->GetType(); + + switch (type) { + case OptionValue::Type_String: { + ok = PutOption(obj_out, i->first, (json::String)i->second->GetString()); + } + break; + + case OptionValue::Type_Int: + ok = PutOption(obj_out, i->first, (json::Number)(const double)i->second->GetInt()); + break; + + case OptionValue::Type_Double: + ok = PutOption(obj_out, i->first, (json::Number)i->second->GetDouble()); + break; + + case OptionValue::Type_Colour: { + std::string str = std::string(i->second->GetColour()); + ok = PutOption(obj_out, i->first, (json::String)str); + } + break; + + case OptionValue::Type_Bool: + ok = PutOption(obj_out, i->first, (json::Boolean)i->second->GetBool()); + break; + + case OptionValue::Type_List_String: { + std::vector array_string; + i->second->GetListString(array_string); + + json::Array array; + + for (std::vector::const_iterator i_str = array_string.begin(); i_str != array_string.end(); ++i_str) { + json::Object obj; + obj["string"] = json::String(*i_str); + array.Insert(obj); + } + + ok = PutOption(obj_out, i->first, (json::Array)array); + } + break; + + case OptionValue::Type_List_Int: { + std::vector array_int; + i->second->GetListInt(array_int); + + json::Array array; + + for (std::vector::const_iterator i_int = array_int.begin(); i_int != array_int.end(); ++i_int) { + json::Object obj; + obj["int"] = json::Number((const double)*i_int); + array.Insert(obj); + } + ok = PutOption(obj_out, i->first, (json::Array)array); + } + break; + + case OptionValue::Type_List_Double: { + std::vector array_double; + i->second->GetListDouble(array_double); + + json::Array array; + + for (std::vector::const_iterator i_double = array_double.begin(); i_double != array_double.end(); ++i_double) { + json::Object obj; + obj["double"] = json::Number(*i_double); + array.Insert(obj); + } + ok = PutOption(obj_out, i->first, (json::Array)array); + } + break; + + case OptionValue::Type_List_Colour: { + std::vector array_colour; + i->second->GetListColour(array_colour); + + json::Array array; + for (std::vector::const_iterator i_colour = array_colour.begin(); i_colour != array_colour.end(); ++i_colour) { + json::Object obj; + + Colour col = *i_colour; + std::string str = std::string(col); + + obj["colour"] = json::String(str); + + array.Insert(obj); + } + ok = PutOption(obj_out, i->first, (json::Array)array); + } + break; + + case OptionValue::Type_List_Bool: { + std::vector array_bool; + + json::Array array; + + i->second->GetListBool(array_bool); + for (std::vector::const_iterator i_bool = array_bool.begin(); i_bool != array_bool.end(); ++i_bool) { + json::Object obj; + obj["bool"] = json::Boolean(*i_bool); + array.Insert(obj); + } + ok = PutOption(obj_out, i->first, (json::Array)array); + } + break; + } + } + + io::Save file(config_file); + json::Writer::Write(obj_out, file.Get()); +} + + +bool Options::PutOption(json::Object &obj, const std::string &path, const json::UnknownElement &value) { + // Having a '/' denotes it is a leaf. + if (path.find('/') == std::string::npos) { + json::Object::iterator pos = obj.Find(path); + + // Fail if a key of the same name already exists. + if (pos != obj.End()) + throw OptionErrorDuplicateKey("Key already exists"); + + obj.Insert(json::Object::Member(path, value)); + return true; + } else { + std::string thispart = path.substr(0, path.find("/")); + std::string restpart = path.substr(path.find("/")+1, path.size()); + json::Object::iterator pos = obj.Find(thispart); + + // New key, make object. + if (pos == obj.End()) + pos = obj.Insert(json::Object::Member(thispart, json::Object())); + + PutOptionVisitor visitor(restpart, value); + pos->element.Accept(visitor); + return visitor.result; + } +} + +} // namespace agi diff --git a/aegisub/libaegisub/common/option_visit.cpp b/aegisub/libaegisub/common/option_visit.cpp new file mode 100644 index 000000000..1609a9b7d --- /dev/null +++ b/aegisub/libaegisub/common/option_visit.cpp @@ -0,0 +1,242 @@ +// Copyright (c) 2010, Amar Takhar +// +// 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. +// +// $Id$ + +/// @file option_visit.cpp +/// @brief Cajun JSON visitor to load config values. +/// @see option_visit.h +/// @ingroup libaegisub + +#ifndef LAGI_PRE +#include + +#include +#include +#endif + +#include +#include "option_visit.h" + +namespace agi { + +ConfigVisitor::ConfigVisitor(OptionValueMap &val, const std::string &member_name): values(val) { + // Corropsonding code is in AddOptionValue() + name = member_name + "/"; +} + +ConfigVisitor::~ConfigVisitor() { +} + + +void ConfigVisitor::Visit(const json::Object& object) { + + json::Object::const_iterator index(object.Begin()), index_end(object.End()); + + for (; index != index_end; ++index) { + const json::Object::Member& member = *index; + const std::string &member_name = member.name; + const json::UnknownElement& element = member.element; + + ConfigVisitor config_visitor(values, name + member_name); + + element.Accept(config_visitor); + } +} + + +void ConfigVisitor::Visit(const json::Array& array) { + int init = 0; + + OptionValueList *array_list; + + json::Array::const_iterator index(array.Begin()), indexEnd(array.End()); + + for (; index != indexEnd; ++index) { + + const json::Object& index_array = *index; + + json::Object::const_iterator index_object(index_array.Begin()), index_objectEnd(index_array.End()); + + for (; index_object != index_objectEnd; ++index_object) { + const json::Object::Member& member = *index_object; + const std::string& member_name = member.name; + + + // This can only happen once since a list must always be of the same + // type, if we try inserting another type into it we want it to fail. + if (!init) { + if (member_name == "string") { + array_list = new OptionValueListString(name); + } else if (member_name == "int") { + array_list = new OptionValueListInt(name); + } else if (member_name == "double") { + array_list = new OptionValueListDouble(name); + } else if (member_name == "bool") { + array_list = new OptionValueListBool(name); + } else if (member_name == "colour") { + array_list = new OptionValueListColour(name); + } else { + throw OptionJsonValueArray("Array type not handled"); + } + init = 1; + } + + try { + if (member_name == "string") { + std::string val = (json::String)member.element; + array_list->InsertString(val); + + } else if (member_name == "int") { + int64_t val = (int64_t)(json::Number)member.element; + array_list->InsertInt(val); + + } else if (member_name == "double") { + double val = (json::Number)member.element; + array_list->InsertDouble(val); + + } else if (member_name == "bool") { + bool val = (json::Boolean)member.element; + array_list->InsertBool(val); + + } else if (member_name == "colour") { + std::string val = (json::String)member.element; + Colour col(val); + array_list->InsertColour(col); + } + + AddOptionValue(array_list); + + } catch (agi::Exception&) { + throw OptionJsonValueArray("Attempt to insert value into array of wrong type"); + } + + } // for index_object + + } // for index +} + + +void ConfigVisitor::Visit(const json::Number& number) { + double val = number.Value(); + + if (int64_t(val) == ceil(val)) { + OptionValue *opt = new OptionValueInt(name, int64_t(val)); + AddOptionValue(opt); + } else { + OptionValue *opt = new OptionValueDouble(name, val); + AddOptionValue(opt); + } + +} + + +void ConfigVisitor::Visit(const json::String& string) { + OptionValue *opt; + if (string.Value().find("rgb(") == 0) { + opt = new OptionValueColour(name, string.Value()); + } else { + opt = new OptionValueString(name, string.Value()); + } + AddOptionValue(opt); +} + + +void ConfigVisitor::Visit(const json::Boolean& boolean) { + OptionValue *opt = new OptionValueBool(name, boolean.Value()); + AddOptionValue(opt); +} + + +void ConfigVisitor::Visit(const json::Null& null) { + throw OptionJsonValueNull("Attempt to read null value"); +} + + +void ConfigVisitor::AddOptionValue(OptionValue* opt) { + // Corrosponding code is in the constuctor. + std::string stripped = name.substr(1, name.rfind("/")-1); + OptionValue *opt_cur; + + OptionValueMap::iterator index; + + if ((index = values.find(stripped)) != values.end()) { + opt_cur = index->second; + } else { + values.insert(OptionValuePair(stripped, opt)); + return; + } + + int type = opt_cur->GetType(); + switch (type) { + case OptionValue::Type_String: + opt_cur->SetString(opt->GetString()); + break; + + case OptionValue::Type_Int: + opt_cur->SetInt(opt->GetInt()); + break; + + case OptionValue::Type_Double: + opt_cur->SetDouble(opt->GetDouble()); + break; + + case OptionValue::Type_Colour: + opt_cur->SetColour(opt->GetColour()); + break; + + case OptionValue::Type_Bool: + opt_cur->SetBool(opt->GetBool()); + break; + + case OptionValue::Type_List_String: { + std::vector array; + opt->GetListString(array); + opt_cur->SetListString(array); + break; + } + + case OptionValue::Type_List_Int: { + std::vector array; + opt->GetListInt(array); + opt_cur->SetListInt(array); + break; + } + + case OptionValue::Type_List_Double: { + std::vector array; + opt->GetListDouble(array); + opt_cur->SetListDouble(array); + break; + } + + case OptionValue::Type_List_Colour: { + std::vector array; + opt->GetListColour(array); + opt_cur->SetListColour(array); + break; + } + + + case OptionValue::Type_List_Bool: { + std::vector array; + opt->GetListBool(array); + opt_cur->SetListBool(array); + break; + } + } + +} + +} // namespace agi diff --git a/aegisub/libaegisub/common/option_visit.h b/aegisub/libaegisub/common/option_visit.h new file mode 100644 index 000000000..537c2427b --- /dev/null +++ b/aegisub/libaegisub/common/option_visit.h @@ -0,0 +1,83 @@ +// Copyright (c) 2010, Amar Takhar +// +// 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. +// +// $Id$ + +/// @file option_visit.h +/// @brief Cajun JSON visitor to load config values. +/// @see option_visit.cpp +/// @ingroup libaegisub + +#ifndef LAGI_PRE +#include "libaegisub/cajun/elements.h" +#include "libaegisub/cajun/visitor.h" +#endif + +#pragma once + +#include "libaegisub/option.h" + +namespace agi { + +DEFINE_BASE_EXCEPTION_NOINNER(OptionJsonValueError, Exception) +DEFINE_SIMPLE_EXCEPTION_NOINNER(OptionJsonValueArray, OptionJsonValueError, "options/value/array") +DEFINE_SIMPLE_EXCEPTION_NOINNER(OptionJsonValueSingle, OptionJsonValueError, "options/value") +DEFINE_SIMPLE_EXCEPTION_NOINNER(OptionJsonValueNull, OptionJsonValueError, "options/value") + +class ConfigVisitor : public json::ConstVisitor { + + OptionValueMap &values; + std::string name; + typedef std::pair OptionValuePair; + + void AddOptionValue(OptionValue* opt); + +public: + + ConfigVisitor(OptionValueMap &val, const std::string &member_name); + ~ConfigVisitor(); + + void Visit(const json::Array& array); + void Visit(const json::Object& object); + void Visit(const json::Number& number); + void Visit(const json::String& string); + void Visit(const json::Boolean& boolean); + void Visit(const json::Null& null); +}; + + +class PutOptionVisitor : public json::Visitor { +public: + bool result; + const std::string &path; + const json::UnknownElement &value; + + PutOptionVisitor(const std::string &path, const json::UnknownElement &value) + : result(false), path(path), value(value) + {} + + // all of these are a fail + virtual void Visit(json::Array& array) { } + virtual void Visit(json::Number& number) { } + virtual void Visit(json::String& string) { } + virtual void Visit(json::Boolean& boolean) { } + virtual void Visit(json::Null& null) { } + + // this one is the win + virtual void Visit(json::Object& object) { + result = Options::PutOption(object, path, value); + } +}; + +} // namespace agi diff --git a/aegisub/libaegisub/common/validator.cpp b/aegisub/libaegisub/common/validator.cpp new file mode 100644 index 000000000..24e8568e7 --- /dev/null +++ b/aegisub/libaegisub/common/validator.cpp @@ -0,0 +1,73 @@ +// Copyright (c) 2010, Amar Takhar +// +// 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. +// +// $Id$ + +/// @file validator.cpp +/// @brief Input validation. +/// @ingroup libaegisub + +#ifndef LAGI_PRE +#endif + +#include + +namespace agi { + +bool ValidAny::CheckType(std::string &value) { + return true; +} + +bool ValidAny::Check(std::string &value) { + return true; +} + + +bool ValidString::CheckType(std::string &value) { + return true; +} + +bool ValidString::Check(std::string &value) { + return CheckType(value); +} + + +bool ValidInt::CheckType(std::string &value) { + return true; +} + +bool ValidInt::Check(std::string &value) { + return CheckType(value); +} + +bool ValidBool::CheckType(std::string &value) { + return true; +} + +bool ValidBool::Check(std::string &value) { + return CheckType(value); +} + +bool ValidColour::Check(std::string &value) { + + if (ValidString::CheckType(value)) { + // check if it's a valid colour + return 1; + } + return 0; +} + + +} // namespace agi + diff --git a/aegisub/libaegisub/include/libaegisub/access.h b/aegisub/libaegisub/include/libaegisub/access.h new file mode 100644 index 000000000..13f87b57d --- /dev/null +++ b/aegisub/libaegisub/include/libaegisub/access.h @@ -0,0 +1,58 @@ +// Copyright (c) 2010, Amar Takhar +// +// 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. +// +// $Id$ + +/// @file access.h +/// @brief Public interface for access methods. +/// @ingroup libaegisub + +#ifndef LAGI_PRE +#endif + +#include + +namespace agi { + namespace acs { + +DEFINE_BASE_EXCEPTION_NOINNER(AcsError, Exception) +DEFINE_SIMPLE_EXCEPTION_NOINNER(AcsFatal, AcsError, "acs/fatal") +DEFINE_SIMPLE_EXCEPTION_NOINNER(AcsNotFound, AcsError, "acs/notfound") +DEFINE_SIMPLE_EXCEPTION_NOINNER(AcsNotAFile, AcsError, "acs/file") +DEFINE_SIMPLE_EXCEPTION_NOINNER(AcsNotADirectory, AcsError, "acs/directory") + +DEFINE_SIMPLE_EXCEPTION_NOINNER(AcsAccess, AcsError, "acs/access") +DEFINE_SIMPLE_EXCEPTION_NOINNER(AcsRead, AcsAccess, "acs/access/read") +DEFINE_SIMPLE_EXCEPTION_NOINNER(AcsWrite, AcsAccess, "acs/access/write") + + +enum Type { + FileRead, + DirRead, + FileWrite, + DirWrite +}; + + +void Check(const std::string &file, acs::Type); + +void CheckFileRead(const std::string &file); +void CheckDirRead(const std::string &dir); + +void CheckFileWrite(const std::string &file); +void CheckDirWrite(const std::string &dir); + + + } // namespace axs +} // namespace agi diff --git a/aegisub/libaegisub/include/libaegisub/cajun/elements.h b/aegisub/libaegisub/include/libaegisub/cajun/elements.h new file mode 100644 index 000000000..dfe619943 --- /dev/null +++ b/aegisub/libaegisub/include/libaegisub/cajun/elements.h @@ -0,0 +1,272 @@ +/********************************************** + +License: BSD +Project Webpage: http://cajun-jsonapi.sourceforge.net/ +Author: Terry Caton + +***********************************************/ + +#pragma once + +#include +#include +#include +#include + +/* + +TODO: +* better documentation (doxygen?) +* Unicode support +* parent element accessors + +*/ + +namespace json +{ + + +///////////////////////////////////////////////// +// forward declarations (more info further below) + + +class Visitor; +class ConstVisitor; + +template +class TrivialType_T; + +typedef TrivialType_T Number; +typedef TrivialType_T Boolean; +typedef TrivialType_T String; + +class Object; +class Array; +class Null; + + + +///////////////////////////////////////////////////////////////////////// +// Exception - base class for all JSON-related runtime errors + +class Exception : public std::runtime_error +{ +public: + Exception(const std::string& sMessage); +}; + + + + +///////////////////////////////////////////////////////////////////////// +// UnknownElement - provides a typesafe surrogate for any of the JSON- +// sanctioned element types. This class allows the Array and Object +// class to effectively contain a heterogeneous set of child elements. +// The cast operators provide convenient implicit downcasting, while +// preserving dynamic type safety by throwing an exception during a +// a bad cast. +// The object & array element index operators (operators [std::string] +// and [size_t]) provide convenient, quick access to child elements. +// They are a logical extension of the cast operators. These child +// element accesses can be chained together, allowing the following +// (when document structure is well-known): +// String str = objInvoices[1]["Customer"]["Company"]; + + +class UnknownElement +{ +public: + UnknownElement(); + UnknownElement(const UnknownElement& unknown); + UnknownElement(const Object& object); + UnknownElement(const Array& array); + UnknownElement(const Number& number); + UnknownElement(const Boolean& boolean); + UnknownElement(const String& string); + UnknownElement(const Null& null); + + ~UnknownElement(); + + UnknownElement& operator = (const UnknownElement& unknown); + + // implicit cast to actual element type. throws on failure + operator const Object& () const; + operator const Array& () const; + operator const Number& () const; + operator const Boolean& () const; + operator const String& () const; + operator const Null& () const; + + // implicit cast to actual element type. *converts* on failure, and always returns success + operator Object& (); + operator Array& (); + operator Number& (); + operator Boolean& (); + operator String& (); + operator Null& (); + + // provides quick access to children when real element type is object + UnknownElement& operator[] (const std::string& key); + const UnknownElement& operator[] (const std::string& key) const; + + // provides quick access to children when real element type is array + UnknownElement& operator[] (size_t index); + const UnknownElement& operator[] (size_t index) const; + + // implements visitor pattern + void Accept(ConstVisitor& visitor) const; + void Accept(Visitor& visitor); + + // tests equality. first checks type, then value if possible + bool operator == (const UnknownElement& element) const; + +private: + class Imp; + + template + class Imp_T; + + class CastVisitor; + class ConstCastVisitor; + + template + class CastVisitor_T; + + template + class ConstCastVisitor_T; + + template + const ElementTypeT& CastTo() const; + + template + ElementTypeT& ConvertTo(); + + Imp* m_pImp; +}; + + +///////////////////////////////////////////////////////////////////////////////// +// Array - mimics std::deque. The array contents are effectively +// heterogeneous thanks to the ElementUnknown class. push_back has been replaced +// by more generic insert functions. + +class Array +{ +public: + typedef std::deque Elements; + typedef Elements::iterator iterator; + typedef Elements::const_iterator const_iterator; + + iterator Begin(); + iterator End(); + const_iterator Begin() const; + const_iterator End() const; + + iterator Insert(const UnknownElement& element, iterator itWhere); + iterator Insert(const UnknownElement& element); + iterator Erase(iterator itWhere); + void Resize(size_t newSize); + void Clear(); + + size_t Size() const; + bool Empty() const; + + UnknownElement& operator[] (size_t index); + const UnknownElement& operator[] (size_t index) const; + + bool operator == (const Array& array) const; + +private: + Elements m_Elements; +}; + + +///////////////////////////////////////////////////////////////////////////////// +// Object - mimics std::map. The member value +// contents are effectively heterogeneous thanks to the UnknownElement class + +class Object +{ +public: + struct Member { + Member(const std::string& nameIn = std::string(), const UnknownElement& elementIn = UnknownElement()); + + bool operator == (const Member& member) const; + + std::string name; + UnknownElement element; + }; + + typedef std::list Members; // map faster, but does not preserve order + typedef Members::iterator iterator; + typedef Members::const_iterator const_iterator; + + bool operator == (const Object& object) const; + + iterator Begin(); + iterator End(); + const_iterator Begin() const; + const_iterator End() const; + + size_t Size() const; + bool Empty() const; + + iterator Find(const std::string& name); + const_iterator Find(const std::string& name) const; + + iterator Insert(const Member& member); + iterator Insert(const Member& member, iterator itWhere); + iterator Erase(iterator itWhere); + void Clear(); + + UnknownElement& operator [](const std::string& name); + const UnknownElement& operator [](const std::string& name) const; + +private: + class Finder; + + Members m_Members; +}; + + +///////////////////////////////////////////////////////////////////////////////// +// TrivialType_T - class template for encapsulates a simple data type, such as +// a string, number, or boolean. Provides implicit const & noncost cast operators +// for that type, allowing "DataTypeT type = trivialType;" + + +template +class TrivialType_T +{ +public: + TrivialType_T(const DataTypeT& t = DataTypeT()); + + operator DataTypeT&(); + operator const DataTypeT&() const; + + DataTypeT& Value(); + const DataTypeT& Value() const; + + bool operator == (const TrivialType_T& trivial) const; + +private: + DataTypeT m_tValue; +}; + + + +///////////////////////////////////////////////////////////////////////////////// +// Null - doesn't do much of anything but satisfy the JSON spec. It is the default +// element type of UnknownElement + +class Null +{ +public: + bool operator == (const Null& trivial) const; +}; + + +} // End namespace + + +#include "elements.inl" diff --git a/aegisub/libaegisub/include/libaegisub/cajun/elements.inl b/aegisub/libaegisub/include/libaegisub/cajun/elements.inl new file mode 100644 index 000000000..db9df1859 --- /dev/null +++ b/aegisub/libaegisub/include/libaegisub/cajun/elements.inl @@ -0,0 +1,412 @@ +/********************************************** + +License: BSD +Project Webpage: http://cajun-jsonapi.sourceforge.net/ +Author: Terry Caton + +***********************************************/ + +#include "visitor.h" +#include "reader.h" +#include +#include +#include + +/* + +TODO: +* better documentation + +*/ + +namespace json +{ + + +inline Exception::Exception(const std::string& sMessage) : + std::runtime_error(sMessage) {} + + +///////////////////////// +// UnknownElement members + +class UnknownElement::Imp +{ +public: + virtual ~Imp() {} + virtual Imp* Clone() const = 0; + + virtual bool Compare(const Imp& imp) const = 0; + + virtual void Accept(ConstVisitor& visitor) const = 0; + virtual void Accept(Visitor& visitor) = 0; +}; + + +template +class UnknownElement::Imp_T : public UnknownElement::Imp +{ +public: + Imp_T(const ElementTypeT& element) : m_Element(element) {} + virtual Imp* Clone() const { return new Imp_T(*this); } + + virtual void Accept(ConstVisitor& visitor) const { visitor.Visit(m_Element); } + virtual void Accept(Visitor& visitor) { visitor.Visit(m_Element); } + + virtual bool Compare(const Imp& imp) const + { + ConstCastVisitor_T castVisitor; + imp.Accept(castVisitor); + return castVisitor.m_pElement && + m_Element == *castVisitor.m_pElement; + } + +private: + ElementTypeT m_Element; +}; + + +class UnknownElement::ConstCastVisitor : public ConstVisitor +{ + virtual void Visit(const Array& array) {} + virtual void Visit(const Object& object) {} + virtual void Visit(const Number& number) {} + virtual void Visit(const String& string) {} + virtual void Visit(const Boolean& boolean) {} + virtual void Visit(const Null& null) {} +}; + +template +class UnknownElement::ConstCastVisitor_T : public ConstCastVisitor +{ +public: + ConstCastVisitor_T() : m_pElement(0) {} + virtual void Visit(const ElementTypeT& element) { m_pElement = &element; } // we don't know what this is, but it overrides one of the base's no-op functions + const ElementTypeT* m_pElement; +}; + + +class UnknownElement::CastVisitor : public Visitor +{ + virtual void Visit(Array& array) {} + virtual void Visit(Object& object) {} + virtual void Visit(Number& number) {} + virtual void Visit(String& string) {} + virtual void Visit(Boolean& boolean) {} + virtual void Visit(Null& null) {} +}; + +template +class UnknownElement::CastVisitor_T : public CastVisitor +{ +public: + CastVisitor_T() : m_pElement(0) {} + virtual void Visit(ElementTypeT& element) { m_pElement = &element; } // we don't know what this is, but it overrides one of the base's no-op functions + ElementTypeT* m_pElement; +}; + + + + +inline UnknownElement::UnknownElement() : m_pImp( new Imp_T( Null() ) ) {} +inline UnknownElement::UnknownElement(const UnknownElement& unknown) : m_pImp( unknown.m_pImp->Clone()) {} +inline UnknownElement::UnknownElement(const Object& object) : m_pImp( new Imp_T(object) ) {} +inline UnknownElement::UnknownElement(const Array& array) : m_pImp( new Imp_T(array) ) {} +inline UnknownElement::UnknownElement(const Number& number) : m_pImp( new Imp_T(number) ) {} +inline UnknownElement::UnknownElement(const Boolean& boolean) : m_pImp( new Imp_T(boolean) ) {} +inline UnknownElement::UnknownElement(const String& string) : m_pImp( new Imp_T(string) ) {} +inline UnknownElement::UnknownElement(const Null& null) : m_pImp( new Imp_T(null) ) {} + +inline UnknownElement::~UnknownElement() { delete m_pImp; } + +inline UnknownElement::operator const Object& () const { return CastTo(); } +inline UnknownElement::operator const Array& () const { return CastTo(); } +inline UnknownElement::operator const Number& () const { return CastTo(); } +inline UnknownElement::operator const Boolean& () const { return CastTo(); } +inline UnknownElement::operator const String& () const { return CastTo(); } +inline UnknownElement::operator const Null& () const { return CastTo(); } + +inline UnknownElement::operator Object& () { return ConvertTo(); } +inline UnknownElement::operator Array& () { return ConvertTo(); } +inline UnknownElement::operator Number& () { return ConvertTo(); } +inline UnknownElement::operator Boolean& () { return ConvertTo(); } +inline UnknownElement::operator String& () { return ConvertTo(); } +inline UnknownElement::operator Null& () { return ConvertTo(); } + +inline UnknownElement& UnknownElement::operator = (const UnknownElement& unknown) +{ + delete m_pImp; + m_pImp = unknown.m_pImp->Clone(); + return *this; +} + +inline UnknownElement& UnknownElement::operator[] (const std::string& key) +{ + // the people want an object. make us one if we aren't already + Object& object = ConvertTo(); + return object[key]; +} + +inline const UnknownElement& UnknownElement::operator[] (const std::string& key) const +{ + // throws if we aren't an object + const Object& object = CastTo(); + return object[key]; +} + +inline UnknownElement& UnknownElement::operator[] (size_t index) +{ + // the people want an array. make us one if we aren't already + Array& array = ConvertTo(); + return array[index]; +} + +inline const UnknownElement& UnknownElement::operator[] (size_t index) const +{ + // throws if we aren't an array + const Array& array = CastTo(); + return array[index]; +} + + +template +const ElementTypeT& UnknownElement::CastTo() const +{ + ConstCastVisitor_T castVisitor; + m_pImp->Accept(castVisitor); + if (castVisitor.m_pElement == 0) + throw Exception("Bad cast"); + return *castVisitor.m_pElement; +} + + + +template +ElementTypeT& UnknownElement::ConvertTo() +{ + CastVisitor_T castVisitor; + m_pImp->Accept(castVisitor); + if (castVisitor.m_pElement == 0) + { + // we're not the right type. fix it & try again + *this = ElementTypeT(); + m_pImp->Accept(castVisitor); + } + + return *castVisitor.m_pElement; +} + + +inline void UnknownElement::Accept(ConstVisitor& visitor) const { m_pImp->Accept(visitor); } +inline void UnknownElement::Accept(Visitor& visitor) { m_pImp->Accept(visitor); } + + +inline bool UnknownElement::operator == (const UnknownElement& element) const +{ + return m_pImp->Compare(*element.m_pImp); +} + + + +////////////////// +// Object members + + +inline Object::Member::Member(const std::string& nameIn, const UnknownElement& elementIn) : + name(nameIn), element(elementIn) {} + +inline bool Object::Member::operator == (const Member& member) const +{ + return name == member.name && + element == member.element; +} + +class Object::Finder : public std::unary_function +{ +public: + Finder(const std::string& name) : m_name(name) {} + bool operator () (const Object::Member& member) { + return member.name == m_name; + } + +private: + std::string m_name; +}; + + + +inline Object::iterator Object::Begin() { return m_Members.begin(); } +inline Object::iterator Object::End() { return m_Members.end(); } +inline Object::const_iterator Object::Begin() const { return m_Members.begin(); } +inline Object::const_iterator Object::End() const { return m_Members.end(); } + +inline size_t Object::Size() const { return m_Members.size(); } +inline bool Object::Empty() const { return m_Members.empty(); } + +inline Object::iterator Object::Find(const std::string& name) +{ + return std::find_if(m_Members.begin(), m_Members.end(), Finder(name)); +} + +inline Object::const_iterator Object::Find(const std::string& name) const +{ + return std::find_if(m_Members.begin(), m_Members.end(), Finder(name)); +} + +inline Object::iterator Object::Insert(const Member& member) +{ + return Insert(member, End()); +} + +inline Object::iterator Object::Insert(const Member& member, iterator itWhere) +{ + iterator it = Find(member.name); + if (it != m_Members.end()) + throw Exception("Object member already exists: " + member.name); + + it = m_Members.insert(itWhere, member); + return it; +} + +inline Object::iterator Object::Erase(iterator itWhere) +{ + return m_Members.erase(itWhere); +} + +inline UnknownElement& Object::operator [](const std::string& name) +{ + + iterator it = Find(name); + if (it == m_Members.end()) + { + Member member(name); + it = Insert(member, End()); + } + return it->element; +} + +inline const UnknownElement& Object::operator [](const std::string& name) const +{ + const_iterator it = Find(name); + if (it == End()) + throw Exception("Object member not found: " + name); + return it->element; +} + +inline void Object::Clear() +{ + m_Members.clear(); +} + +inline bool Object::operator == (const Object& object) const +{ + return m_Members == object.m_Members; +} + + +///////////////// +// Array members + +inline Array::iterator Array::Begin() { return m_Elements.begin(); } +inline Array::iterator Array::End() { return m_Elements.end(); } +inline Array::const_iterator Array::Begin() const { return m_Elements.begin(); } +inline Array::const_iterator Array::End() const { return m_Elements.end(); } + +inline Array::iterator Array::Insert(const UnknownElement& element, iterator itWhere) +{ + return m_Elements.insert(itWhere, element); +} + +inline Array::iterator Array::Insert(const UnknownElement& element) +{ + return Insert(element, End()); +} + +inline Array::iterator Array::Erase(iterator itWhere) +{ + return m_Elements.erase(itWhere); +} + +inline void Array::Resize(size_t newSize) +{ + m_Elements.resize(newSize); +} + +inline size_t Array::Size() const { return m_Elements.size(); } +inline bool Array::Empty() const { return m_Elements.empty(); } + +inline UnknownElement& Array::operator[] (size_t index) +{ + size_t nMinSize = index + 1; // zero indexed + if (m_Elements.size() < nMinSize) + m_Elements.resize(nMinSize); + return m_Elements[index]; +} + +inline const UnknownElement& Array::operator[] (size_t index) const +{ + if (index >= m_Elements.size()) + throw Exception("Array out of bounds"); + return m_Elements[index]; +} + +inline void Array::Clear() { + m_Elements.clear(); +} + +inline bool Array::operator == (const Array& array) const +{ + return m_Elements == array.m_Elements; +} + + +//////////////////////// +// TrivialType_T members + +template +TrivialType_T::TrivialType_T(const DataTypeT& t) : + m_tValue(t) {} + +template +TrivialType_T::operator DataTypeT&() +{ + return Value(); +} + +template +TrivialType_T::operator const DataTypeT&() const +{ + return Value(); +} + +template +DataTypeT& TrivialType_T::Value() +{ + return m_tValue; +} + +template +const DataTypeT& TrivialType_T::Value() const +{ + return m_tValue; +} + +template +bool TrivialType_T::operator == (const TrivialType_T& trivial) const +{ + return m_tValue == trivial.m_tValue; +} + + + +////////////////// +// Null members + +inline bool Null::operator == (const Null& trivial) const +{ + return true; +} + + + +} // End namespace diff --git a/aegisub/libaegisub/include/libaegisub/cajun/reader.h b/aegisub/libaegisub/include/libaegisub/cajun/reader.h new file mode 100644 index 000000000..cd02977ba --- /dev/null +++ b/aegisub/libaegisub/include/libaegisub/cajun/reader.h @@ -0,0 +1,125 @@ +/********************************************** + +License: BSD +Project Webpage: http://cajun-jsonapi.sourceforge.net/ +Author: Terry Caton + +***********************************************/ + +#pragma once + +#include "elements.h" +#include +#include + +namespace json +{ + +class Reader +{ +public: + // this structure will be reported in one of the exceptions defined below + struct Location + { + Location(); + + unsigned int m_nLine; // document line, zero-indexed + unsigned int m_nLineOffset; // character offset from beginning of line, zero indexed + unsigned int m_nDocOffset; // character offset from entire document, zero indexed + }; + + // thrown during the first phase of reading. generally catches low-level problems such + // as errant characters or corrupt/incomplete documents + class ScanException : public Exception + { + public: + ScanException(const std::string& sMessage, const Reader::Location& locError) : + Exception(sMessage), + m_locError(locError) {} + + Reader::Location m_locError; + }; + + // thrown during the second phase of reading. generally catches higher-level problems such + // as missing commas or brackets + class ParseException : public Exception + { + public: + ParseException(const std::string& sMessage, const Reader::Location& locTokenBegin, const Reader::Location& locTokenEnd) : + Exception(sMessage), + m_locTokenBegin(locTokenBegin), + m_locTokenEnd(locTokenEnd) {} + + Reader::Location m_locTokenBegin; + Reader::Location m_locTokenEnd; + }; + + + // if you know what the document looks like, call one of these... + static void Read(Object& object, std::istream& istr); + static void Read(Array& array, std::istream& istr); + static void Read(String& string, std::istream& istr); + static void Read(Number& number, std::istream& istr); + static void Read(Boolean& boolean, std::istream& istr); + static void Read(Null& null, std::istream& istr); + + // ...otherwise, if you don't know, call this & visit it + static void Read(UnknownElement& elementRoot, std::istream& istr); + +private: + struct Token + { + enum Type + { + TOKEN_OBJECT_BEGIN, // { + TOKEN_OBJECT_END, // } + TOKEN_ARRAY_BEGIN, // [ + TOKEN_ARRAY_END, // ] + TOKEN_NEXT_ELEMENT, // , + TOKEN_MEMBER_ASSIGN, // : + TOKEN_STRING, // "xxx" + TOKEN_NUMBER, // [+/-]000.000[e[+/-]000] + TOKEN_BOOLEAN, // true -or- false + TOKEN_NULL // null + }; + + Type nType; + std::string sValue; + + // for malformed file debugging + Reader::Location locBegin; + Reader::Location locEnd; + }; + + class InputStream; + class TokenStream; + typedef std::vector Tokens; + + template + static void Read_i(ElementTypeT& element, std::istream& istr); + + // scanning istream into token sequence + void Scan(Tokens& tokens, InputStream& inputStream); + + void EatWhiteSpace(InputStream& inputStream); + void MatchString(std::string& sValue, InputStream& inputStream); + void MatchNumber(std::string& sNumber, InputStream& inputStream); + void MatchExpectedString(const std::string& sExpected, InputStream& inputStream); + + // parsing token sequence into element structure + void Parse(UnknownElement& element, TokenStream& tokenStream); + void Parse(Object& object, TokenStream& tokenStream); + void Parse(Array& array, TokenStream& tokenStream); + void Parse(String& string, TokenStream& tokenStream); + void Parse(Number& number, TokenStream& tokenStream); + void Parse(Boolean& boolean, TokenStream& tokenStream); + void Parse(Null& null, TokenStream& tokenStream); + + const std::string& MatchExpectedToken(Token::Type nExpected, TokenStream& tokenStream); +}; + + +} // End namespace + + +#include "reader.inl" diff --git a/aegisub/libaegisub/include/libaegisub/cajun/reader.inl b/aegisub/libaegisub/include/libaegisub/cajun/reader.inl new file mode 100644 index 000000000..8b9e1c770 --- /dev/null +++ b/aegisub/libaegisub/include/libaegisub/cajun/reader.inl @@ -0,0 +1,519 @@ +/********************************************** + +License: BSD +Project Webpage: http://cajun-jsonapi.sourceforge.net/ +Author: Terry Caton + +***********************************************/ + +#include +#include +#include + +/* + +TODO: +* better documentation +* unicode character decoding + +*/ + +namespace json +{ + + + inline std::istream& operator >> (std::istream& istr, UnknownElement& elementRoot) { + Reader::Read(elementRoot, istr); + return istr; +} + +inline Reader::Location::Location() : + m_nLine(0), + m_nLineOffset(0), + m_nDocOffset(0) +{} + + +////////////////////// +// Reader::InputStream + +class Reader::InputStream // would be cool if we could inherit from std::istream & override "get" +{ +public: + InputStream(std::istream& iStr) : + m_iStr(iStr) {} + + // protect access to the input stream, so we can keeep track of document/line offsets + char Get(); // big, define outside + char Peek() { + assert(m_iStr.eof() == false); // enforce reading of only valid stream data + return m_iStr.peek(); + } + + bool EOS() { + m_iStr.peek(); // apparently eof flag isn't set until a character read is attempted. whatever. + return m_iStr.eof(); + } + + const Location& GetLocation() const { return m_Location; } + +private: + std::istream& m_iStr; + Location m_Location; +}; + + +inline char Reader::InputStream::Get() +{ + assert(m_iStr.eof() == false); // enforce reading of only valid stream data + char c = m_iStr.get(); + + ++m_Location.m_nDocOffset; + if (c == '\n') { + ++m_Location.m_nLine; + m_Location.m_nLineOffset = 0; + } + else { + ++m_Location.m_nLineOffset; + } + + return c; +} + + + +////////////////////// +// Reader::TokenStream + +class Reader::TokenStream +{ +public: + TokenStream(const Tokens& tokens); + + const Token& Peek(); + const Token& Get(); + + bool EOS() const; + +private: + const Tokens& m_Tokens; + Tokens::const_iterator m_itCurrent; +}; + + +inline Reader::TokenStream::TokenStream(const Tokens& tokens) : + m_Tokens(tokens), + m_itCurrent(tokens.begin()) +{} + +inline const Reader::Token& Reader::TokenStream::Peek() { + assert(m_itCurrent != m_Tokens.end()); + return *(m_itCurrent); +} + +inline const Reader::Token& Reader::TokenStream::Get() { + assert(m_itCurrent != m_Tokens.end()); + return *(m_itCurrent++); +} + +inline bool Reader::TokenStream::EOS() const { + return m_itCurrent == m_Tokens.end(); +} + +/////////////////// +// Reader (finally) + + +inline void Reader::Read(Object& object, std::istream& istr) { Read_i(object, istr); } +inline void Reader::Read(Array& array, std::istream& istr) { Read_i(array, istr); } +inline void Reader::Read(String& string, std::istream& istr) { Read_i(string, istr); } +inline void Reader::Read(Number& number, std::istream& istr) { Read_i(number, istr); } +inline void Reader::Read(Boolean& boolean, std::istream& istr) { Read_i(boolean, istr); } +inline void Reader::Read(Null& null, std::istream& istr) { Read_i(null, istr); } +inline void Reader::Read(UnknownElement& unknown, std::istream& istr) { Read_i(unknown, istr); } + + +template +void Reader::Read_i(ElementTypeT& element, std::istream& istr) +{ + Reader reader; + + Tokens tokens; + InputStream inputStream(istr); + reader.Scan(tokens, inputStream); + + TokenStream tokenStream(tokens); + reader.Parse(element, tokenStream); + + if (tokenStream.EOS() == false) + { + const Token& token = tokenStream.Peek(); + std::string sMessage = "Expected End of token stream; found " + token.sValue; + throw ParseException(sMessage, token.locBegin, token.locEnd); + } +} + + +inline void Reader::Scan(Tokens& tokens, InputStream& inputStream) +{ + while (EatWhiteSpace(inputStream), // ignore any leading white space... + inputStream.EOS() == false) // ...before checking for EOS + { + // if all goes well, we'll create a token each pass + Token token; + token.locBegin = inputStream.GetLocation(); + + // gives us null-terminated string + std::string sChar; + sChar.push_back(inputStream.Peek()); + + switch (sChar[0]) + { + case '{': + token.sValue = sChar[0]; + MatchExpectedString(sChar, inputStream); + token.nType = Token::TOKEN_OBJECT_BEGIN; + break; + + case '}': + token.sValue = sChar[0]; + MatchExpectedString(sChar, inputStream); + token.nType = Token::TOKEN_OBJECT_END; + break; + + case '[': + token.sValue = sChar[0]; + MatchExpectedString(sChar, inputStream); + token.nType = Token::TOKEN_ARRAY_BEGIN; + break; + + case ']': + token.sValue = sChar[0]; + MatchExpectedString(sChar, inputStream); + token.nType = Token::TOKEN_ARRAY_END; + break; + + case ',': + token.sValue = sChar[0]; + MatchExpectedString(sChar, inputStream); + token.nType = Token::TOKEN_NEXT_ELEMENT; + break; + + case ':': + token.sValue = sChar[0]; + MatchExpectedString(sChar, inputStream); + token.nType = Token::TOKEN_MEMBER_ASSIGN; + break; + + case '"': + MatchString(token.sValue, inputStream); + token.nType = Token::TOKEN_STRING; + break; + + case '-': + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': + MatchNumber(token.sValue, inputStream); + token.nType = Token::TOKEN_NUMBER; + break; + + case 't': + token.sValue = "true"; + MatchExpectedString(token.sValue, inputStream); + token.nType = Token::TOKEN_BOOLEAN; + break; + + case 'f': + token.sValue = "false"; + MatchExpectedString(token.sValue, inputStream); + token.nType = Token::TOKEN_BOOLEAN; + break; + + case 'n': + token.sValue = "null"; + MatchExpectedString(token.sValue, inputStream); + token.nType = Token::TOKEN_NULL; + break; + + default: { + std::string sErrorMessage = "Unexpected character in stream: " + sChar; + throw ScanException(sErrorMessage, inputStream.GetLocation()); + } + } + + token.locEnd = inputStream.GetLocation(); + tokens.push_back(token); + } +} + + +inline void Reader::EatWhiteSpace(InputStream& inputStream) +{ + while (inputStream.EOS() == false && + ::isspace(inputStream.Peek())) + inputStream.Get(); +} + +inline void Reader::MatchExpectedString(const std::string& sExpected, InputStream& inputStream) +{ + std::string::const_iterator it(sExpected.begin()), + itEnd(sExpected.end()); + for ( ; it != itEnd; ++it) { + if (inputStream.EOS() || // did we reach the end before finding what we're looking for... + inputStream.Get() != *it) // ...or did we find something different? + { + std::string sMessage = "Expected string: " + sExpected; + throw ScanException(sMessage, inputStream.GetLocation()); + } + } + + // all's well if we made it here, return quietly +} + + +inline void Reader::MatchString(std::string& string, InputStream& inputStream) +{ + MatchExpectedString("\"", inputStream); + + while (inputStream.EOS() == false && + inputStream.Peek() != '"') + { + char c = inputStream.Get(); + + // escape? + if (c == '\\' && + inputStream.EOS() == false) // shouldn't have reached the end yet + { + c = inputStream.Get(); + switch (c) { + case '/': string.push_back('/'); break; + case '"': string.push_back('"'); break; + case '\\': string.push_back('\\'); break; + case 'b': string.push_back('\b'); break; + case 'f': string.push_back('\f'); break; + case 'n': string.push_back('\n'); break; + case 'r': string.push_back('\r'); break; + case 't': string.push_back('\t'); break; + case 'u': // TODO: what do we do with this? + default: { + std::string sMessage = "Unrecognized escape sequence found in string: \\" + c; + throw ScanException(sMessage, inputStream.GetLocation()); + } + } + } + else { + string.push_back(c); + } + } + + // eat the last '"' that we just peeked + MatchExpectedString("\"", inputStream); +} + + +inline void Reader::MatchNumber(std::string& sNumber, InputStream& inputStream) +{ + const char sNumericChars[] = "0123456789.eE-+"; + std::set numericChars; + numericChars.insert(sNumericChars, sNumericChars + sizeof(sNumericChars)); + + while (inputStream.EOS() == false && + numericChars.find(inputStream.Peek()) != numericChars.end()) + { + sNumber.push_back(inputStream.Get()); + } +} + + +inline void Reader::Parse(UnknownElement& element, Reader::TokenStream& tokenStream) +{ + if (tokenStream.EOS()) { + std::string sMessage = "Unexpected end of token stream"; + throw ParseException(sMessage, Location(), Location()); // nowhere to point to + } + + const Token& token = tokenStream.Peek(); + switch (token.nType) { + case Token::TOKEN_OBJECT_BEGIN: + { + // implicit non-const cast will perform conversion for us (if necessary) + Object& object = element; + Parse(object, tokenStream); + break; + } + + case Token::TOKEN_ARRAY_BEGIN: + { + Array& array = element; + Parse(array, tokenStream); + break; + } + + case Token::TOKEN_STRING: + { + String& string = element; + Parse(string, tokenStream); + break; + } + + case Token::TOKEN_NUMBER: + { + Number& number = element; + Parse(number, tokenStream); + break; + } + + case Token::TOKEN_BOOLEAN: + { + Boolean& boolean = element; + Parse(boolean, tokenStream); + break; + } + + case Token::TOKEN_NULL: + { + Null& null = element; + Parse(null, tokenStream); + break; + } + + default: + { + std::string sMessage = "Unexpected token: " + token.sValue; + throw ParseException(sMessage, token.locBegin, token.locEnd); + } + } +} + + +inline void Reader::Parse(Object& object, Reader::TokenStream& tokenStream) +{ + MatchExpectedToken(Token::TOKEN_OBJECT_BEGIN, tokenStream); + + bool bContinue = (tokenStream.EOS() == false && + tokenStream.Peek().nType != Token::TOKEN_OBJECT_END); + while (bContinue) + { + Object::Member member; + + // first the member name. save the token in case we have to throw an exception + const Token& tokenName = tokenStream.Peek(); + member.name = MatchExpectedToken(Token::TOKEN_STRING, tokenStream); + + // ...then the key/value separator... + MatchExpectedToken(Token::TOKEN_MEMBER_ASSIGN, tokenStream); + + // ...then the value itself (can be anything). + Parse(member.element, tokenStream); + + // try adding it to the object (this could throw) + try + { + object.Insert(member); + } + catch (Exception&) + { + // must be a duplicate name + std::string sMessage = "Duplicate object member token: " + member.name; + throw ParseException(sMessage, tokenName.locBegin, tokenName.locEnd); + } + + bContinue = (tokenStream.EOS() == false && + tokenStream.Peek().nType == Token::TOKEN_NEXT_ELEMENT); + if (bContinue) + MatchExpectedToken(Token::TOKEN_NEXT_ELEMENT, tokenStream); + } + + MatchExpectedToken(Token::TOKEN_OBJECT_END, tokenStream); +} + + +inline void Reader::Parse(Array& array, Reader::TokenStream& tokenStream) +{ + MatchExpectedToken(Token::TOKEN_ARRAY_BEGIN, tokenStream); + + bool bContinue = (tokenStream.EOS() == false && + tokenStream.Peek().nType != Token::TOKEN_ARRAY_END); + while (bContinue) + { + // ...what's next? could be anything + Array::iterator itElement = array.Insert(UnknownElement()); + UnknownElement& element = *itElement; + Parse(element, tokenStream); + + bContinue = (tokenStream.EOS() == false && + tokenStream.Peek().nType == Token::TOKEN_NEXT_ELEMENT); + if (bContinue) + MatchExpectedToken(Token::TOKEN_NEXT_ELEMENT, tokenStream); + } + + MatchExpectedToken(Token::TOKEN_ARRAY_END, tokenStream); +} + + +inline void Reader::Parse(String& string, Reader::TokenStream& tokenStream) +{ + string = MatchExpectedToken(Token::TOKEN_STRING, tokenStream); +} + + +inline void Reader::Parse(Number& number, Reader::TokenStream& tokenStream) +{ + const Token& currentToken = tokenStream.Peek(); // might need this later for throwing exception + const std::string& sValue = MatchExpectedToken(Token::TOKEN_NUMBER, tokenStream); + + std::istringstream iStr(sValue); + double dValue; + iStr >> dValue; + + // did we consume all characters in the token? + if (iStr.eof() == false) + { + std::string sMessage = "Unexpected character in NUMBER token: " + iStr.peek(); + throw ParseException(sMessage, currentToken.locBegin, currentToken.locEnd); + } + + number = dValue; +} + + +inline void Reader::Parse(Boolean& boolean, Reader::TokenStream& tokenStream) +{ + const std::string& sValue = MatchExpectedToken(Token::TOKEN_BOOLEAN, tokenStream); + boolean = (sValue == "true" ? true : false); +} + + +inline void Reader::Parse(Null&, Reader::TokenStream& tokenStream) +{ + MatchExpectedToken(Token::TOKEN_NULL, tokenStream); +} + + +inline const std::string& Reader::MatchExpectedToken(Token::Type nExpected, Reader::TokenStream& tokenStream) +{ + if (tokenStream.EOS()) + { + std::string sMessage = "Unexpected End of token stream"; + throw ParseException(sMessage, Location(), Location()); // nowhere to point to + } + + const Token& token = tokenStream.Get(); + if (token.nType != nExpected) + { + std::string sMessage = "Unexpected token: " + token.sValue; + throw ParseException(sMessage, token.locBegin, token.locEnd); + } + + return token.sValue; +} + +} // End namespace diff --git a/aegisub/libaegisub/include/libaegisub/cajun/visitor.h b/aegisub/libaegisub/include/libaegisub/cajun/visitor.h new file mode 100644 index 000000000..78b7b8367 --- /dev/null +++ b/aegisub/libaegisub/include/libaegisub/cajun/visitor.h @@ -0,0 +1,44 @@ +/********************************************** + +License: BSD +Project Webpage: http://cajun-jsonapi.sourceforge.net/ +Author: Terry Caton + +***********************************************/ + +#pragma once + +#include "elements.h" + +namespace json +{ + + +class Visitor +{ +public: + virtual ~Visitor() {} + + virtual void Visit(Array& array) = 0; + virtual void Visit(Object& object) = 0; + virtual void Visit(Number& number) = 0; + virtual void Visit(String& string) = 0; + virtual void Visit(Boolean& boolean) = 0; + virtual void Visit(Null& null) = 0; +}; + +class ConstVisitor +{ +public: + virtual ~ConstVisitor() {} + + virtual void Visit(const Array& array) = 0; + virtual void Visit(const Object& object) = 0; + virtual void Visit(const Number& number) = 0; + virtual void Visit(const String& string) = 0; + virtual void Visit(const Boolean& boolean) = 0; + virtual void Visit(const Null& null) = 0; +}; + + +} // End namespace diff --git a/aegisub/libaegisub/include/libaegisub/cajun/writer.h b/aegisub/libaegisub/include/libaegisub/cajun/writer.h new file mode 100644 index 000000000..e5c83c8ee --- /dev/null +++ b/aegisub/libaegisub/include/libaegisub/cajun/writer.h @@ -0,0 +1,57 @@ +/********************************************** + +License: BSD +Project Webpage: http://cajun-jsonapi.sourceforge.net/ +Author: Terry Caton + +***********************************************/ + +#pragma once + +#include "elements.h" +#include "visitor.h" + +namespace json +{ + +class Writer : private ConstVisitor +{ +public: + static void Write(const Object& object, std::ostream& ostr); + static void Write(const Array& array, std::ostream& ostr); + static void Write(const String& string, std::ostream& ostr); + static void Write(const Number& number, std::ostream& ostr); + static void Write(const Boolean& boolean, std::ostream& ostr); + static void Write(const Null& null, std::ostream& ostr); + static void Write(const UnknownElement& elementRoot, std::ostream& ostr); + +private: + Writer(std::ostream& ostr); + + template + static void Write_i(const ElementTypeT& element, std::ostream& ostr); + + void Write_i(const Object& object); + void Write_i(const Array& array); + void Write_i(const String& string); + void Write_i(const Number& number); + void Write_i(const Boolean& boolean); + void Write_i(const Null& null); + void Write_i(const UnknownElement& unknown); + + virtual void Visit(const Array& array); + virtual void Visit(const Object& object); + virtual void Visit(const Number& number); + virtual void Visit(const String& string); + virtual void Visit(const Boolean& boolean); + virtual void Visit(const Null& null); + + std::ostream& m_ostr; + int m_nTabDepth; +}; + + +} // End namespace + + +#include "writer.inl" diff --git a/aegisub/libaegisub/include/libaegisub/cajun/writer.inl b/aegisub/libaegisub/include/libaegisub/cajun/writer.inl new file mode 100644 index 000000000..f7b5e2b9e --- /dev/null +++ b/aegisub/libaegisub/include/libaegisub/cajun/writer.inl @@ -0,0 +1,153 @@ +/********************************************** + +License: BSD +Project Webpage: http://cajun-jsonapi.sourceforge.net/ +Author: Terry Caton + +***********************************************/ + +#include "writer.h" +#include +#include + +/* + +TODO: +* better documentation +* unicode character encoding + +*/ + +namespace json +{ + + +inline void Writer::Write(const UnknownElement& elementRoot, std::ostream& ostr) { Write_i(elementRoot, ostr); } +inline void Writer::Write(const Object& object, std::ostream& ostr) { Write_i(object, ostr); } +inline void Writer::Write(const Array& array, std::ostream& ostr) { Write_i(array, ostr); } +inline void Writer::Write(const Number& number, std::ostream& ostr) { Write_i(number, ostr); } +inline void Writer::Write(const String& string, std::ostream& ostr) { Write_i(string, ostr); } +inline void Writer::Write(const Boolean& boolean, std::ostream& ostr) { Write_i(boolean, ostr); } +inline void Writer::Write(const Null& null, std::ostream& ostr) { Write_i(null, ostr); } + + +inline Writer::Writer(std::ostream& ostr) : + m_ostr(ostr), + m_nTabDepth(0) +{} + +template +void Writer::Write_i(const ElementTypeT& element, std::ostream& ostr) +{ + Writer writer(ostr); + writer.Write_i(element); + ostr.flush(); // all done +} + +inline void Writer::Write_i(const Array& array) +{ + if (array.Empty()) + m_ostr << "[]"; + else + { + m_ostr << '[' << std::endl; + ++m_nTabDepth; + + Array::const_iterator it(array.Begin()), + itEnd(array.End()); + while (it != itEnd) { + m_ostr << std::string(m_nTabDepth, '\t'); + + Write_i(*it); + + if (++it != itEnd) + m_ostr << ','; + m_ostr << std::endl; + } + + --m_nTabDepth; + m_ostr << std::string(m_nTabDepth, '\t') << ']'; + } +} + +inline void Writer::Write_i(const Object& object) +{ + if (object.Empty()) + m_ostr << "{}"; + else + { + m_ostr << '{' << std::endl; + ++m_nTabDepth; + + Object::const_iterator it(object.Begin()), + itEnd(object.End()); + while (it != itEnd) { + m_ostr << std::string(m_nTabDepth, '\t') << '"' << it->name << "\" : "; + Write_i(it->element); + + if (++it != itEnd) + m_ostr << ','; + m_ostr << std::endl; + } + + --m_nTabDepth; + m_ostr << std::string(m_nTabDepth, '\t') << '}'; + } +} + +inline void Writer::Write_i(const Number& numberElement) +{ + m_ostr << std::setprecision(20) << numberElement.Value(); +} + +inline void Writer::Write_i(const Boolean& booleanElement) +{ + m_ostr << (booleanElement.Value() ? "true" : "false"); +} + +inline void Writer::Write_i(const String& stringElement) +{ + m_ostr << '"'; + + const std::string& s = stringElement.Value(); + std::string::const_iterator it(s.begin()), + itEnd(s.end()); + for (; it != itEnd; ++it) + { + switch (*it) + { + case '"': m_ostr << "\\\""; break; + case '\\': m_ostr << "\\\\"; break; + case '\b': m_ostr << "\\b"; break; + case '\f': m_ostr << "\\f"; break; + case '\n': m_ostr << "\\n"; break; + case '\r': m_ostr << "\\r"; break; + case '\t': m_ostr << "\\t"; break; + //case '\u': m_ostr << ""; break; ?? + default: m_ostr << *it; break; + } + } + + m_ostr << '"'; +} + +inline void Writer::Write_i(const Null& ) +{ + m_ostr << "null"; +} + +inline void Writer::Write_i(const UnknownElement& unknown) +{ + unknown.Accept(*this); +} + +inline void Writer::Visit(const Array& array) { Write_i(array); } +inline void Writer::Visit(const Object& object) { Write_i(object); } +inline void Writer::Visit(const Number& number) { Write_i(number); } +inline void Writer::Visit(const String& string) { Write_i(string); } +inline void Writer::Visit(const Boolean& boolean) { Write_i(boolean); } +inline void Writer::Visit(const Null& null) { Write_i(null); } + + + +} // End namespace diff --git a/aegisub/libaegisub/include/libaegisub/colour.h b/aegisub/libaegisub/include/libaegisub/colour.h new file mode 100644 index 000000000..fc35eeb5e --- /dev/null +++ b/aegisub/libaegisub/include/libaegisub/colour.h @@ -0,0 +1,31 @@ +// Copyright (c) 2010, Amar Takhar +// +// 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. +// +// $Id$ + +/// @file colour.h +/// @brief Colourspace class and functions. +/// @ingroup libaegisub + +#ifndef LAGI_PRE +#include +#endif + +// This file is a stub for now. + +namespace agi { + +typedef std::string Colour; + +} // namespace agi diff --git a/aegisub/src/include/aegisub/exception.h b/aegisub/libaegisub/include/libaegisub/exception.h similarity index 88% rename from aegisub/src/include/aegisub/exception.h rename to aegisub/libaegisub/include/libaegisub/exception.h index cce6d4f06..0b5514488 100644 --- a/aegisub/src/include/aegisub/exception.h +++ b/aegisub/libaegisub/include/libaegisub/exception.h @@ -36,13 +36,10 @@ #pragma once -#ifndef AGI_PRE -#include -#endif - +#include /// @see aegisub.h -namespace Aegisub { +namespace agi { /// @class Exception @@ -61,11 +58,11 @@ namespace Aegisub { /// When throwing exceptions, throw temporaries, not heap allocated /// objects. (C++ FAQ Lite 17.6.) I.e. this is correct: /// @code - /// throw Aegisub::SomeException(_T("Message for exception")); + /// throw Aegisub::SomeException("Message for exception"); /// @endcode /// This is wrong: /// @code - /// throw new Aegisub::SomeException(_T("Remember this is the wrong way!")); + /// throw new Aegisub::SomeException("Remember this is the wrong way!"); /// @endcode /// Exceptions must not be allocated on heap, because of the risks of /// leaking memory that way. (C++ FAQ Lite 17.8.) @@ -96,7 +93,7 @@ namespace Aegisub { class Exception { /// The error message - wxString message; + std::string message; /// An inner exception, the cause of this exception Exception *inner; @@ -109,7 +106,7 @@ namespace Aegisub { /// /// Deriving classes should always use this constructor for initialising /// the base class. - Exception(const wxString &msg, const Exception *inr = 0) + Exception(const std::string &msg, const Exception *inr = 0) : message(msg) , inner(0) { @@ -136,7 +133,7 @@ namespace Aegisub { /// @brief Get the outer exception error message /// @return Error message - virtual wxString GetMessage() const { return message; } + virtual std::string GetMessage() const { return message; } /// @brief Get error messages for chained exceptions /// @return Chained error message @@ -144,7 +141,7 @@ namespace Aegisub { /// If there is an inner exception, prepend its chained error message to /// our error message, with a CRLF between. Returns our own error message /// alone if there is no inner exception. - wxString GetChainedMessage() const { if (inner) return inner->GetChainedMessage() + _T("\r\n") + GetMessage(); else return GetMessage(); } + std::string GetChainedMessage() const { if (inner) return inner->GetChainedMessage() + "\r\n" + GetMessage(); else return GetMessage(); } /// @brief Exception class printable name /// @@ -155,16 +152,16 @@ namespace Aegisub { /// name for their sub-tree, further sub-classes add further levels, each /// level is separated by a slash. Characters allowed in the name for a /// level are [a-z0-9_]. - virtual const wxChar * GetName() const = 0; + virtual const char * GetName() const = 0; - /// @brief Convert to wxChar array as the error message + /// @brief Convert to char array as the error message /// @return The error message - operator const wxChar * () { return GetMessage().c_str(); } + operator const char * () { return GetMessage().c_str(); } - /// @brief Convert to wxString as the error message + /// @brief Convert to std::string as the error message /// @return The error message - operator wxString () { return GetMessage(); } + operator std::string () { return GetMessage(); } /// @brief Create a copy of the exception allocated on the heap /// @return A heap-allocated exception object @@ -180,7 +177,7 @@ namespace Aegisub { /// /// Intended for use in error messages where it can sometimes be convenient to /// indicate the exact position the error occurred at. -#define AG_WHERE _T(" (at ") _T(__FILE__) _T(":") _T(#__LINE__) _T(")") +#define AG_WHERE " (at " __FILE__ ":" #__LINE__ ")" @@ -194,8 +191,8 @@ namespace Aegisub { #define DEFINE_SIMPLE_EXCEPTION_NOINNER(classname,baseclass,displayname) \ class classname : public baseclass { \ public: \ - classname(const wxString &msg) : baseclass(msg) { } \ - const wxChar * GetName() const { return _T(displayname); } \ + classname(const std::string &msg) : baseclass(msg) { } \ + const char * GetName() const { return displayname; } \ Exception * Copy() const { return new classname(*this); } \ }; @@ -209,8 +206,8 @@ namespace Aegisub { #define DEFINE_SIMPLE_EXCEPTION(classname,baseclass,displayname) \ class classname : public baseclass { \ public: \ - classname(const wxString &msg, Exception *inner) : baseclass(msg, inner) { } \ - const wxChar * GetName() const { return _T(displayname); } \ + classname(const std::string &msg, Exception *inner) : baseclass(msg, inner) { } \ + const char * GetName() const { return displayname; } \ Exception * Copy() const { return new classname(*this); } \ }; @@ -224,7 +221,7 @@ namespace Aegisub { #define DEFINE_BASE_EXCEPTION_NOINNER(classname,baseclass) \ class classname : public baseclass { \ public: \ - classname(const wxString &msg) : baseclass(msg) { } \ + classname(const std::string &msg) : baseclass(msg) { } \ }; /// @brief Macro for declaring non-instantiable exception base classes with inner @@ -238,7 +235,7 @@ namespace Aegisub { #define DEFINE_BASE_EXCEPTION(classname,baseclass) \ class classname : public baseclass { \ public: \ - classname(const wxString &msg, Exception *inner) : baseclass(msg, inner) { } \ + classname(const std::string &msg, Exception *inner) : baseclass(msg, inner) { } \ }; @@ -291,10 +288,10 @@ namespace Aegisub { /// @brief Constructor, automatically builds the error message /// @param filename Name of the file that could not be found - FileNotFoundError(const wxString &filename) : FileNotAccessibleError(wxString(_T("File not found: ")) + filename) { } + FileNotFoundError(const std::string &filename) : FileNotAccessibleError(std::string("File not found: ") + filename) { } // Not documented, see Aegisub::Exception class - const wxChar * GetName() const { return _T("filesystem/not_accessible/not_found"); } + const char * GetName() const { return "filesystem/not_accessible/not_found"; } // Not documented, see Aegisub::Exception class Exception * Copy() const { return new FileNotFoundError(*this); } \ diff --git a/aegisub/libaegisub/include/libaegisub/io.h b/aegisub/libaegisub/include/libaegisub/io.h new file mode 100644 index 000000000..672adb764 --- /dev/null +++ b/aegisub/libaegisub/include/libaegisub/io.h @@ -0,0 +1,57 @@ +// Copyright (c) 2010, Amar Takhar +// +// 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. +// +// $Id$ + +/// @file io.h +/// @brief Public interface for IO methods. +/// @ingroup libaegisub + +#ifndef LAGI_PRE +#endif + +#include + +namespace agi { + namespace io { + +DEFINE_BASE_EXCEPTION_NOINNER(IOError, Exception) +DEFINE_SIMPLE_EXCEPTION_NOINNER(IOFatal, IOError, "io/fatal") + +/* +DEFINE_SIMPLE_EXCEPTION_NOINNER(IOAccess, IOError, "io/access") +DEFINE_SIMPLE_EXCEPTION_NOINNER(IONotFound, IOError, "io/notfound") +DEFINE_SIMPLE_EXCEPTION_NOINNER(IONotAFile, IOError, "io/file") +DEFINE_SIMPLE_EXCEPTION_NOINNER(IONotADirectory, IOError, "io/directory") +DEFINE_SIMPLE_EXCEPTION_NOINNER(IOAccessRead, IOError, "io/read") +DEFINE_SIMPLE_EXCEPTION_NOINNER(IOAccessWrite, IOError, "io/write") +*/ + +std::ifstream* Open(const std::string &file); + +class Save { + std::ofstream *fp; + const std::string file_name; + +public: + Save(const std::string& file); + ~Save(); + std::ofstream& Get(); +}; + + + } // namespace io +} // namespace agi + + diff --git a/aegisub/libaegisub/include/libaegisub/mru.h b/aegisub/libaegisub/include/libaegisub/mru.h new file mode 100644 index 000000000..a7f148fcf --- /dev/null +++ b/aegisub/libaegisub/include/libaegisub/mru.h @@ -0,0 +1,104 @@ +// Copyright (c) 2010, Amar Takhar +// +// 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. +// +// $Id$ + +/// @file mru.h +/// @brief Public interface for MRU (Most Recently Used) lists. +/// @ingroup libaegisub + +#ifndef LAGI_PRE +#include +#include + +#include "libaegisub/cajun/reader.h" +#include "libaegisub/cajun/writer.h" +#include "libaegisub/cajun/elements.h" +#endif + +#include + +namespace agi { + +DEFINE_BASE_EXCEPTION_NOINNER(MRUError,Exception) +DEFINE_SIMPLE_EXCEPTION_NOINNER(MRUErrorInvalidKey, MRUError, "mru/invalid") +DEFINE_SIMPLE_EXCEPTION_NOINNER(MRUErrorIndexOutOfRange, MRUError, "mru/invalid") + +/// @class MRUManager +/// @brief Most Recently Used (MRU) list handling +/// +/// Add() should be called anytime a file is opened, this will either add the +/// entry or update it if it already exists. +/// +/// If a file fails to open, Remove() should be called. +/// +class MRUManager { + +public: + /// @brief Map for time->value pairs. + /// @param int Last time loaded + /// @param std::string File or value that was last loaded. + typedef std::multimap > MRUListMap; + + /// @brief Constructor + /// @param config File to load MRU values from + MRUManager(const std::string &config, const std::string &default_config); + + /// Destructor + ~MRUManager(); + + /// @brief Add entry to the list. + /// @param key List name + /// @param entry Entry to add + /// @exception MRUErrorInvalidKey thrown when an invalid key is used. + void Add(const std::string &key, const std::string &entry); + + /// @brief Remove entry from the list. + /// @param key List name + /// @param entry Entry to add + /// @exception MRUErrorInvalidKey thrown when an invalid key is used. + void Remove(const std::string &key, const std::string &entry); + + /// @brief Return list + /// @param key List name + /// @exception MRUErrorInvalidKey thrown when an invalid key is used. + const MRUListMap* Get(const std::string &key); + + /// @brief Return A single entry in a list. + /// @param key List name + /// @param entry 0-base position of entry + /// @exception MRUErrorInvalidKey thrown when an invalid key is used. + const std::string GetEntry(const std::string &key, const int entry); + + /// Write MRU lists to disk. + void Flush(); + +private: + + /// Internal name of the config file, set during object construction. + const std::string config_name; + + /// @brief Map for MRUListMap values. + /// @param std::string Name + /// @param MRUListMap instance. + typedef std::map MRUMap; + + /// Internal MRUMap values. + MRUMap mru; + + void Load(const std::string &key, const json::Array& array); + inline void Prune(MRUListMap& map); +}; + +} // namespace agi diff --git a/aegisub/libaegisub/include/libaegisub/option.h b/aegisub/libaegisub/include/libaegisub/option.h new file mode 100644 index 000000000..6e9e8defb --- /dev/null +++ b/aegisub/libaegisub/include/libaegisub/option.h @@ -0,0 +1,120 @@ +// Copyright (c) 2010, Amar Takhar +// +// 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. +// +// $Id$ + +/// @file option.h +/// @brief Public interface for option values. +/// @ingroup libaegisub + + +#ifndef LAGI_PRE +#include + +#include "libaegisub/cajun/reader.h" +#include "libaegisub/cajun/writer.h" +#include "libaegisub/cajun/elements.h" +#endif + +#include +#include + +namespace agi { + +DEFINE_BASE_EXCEPTION_NOINNER(OptionError,Exception) +DEFINE_SIMPLE_EXCEPTION_NOINNER(OptionErrorNotFound, OptionError, "options/not_found") +DEFINE_SIMPLE_EXCEPTION_NOINNER(OptionErrorDuplicateKey, OptionError, "options/dump/duplicate") + + +/// This is a cool trick: make a class un-copyable, in this case we always want +/// to update our *original* map, this will ensure that it is always updated in +/// every situation. +class OptionValueMap : public std::map { +private: + OptionValueMap(const OptionValueMap& x); + OptionValueMap& operator=(const OptionValueMap& x); +public: + OptionValueMap() {}; +}; + + +class Options { + friend class PutOptionVisitor; + + /// Root json::Object, used for loading. + json::UnknownElement config_root; + + /// Internal OptionValueMap + OptionValueMap values; + + /// @brief Create option object. + /// @param path Path to store + json::Object CreateObject(std::string path); + + /// User config (file that will be written to disk) + const std::string config_file; + + /// Default config (for use when config file is/gets corrupted) + const std::string config_default; + + /// Whether the user (final) config has been loaded + bool config_loaded; + + /// @brief Load a config file into the Options object. + /// @param config Config to load. + void LoadConfig(std::istream& stream); + + +protected: + /// @brief Write an option to file. + /// @param[out] obj Parent object + /// @param[in] path Path option should be stored in. + /// @param[in] value Value to write. + static bool PutOption(json::Object &obj, const std::string &path, const json::UnknownElement &value); + + +public: + /// @brief Constructor + /// @param file User config that will be loaded from and written back to. + /// @param default_config Default configuration. + Options(const std::string &file, const std::string &default_config); + + /// Destructor + ~Options(); + + /// @brief Get an option by name. + /// @param name Option to get. + /// Get an option value object by name throw an internal exception if the option is not found. + OptionValue* Get(const std::string &name); + + /// @brief Next configuration file to load. + /// @param[in] src Stream to load from. + /// Load next config which will superceed any values from previous configs + /// can be called as many times as required, but only after ConfigDefault() and + /// before ConfigUser() + void ConfigNext(std::istream &stream); + + /// @brief Set user config file. + /// Set the user configuration file and read options from it, closes all possible + /// config file loading and sets the file to write to. + void ConfigUser(); + + /// Write the user configuration to disk, throws an exeption if something goes wrong. + void Flush(); + + /// Print internal option type, name and values. + void DumpAll(); +}; + +} // namespace agi diff --git a/aegisub/libaegisub/include/libaegisub/option_value.h b/aegisub/libaegisub/include/libaegisub/option_value.h new file mode 100644 index 000000000..06aa063b4 --- /dev/null +++ b/aegisub/libaegisub/include/libaegisub/option_value.h @@ -0,0 +1,199 @@ +// Copyright (c) 2010, Amar Takhar +// +// 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. +// +// $Id$ + +/// @file option_value.h +/// @brief Container for holding an actual option value. +/// @ingroup libaegisub + +#ifndef LAGI_PRE +#include +#include + +#include "libaegisub/cajun/reader.h" +#include "libaegisub/cajun/writer.h" +#include "libaegisub/cajun/elements.h" +#endif + +#include +#include + +namespace agi { + + +DEFINE_BASE_EXCEPTION_NOINNER(OptionValueError, Exception) +DEFINE_SIMPLE_EXCEPTION_NOINNER(OptionValueErrorNotFound, OptionValueError, "options/not_found") +DEFINE_SIMPLE_EXCEPTION_NOINNER(OptionValueErrorInvalidType, OptionValueError, "options/invalid_type") +DEFINE_SIMPLE_EXCEPTION_NOINNER(OptionValueErrorInvalidListType, OptionValueError, "options/array/invalid_type") + + +class OptionValue; +class ConfigVisitor; + + +/// @class OptionValueListener +/// Inherit from this class to get the proper type for the notification callback +/// signature. +class OptionValueListener { +public: + // (I might have messed up the syntax here. It's supposed to be a pointer + // to a member function of an OptionValueListener-derived class.) + typedef void (OptionValueListener::*ChangeEvent)(const OptionValue *option); +}; + + +/// @class OptionValue +/// Holds an actual option. +class OptionValue { + std::set listeners; + +protected: + void NotifyChanged(); + +public: + OptionValue() {}; + virtual ~OptionValue() {}; + + + /// Option type + /// No bitsets here. + enum OptionType { + Type_String = 0, ///< String + Type_Int = 1, ///< Integer + Type_Double = 2, ///< Double + Type_Colour = 3, ///< Colour + Type_Bool = 4, ///< Bool + Type_List_String = 100, ///< List of Strings + Type_List_Int = 101, ///< List of Integers + Type_List_Double = 102, ///< List of Doubles + Type_List_Colour = 103, ///< List of Colours + Type_List_Bool = 104 ///< List of Bools + }; + + virtual OptionType GetType() const = 0; + virtual std::string GetName() const = 0; + virtual bool IsDefault() const = 0; + virtual void Reset() = 0; + + virtual std::string GetString() const { throw OptionValueErrorInvalidType("Attempt to retrieve string from non-string value"); } + virtual int64_t GetInt() const { throw OptionValueErrorInvalidType("Attempt to retrieve int from non-int value"); } + virtual double GetDouble() const { throw OptionValueErrorInvalidType("Attempt to retrieve double from non-double value"); } + virtual Colour GetColour() const { throw OptionValueErrorInvalidType("Attempt to retrieve colour from non-colour value"); } + virtual bool GetBool() const { throw OptionValueErrorInvalidType("Attempt to retrieve bool from non-bool value"); } + + virtual void SetString(const std::string val) { throw OptionValueErrorInvalidType("Attempt to set string in a non-string value"); } + virtual void SetInt(const int64_t val) { throw OptionValueErrorInvalidType("Attempt to set int in a non-int value"); } + virtual void SetDouble(const double val) { throw OptionValueErrorInvalidType("Attempt to set double in a non-double value"); } + virtual void SetColour(const Colour val) { throw OptionValueErrorInvalidType("Attempt to set colour in a non-colour value"); } + virtual void SetBool(const bool val) { throw OptionValueErrorInvalidType("Attempt to set bool in a non-bool value"); } + + virtual std::string GetDefaultString() const { throw OptionValueErrorInvalidType("Attempt to retrieve string from non-string value"); } + virtual int64_t GetDefaultInt() const { throw OptionValueErrorInvalidType("Attempt to retrieve int from non-int value"); } + virtual double GetDefaultDouble() const { throw OptionValueErrorInvalidType("Attempt to retrieve double from non-double value"); } + virtual Colour GetDefaultColour() const { throw OptionValueErrorInvalidType("Attempt to retrieve colour from non-colour value"); } + virtual bool GetDefaultBool() const { throw OptionValueErrorInvalidType("Attempt to retrieve bool from non-bool value"); } + + + virtual void GetListString(std::vector &out) const { throw OptionValueErrorInvalidListType("Attempt to retrive string list from non-string list"); } + virtual void GetListInt(std::vector &out) const { throw OptionValueErrorInvalidListType("Attempt to retrive int list from non-int list"); } + virtual void GetListDouble(std::vector &out) const { throw OptionValueErrorInvalidListType("Attempt to retrive double list from non-double list"); } + virtual void GetListColour(std::vector &out) const { throw OptionValueErrorInvalidListType("Attempt to retrive colour list from non-colour list"); } + virtual void GetListBool(std::vector &out) const { throw OptionValueErrorInvalidListType("Attempt to retrive string bool from non-bool list"); } + + virtual void SetListString(const std::vector val) { throw OptionValueErrorInvalidListType("Attempt to set string list in a non-string list"); } + virtual void SetListInt(const std::vector val) { throw OptionValueErrorInvalidListType("Attempt to set int list in a non-int list"); } + virtual void SetListDouble(const std::vector val) { throw OptionValueErrorInvalidListType("Attempt to set double list in a non-double list"); } + virtual void SetListColour(const std::vector val) { throw OptionValueErrorInvalidListType("Attempt to set colour list in a non-colour list"); } + virtual void SetListBool(const std::vector val) { throw OptionValueErrorInvalidListType("Attempt to set string in a non-bool list"); } + + virtual void GetDefaultListString(std::vector &out) const { throw OptionValueErrorInvalidListType("Attempt to retrive string list from non-string list"); } + virtual void GetDefaultListInt(std::vector &out) const { throw OptionValueErrorInvalidListType("Attempt to retrive int list from non-int list"); } + virtual void GetDefaultListDouble(std::vector &out) const { throw OptionValueErrorInvalidListType("Attempt to retrive double list from non-double list"); } + virtual void GetDefaultListColour(std::vector &out) const { throw OptionValueErrorInvalidListType("Attempt to retrive colour list from non-colour list"); } + virtual void GetDefaultListBool(std::vector &out) const { throw OptionValueErrorInvalidListType("Attempt to retrive string bool from non-bool list"); } + + + void Subscribe(OptionValueListener*); + void Unsubscribe(OptionValueListener*); + + void Subscribe(OptionValueListener *listener, OptionValueListener::ChangeEvent handler); + void Unsubscribe(OptionValueListener *listener, OptionValueListener::ChangeEvent handler); + +}; + +#define CONFIG_OPTIONVALUE(type_name, type) \ + class OptionValue##type_name : public OptionValue { \ + type value; \ + type value_default; \ + std::string name; \ + public: \ + OptionValue##type_name(std::string member_name, type member_value): \ + value(member_value), name(member_name) {} \ + type Get##type_name() const { return value; } \ + void Set##type_name(const type new_val) { value = new_val; } \ + type GetDefault##type_name() const { return value_default; } \ + OptionType GetType() const { return OptionValue::Type_##type_name; } \ + std::string GetName() const { return name; } \ + void Reset() { value = value_default; } \ + bool IsDefault() const { return (value == value_default) ? 1 : 0; } \ + }; + +CONFIG_OPTIONVALUE(String, std::string) +CONFIG_OPTIONVALUE(Int, int64_t) +CONFIG_OPTIONVALUE(Double, double) +CONFIG_OPTIONVALUE(Colour, Colour) +CONFIG_OPTIONVALUE(Bool, bool) + + +class OptionValueList: public OptionValue { + friend class ConfigVisitor; + +protected: + OptionValueList() {}; + virtual ~OptionValueList() {}; + virtual void InsertString(const std::string val) { throw OptionValueErrorInvalidListType("Attempt to insert string in a non-string list"); } + virtual void InsertInt(const int64_t val) { throw OptionValueErrorInvalidListType("Attempt to insert int in a non-int list"); } + virtual void InsertDouble(const double val) { throw OptionValueErrorInvalidListType("Attempt to insert double in a non-double list"); } + virtual void InsertColour(const Colour val) { throw OptionValueErrorInvalidListType("Attempt insert set colour in a from non-colour list"); } + virtual void InsertBool(const bool val) { throw OptionValueErrorInvalidListType("Attempt to insert bool in a non-bool list"); } +}; + + +#define CONFIG_OPTIONVALUE_LIST(type_name, type) \ + class OptionValueList##type_name : public OptionValueList { \ + std::vector array; \ + std::vector array_default; \ + std::string name; \ + void Insert##type_name(const type val) { array.push_back(val); } \ + public: \ + virtual std::string GetString() const { return "";} \ + OptionValueList##type_name(std::string member_name): name(member_name) {} \ + void GetList##type_name(std::vector &out) const { out = array; } \ + void SetList##type_name(const std::vector val) { array = val;} \ + void GetDefaultList##type_name(std::vector &out) const { out = array_default; } \ + OptionType GetType() const { return OptionValue::Type_List_##type_name; } \ + std::string GetName() const { return name; } \ + void Reset() { array = array_default; } \ + bool IsDefault() const { return (array == array_default) ? 1 : 0; } \ + }; + + +CONFIG_OPTIONVALUE_LIST(String, std::string) +CONFIG_OPTIONVALUE_LIST(Int, int64_t) +CONFIG_OPTIONVALUE_LIST(Double, double) +CONFIG_OPTIONVALUE_LIST(Colour, Colour) +CONFIG_OPTIONVALUE_LIST(Bool, bool) + +} // namespace agi diff --git a/aegisub/libaegisub/include/libaegisub/util.h b/aegisub/libaegisub/include/libaegisub/util.h new file mode 100644 index 000000000..61ebb0c53 --- /dev/null +++ b/aegisub/libaegisub/include/libaegisub/util.h @@ -0,0 +1,36 @@ +// Copyright (c) 2010, Amar Takhar +// +// 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. +// +// $Id$ + +/// @file util.h +/// @brief Public interface for general utilities. +/// @ingroup libaegisub + +#ifndef LAGI_PRE +#include +#include +#endif + +#include + +namespace agi { + namespace util { + + const std::string DirName(const std::string& path); + void Rename(const std::string& from, const std::string& to); + + + } // namespace util +} // namespace agi diff --git a/aegisub/libaegisub/include/libaegisub/validator.h b/aegisub/libaegisub/include/libaegisub/validator.h new file mode 100644 index 000000000..f8b644049 --- /dev/null +++ b/aegisub/libaegisub/include/libaegisub/validator.h @@ -0,0 +1,83 @@ +// Copyright (c) 2010, Amar Takhar +// +// 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. +// +// $Id$ + +/// @file validator.h +/// @brief Input validation. +/// @ingroup libaegisub + +#ifndef LAGI_PRE +#endif + +#include + +namespace agi { + + +class Validator { +public: + /// Types supported. + enum ValidType { + Type_Any = 0, ///< Any (should be used instead of "String" + /// to accept any value for code clarity.) + Type_String = 1, ///< String + Type_Int = 2, ///< Integer + Type_Bool = 3, ///< Bool + Type_Colour = 4 ///< Colour + }; + + /// @brief Check value type. + /// @param value Value + /// @return true/false + /// + /// If the value type is "int" or "string" it will return true/false based on this alone. + /// This should validate against full values or single characters to make it suitable for input boxes. + virtual bool CheckType(std::string &value)=0; + + /// @brief Check value including constraints. + /// @param value Value + /// @return true/false + /// + /// Check value including bounds checking. + /// CheckType() should always be the first function called. + virtual bool Check(std::string &value)=0; + + /// @brief Return validation type. + /// @return Type + virtual ValidType GetType()=0; +}; + + +#define VALID_BASE(type_name) \ + class Valid##type_name : public Validator { \ + public: \ + ValidType GetType() { return Type_##type_name; } \ + bool CheckType(std::string &value); \ + virtual bool Check(std::string &value); \ + }; + +VALID_BASE(Any) +VALID_BASE(String) +VALID_BASE(Int) +VALID_BASE(Bool) + + +class ValidColour: public ValidString { +public: + ValidType GetType() { return Type_Colour; } + virtual bool Check(std::string &value); +}; + +} // namespace agi diff --git a/aegisub/libaegisub/lagi_pre.h b/aegisub/libaegisub/lagi_pre.h new file mode 100644 index 000000000..0d5b5f5f2 --- /dev/null +++ b/aegisub/libaegisub/lagi_pre.h @@ -0,0 +1,23 @@ +#define LAGI_PRE + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include "libaegisub/cajun/elements.h" +#include "libaegisub/cajun/reader.h" +#include "libaegisub/cajun/visitor.h" +#include "libaegisub/cajun/writer.h" + +#define LAGI_PRE diff --git a/aegisub/libaegisub/unix/access.cpp b/aegisub/libaegisub/unix/access.cpp new file mode 100644 index 000000000..5e3b69783 --- /dev/null +++ b/aegisub/libaegisub/unix/access.cpp @@ -0,0 +1,109 @@ +// Copyright (c) 2010, Amar Takhar +// +// 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. +// +// $Id$ + +/// @file access.cpp +/// @brief Unix access methods. +/// @ingroup libaegisub unix + +#ifndef LAGI_PRE +#include +#include + +#include +#include +#endif + +#include "libaegisub/util.h" + +namespace agi { + namespace acs { + + +void CheckFileRead(const std::string &file) { + Check(file, acs::FileRead); +} + + +void CheckFileWrite(const std::string &file) { + Check(file, acs::FileWrite); +} + + +void CheckDirRead(const std::string &dir) { + Check(dir, acs::DirRead); +} + + +void CheckDirWrite(const std::string &dir) { + Check(dir, acs::DirWrite); +} + + +void Check(const std::string &file, acs::Type type) { + struct stat file_stat; + int file_status; + + file_status = stat(file.c_str(), &file_stat); + + if (file_status != 0) { + switch (errno) { + case ENOENT: + throw AcsNotFound("File or path not found."); + break; + + case EACCES: + throw AcsAccess("Access Denied to file, path or path component."); + break; + + case EIO: + throw AcsFatal("Fatal I/O error occurred."); + break; + } + } + + switch (type) { + case FileRead: + case FileWrite: + if ((file_stat.st_mode & S_IFREG) == 0) + throw AcsNotAFile("Not a file."); + break; + + case DirRead: + case DirWrite: + if ((file_stat.st_mode & S_IFDIR) == 0) + throw AcsNotADirectory("Not a directory."); + break; + } + + switch (type) { + case DirRead: + case FileRead: + file_status = access(file.c_str(), R_OK); + if (file_status != 0) + throw AcsRead("File or directory is not readable."); + break; + + case DirWrite: + case FileWrite: + file_status = access(file.c_str(), W_OK); + if (file_status != 0) + throw AcsWrite("File or directory is not writable."); + break; + } +} + + } // namespace acs +} // namespace agi diff --git a/aegisub/libaegisub/unix/io.cpp b/aegisub/libaegisub/unix/io.cpp new file mode 100644 index 000000000..2cf64356c --- /dev/null +++ b/aegisub/libaegisub/unix/io.cpp @@ -0,0 +1,87 @@ +// Copyright (c) 2010, Amar Takhar +// +// 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. +// +// $Id$ + +/// @file io.cpp +/// @brief Unix IO methods. +/// @ingroup libaegisub unix + +#ifndef LAGI_PRE +#include +#include + +#include +#include +#endif + +#include "libaegisub/io.h" +#include "libaegisub/util.h" + + +namespace agi { + namespace io { + +std::ifstream* Open(const std::string &file) { + acs::CheckFileRead(file); + + std::ifstream *stream = new std::ifstream(file.c_str()); + + if (stream->fail()) + throw IOFatal("Unknown fatal error as occurred"); + + return stream; +} + + +Save::Save(const std::string& file): file_name(file) { + + const std::string pwd = util::DirName(file); + + acs::CheckDirWrite(pwd.c_str()); + + try { + acs::CheckFileWrite(file); + } catch (acs::AcsNotFound& e) { + // If the file doesn't exist we create a 0 byte file, this so so + // util::Rename will find it, and to let users know something went + // wrong by leaving a 0 byte file. + std::ofstream fp_touch(file.c_str()); + fp_touch.close(); + } + + /// @todo This is a temp hack, proper implementation needs to come after + /// Windows support is added. The code in the destructor needs fixing + /// as well. + const std::string tmp = file + "_tmp"; + + // This will open to file.XXXX. (tempfile) + fp = new std::ofstream(tmp.c_str()); +} + +Save::~Save() { + + const std::string tmp(file_name + "_tmp"); + util::Rename(tmp, file_name); + delete fp; + fp = 0; // to avoid any silly errors. +} + +std::ofstream& Save::Get() { + return *fp; +} + + + } // namespace io +} // namespace agi diff --git a/aegisub/libaegisub/unix/util.cpp b/aegisub/libaegisub/unix/util.cpp new file mode 100644 index 000000000..565f9aad3 --- /dev/null +++ b/aegisub/libaegisub/unix/util.cpp @@ -0,0 +1,59 @@ +// Copyright (c) 2010, Amar Takhar +// +// 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. +// +// $Id$ + +/// @file util.cpp +/// @brief Unix utility methods. +/// @ingroup libaegisub unix + +#ifndef LAGI_PRE +#include +#include + +#include +#include +#endif + +#include +#include "libaegisub/util.h" + +namespace agi { + namespace util { + + +const std::string DirName(const std::string& path) { + if (path.find('/') == std::string::npos) { + const std::string cwd("."); + return cwd; + } + + const std::string stripped = path.substr(0, path.rfind("/")+1); + return stripped; +} + +void Rename(const std::string& from, const std::string& to) { + acs::CheckFileWrite(from); + + try { + acs::CheckFileWrite(to); + } catch (acs::AcsNotFound& e) { + acs::CheckDirWrite(DirName(to)); + } + + rename(from.c_str(), to.c_str()); +} + + } // namespace io +} // namespace agi diff --git a/aegisub/libaegisub/windows/access.cpp b/aegisub/libaegisub/windows/access.cpp new file mode 100644 index 000000000..4264aefd6 --- /dev/null +++ b/aegisub/libaegisub/windows/access.cpp @@ -0,0 +1,118 @@ +// Copyright (c) 2010, Amar Takhar +// +// 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. +// +// $Id$ + +/// @file access.cpp +/// @brief Windows access methods. +/// @ingroup libaegisub windows + +#ifndef LAGI_PRE +#include +#include +#include + +#include +#include +#endif + +#ifndef R_OK +#define R_OK 04 +#endif +#ifndef W_OK +#define W_OK 02 +#endif + +#pragma warning(disable: 4996) + + +#include "libaegisub/util.h" + +namespace agi { + namespace acs { + +void CheckFileRead(const std::string &file) { + Check(file, acs::FileRead); +} + + +void CheckFileWrite(const std::string &file) { + Check(file, acs::FileWrite); +} + + +void CheckDirRead(const std::string &dir) { + Check(dir, acs::DirRead); +} + + +void CheckDirWrite(const std::string &dir) { + Check(dir, acs::DirWrite); +} + + +void Check(const std::string &file, acs::Type type) { + struct stat file_stat; + int file_status; + + file_status = stat(file.c_str(), &file_stat); + + if (file_status != 0) { + switch (errno) { + case ENOENT: + throw AcsNotFound("File or path not found."); + break; + + case EACCES: + throw AcsAccess("Access Denied to file, path or path component."); + break; + + case EIO: + throw AcsFatal("Fatal I/O error occurred."); + break; + } + } + + switch (type) { + case FileRead: + case FileWrite: + if ((file_stat.st_mode & S_IFREG) == 0) + throw AcsNotAFile("Not a file."); + break; + + case DirRead: + case DirWrite: + if ((file_stat.st_mode & S_IFDIR) == 0) + throw AcsNotADirectory("Not a directory."); + break; + } + + switch (type) { + case DirRead: + case FileRead: + file_status = access(file.c_str(), R_OK); + if (file_status != 0) + throw AcsRead("File or directory is not readable."); + break; + + case DirWrite: + case FileWrite: + file_status = access(file.c_str(), W_OK); + if (file_status != 0) + throw AcsWrite("File or directory is not writable."); + break; + } +} + } +} diff --git a/aegisub/libaegisub/windows/io.cpp b/aegisub/libaegisub/windows/io.cpp new file mode 100644 index 000000000..8a21a2546 --- /dev/null +++ b/aegisub/libaegisub/windows/io.cpp @@ -0,0 +1,89 @@ +// Copyright (c) 2010, Amar Takhar +// +// 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. +// +// $Id$ + +/// @file io.cpp +/// @brief Windows IO methods. +/// @ingroup libaegisub windows + +#ifndef LAGI_PRE +#include +#include + +#include +#include +#endif + +#include "libaegisub/io.h" +#include "libaegisub/util.h" + + +namespace agi { + namespace io { + +std::ifstream* Open(const std::string &file) { + acs::CheckFileRead(file); + + std::ifstream *stream = new std::ifstream(file.c_str()); + + if (stream->fail()) { + delete stream; + throw IOFatal("Unknown fatal error as occurred"); + } + + return stream; +} + + +Save::Save(const std::string& file): file_name(file) { + + const std::string pwd = util::DirName(file); + + acs::CheckDirWrite(pwd.c_str()); + + try { + acs::CheckFileWrite(file); + } catch (acs::AcsNotFound&) { + // If the file doesn't exist we create a 0 byte file, this so so + // util::Rename will find it, and to let users know something went + // wrong by leaving a 0 byte file. + std::ofstream fp_touch(file.c_str()); + fp_touch.close(); + } + + /// @todo This is a temp hack, proper implementation needs to come after + /// Windows support is added. The code in the destructor needs fixing + /// as well. + const std::string tmp = file + "_tmp"; + + // This will open to file.XXXX. (tempfile) + fp = new std::ofstream(tmp.c_str()); +} + +Save::~Save() { + + const std::string tmp(file_name + "_tmp"); + util::Rename(tmp, file_name); + delete fp; + fp = 0; // to avoid any silly errors. +} + +std::ofstream& Save::Get() { + return *fp; +} + + + } // namespace io +} // namespace agi diff --git a/aegisub/libaegisub/windows/lagi_pre.cpp b/aegisub/libaegisub/windows/lagi_pre.cpp new file mode 100644 index 000000000..e69de29bb diff --git a/aegisub/libaegisub/windows/util.cpp b/aegisub/libaegisub/windows/util.cpp new file mode 100644 index 000000000..4358e7ff6 --- /dev/null +++ b/aegisub/libaegisub/windows/util.cpp @@ -0,0 +1,59 @@ +// Copyright (c) 2010, Amar Takhar +// +// 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. +// +// $Id$ + +/// @file util.cpp +/// @brief Windows utility methods. +/// @ingroup libaegisub windows + +#ifndef LAGI_PRE +#include +#include + +#include +#include +#endif + +#include +#include "libaegisub/util.h" + +namespace agi { + namespace util { + + +const std::string DirName(const std::string& path) { + if (path.find('/') == std::string::npos) { + const std::string cwd("."); + return cwd; + } + + const std::string stripped = path.substr(0, path.rfind("/")+1); + return stripped; +} + +void Rename(const std::string& from, const std::string& to) { + acs::CheckFileWrite(from); + + try { + acs::CheckFileWrite(to); + } catch (acs::AcsNotFound&) { + acs::CheckDirWrite(DirName(to)); + } + + rename(from.c_str(), to.c_str()); +} + + } // namespace io +} // namespace agi diff --git a/aegisub/src/Makefile.am b/aegisub/src/Makefile.am index 3e99c0d01..b174e2ce1 100644 --- a/aegisub/src/Makefile.am +++ b/aegisub/src/Makefile.am @@ -23,10 +23,10 @@ SUBDIRS = \ libresrc \ $(libosxutil_subdir) -AM_CXXFLAGS += -DAEGISUB -Iinclude -I../libffms/include @WX_CPPFLAGS@ @OPENMP_CXXFLAGS@ @LIBAVFORMAT_CFLAGS@ @LIBAVCODEC_CFLAGS@ @LIBSWSCALE_CFLAGS@ @LIBAVUTIL_CFLAGS@ +AM_CXXFLAGS += -DAEGISUB -Iinclude -I../libffms/include -I../libaegisub/include @WX_CPPFLAGS@ @OPENMP_CXXFLAGS@ @LIBAVFORMAT_CFLAGS@ @LIBAVCODEC_CFLAGS@ @LIBSWSCALE_CFLAGS@ @LIBAVUTIL_CFLAGS@ bin_PROGRAMS = aegisub-2.2 -aegisub_2_2_LDADD = libresrc/libresrc.a $(libosxutil_lib) +aegisub_2_2_LDADD = libresrc/libresrc.a $(libosxutil_lib) -L../libaegisub -laegisub-2.2 aegisub_2_2_CPPFLAGS = @FREETYPE_CFLAGS@ aegisub_2_2_LDFLAGS = @DEBUG_FLAGS@ @PROFILE_FLAGS@ @GL_LIBS@ @PTHREAD_LIBS@ @WX_LIBS@ @ICONV_LDFLAGS@ $(libosxutil_ldflags) @CCMALLOC_LDFLAGS@ @EFENCE_LDFLAGS@ LIBS += @FREETYPE_LIBS@ @FONTCONFIG_LIBS@ @CCMALLOC_LIBS@ @@ -222,6 +222,7 @@ aegisub_2_2_SOURCES = \ charset_conv.cpp \ colorspace.cpp \ colour_button.cpp \ + compat.cpp \ dialog_about.cpp \ dialog_attachments.cpp \ dialog_automation.cpp \ @@ -232,7 +233,6 @@ aegisub_2_2_SOURCES = \ dialog_fonts_collector.cpp \ dialog_jumpto.cpp \ dialog_kara_timing_copy.cpp \ - dialog_options.cpp \ dialog_paste_over.cpp \ dialog_progress.cpp \ dialog_properties.cpp \ @@ -274,6 +274,7 @@ aegisub_2_2_SOURCES = \ mythes.cxx \ options.cpp \ plugin_manager.cpp \ + preferences.cpp \ scintilla_text_ctrl.cpp \ spellchecker.cpp \ spline.cpp \ diff --git a/aegisub/src/agi_pre.h b/aegisub/src/agi_pre.h index cd97a4757..2e2557e1f 100644 --- a/aegisub/src/agi_pre.h +++ b/aegisub/src/agi_pre.h @@ -243,10 +243,6 @@ #undef _CRT_SECURE_NO_WARNINGS #endif -/////////////////// -// Aegisub headers -#include "include/aegisub/exception.h" - #endif // C++ #endif // AGI_PRE_H diff --git a/aegisub/src/ass_entry.h b/aegisub/src/ass_entry.h index f2d65a420..4f511c049 100644 --- a/aegisub/src/ass_entry.h +++ b/aegisub/src/ass_entry.h @@ -42,10 +42,9 @@ // Headers #ifndef AGI_PRE #include - -#include "include/aegisub/exception.h" #endif +#include ////////////// // Prototypes @@ -81,18 +80,18 @@ namespace Aegisub { /// @brief DOCME /// /// DOCME - class InvalidMarginIdError : public InternalError { + class InvalidMarginIdError : public agi::InternalError { public: /// @brief DOCME /// @return /// - InvalidMarginIdError() : InternalError(_T("Invalid margin id"), 0) { } + InvalidMarginIdError() : InternalError("Invalid margin id", 0) { } /// @brief DOCME /// @return /// - const wxChar *GetName() { return _T("internal_error/invalid_margin_id"); } + const char *GetName() { return "internal_error/invalid_margin_id"; } }; }; diff --git a/aegisub/src/ass_file.cpp b/aegisub/src/ass_file.cpp index 8be39161f..94c98228e 100644 --- a/aegisub/src/ass_file.cpp +++ b/aegisub/src/ass_file.cpp @@ -50,6 +50,8 @@ #include "ass_file.h" #include "ass_override.h" #include "ass_style.h" +#include "compat.h" +#include "main.h" #include "options.h" #include "subtitle_format.h" #include "text_file_reader.h" @@ -794,7 +796,7 @@ AssStyle *AssFile::GetStyle(wxString name) { /// @brief Adds file name to list of recent /// @param file void AssFile::AddToRecent(wxString file) { - Options.AddToRecentList(file,_T("Recent sub")); + AegisubApp::Get()->mru->Add("Subtitle", STD_STR(file)); } /// @brief List of supported wildcards @@ -861,7 +863,7 @@ void AssFile::StackPush(wxString desc) { for (std::list::iterator cur=UndoStack.begin();cur!=UndoStack.end();cur++) { n++; } - int depth = Options.AsInt(_T("Undo levels")); + int depth = OPT_GET("Limits/Undo Levels")->GetInt(); while (n > depth) { delete UndoStack.front(); UndoStack.pop_front(); diff --git a/aegisub/src/ass_file.h b/aegisub/src/ass_file.h index 30d585de8..49f39a95d 100644 --- a/aegisub/src/ass_file.h +++ b/aegisub/src/ass_file.h @@ -113,7 +113,7 @@ public: void Save(wxString file,bool setfilename=false,bool addToRecent=true,const wxString encoding=_T("")); // Save to a file. Pass true to second argument if this isn't a copy void SaveMemory(std::vector &dst,const wxString encoding=_T("")); // Save to a memory string void Export(wxString file); // Saves exported copy, with effects applied - void AddToRecent(wxString file); // Adds file name to list of recently opened files + void AddToRecent(wxString file); // Adds file name to list of recently opened files bool CanSave(); // Returns true if the file can be saved in its current format static wxString GetWildcardList(int mode); // Returns the list of wildcards supported (0 = open, 1 = save, 2 = export) diff --git a/aegisub/src/audio_box.cpp b/aegisub/src/audio_box.cpp index 93c6887fe..3cea98e7f 100644 --- a/aegisub/src/audio_box.cpp +++ b/aegisub/src/audio_box.cpp @@ -54,6 +54,7 @@ #include "frame_main.h" #include "hotkeys.h" #include "libresrc/libresrc.h" +#include "main.h" #include "options.h" #include "toggle_bitmap.h" #include "tooltip_manager.h" @@ -97,7 +98,7 @@ wxPanel(parent,-1,wxDefaultPosition,wxDefaultSize,wxTAB_TRAVERSAL|wxBORDER_RAISE VolumeBar = new wxSlider(this,Audio_Volume,50,0,100,wxDefaultPosition,wxSize(-1,20),wxSL_VERTICAL|wxSL_BOTH|wxSL_INVERSE); VolumeBar->PushEventHandler(new FocusEvent()); VolumeBar->SetToolTip(_("Audio Volume")); - bool link = Options.AsBool(_T("Audio Link")); + bool link = OPT_GET("Audio/Link")->GetBool(); if (link) { VolumeBar->SetValue(VerticalZoom->GetValue()); VolumeBar->Enable(false); @@ -177,23 +178,23 @@ wxPanel(parent,-1,wxDefaultPosition,wxDefaultSize,wxTAB_TRAVERSAL|wxBORDER_RAISE AutoCommit = new ToggleBitmap(this,Audio_Check_AutoCommit,GETIMAGE(toggle_audio_autocommit_24),wxSize(30,-1)); AutoCommit->SetToolTip(_("Automatically commit all changes")); - AutoCommit->SetValue(Options.AsBool(_T("Audio Autocommit"))); + AutoCommit->SetValue(OPT_GET("Audio/Auto/Commit")->GetBool()); ButtonSizer->Add(AutoCommit,0,wxRIGHT | wxALIGN_CENTER | wxEXPAND,0); NextCommit = new ToggleBitmap(this,Audio_Check_NextCommit,GETIMAGE(toggle_audio_nextcommit_24),wxSize(30,-1)); NextCommit->SetToolTip(_("Auto goes to next line on commit")); - NextCommit->SetValue(Options.AsBool(_T("Audio Next Line on Commit"))); + NextCommit->SetValue(OPT_GET("Audio/Next Line on Commit")->GetBool()); ButtonSizer->Add(NextCommit,0,wxRIGHT | wxALIGN_CENTER | wxEXPAND,0); AutoScroll = new ToggleBitmap(this,Audio_Check_AutoGoto,GETIMAGE(toggle_audio_autoscroll_24),wxSize(30,-1)); AutoScroll->SetToolTip(_("Auto scrolls audio display to selected line")); - AutoScroll->SetValue(Options.AsBool(_T("Audio Autoscroll"))); + AutoScroll->SetValue(OPT_GET("Audio/Auto/Scroll")->GetBool()); ButtonSizer->Add(AutoScroll,0,wxRIGHT | wxALIGN_CENTER | wxEXPAND,0); SpectrumMode = new ToggleBitmap(this,Audio_Check_Spectrum,GETIMAGE(toggle_audio_spectrum_24),wxSize(30,-1)); SpectrumMode->SetToolTip(_("Spectrum analyzer mode")); - SpectrumMode->SetValue(Options.AsBool(_T("Audio Spectrum"))); + SpectrumMode->SetValue(OPT_GET("Audio/Spectrum")->GetBool()); ButtonSizer->Add(SpectrumMode,0,wxRIGHT | wxALIGN_CENTER | wxEXPAND,0); MedusaMode = new ToggleBitmap(this,Audio_Check_Medusa,GETIMAGE(toggle_audio_medusa_24),wxSize(30,-1)); MedusaMode->SetToolTip(_("Enable Medusa-Style Timing Shortcuts")); - MedusaMode->SetValue(Options.AsBool(_T("Audio Medusa Timing Hotkeys"))); + MedusaMode->SetValue(OPT_GET("Audio/Medusa Timing Hotkeys")->GetBool()); ButtonSizer->Add(MedusaMode,0,wxRIGHT | wxALIGN_CENTER | wxEXPAND,0); ButtonSizer->AddStretchSpacer(1); @@ -383,8 +384,7 @@ void AudioBox::OnVerticalLink(wxCommandEvent &event) { } VolumeBar->Enable(!VerticalLink->GetValue()); - Options.SetBool(_T("Audio Link"),VerticalLink->GetValue()); - Options.Save(); + OPT_SET("Audio/Link")->SetBool(VerticalLink->GetValue()); } @@ -419,8 +419,7 @@ void AudioBox::OnSash(wxSashEvent& event) { Sash->GetParent()->Layout(); // Store new size - Options.SetInt(_T("Audio Display Height"),h); - Options.Save(); + OPT_SET("Audio/Display Height")->SetInt(h); // Fix layout frameMain->Freeze(); @@ -683,8 +682,7 @@ void AudioBox::OnGoto(wxCommandEvent &event) { /// void AudioBox::OnAutoGoto(wxCommandEvent &event) { audioDisplay->SetFocus(); - Options.SetBool(_T("Audio Autoscroll"),AutoScroll->GetValue()); - Options.Save(); + OPT_SET("Audio/Auto/Scroll")->SetBool(AutoScroll->GetValue()); } @@ -694,8 +692,7 @@ void AudioBox::OnAutoGoto(wxCommandEvent &event) { /// void AudioBox::OnAutoCommit(wxCommandEvent &event) { audioDisplay->SetFocus(); - Options.SetBool(_T("Audio Autocommit"),AutoCommit->GetValue()); - Options.Save(); + OPT_SET("Audio/Auto/Commit")->SetBool(AutoCommit->GetValue()); } @@ -705,8 +702,7 @@ void AudioBox::OnAutoCommit(wxCommandEvent &event) { /// void AudioBox::OnNextLineCommit(wxCommandEvent &event) { audioDisplay->SetFocus(); - Options.SetBool(_T("Audio Next Line on Commit"),NextCommit->GetValue()); - Options.Save(); + OPT_SET("Audio/Next Line on Commit")->SetBool(NextCommit->GetValue()); } @@ -716,8 +712,7 @@ void AudioBox::OnNextLineCommit(wxCommandEvent &event) { /// void AudioBox::OnMedusaMode(wxCommandEvent &event) { audioDisplay->SetFocus(); - Options.SetBool(_T("Audio Medusa Timing Hotkeys"),MedusaMode->GetValue()); - Options.Save(); + OPT_SET("Audio/Medusa Timing Hotkeys")->SetBool(MedusaMode->GetValue()); frameMain->SetAccelerators(); } @@ -727,8 +722,7 @@ void AudioBox::OnMedusaMode(wxCommandEvent &event) { /// @param event /// void AudioBox::OnSpectrumMode(wxCommandEvent &event) { - Options.SetBool(_T("Audio Spectrum"),SpectrumMode->GetValue()); - Options.Save(); + OPT_SET("Audio/Spectrum")->SetBool(SpectrumMode->GetValue()); audioDisplay->UpdateImage(false); audioDisplay->SetFocus(); audioDisplay->Refresh(false); diff --git a/aegisub/src/audio_display.cpp b/aegisub/src/audio_display.cpp index e45234bde..46e945b2c 100644 --- a/aegisub/src/audio_display.cpp +++ b/aegisub/src/audio_display.cpp @@ -55,8 +55,10 @@ #endif #include "audio_provider_stream.h" #include "colorspace.h" +#include "compat.h" #include "fft.h" #include "hotkeys.h" +#include "main.h" #include "options.h" #include "standard_paths.h" #include "subs_edit_box.h" @@ -79,7 +81,7 @@ /// @brief Constructor /// @param parent AudioDisplay::AudioDisplay(wxWindow *parent) -: wxWindow (parent, -1, wxDefaultPosition, wxSize(200,Options.AsInt(_T("Audio Display Height"))), AudioDisplayWindowStyle , _T("Audio Display")) +: wxWindow (parent, -1, wxDefaultPosition, wxSize(200,OPT_GET("Audio/Display Height")->GetInt()), AudioDisplayWindowStyle , _T("Audio Display")) { // Set variables origImage = NULL; @@ -118,7 +120,7 @@ AudioDisplay::AudioDisplay(wxWindow *parent) // Init UpdateTimer.SetOwner(this,Audio_Update_Timer); GetClientSize(&w,&h); - h -= Options.AsBool(_T("Audio Draw Timeline")) ? 20 : 0; + h -= OPT_GET("Audio/Display/Draw/Timeline")->GetBool() ? 20 : 0; SetSamplesPercent(50,false); // Set cursor @@ -188,7 +190,7 @@ void AudioDisplay::DoUpdateImage() { bool weak = needImageUpdateWeak; // Prepare bitmap - int timelineHeight = Options.AsBool(_T("Audio Draw Timeline")) ? 20 : 0; + int timelineHeight = OPT_GET("Audio/Display/Draw/Timeline")->GetBool() ? 20 : 0; int displayH = h+timelineHeight; if (origImage) { if (origImage->GetWidth() != w || origImage->GetHeight() != displayH) { @@ -198,9 +200,9 @@ void AudioDisplay::DoUpdateImage() { } // Options - bool draw_boundary_lines = Options.AsBool(_T("Audio Draw Secondary Lines")); - bool draw_selection_background = Options.AsBool(_T("Audio Draw Selection Background")); - bool drawKeyframes = Options.AsBool(_T("Audio Draw Keyframes")); + bool draw_boundary_lines = OPT_GET("Audio/Display/Draw/Secondary Lines")->GetBool(); + bool draw_selection_background = OPT_GET("Audio/Display/Draw/Selection Background")->GetBool(); + bool drawKeyframes = OPT_GET("Audio/Display/Draw/Keyframes")->GetBool(); // Invalid dimensions if (w == 0 || displayH == 0) return; @@ -210,7 +212,7 @@ void AudioDisplay::DoUpdateImage() { // Is spectrum? bool spectrum = false; - if (provider && Options.AsBool(_T("Audio Spectrum"))) { + if (provider && OPT_GET("Audio/Spectrum")->GetBool()) { spectrum = true; } @@ -220,7 +222,7 @@ void AudioDisplay::DoUpdateImage() { // Black background dc.SetPen(*wxTRANSPARENT_PEN); - dc.SetBrush(wxBrush(Options.AsColour(_T("Audio Background")))); + dc.SetBrush(wxBrush(lagi_wxColour(OPT_GET("Colour/Audio Display/Background/Background")->GetColour()))); dc.DrawRectangle(0,0,w,h); // Selection position @@ -254,8 +256,8 @@ void AudioDisplay::DoUpdateImage() { // Draw selection bg if (hasSel && drawSelStart < drawSelEnd && draw_selection_background) { - if (NeedCommit && !karaoke->enabled) dc.SetBrush(wxBrush(Options.AsColour(_T("Audio Selection Background Modified")))); - else dc.SetBrush(wxBrush(Options.AsColour(_T("Audio Selection Background")))); + if (NeedCommit && !karaoke->enabled) dc.SetBrush(wxBrush(lagi_wxColour(OPT_GET("Colour/Audio Display/Background/Selection Modified")->GetColour()))); + else dc.SetBrush(wxBrush(lagi_wxColour(OPT_GET("Colour/Audio Display/Background/Background")->GetColour()))); dc.DrawRectangle(drawSelStart,0,drawSelEnd-drawSelStart,h); } @@ -279,7 +281,7 @@ void AudioDisplay::DoUpdateImage() { int64_t start = Position*samples; int rate = provider->GetSampleRate(); int pixBounds = rate / samples; - dc.SetPen(wxPen(Options.AsColour(_T("Audio Seconds Boundaries")),1,wxDOT)); + dc.SetPen(wxPen(lagi_wxColour(OPT_GET("Colour/Audio Display/Seconds Boundaries")->GetColour()),1,wxDOT)); if (pixBounds >= 8) { for (int x=0;xGetBool()) { if (VideoContext::Get()->IsLoaded()) { - dc.SetPen(wxPen(Options.AsColour(_T("Audio Play Cursor")),2,wxLONG_DASH)); + dc.SetPen(wxPen(lagi_wxColour(OPT_GET("Colour/Audio Display/Play Cursor")->GetColour()))); int x = GetXAtMS(VFR_Output.GetTimeAtFrame(VideoContext::Get()->GetFrameN())); dc.DrawLine(x,0,x,h); } @@ -310,9 +312,9 @@ void AudioDisplay::DoUpdateImage() { // Draw boundaries if (true) { // Draw start boundary - int selWidth = Options.AsInt(_T("Audio Line boundaries Thickness")); - dc.SetPen(wxPen(Options.AsColour(_T("Audio Line boundary start")))); - dc.SetBrush(wxBrush(Options.AsColour(_T("Audio Line boundary start")))); + int selWidth = OPT_GET("Audio/Line Boundaries Thickness")->GetInt(); + dc.SetPen(wxPen(lagi_wxColour(OPT_GET("Colour/Audio Display/Line boundary Start")->GetColour()))); + dc.SetBrush(wxBrush(lagi_wxColour(OPT_GET("Colour/Audio Display/Line boundary Start")->GetColour()))); dc.DrawRectangle(lineStart-selWidth/2+1,0,selWidth,h); wxPoint points1[3] = { wxPoint(lineStart,0), wxPoint(lineStart+10,0), wxPoint(lineStart,10) }; wxPoint points2[3] = { wxPoint(lineStart,h-1), wxPoint(lineStart+10,h-1), wxPoint(lineStart,h-11) }; @@ -320,8 +322,8 @@ void AudioDisplay::DoUpdateImage() { dc.DrawPolygon(3,points2); // Draw end boundary - dc.SetPen(wxPen(Options.AsColour(_T("Audio Line boundary end")))); - dc.SetBrush(wxBrush(Options.AsColour(_T("Audio Line boundary end")))); + dc.SetPen(wxPen(lagi_wxColour(OPT_GET("Colour/Audio Display/Line boundary End")->GetColour()))); + dc.SetBrush(wxBrush(lagi_wxColour(OPT_GET("Colour/Audio Display/Line boundary End")->GetColour()))); dc.DrawRectangle(lineEnd-selWidth/2+1,0,selWidth,h); wxPoint points3[3] = { wxPoint(lineEnd,0), wxPoint(lineEnd-10,0), wxPoint(lineEnd,10) }; wxPoint points4[3] = { wxPoint(lineEnd,h-1), wxPoint(lineEnd-10,h-1), wxPoint(lineEnd,h-11) }; @@ -333,11 +335,11 @@ void AudioDisplay::DoUpdateImage() { if (hasKaraoke) { try { // Prepare - wxPen curPen(Options.AsColour(_T("Audio Syllable boundaries")),1,wxDOT); + wxPen curPen(lagi_wxColour(OPT_GET("Colour/Audio Display/Syllable Boundaries")->GetColour()),1,wxDOT); dc.SetPen(curPen); wxFont curFont(9,wxFONTFAMILY_DEFAULT,wxFONTSTYLE_NORMAL,wxFONTWEIGHT_BOLD,false,_T("Verdana"),wxFONTENCODING_SYSTEM); dc.SetFont(curFont); - if (!spectrum) dc.SetTextForeground(Options.AsColour(_T("Audio Syllable text"))); + if (!spectrum) dc.SetTextForeground(lagi_wxColour(OPT_GET("Colour/Audio Display/Syllable Text")->GetColour())); else dc.SetTextForeground(wxColour(255,255,255)); size_t karn = karaoke->syllables.size(); int64_t pos1,pos2; @@ -403,18 +405,18 @@ void AudioDisplay::DoUpdateImage() { /// Draws markers for inactive lines, eg. the previous line, per configuration. void AudioDisplay::DrawInactiveLines(wxDC &dc) { // Check if there is anything to do - int shadeType = Options.AsInt(_T("Audio Inactive Lines Display Mode")); + int shadeType = OPT_GET("Audio/Inactive Lines Display Mode")->GetInt(); if (shadeType == 0) return; // Spectrum? bool spectrum = false; - if (provider && Options.AsBool(_T("Audio Spectrum"))) { + if (provider && OPT_GET("Audio/Spectrum")->GetBool()) { spectrum = true; } // Set options - dc.SetBrush(wxBrush(Options.AsColour(_T("Audio Line boundary inactive line")))); - int selWidth = Options.AsInt(_T("Audio Line boundaries Thickness")); + dc.SetBrush(wxBrush(lagi_wxColour(OPT_GET("Colour/Audio Display/Line Boundary Inactive Line")->GetColour()))); + int selWidth = OPT_GET("Audio/Line Boundaries Thickness")->GetInt(); AssDialogue *shade; int shadeX1,shadeX2; int shadeFrom,shadeTo; @@ -459,13 +461,13 @@ void AudioDisplay::DrawInactiveLines(wxDC &dc) { x2 = MIN(x2,selX1); // Set pen and draw - dc.SetPen(wxPen(Options.AsColour(_T("Audio Waveform Inactive")))); + dc.SetPen(wxPen(lagi_wxColour(OPT_GET("Colour/Audio Display/Waveform Inactive")->GetColour()))); for (int i=x1;iGetColour()))); dc.DrawRectangle(shadeX1-selWidth/2+1,0,selWidth,h); dc.DrawRectangle(shadeX2-selWidth/2+1,0,selWidth,h); } @@ -498,7 +500,7 @@ void AudioDisplay::DrawKeyframes(wxDC &dc) { /// @param dc The DC to draw to. void AudioDisplay::DrawTimescale(wxDC &dc) { // Set size - int timelineHeight = Options.AsBool(_T("Audio Draw Timeline")) ? 20 : 0; + int timelineHeight = OPT_GET("Audio/Display/Draw/Timeline")->GetBool() ? 20 : 0; // Set colours dc.SetBrush(wxSystemSettings::GetColour(wxSYS_COLOUR_BTNFACE)); @@ -577,23 +579,23 @@ void AudioDisplay::DrawWaveform(wxDC &dc,bool weak) { // Draw pre-selection if (!hasSel) selStartCap = w; - dc.SetPen(wxPen(Options.AsColour(_T("Audio Waveform")))); + dc.SetPen(wxPen(lagi_wxColour(OPT_GET("Colour/Audio Display/Waveform")->GetColour()))); for (int64_t i=0;ienabled) dc.SetPen(wxPen(Options.AsColour(_T("Audio Waveform Modified")))); - else dc.SetPen(wxPen(Options.AsColour(_T("Audio Waveform Selected")))); + if (OPT_GET("Audio/Display/Draw/Selection Background")->GetBool()) { + if (NeedCommit && !karaoke->enabled) dc.SetPen(wxPen(lagi_wxColour(OPT_GET("Colour/Audio Display/Waveform Modified")->GetColour()))); + else dc.SetPen(wxPen(lagi_wxColour(OPT_GET("Colour/Audio Display/Waveform Selected")->GetColour()))); } for (int64_t i=selStartCap;iGetColour()))); for (int64_t i=selEndCap;iGetBool()) MakeDialogueVisible(); else UpdateImage(true); @@ -717,7 +719,7 @@ void AudioDisplay::Update() { /// @brief Recreate the image void AudioDisplay::RecreateImage() { GetClientSize(&w,&h); - h -= Options.AsBool(_T("Audio Draw Timeline")) ? 20 : 0; + h -= OPT_GET("Audio/Display/Draw/Timeline")->GetBool() ? 20 : 0; delete origImage; origImage = NULL; UpdateImage(false); @@ -919,7 +921,7 @@ void AudioDisplay::SetFile(wxString file) { // Add to recent if (!is_dummy) { wxLogDebug(_T("AudioDisplay::SetFile: add to recent")); - Options.AddToRecentList(file,_T("Recent aud")); + AegisubApp::Get()->mru->Add("Audio", STD_STR(file)); wxFileName fn(file); StandardPaths::SetPathValue(_T("?audio"),fn.GetPath()); } @@ -1140,7 +1142,7 @@ void AudioDisplay::SetDialogue(SubtitlesGrid *_grid,AssDialogue *diag,int n) { NeedCommit = false; // Set times - if (dialogue && !dontReadTimes && Options.AsBool(_T("Audio grab times on select"))) { + if (dialogue && !dontReadTimes && OPT_GET("Audio/Grab Times on Select")->GetBool()) { wxLogDebug(_T("AudioDisplay::SetDialogue: grabbing times")); int s = dialogue->Start.GetMS(); int e = dialogue->End.GetMS(); @@ -1249,7 +1251,7 @@ void AudioDisplay::CommitChanges (bool nextLine) { } // Next line (ugh what a condition, can this be simplified?) - if (nextLine && !karaoke->enabled && Options.AsBool(_T("Audio Next Line on Commit")) && !wasKaraSplitting) { + if (nextLine && !karaoke->enabled && OPT_GET("Audio/Next Line on Commit")->GetBool() && !wasKaraSplitting) { wxLogDebug(_T("AudioDisplay::CommitChanges: going to next line")); // Insert a line if it doesn't exist int nrows = grid->GetRows(); @@ -1258,15 +1260,15 @@ void AudioDisplay::CommitChanges (bool nextLine) { AssDialogue *def = new AssDialogue; def->Start = grid->GetDialogue(line_n)->End; def->End = grid->GetDialogue(line_n)->End; - def->End.SetMS(def->End.GetMS()+Options.AsInt(_T("Timing Default Duration"))); + def->End.SetMS(def->End.GetMS()+OPT_GET("Timing/Default Duration")->GetInt()); def->Style = grid->GetDialogue(line_n)->Style; grid->InsertLine(def,line_n,true); curStartMS = curEndMS; - curEndMS = curStartMS + Options.AsInt(_T("Timing Default Duration")); + curEndMS = curStartMS + OPT_GET("Timing/Default Duration")->GetInt(); } else if (grid->GetDialogue(line_n+1)->Start.GetMS() == 0 && grid->GetDialogue(line_n+1)->End.GetMS() == 0) { curStartMS = curEndMS; - curEndMS = curStartMS + Options.AsInt(_T("Timing Default Duration")); + curEndMS = curStartMS + OPT_GET("Timing/Default Duration")->GetInt(); } else { curStartMS = grid->GetDialogue(line_n+1)->Start.GetMS(); @@ -1289,19 +1291,19 @@ void AudioDisplay::CommitChanges (bool nextLine) { void AudioDisplay::AddLead(bool in,bool out) { // Lead in if (in) { - curStartMS -= Options.AsInt(_T("Audio Lead in")); + curStartMS -= OPT_GET("Audio/Lead/IN")->GetInt(); if (curStartMS < 0) curStartMS = 0; } // Lead out if (out) { - curEndMS += Options.AsInt(_T("Audio Lead out")); + curEndMS += OPT_GET("Audio/Lead/OUT")->GetInt(); } // Set changes UpdateTimeEditCtrls(); NeedCommit = true; - if (Options.AsBool(_T("Audio Autocommit"))) CommitChanges(); + if (OPT_GET("Audio/Auto/Commit")->GetBool()) CommitChanges(); Update(); } @@ -1337,7 +1339,7 @@ void AudioDisplay::OnMouseEvent(wxMouseEvent& event) { int64_t y = event.GetY(); bool karMode = karaoke->enabled; bool shiftDown = event.m_shiftDown; - int timelineHeight = Options.AsBool(_T("Audio Draw Timeline")) ? 20 : 0; + int timelineHeight = OPT_GET("Audio/Display/Draw/Timeline")->GetBool() ? 20 : 0; // Leaving event if (event.Leaving()) { @@ -1358,7 +1360,7 @@ void AudioDisplay::OnMouseEvent(wxMouseEvent& event) { inside = true; // Get focus - if (wxWindow::FindFocus() != this && Options.AsBool(_T("Audio Autofocus"))) SetFocus(); + if (wxWindow::FindFocus() != this && OPT_GET("Audio/Auto/Focus")->GetBool()) SetFocus(); } else if (y < h+timelineHeight) onScale = true; } @@ -1387,7 +1389,7 @@ void AudioDisplay::OnMouseEvent(wxMouseEvent& event) { if (event.GetWheelRotation() != 0) { // Zoom or scroll? bool zoom = shiftDown; - if (Options.AsBool(_T("Audio Wheel Default To Zoom"))) zoom = !zoom; + if (OPT_GET("Audio/Wheel Default to Zoom")->GetBool()) zoom = !zoom; // Zoom if (zoom) { @@ -1423,7 +1425,7 @@ void AudioDisplay::OnMouseEvent(wxMouseEvent& event) { dc.DrawLine(x,0,x,h); // Time - if (Options.AsBool(_T("Audio Draw Cursor Time"))) { + if (OPT_GET("Audio/Display/Draw/Cursor")->GetBool()) { // Time string AssTime time; time.SetMS(GetMSAtX(x)); @@ -1525,7 +1527,7 @@ void AudioDisplay::OnMouseEvent(wxMouseEvent& event) { // Line timing mode if (!karTime) { // Grab start - if (abs64 (x - selStart) < 6 && Options.AsBool(_T("Disable Dragging Times"))==false) { + if (abs64 (x - selStart) < 6 && OPT_GET("Audio/Display/Dragging Times")->GetBool()==false) { wxCursor cursor(wxCURSOR_SIZEWE); SetCursor(cursor); defCursor = false; @@ -1536,7 +1538,7 @@ void AudioDisplay::OnMouseEvent(wxMouseEvent& event) { } // Grab end - else if (abs64 (x - selEnd) < 6 && Options.AsBool(_T("Disable Dragging Times"))==false) { + else if (abs64 (x - selEnd) < 6 && OPT_GET("Audio/Display/Dragging Times")->GetBool()==false) { wxCursor cursor(wxCURSOR_SIZEWE); SetCursor(cursor); defCursor = false; @@ -1608,7 +1610,7 @@ void AudioDisplay::OnMouseEvent(wxMouseEvent& event) { updated = true; diagUpdated = true; - if (leftIsDown && abs((long)(x-lastX)) > Options.AsInt(_T("Audio Start Drag Sensitivity"))) { + if (leftIsDown && abs((long)(x-lastX)) > OPT_GET("Audio/Start Drag Sensitivity")->GetInt()) { selStart = lastX; selEnd = x; curStartMS = GetBoundarySnap(GetMSAtX(lastX),10,event.ShiftDown(),true); @@ -1697,7 +1699,7 @@ void AudioDisplay::OnMouseEvent(wxMouseEvent& event) { NeedCommit = true; if (curStartMS <= curEndMS) { UpdateTimeEditCtrls(); - if (Options.AsBool(_T("Audio Autocommit"))) CommitChanges(); + if (OPT_GET("Audio/Auto/Commit")->GetBool()) CommitChanges(); } else UpdateImage(true); @@ -1750,9 +1752,9 @@ int AudioDisplay::GetBoundarySnap(int ms,int rangeX,bool shiftHeld,bool start) { // Keyframe boundaries wxArrayInt boundaries; - bool snapKey = Options.AsBool(_T("Audio snap to keyframes")); + bool snapKey = OPT_GET("Audio/Display/Snap/Keyframes")->GetBool(); if (shiftHeld) snapKey = !snapKey; - if (snapKey && VideoContext::Get()->KeyFramesLoaded() && Options.AsBool(_T("Audio Draw Keyframes"))) { + if (snapKey && VideoContext::Get()->KeyFramesLoaded() && OPT_GET("Audio/Display/Draw/Keyframes")->GetBool()) { int64_t keyMS; wxArrayInt keyFrames = VideoContext::Get()->GetKeyFrames(); int frame; @@ -1767,8 +1769,8 @@ int AudioDisplay::GetBoundarySnap(int ms,int rangeX,bool shiftHeld,bool start) { } // Other subtitles' boundaries - int inactiveType = Options.AsInt(_T("Audio Inactive Lines Display Mode")); - bool snapLines = Options.AsBool(_T("Audio snap to other lines")); + int inactiveType = OPT_GET("Audio/Inactive Lines Display Mode")->GetInt(); + bool snapLines = OPT_GET("Audio/Display/Snap/Other Lines")->GetBool(); if (shiftHeld) snapLines = !snapLines; if (snapLines && (inactiveType == 1 || inactiveType == 2)) { AssDialogue *shade; @@ -1932,7 +1934,7 @@ int AudioDisplay::GetBoundarySnap(int ms,int rangeX,bool shiftHeld,bool start) { void AudioDisplay::OnSize(wxSizeEvent &event) { // Set size GetClientSize(&w,&h); - h -= Options.AsBool(_T("Audio Draw Timeline")) ? 20 : 0; + h -= OPT_GET("Audio/Display/Draw/Timeline")->GetBool() ? 20 : 0; // Update image UpdateSamples(); @@ -1973,7 +1975,7 @@ void AudioDisplay::OnUpdateTimer(wxTimerEvent &event) { int posX = GetXAtSample(curPos); bool fullDraw = false; bool centerLock = false; - bool scrollToCursor = Options.AsBool(_T("Audio lock scroll on cursor")); + bool scrollToCursor = OPT_GET("Audio/Lock Scroll on Cursor")->GetBool(); if (centerLock) { int goTo = MAX(0,curPos - w*samples/2); if (goTo >= 0) { @@ -1999,7 +2001,7 @@ void AudioDisplay::OnUpdateTimer(wxTimerEvent &event) { wxMemoryDC src; curpos = GetXAtSample(curPos); if (curpos >= 0 && curpos < GetClientSize().GetWidth()) { - dc.SetPen(wxPen(Options.AsColour(_T("Audio Play cursor")))); + dc.SetPen(wxPen(lagi_wxColour(OPT_GET("Colour/Audio Display/Play Cursor")->GetColour()))); src.SelectObject(*origImage); if (fullDraw) { //dc.Blit(0,0,w,h,&src,0,0); @@ -2195,7 +2197,7 @@ void AudioDisplay::OnKeyDown(wxKeyEvent &event) { if (diagUpdated) { diagUpdated = false; NeedCommit = true; - if (Options.AsBool(_T("Audio Autocommit")) && curStartMS <= curEndMS) CommitChanges(); + if (OPT_GET("Audio/Auto/Commit")->GetBool() && curStartMS <= curEndMS) CommitChanges(); else UpdateImage(true); } } diff --git a/aegisub/src/audio_player.cpp b/aegisub/src/audio_player.cpp index ea822dc8e..8d354f939 100644 --- a/aegisub/src/audio_player.cpp +++ b/aegisub/src/audio_player.cpp @@ -59,6 +59,8 @@ #ifdef WITH_PULSEAUDIO #include "audio_player_pulse.h" #endif +#include "compat.h" +#include "main.h" #include "options.h" @@ -151,7 +153,7 @@ void AudioPlayer::OnStopAudio(wxCommandEvent &event) { /// AudioPlayer* AudioPlayerFactoryManager::GetAudioPlayer() { // List of providers - wxArrayString list = GetFactoryList(Options.AsText(_T("Audio player"))); + wxArrayString list = GetFactoryList(lagi_wxString(OPT_GET("Audio/Player")->GetString())); // None available if (list.Count() == 0) throw _T("No audio players are available."); diff --git a/aegisub/src/audio_player_alsa.cpp b/aegisub/src/audio_player_alsa.cpp index 60b782e32..1c39b7178 100644 --- a/aegisub/src/audio_player_alsa.cpp +++ b/aegisub/src/audio_player_alsa.cpp @@ -85,7 +85,7 @@ void AlsaPlayer::OpenStream() // We want playback stream = SND_PCM_STREAM_PLAYBACK; // And get a device name - wxString device = Options.AsText(_T("Audio Alsa Device")); + wxString device = lagi_wxString(OPT_GET("Player/Audio/ALSA/Device")->GetString()); // Open device for blocking access if (snd_pcm_open(&pcm_handle, device.mb_str(wxConvUTF8), stream, 0) < 0) { // supposedly we don't want SND_PCM_ASYNC even for async playback diff --git a/aegisub/src/audio_player_dsound2.cpp b/aegisub/src/audio_player_dsound2.cpp index 118b0e8e3..f36bafd96 100644 --- a/aegisub/src/audio_player_dsound2.cpp +++ b/aegisub/src/audio_player_dsound2.cpp @@ -863,8 +863,8 @@ DirectSoundPlayer2::DirectSoundPlayer2() thread = 0; // The buffer will hold BufferLength times WantedLatency milliseconds of audio - WantedLatency = Options.AsInt(_T("Audio dsound buffer latency")); - BufferLength = Options.AsInt(_T("Audio dsound buffer length")); + WantedLatency = OPT_GET("Player/Audio/DirectSound/Buffer Latency")->GetInt(); + BufferLength = OPT_GET("Player/Audio/DirectSound/Buffer Length")->GetInt(); // sanity checking if (WantedLatency <= 0) diff --git a/aegisub/src/audio_player_oss.cpp b/aegisub/src/audio_player_oss.cpp index 8fcbff164..e01eb2d79 100644 --- a/aegisub/src/audio_player_oss.cpp +++ b/aegisub/src/audio_player_oss.cpp @@ -43,6 +43,8 @@ #include "audio_player_oss.h" #include "audio_provider_manager.h" #include "frame_main.h" +#include "compat.h" +#include "main.h" #include "options.h" #include "utils.h" @@ -81,7 +83,7 @@ void OSSPlayer::OpenStream() bpf = provider->GetChannels() * provider->GetBytesPerSample(); // Open device - wxString device = Options.AsText(_T("Audio OSS Device")); + wxString device = lagi_wxString(OPT_GET("Audio/OSS/Device")->GetString()); dspdev = ::open(device.mb_str(wxConvUTF8), O_WRONLY, 0); if (dspdev < 0) { throw _T("OSS player: opening device failed"); diff --git a/aegisub/src/audio_player_portaudio.cpp b/aegisub/src/audio_player_portaudio.cpp index f10e3792f..08d49e5fa 100644 --- a/aegisub/src/audio_player_portaudio.cpp +++ b/aegisub/src/audio_player_portaudio.cpp @@ -44,6 +44,7 @@ #include "audio_player_portaudio.h" #include "audio_provider_manager.h" #include "charset_conv.h" +#include "main.h" #include "options.h" #include "utils.h" #include @@ -84,7 +85,7 @@ void PortAudioPlayer::OpenStream() { // Open stream PaStreamParameters pa_output_p; - int pa_config_default = Options.AsInt(_T("Audio PortAudio Device")); + int pa_config_default = OPT_GET("Player/Audio/PortAudio/Device")->GetInt(); PaDeviceIndex pa_device; if (pa_config_default < 0) { diff --git a/aegisub/src/audio_provider.cpp b/aegisub/src/audio_provider.cpp index 71c7a2c61..62ee5d85a 100644 --- a/aegisub/src/audio_provider.cpp +++ b/aegisub/src/audio_provider.cpp @@ -57,6 +57,8 @@ #include "audio_provider_quicktime.h" #endif #include "audio_provider_ram.h" +#include "compat.h" +#include "main.h" #include "options.h" @@ -243,7 +245,7 @@ AudioProvider *AudioProviderFactoryManager::GetAudioProvider(wxString filename, // Prepare provider AudioProvider *provider = NULL; - if (!Options.AsBool(_T("Audio Disable PCM Provider"))) { + if (!OPT_GET("Provider/Audio/PCM/Disable")->GetBool()) { // Try a PCM provider first provider = CreatePCMAudioProvider(filename); if (provider) { @@ -257,7 +259,7 @@ AudioProvider *AudioProviderFactoryManager::GetAudioProvider(wxString filename, } // List of providers - wxArrayString list = GetFactoryList(Options.AsText(_T("Audio provider"))); + wxArrayString list = GetFactoryList(lagi_wxString(OPT_GET("Audio/Provider")->GetString())); // None available if (list.Count() == 0) throw _T("No audio providers are available."); @@ -285,7 +287,7 @@ AudioProvider *AudioProviderFactoryManager::GetAudioProvider(wxString filename, provider = CreateConvertAudioProvider(provider); // Change provider to RAM/HD cache if needed - if (cache == -1) cache = Options.AsInt(_T("Audio Cache")); + if (cache == -1) cache = OPT_GET("Audio/Cache/Type")->GetInt(); if (cache) { AudioProvider *final = NULL; diff --git a/aegisub/src/audio_provider_avs.cpp b/aegisub/src/audio_provider_avs.cpp index 04e6d6466..a3d778ede 100644 --- a/aegisub/src/audio_provider_avs.cpp +++ b/aegisub/src/audio_provider_avs.cpp @@ -51,6 +51,8 @@ #include "audio_provider_avs.h" #include "charset_conv.h" +#include "compat.h" +#include "main.h" #include "options.h" #include "standard_paths.h" #include "utils.h" @@ -152,7 +154,7 @@ void AvisynthAudioProvider::LoadFromClip(AVSValue _clip) { // Convert to one channel char buffer[1024]; - strcpy(buffer,Options.AsText(_T("Audio Downmixer")).mb_str(csConvLocal)); + strcpy(buffer,lagi_wxString(OPT_GET("Audio/Downmixer")->GetString()).mb_str(csConvLocal)); script = env->Invoke(buffer, _clip); // Convert to 16 bits per sample @@ -160,7 +162,7 @@ void AvisynthAudioProvider::LoadFromClip(AVSValue _clip) { vi = script.AsClip()->GetVideoInfo(); // Convert sample rate - int setsample = Options.AsInt(_T("Audio Sample Rate")); + int setsample = OPT_GET("Provider/Audio/AVS/Sample Rate")->GetInt(); if (vi.SamplesPerSecond() < 32000) setsample = 44100; if (setsample != 0) { AVSValue args[2] = { script, setsample }; diff --git a/aegisub/src/audio_provider_ffmpegsource.cpp b/aegisub/src/audio_provider_ffmpegsource.cpp index 1134b2445..2d9b50203 100644 --- a/aegisub/src/audio_provider_ffmpegsource.cpp +++ b/aegisub/src/audio_provider_ffmpegsource.cpp @@ -50,6 +50,7 @@ #include "audio_provider_ffmpegsource.h" #include "include/aegisub/aegisub.h" +#include "main.h" #include "options.h" @@ -164,7 +165,7 @@ void FFmpegSourceAudioProvider::LoadAudio(wxString filename) { // moment of truth if (!IndexIsValid) { int TrackMask; - if (Options.AsBool(_T("FFmpegSource always index all tracks")) || TrackNumber == FFMS_TRACKMASK_ALL) + if (OPT_GET("Provider/FFmpegSource/Index All Tracks")->GetBool() || TrackNumber == FFMS_TRACKMASK_ALL) TrackMask = FFMS_TRACKMASK_ALL; else TrackMask = (1 << TrackNumber); diff --git a/aegisub/src/audio_provider_hd.cpp b/aegisub/src/audio_provider_hd.cpp index 8704322a8..5d6eb1fce 100644 --- a/aegisub/src/audio_provider_hd.cpp +++ b/aegisub/src/audio_provider_hd.cpp @@ -47,6 +47,7 @@ #endif #include "audio_provider_hd.h" +#include "compat.h" #include "dialog_progress.h" #include "frame_main.h" #include "main.h" @@ -159,7 +160,7 @@ void HDAudioProvider::GetAudio(void *buf, int64_t start, int64_t count) { /// wxString HDAudioProvider::DiskCachePath() { // Default - wxString path = Options.AsText(_T("Audio HD Cache Location")); + wxString path = lagi_wxString(OPT_GET("Audio/Cache/HD/Location")->GetString()); if (path == _T("default")) return StandardPaths::DecodePath(_T("?temp/")); // Specified @@ -172,7 +173,7 @@ wxString HDAudioProvider::DiskCachePath() { /// wxString HDAudioProvider::DiskCacheName() { // Get pattern - wxString pattern = Options.AsText(_T("Audio HD Cache Name")); + wxString pattern = lagi_wxString(OPT_GET("Audio/Cache/HD/Name")->GetString()); if (pattern.Find(_T("%02i")) == wxNOT_FOUND) pattern = _T("audio%02i.tmp"); // Try from 00 to 99 diff --git a/aegisub/src/audio_renderer_spectrum.cpp b/aegisub/src/audio_renderer_spectrum.cpp index a37a76b75..dbac71246 100644 --- a/aegisub/src/audio_renderer_spectrum.cpp +++ b/aegisub/src/audio_renderer_spectrum.cpp @@ -54,6 +54,7 @@ #include "audio_renderer_spectrum.h" #include "colorspace.h" #include "fft.h" +#include "main.h" #include "options.h" #include "utils.h" @@ -565,7 +566,7 @@ public: cache_root = new IntermediateSpectrumCache(provider, 0, num_lines, num_overlaps, 0); // option is stored in megabytes, but we want number of bytes - unsigned long max_cache_size = Options.AsInt(_T("Audio Spectrum Memory Max")); + unsigned long max_cache_size = OPT_GET("Audio/Renderer/Spectrum/Memory Max")->GetInt(); // It can't go too low if (max_cache_size < 5) max_cache_size = 128; max_cache_size *= 1024 * 1024; @@ -590,7 +591,7 @@ AudioSpectrum::AudioSpectrum(AudioProvider *_provider) provider = _provider; // Determine the quality of the spectrum rendering based on an index - int quality_index = Options.AsInt(_T("Audio Spectrum Quality")); + int quality_index = OPT_GET("Audio/Renderer/Spectrum/Quality")->GetInt(); if (quality_index < 0) quality_index = 0; if (quality_index > 5) quality_index = 5; // no need to go freaking insane @@ -655,7 +656,7 @@ AudioSpectrum::AudioSpectrum(AudioProvider *_provider) cache = new AudioSpectrumCacheManager(provider, line_length, num_lines, fft_overlaps); power_scale = 1; - minband = Options.AsInt(_T("Audio Spectrum Cutoff")); + minband = OPT_GET("Audio/Renderer/Spectrum/Cutoff")->GetInt(); maxband = line_length - minband * 2/3; // TODO: make this customisable? // Generate colour maps diff --git a/aegisub/src/auto4_base.cpp b/aegisub/src/auto4_base.cpp index a8254b2ff..b0dc0506d 100644 --- a/aegisub/src/auto4_base.cpp +++ b/aegisub/src/auto4_base.cpp @@ -68,6 +68,8 @@ #include "ass_file.h" #include "ass_style.h" #include "auto4_base.h" +#include "compat.h" +#include "main.h" #include "options.h" #include "standard_paths.h" #include "string_codec.h" @@ -491,7 +493,7 @@ namespace Automation4 { Center(); // Init trace level - trace_level = Options.AsInt(_T("Automation Trace Level")); + trace_level = OPT_GET("Automation/Trace Level")->GetInt(); } @@ -678,7 +680,7 @@ namespace Automation4 { // copied from auto3 include_path.clear(); include_path.EnsureFileAccessible(filename); - wxStringTokenizer toker(Options.AsText(_T("Automation Include Path")), _T("|"), wxTOKEN_STRTOK); + wxStringTokenizer toker(lagi_wxString(OPT_GET("Path/Automation/Include")->GetString()), _T("|"), wxTOKEN_STRTOK); while (toker.HasMoreTokens()) { // todo? make some error reporting here wxFileName path(StandardPaths::DecodePath(toker.GetNextToken())); diff --git a/aegisub/src/auto4_lua.cpp b/aegisub/src/auto4_lua.cpp index 34a31ab56..fc1e5b6b4 100644 --- a/aegisub/src/auto4_lua.cpp +++ b/aegisub/src/auto4_lua.cpp @@ -58,6 +58,7 @@ #include "auto4_lua.h" #include "auto4_lua_factory.h" #include "auto4_lua_scriptreader.h" +#include "main.h" #include "options.h" #include "standard_paths.h" #include "text_file_reader.h" @@ -196,7 +197,7 @@ namespace Automation4 { lua_pushstring(L, "path"); lua_gettable(L, -3); - wxStringTokenizer toker(Options.AsText(_T("Automation Include Path")), _T("|"), wxTOKEN_STRTOK); + wxStringTokenizer toker(lagi_wxString(OPT_GET("Path/Automation/Include")->GetString()), _T("|"), wxTOKEN_STRTOK); while (toker.HasMoreTokens()) { wxFileName path(StandardPaths::DecodePath(toker.GetNextToken())); if (path.IsOk() && !path.IsRelative() && path.DirExists()) { @@ -563,7 +564,7 @@ namespace Automation4 { , nargs(_nargs) , nresults(_nresults) { - int prio = Options.AsInt(_T("Automation Thread Priority")); + int prio = OPT_GET("Automation/Lua/Thread Priority")->GetInt(); if (prio == 0) prio = 50; // normal else if (prio == 1) prio = 30; // below normal else if (prio == 2) prio = 10; // lowest diff --git a/aegisub/src/auto4_lua.h b/aegisub/src/auto4_lua.h index 6c3565683..d896500ea 100644 --- a/aegisub/src/auto4_lua.h +++ b/aegisub/src/auto4_lua.h @@ -42,6 +42,7 @@ #include #endif +#include "compat.h" #include "auto4_base.h" #ifdef __WINDOWS__ diff --git a/aegisub/src/avisynth_wrap.cpp b/aegisub/src/avisynth_wrap.cpp index 6f5f74a04..95a8aae02 100644 --- a/aegisub/src/avisynth_wrap.cpp +++ b/aegisub/src/avisynth_wrap.cpp @@ -42,6 +42,7 @@ #ifdef WITH_AVISYNTH #include "avisynth_wrap.h" +#include "main.h" #include "options.h" #ifdef DEBUG_AVISYNTH_CODE @@ -101,7 +102,7 @@ AviSynthWrapper::AviSynthWrapper() { AVSTRACE(_T("Got address of CreateScriptEnv")); // Require Avisynth 2.5.6+? - if (Options.AsBool(_T("Allow Ancient Avisynth"))) + if (OPT_GET("Provider/Avisynth/Allow Ancient")->GetBool()) env = CreateScriptEnv(AVISYNTH_INTERFACE_VERSION-1); else env = CreateScriptEnv(AVISYNTH_INTERFACE_VERSION); @@ -112,7 +113,7 @@ AviSynthWrapper::AviSynthWrapper() { } AVSTRACE(_T("Created script environment")); // Set memory limit - int memoryMax = Options.AsInt(_T("Avisynth MemoryMax")); + const int memoryMax = OPT_GET("Provider/Avisynth/Memory Max")->GetInt(); if (memoryMax != 0) { env->SetMemoryMax(memoryMax); AVSTRACE(_T("Set Avisynth memory limit")); diff --git a/aegisub/src/base_grid.cpp b/aegisub/src/base_grid.cpp index a855a2cb1..329caf23c 100644 --- a/aegisub/src/base_grid.cpp +++ b/aegisub/src/base_grid.cpp @@ -48,7 +48,9 @@ #include "ass_style.h" #include "audio_display.h" #include "base_grid.h" +#include "compat.h" #include "frame_main.h" +#include "main.h" #include "options.h" #include "subs_edit_box.h" #include "utils.h" @@ -106,10 +108,10 @@ BaseGrid::~BaseGrid() { /// void BaseGrid::UpdateStyle() { // Set font - wxString fontname = Options.AsText(_T("Grid Font Face")); + wxString fontname = lagi_wxString(OPT_GET("Subtitle/Grid/Font Face")->GetString()); if (fontname.IsEmpty()) fontname = _T("Tahoma"); font.SetFaceName(fontname); - font.SetPointSize(Options.AsInt(_T("Grid font size"))); + font.SetPointSize(OPT_GET("Subtitle/Grid/Font Size")->GetInt()); font.SetWeight(wxFONTWEIGHT_NORMAL); // Set line height @@ -122,7 +124,9 @@ void BaseGrid::UpdateStyle() { } // Set column widths - for (int i=0;i<10;i++) showCol[i] = Options.AsBool(_T("Grid show column ") + AegiIntegerToString(i)); + std::vector column_array; + OPT_GET("Subtitle/Grid/Column")->GetListBool(column_array); + for (int i=0;i<10;i++) showCol[i] = column_array.at(i); SetColumnWidths(); // Update @@ -418,12 +422,12 @@ void BaseGrid::DrawImage(wxDC &dc) { dc.SetFont(font); // Clear background - dc.SetBackground(wxBrush(Options.AsColour(_T("Grid Background")))); + dc.SetBackground(wxBrush(lagi_wxColour(OPT_GET("Colour/Subtitle Grid/Background/Background")->GetColour()))); dc.Clear(); // Draw labels dc.SetPen(*wxTRANSPARENT_PEN); - dc.SetBrush(wxBrush(Options.AsColour(_T("Grid left column")))); + dc.SetBrush(wxBrush(lagi_wxColour(OPT_GET("Colour/Subtitle Grid/Left Column")->GetColour()))); dc.DrawRectangle(0,lineHeight,colWidth[0],h-lineHeight); // Visible lines @@ -434,23 +438,23 @@ void BaseGrid::DrawImage(wxDC &dc) { // Row colors std::vector rowColors; std::vector foreColors; - rowColors.push_back(wxBrush(Options.AsColour(_T("Grid Background")))); // 0 = Standard - foreColors.push_back(Options.AsColour(_T("Grid standard foreground"))); - rowColors.push_back(wxBrush(Options.AsColour(_T("Grid Header")))); // 1 = Header - foreColors.push_back(Options.AsColour(_T("Grid standard foreground"))); - rowColors.push_back(wxBrush(Options.AsColour(_T("Grid selection background")))); // 2 = Selected - foreColors.push_back(Options.AsColour(_T("Grid selection foreground"))); - rowColors.push_back(wxBrush(Options.AsColour(_T("Grid comment background")))); // 3 = Commented - foreColors.push_back(Options.AsColour(_T("Grid selection foreground"))); - rowColors.push_back(wxBrush(Options.AsColour(_T("Grid inframe background")))); // 4 = Video Highlighted - foreColors.push_back(Options.AsColour(_T("Grid selection foreground"))); - rowColors.push_back(wxBrush(Options.AsColour(_T("Grid selected comment background")))); // 5 = Commented & selected - foreColors.push_back(Options.AsColour(_T("Grid selection foreground"))); + rowColors.push_back(wxBrush(lagi_wxColour(OPT_GET("Colour/Subtitle Grid/Background/Background")->GetColour()))); // 0 = Standard + foreColors.push_back(lagi_wxColour(OPT_GET("Colour/Subtitle Grid/Standard")->GetColour())); + rowColors.push_back(wxBrush(lagi_wxColour(OPT_GET("Colour/Subtitle Grid/Header")->GetColour()))); // 1 = Header + foreColors.push_back(lagi_wxColour(OPT_GET("Colour/Subtitle Grid/Standard")->GetColour())); + rowColors.push_back(wxBrush(lagi_wxColour(OPT_GET("Colour/Subtitle Grid/Background/Selection")->GetColour()))); // 2 = Selected + foreColors.push_back(lagi_wxColour(OPT_GET("Colour/Subtitle Grid/Selection")->GetColour())); + rowColors.push_back(wxBrush(lagi_wxColour(OPT_GET("Colour/Subtitle Grid/Background/Comment")->GetColour()))); // 3 = Commented + foreColors.push_back(lagi_wxColour(OPT_GET("Colour/Subtitle Grid/Selection")->GetColour())); + rowColors.push_back(wxBrush(lagi_wxColour(OPT_GET("Colour/Subtitle Grid/Background/Inframe")->GetColour()))); // 4 = Video Highlighted + foreColors.push_back(lagi_wxColour(OPT_GET("Colour/Subtitle Grid/Selection")->GetColour())); + rowColors.push_back(wxBrush(lagi_wxColour(OPT_GET("Colour/Subtitle Grid/Background/Selected Comment")->GetColour()))); // 5 = Commented & selected + foreColors.push_back(lagi_wxColour(OPT_GET("Colour/Subtitle Grid/Selection")->GetColour())); // First grid row bool drawGrid = true; if (drawGrid) { - dc.SetPen(wxPen(Options.AsColour(_T("Grid lines")))); + dc.SetPen(wxPen(lagi_wxColour(OPT_GET("Colour/Subtitle Grid/Lines")->GetColour()))); dc.DrawLine(0,0,w,0); dc.SetPen(*wxTRANSPARENT_PEN); } @@ -516,12 +520,12 @@ void BaseGrid::DrawImage(wxDC &dc) { strings.Add(curDiag->GetMarginString(2)); // Set text - int mode = Options.AsInt(_T("Grid Hide Overrides")); + int mode = OPT_GET("Subtitle/Grid/Hide Overrides")->GetInt(); wxString value = _T(""); // Hidden overrides if (mode == 1 || mode == 2) { - wxString replaceWith = Options.AsText(_T("Grid hide overrides char")); + wxString replaceWith = lagi_wxString(OPT_GET("Subtitle/Grid/Hide Overrides Char")->GetString()); int textlen = curDiag->Text.Length(); int depth = 0; wxChar curChar; @@ -550,7 +554,7 @@ void BaseGrid::DrawImage(wxDC &dc) { if (inSel && curDiag->Comment) curColor = 5; else if (inSel) curColor = 2; else if (curDiag->Comment) curColor = 3; - else if (Options.AsBool(_T("Highlight subs in frame")) && IsDisplayed(curDiag)) curColor = 4; + else if (OPT_GET("Subtitle/Grid/Highlight Subtitles in Frame")->GetBool() && IsDisplayed(curDiag)) curColor = 4; } else { @@ -564,7 +568,7 @@ void BaseGrid::DrawImage(wxDC &dc) { } // Set text color - if (collides) dc.SetTextForeground(Options.AsColour(_T("Grid collision foreground"))); + if (collides) dc.SetTextForeground(lagi_wxColour(OPT_GET("Colour/Subtitle Grid/Collision")->GetColour())); else { dc.SetTextForeground(foreColors[curColor]); } @@ -595,7 +599,7 @@ void BaseGrid::DrawImage(wxDC &dc) { // Draw grid dc.DestroyClippingRegion(); if (drawGrid) { - dc.SetPen(wxPen(Options.AsColour(_T("Grid lines")))); + dc.SetPen(wxPen(lagi_wxColour(OPT_GET("Colour/Subtitle Grid/Lines")->GetColour()))); dc.DrawLine(0,dy+lineHeight,w,dy+lineHeight); dc.SetPen(*wxTRANSPARENT_PEN); } @@ -604,7 +608,7 @@ void BaseGrid::DrawImage(wxDC &dc) { // Draw grid columns dx = 0; if (drawGrid) { - dc.SetPen(wxPen(Options.AsColour(_T("Grid lines")))); + dc.SetPen(wxPen(lagi_wxColour(OPT_GET("Colour/Subtitle Grid/Lines")->GetColour()))); for (int i=0;i<10;i++) { dx += colWidth[i]; dc.DrawLine(dx,0,dx,maxH); @@ -614,7 +618,7 @@ void BaseGrid::DrawImage(wxDC &dc) { } // Draw currently active line border - dc.SetPen(wxPen(Options.AsColour(_T("Grid Active border")))); + dc.SetPen(wxPen(lagi_wxColour(OPT_GET("Colour/Subtitle Grid/Active Border")->GetColour()))); dc.SetBrush(*wxTRANSPARENT_BRUSH); dy = (editBox->linen+1-yPos) * lineHeight; dc.DrawRectangle(0,dy,w,lineHeight+1); @@ -677,7 +681,7 @@ void BaseGrid::OnMouseEvent(wxMouseEvent &event) { // Get focus if (event.ButtonDown()) { - if (Options.AsBool(_T("Grid Allow Focus"))) { + if (OPT_GET("Subtitle/Grid/Focus Allow")->GetBool()) { SetFocus(); } } diff --git a/aegisub/src/compat.cpp b/aegisub/src/compat.cpp new file mode 100644 index 000000000..f9781ee1b --- /dev/null +++ b/aegisub/src/compat.cpp @@ -0,0 +1,14 @@ +#include "compat.h" +#include "main.h" + +wxArrayString lagi_MRU_wxAS(const wxString &list) { + wxArrayString work; + + const agi::MRUManager::MRUListMap *map_list = AegisubApp::Get()->mru->Get(STD_STR(list)); + + for (agi::MRUManager::MRUListMap::const_iterator i_lst = map_list->begin(); i_lst != map_list->end(); ++i_lst) { + work.Add(wxString(i_lst->second)); + } + + return work; +} diff --git a/aegisub/src/compat.h b/aegisub/src/compat.h new file mode 100644 index 000000000..fe794f772 --- /dev/null +++ b/aegisub/src/compat.h @@ -0,0 +1,15 @@ +#ifndef AGI_PRE +#include + +#include +#include +#include +#endif + +#include + +#define STD_STR(x) std::string(x.mb_str()) + +inline wxColour lagi_wxColour(const agi::Colour &colour) { return wxColour(colour); } +inline wxString lagi_wxString(const std::string &str) { return wxString(str); } +wxArrayString lagi_MRU_wxAS(const wxString &list); diff --git a/aegisub/src/dialog_attachments.cpp b/aegisub/src/dialog_attachments.cpp index da4fcb653..390cb84f8 100644 --- a/aegisub/src/dialog_attachments.cpp +++ b/aegisub/src/dialog_attachments.cpp @@ -50,9 +50,11 @@ #include "ass_attachment.h" #include "ass_file.h" +#include "compat.h" #include "dialog_attachments.h" #include "help_button.h" #include "libresrc/libresrc.h" +#include "main.h" #include "options.h" #include "utils.h" @@ -153,7 +155,7 @@ void DialogAttachments::OnAttachFont(wxCommandEvent &event) { wxArrayString filenames; wxArrayString paths; { - wxFileDialog diag (this,_("Choose file to be attached"), Options.AsText(_T("Fonts Collector Destination")), _T(""), _T("Font Files (*.ttf)|*.ttf"), wxFD_OPEN | wxFD_FILE_MUST_EXIST | wxFD_MULTIPLE); + wxFileDialog diag (this,_("Choose file to be attached"), lagi_wxString(OPT_GET("Path/Fonts Collector Destination")->GetString()), _T(""), _T("Font Files (*.ttf)|*.ttf"), wxFD_OPEN | wxFD_FILE_MUST_EXIST | wxFD_MULTIPLE); if (diag.ShowModal() == wxID_CANCEL) return; diag.GetFilenames(filenames); diag.GetPaths(paths); @@ -230,11 +232,11 @@ void DialogAttachments::OnExtract(wxCommandEvent &event) { bool fullPath = false; // Multiple or single? - if (listView->GetNextSelected(i) != -1) path = wxDirSelector(_("Select the path to save the files to:"),Options.AsText(_T("Fonts Collector Destination"))) + _T("/"); + if (listView->GetNextSelected(i) != -1) path = wxDirSelector(_("Select the path to save the files to:"),lagi_wxString(OPT_GET("Path/Fonts Collector Destination")->GetString())) + _T("/"); else { // Default path wxString defPath = ((AssAttachment*) wxUIntToPtr(listView->GetItemData(i)))->GetFileName(); - path = wxFileSelector(_("Select the path to save the file to:"),Options.AsText(_T("Fonts Collector Destination")),defPath); + path = wxFileSelector(_("Select the path to save the file to:"),lagi_wxString(OPT_GET("Path/Fonts Collector Destination")->GetString()),defPath); fullPath = true; } if (path.IsEmpty()) return; diff --git a/aegisub/src/dialog_automation.cpp b/aegisub/src/dialog_automation.cpp index 290ec7d93..bb07b6a62 100644 --- a/aegisub/src/dialog_automation.cpp +++ b/aegisub/src/dialog_automation.cpp @@ -47,6 +47,7 @@ #endif #include "auto4_base.h" +#include "compat.h" #include "dialog_automation.h" #include "help_button.h" #include "libresrc/libresrc.h" @@ -230,12 +231,12 @@ void DialogAutomation::OnAdd(wxCommandEvent &evt) fnfilter = _T("All supported scripts|") + catchall + _T("|") + fnfilter; } - wxString fname = wxFileSelector(_("Add Automation script"), Options.AsText(_T("Last open automation path")), wxEmptyString, wxEmptyString, fnfilter, wxFD_OPEN|wxFD_FILE_MUST_EXIST, this); + wxString fname = wxFileSelector(_("Add Automation script"), lagi_wxString(OPT_GET("Path/Last/Automation")->GetString()), wxEmptyString, wxEmptyString, fnfilter, wxFD_OPEN|wxFD_FILE_MUST_EXIST, this); if (!fname.IsEmpty()) { wxFileName fnpath(fname); - Options.SetText(_T("Last open automation path"), fnpath.GetPath()); + OPT_SET("Path/Last/Automation")->SetString(STD_STR(fnpath.GetPath())); // TODO: make sure each script is only loaded once. check in both local and global managers!! // it doesn't break for macros, but will for export filters, and maybe for file formats, diff --git a/aegisub/src/dialog_colorpicker.cpp b/aegisub/src/dialog_colorpicker.cpp index bfc3cf305..4994d816b 100644 --- a/aegisub/src/dialog_colorpicker.cpp +++ b/aegisub/src/dialog_colorpicker.cpp @@ -56,9 +56,11 @@ #include "ass_style.h" #include "colorspace.h" +#include "compat.h" #include "dialog_colorpicker.h" #include "help_button.h" #include "libresrc/libresrc.h" +#include "main.h" #include "options.h" #include "utils.h" @@ -723,7 +725,7 @@ DialogColorPicker::DialogColorPicker(wxWindow *parent, wxColour initial_color) wxSizer *recent_sizer = new wxBoxSizer(wxVERTICAL); recent_sizer->Add(recent_box, 1, wxEXPAND); - if (Options.AsBool(_T("RGBAdjust Tool"))) recent_sizer->Add(new wxButton(this,BUTTON_RGBADJUST,_T("rgbadjust()")), 0, wxEXPAND); + if (OPT_GET("Tool/Colour Picker/RGBAdjust Tool")->GetBool()) recent_sizer->Add(new wxButton(this,BUTTON_RGBADJUST,_T("rgbadjust()")), 0, wxEXPAND); wxSizer *picker_sizer = new wxBoxSizer(wxHORIZONTAL); picker_sizer->AddStretchSpacer(); @@ -764,11 +766,11 @@ DialogColorPicker::DialogColorPicker(wxWindow *parent, wxColour initial_color) // Fill the controls updating_controls = false; - int mode = Options.AsInt(_T("Color Picker Mode")); + int mode = OPT_GET("Tool/Colour Picker/Mode")->GetInt(); if (mode < 0 || mode > 4) mode = 3; // HSL default colorspace_choice->SetSelection(mode); SetColor(initial_color); - recent_box->LoadFromString(Options.AsText(_T("Color Picker Recent"))); + recent_box->LoadFromString(lagi_wxString(OPT_GET("Tool/Colour Picker/Recent")->GetString())); // The mouse event handler for the Dropper control must be manually assigned // The EVT_MOUSE_EVENTS macro can't take a control id @@ -821,8 +823,7 @@ void DialogColorPicker::SetColor(wxColour new_color) wxColour DialogColorPicker::GetColor() { recent_box->AddColor(cur_color); - Options.SetText(_T("Color Picker Recent"), recent_box->StoreToString()); - Options.Save(); + OPT_SET("Tool/Colour Picker/Recent")->SetString(STD_STR(recent_box->StoreToString())); return cur_color; } @@ -1326,7 +1327,7 @@ void DialogColorPicker::OnChangeMode(wxCommandEvent &evt) { if (!updating_controls) spectrum_dirty = true; - Options.SetInt(_T("Color Picker Mode"), colorspace_choice->GetSelection()); + OPT_SET("Tool/Colour Picker/Mode")->SetInt(colorspace_choice->GetSelection()); UpdateSpectrumDisplay(); } diff --git a/aegisub/src/dialog_detached_video.cpp b/aegisub/src/dialog_detached_video.cpp index b632208b2..a617ceece 100644 --- a/aegisub/src/dialog_detached_video.cpp +++ b/aegisub/src/dialog_detached_video.cpp @@ -44,6 +44,7 @@ #include "dialog_detached_video.h" #include "frame_main.h" +#include "main.h" #include "options.h" #include "video_box.h" #include "video_context.h" @@ -63,10 +64,10 @@ DialogDetachedVideo::DialogDetachedVideo(FrameMain *par, const wxSize &initialDi parent = par; // Set up window - int x = Options.AsInt(_T("Detached video last x")); - int y = Options.AsInt(_T("Detached video last y")); + int x = OPT_GET("Video/Detached/Last/X")->GetInt(); + int y = OPT_GET("Video/Detached/Last/Y")->GetInt(); if (x != -1 && y != -1) SetPosition(wxPoint(x,y)); - if (Options.AsBool(_T("Detached video maximized"))) Maximize(); + if (OPT_GET("Video/Detached/Maximized")->GetBool()) Maximize(); // Set obscure stuff SetExtraStyle((GetExtraStyle() & ~wxWS_EX_BLOCK_EVENTS) | wxWS_EX_PROCESS_UI_UPDATES); @@ -127,10 +128,9 @@ DialogDetachedVideo::DialogDetachedVideo(FrameMain *par, const wxSize &initialDi // Update parent->SetDisplayMode(0, -1); GetPosition(&x, &y); - Options.SetInt(_T("Detached video last x"), x); - Options.SetInt(_T("Detached video last y"), y); - Options.SetBool(_T("Detached video"),true); - Options.Save(); + OPT_SET("Video/Detached/Last/X")->SetInt(x); + OPT_SET("Video/Detached/Last/Y")->SetInt(y); + OPT_SET("Video/Detached/Enabled")->SetBool(true); // Copy the main accelerator table to this dialog wxAcceleratorTable *table = par->GetAcceleratorTable(); @@ -139,8 +139,7 @@ DialogDetachedVideo::DialogDetachedVideo(FrameMain *par, const wxSize &initialDi /// @brief Destructor DialogDetachedVideo::~DialogDetachedVideo() { - Options.SetBool(_T("Detached video maximized"),IsMaximized()); - Options.Save(); + OPT_SET("Video/Detached/Maximized")->SetBool(IsMaximized()); } // Event table @@ -154,7 +153,7 @@ END_EVENT_TABLE() /// @param event UNUSED void DialogDetachedVideo::OnClose(wxCloseEvent &WXUNUSED(event)) { FrameMain *par = parent; - Options.SetBool(_T("Detached video"),false); + OPT_SET("Video/Detached/Enabled")->SetBool(false); Destroy(); par->detachedVideo = NULL; par->SetDisplayMode(1,-1); @@ -164,8 +163,8 @@ void DialogDetachedVideo::OnClose(wxCloseEvent &WXUNUSED(event)) { /// @param event void DialogDetachedVideo::OnMove(wxMoveEvent &event) { wxPoint pos = event.GetPosition(); - Options.SetInt(_T("Detached video last x"),pos.x); - Options.SetInt(_T("Detached video last y"),pos.y); + OPT_SET("Video/Detached/Last/X")->SetInt(pos.x); + OPT_SET("Video/Detached/Last/Y")->SetInt(pos.y); } /// @brief Minimize event handler diff --git a/aegisub/src/dialog_dummy_video.cpp b/aegisub/src/dialog_dummy_video.cpp index 37b002da1..401f767a0 100644 --- a/aegisub/src/dialog_dummy_video.cpp +++ b/aegisub/src/dialog_dummy_video.cpp @@ -44,10 +44,12 @@ #include #endif +#include "compat.h" #include "dialog_dummy_video.h" #include "help_button.h" +#include "main.h" #include "options.h" - +#include "utils.h" /// DOCME struct ResolutionShortcut { @@ -123,12 +125,12 @@ bool DialogDummyVideo::CreateDummyVideo(wxWindow *parent, wxString &out_filename pattern = dlg.pattern->GetValue(); // Write to options - Options.SetFloat(_T("Video Dummy Last FPS"), fps); - Options.SetInt(_T("Video Dummy Last Width"), width); - Options.SetInt(_T("Video Dummy Last Height"), height); - Options.SetInt(_T("Video Dummy Last Length"), length); - Options.SetColour(_T("Video Dummy Last Colour"), colour); - Options.SetBool(_T("Video Dummy Pattern"), pattern); + OPT_SET("Video/Dummy/FPS")->SetDouble(fps); + OPT_SET("Video/Dummy/Last/Width")->SetInt(width); + OPT_SET("Video/Dummy/Last/Height")->SetInt(height); + OPT_SET("Video/Dummy/Last/Length")->SetInt(length); + OPT_SET("Colour/Video Dummy/Last Colour")->SetColour(STD_STR(colour.GetAsString(wxC2S_CSS_SYNTAX))); + OPT_SET("Video/Dummy/Pattern")->SetBool(pattern); out_filename = DummyVideoProvider::MakeFilename(fps, length, width, height, colour, pattern); return true; @@ -150,10 +152,10 @@ DialogDummyVideo::DialogDummyVideo(wxWindow *parent) resolution_shortcuts = new wxComboBox(this, Dummy_Video_Resolution_Shortcut, _T(""), wxDefaultPosition, wxDefaultSize, 0, 0, wxCB_READONLY); width = new wxTextCtrl(this, -1); height = new wxTextCtrl(this, -1); - colour = new ColourButton(this, -1, wxSize(30, 17), Options.AsColour(_T("Video Dummy Last Colour"))); + colour = new ColourButton(this, -1, wxSize(30, 17), lagi_wxColour(OPT_GET("Colour/Video Dummy/Last Colour")->GetColour())); pattern = new wxCheckBox(this, -1, _("Checkerboard pattern")); //fps = new wxComboBox(this, Dummy_Video_FPS, Options.AsText(_T("Video Dummy Last FPS")), wxDefaultPosition, wxDefaultSize, 0, 0, wxCB_DROPDOWN); - fps = new wxTextCtrl(this, Dummy_Video_FPS, Options.AsText(_T("Video Dummy Last FPS"))); + fps = new wxTextCtrl(this, Dummy_Video_FPS, wxString::Format("%f", OPT_GET("Video/Dummy/FPS")->GetDouble())); length = new wxSpinCtrl(this, Dummy_Video_Length); length_display = new wxStaticText(this, -1, _T("")); @@ -195,24 +197,24 @@ DialogDummyVideo::DialogDummyVideo(wxWindow *parent) // Initialise controls int lastwidth, lastheight, lastres = 0; - lastwidth = Options.AsInt(_T("Video Dummy Last Width")); - lastheight = Options.AsInt(_T("Video Dummy Last Height")); + lastwidth = OPT_GET("Video/Dummy/Last/Width")->GetInt(); + lastheight = OPT_GET("Video/Dummy/Last/Height")->GetInt(); for (ResolutionShortcut *res = resolutions; res->name; ++res) { resolution_shortcuts->Append(res->name); if (res->width == lastwidth && res->height == lastheight) resolution_shortcuts->SetSelection(lastres); lastres++; } - pattern->SetValue(Options.AsBool(_T("Video Dummy Pattern"))); + pattern->SetValue(OPT_GET("Video/Dummy/Pattern")->GetBool()); /*fps->Append(_T("23.976")); fps->Append(_T("29.97")); fps->Append(_T("24")); fps->Append(_T("25")); fps->Append(_T("30"));*/ - width->ChangeValue(Options.AsText(_T("Video Dummy Last Width"))); - height->ChangeValue(Options.AsText(_T("Video Dummy Last Height"))); + width->ChangeValue(AegiIntegerToString(OPT_GET("Video/Dummy/Last/Width")->GetInt())); + height->ChangeValue(AegiIntegerToString(OPT_GET("Video/Dummy/Last/Height")->GetInt())); length->SetRange(0, 0x10000000); - length->SetValue(Options.AsInt(_T("Video Dummy Last Length"))); + length->SetValue(OPT_GET("Video/Dummy/Last/Length")->GetInt()); UpdateLengthDisplay(); // Layout diff --git a/aegisub/src/dialog_fonts_collector.cpp b/aegisub/src/dialog_fonts_collector.cpp index 4726095c4..b1b239cf4 100644 --- a/aegisub/src/dialog_fonts_collector.cpp +++ b/aegisub/src/dialog_fonts_collector.cpp @@ -51,11 +51,13 @@ #include "ass_file.h" #include "ass_override.h" #include "ass_style.h" +#include "compat.h" #include "dialog_fonts_collector.h" #include "font_file_lister.h" #include "frame_main.h" #include "help_button.h" #include "libresrc/libresrc.h" +#include "main.h" #include "options.h" #include "scintilla_text_ctrl.h" #include "subs_grid.h" @@ -96,7 +98,7 @@ DialogFontsCollector::DialogFontsCollector(wxWindow *parent) main = (FrameMain*) parent; // Destination box - wxString dest = Options.AsText(_T("Fonts Collector Destination")); + wxString dest = lagi_wxString(OPT_GET("Path/Fonts Collector Destination")->GetString()); if (dest == _T("?script")) { wxFileName filename(AssFile::top->filename); dest = filename.GetPath(); @@ -122,7 +124,7 @@ DialogFontsCollector::DialogFontsCollector(wxWindow *parent) choices.Add(_("DEBUG: Verify all fonts in system")); #endif CollectAction = new wxRadioBox(this,RADIO_BOX,_T("Action"),wxDefaultPosition,wxDefaultSize,choices,1); - size_t lastAction = Options.AsInt(_T("Fonts Collector Action")); + size_t lastAction = OPT_GET("Tool/Fonts Collector/Action")->GetInt(); if (lastAction >= choices.GetCount()) lastAction = 0; CollectAction->SetSelection(lastAction); @@ -241,10 +243,9 @@ void DialogFontsCollector::OnStart(wxCommandEvent &event) { if (filename.GetPath() == dest) { dest = _T("?script"); } - Options.SetText(_T("Fonts Collector Destination"),dest); + OPT_SET("Path/Fonts Collector Destination")->SetString(STD_STR(dest)); } - Options.SetInt(_T("Fonts Collector Action"),action); - Options.Save(); + OPT_SET("Tool/Fonts Collector/Action")->SetInt(action); // Set buttons StartButton->Enable(false); diff --git a/aegisub/src/dialog_kara_timing_copy.cpp b/aegisub/src/dialog_kara_timing_copy.cpp index b87648e53..6947ab8ce 100644 --- a/aegisub/src/dialog_kara_timing_copy.cpp +++ b/aegisub/src/dialog_kara_timing_copy.cpp @@ -54,6 +54,7 @@ #include "dialog_kara_timing_copy.h" #include "help_button.h" #include "libresrc/libresrc.h" +#include "main.h" #include "subs_grid.h" #include "utils.h" #include "validators.h" @@ -852,7 +853,7 @@ DialogKanjiTimer::DialogKanjiTimer(wxWindow *parent, SubtitlesGrid *_grid) //Checkbox Interpolate = new wxCheckBox(this,-1,_("Attempt to interpolate kanji."),wxDefaultPosition,wxDefaultSize,wxALIGN_LEFT); - Interpolate->SetValue(Options.AsBool(_T("kanji timer interpolation"))); + Interpolate->SetValue(OPT_GET("Tool/Kanji Timer/Interpolation")->GetBool()); SourceStyle=new wxComboBox(this,-1,_T(""),wxDefaultPosition,wxSize(160,-1), subs->GetStyles(),wxCB_READONLY,wxDefaultValidator,_("Source Style")); @@ -934,8 +935,7 @@ END_EVENT_TABLE() /// @param event /// void DialogKanjiTimer::OnClose(wxCommandEvent &event) { - Options.SetBool(_T("kanji timer interpolation"),Interpolate->IsChecked()); - Options.Save(); + OPT_SET("Tool/Kanji Timer/Interpolation")->SetBool(Interpolate->IsChecked()); bool modified = !LinesToChange.empty(); while(LinesToChange.empty()==false) { diff --git a/aegisub/src/dialog_options.cpp b/aegisub/src/dialog_options.cpp deleted file mode 100644 index 93fbe493c..000000000 --- a/aegisub/src/dialog_options.cpp +++ /dev/null @@ -1,1229 +0,0 @@ -// Copyright (c) 2006, Rodrigo Braz Monteiro -// All rights reserved. -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are met: -// -// * Redistributions of source code must retain the above copyright notice, -// this list of conditions and the following disclaimer. -// * Redistributions in binary form must reproduce the above copyright notice, -// this list of conditions and the following disclaimer in the documentation -// and/or other materials provided with the distribution. -// * Neither the name of the Aegisub Group nor the names of its contributors -// may be used to endorse or promote products derived from this software -// without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" -// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE -// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE -// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR -// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF -// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS -// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN -// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) -// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE -// POSSIBILITY OF SUCH DAMAGE. -// -// Aegisub Project http://www.aegisub.org/ -// -// $Id$ - -/// @file dialog_options.cpp -/// @brief Main configuration dialogue box, including all pages -/// @ingroup configuration_ui -/// - - -/////////// -// Headers -#include "config.h" - -#ifndef AGI_PRE -#include -#include -#include -#if wxUSE_TREEBOOK -#include -#endif -#endif - -#include "audio_box.h" -#include "audio_display.h" -#include "browse_button.h" -#include "colour_button.h" -#include "dialog_options.h" -#include "frame_main.h" -#include "help_button.h" -#include "libresrc/libresrc.h" -#include "options.h" -#include "standard_paths.h" -#include "subs_edit_box.h" -#include "subs_grid.h" -#include "subtitles_provider_manager.h" -#include "tooltip_manager.h" -#include "utils.h" -#include "validators.h" -#include "video_box.h" -#include "video_context.h" -#include "video_provider_manager.h" -#include "video_slider.h" - - -#if wxUSE_TREEBOOK -/// DOCME -#define AddSubPage(page,text,select) AddPage(page,wxString::Format(_T("\t%s"),text),select) -#endif - -/////// -// IDs -enum { - - /// DOCME - BUTTON_DEFAULTS = 2500, - - /// DOCME - HOTKEY_LIST, - - /// DOCME - BUTTON_HOTKEY_SET, - - /// DOCME - BUTTON_HOTKEY_CLEAR, - - /// DOCME - BUTTON_HOTKEY_DEFAULT, - - /// DOCME - BUTTON_HOTKEY_DEFAULT_ALL -}; - - - -/// @brief Constructor -/// @param parent -/// -DialogOptions::DialogOptions(wxWindow *parent) -: wxDialog(parent, -1, _("Options"), wxDefaultPosition, wxDefaultSize) -{ - // Set icon - SetIcon(BitmapToIcon(GETIMAGE(options_button_24))); - - // Create book - book = new wxTreebook(this,-1,wxDefaultPosition,wxDefaultSize); - needsRestart = false; - - // Panels - wxPanel *generalPage = new wxPanel(book,-1); - wxPanel *filePage = new wxPanel(book,-1); - wxPanel *gridPage = new wxPanel(book,-1); - wxPanel *editPage = new wxPanel(book,-1); - wxPanel *videoPage = new wxPanel(book,-1); - wxPanel *audioPage = new wxPanel(book,-1); - wxPanel *audioAdvPage = new wxPanel(book,-1); - wxPanel *displayPage = new wxPanel(book,-1); - wxPanel *autoPage = new wxPanel(book,-1); - wxPanel *hotkeysPage = new wxPanel(book,-1); - BrowseButton *browse; - - // General page - { - wxSizer *genMainSizer = new wxBoxSizer(wxVERTICAL); - wxSizer *genSizer1 = new wxStaticBoxSizer(wxHORIZONTAL,generalPage,_("Startup")); - wxFlexGridSizer *genSizer4 = new wxFlexGridSizer(2,5,5); - - AddCheckBox(generalPage,genSizer4,_("Show Splash Screen"),_T("Show splash")); -#ifdef __WXMSW__ - AddCheckBox(generalPage,genSizer4,_("Auto Check for Updates"),_T("Auto check for updates")); -#endif - genSizer4->AddGrowableCol(0,1); - - genSizer1->Add(genSizer4,1,wxEXPAND|wxALL,5); - wxSizer *genSizer2 = new wxStaticBoxSizer(wxVERTICAL,generalPage,_("Limits for levels and recent files")); - wxFlexGridSizer *genSizer3 = new wxFlexGridSizer(2,5,5); - wxString options[8] = { _T("Undo levels"), _T("Recent timecodes max"), _T("Recent keyframes max"), _T("Recent sub max"), _T("Recent vid max"), _T("Recent aud max"), _T("Recent find max"), _T("Recent replace max") }; - wxString labels[8] = { _("Maximum undo levels"), _("Maximum recent timecode files"), _("Maximum recent keyframe files"), _("Maximum recent subtitle files"), _("Maximum recent video files"), _("Maximum recent audio files"), _("Maximum recent find strings"), _("Maximum recent replace strings") }; - for (int i=0;i<8;i++) { - wxSpinCtrl *spin = new wxSpinCtrl(generalPage,-1,_T(""),wxDefaultPosition,wxSize(70,-1),wxSP_ARROW_KEYS,0,32,0); - Bind(spin,options[i]); - genSizer3->Add(new wxStaticText(generalPage,-1,labels[i] + _T(": ")),1,wxALIGN_CENTRE_VERTICAL); - genSizer3->Add(spin,0); - } - genSizer3->AddGrowableCol(0,1); - genSizer2->Add(genSizer3,1,wxEXPAND | wxALL,5); - genMainSizer->Add(genSizer1,0,wxEXPAND | wxBOTTOM,5); - genMainSizer->Add(genSizer2,0,wxEXPAND,0); - genMainSizer->AddStretchSpacer(1); - generalPage->SetSizerAndFit(genMainSizer); - } - - // File save/load page - { - // Sizers - wxSizer *fileMainSizer = new wxBoxSizer(wxVERTICAL); - wxSizer *fileSizer1 = new wxStaticBoxSizer(wxVERTICAL,filePage,_("Auto-save")); - wxSizer *fileSizer2 = new wxBoxSizer(wxHORIZONTAL); - wxSizer *fileSizer3 = new wxStaticBoxSizer(wxHORIZONTAL,filePage,_("File paths")); - wxFlexGridSizer *fileSizer4 = new wxFlexGridSizer(3,5,5); - wxSizer *fileSizer5 = new wxStaticBoxSizer(wxHORIZONTAL,filePage,_("Miscellanea")); - wxFlexGridSizer *fileSizer6 = new wxFlexGridSizer(2,5,5); - - // First static box - wxCheckBox *check = new wxCheckBox(filePage,-1,_("Auto-backup")); - Bind(check,_T("Auto backup")); - wxTextCtrl *edit = new wxTextCtrl(filePage,-1,_T(""),wxDefaultPosition,wxSize(50,-1),0,NumValidator(NULL,false)); - Bind(edit,_T("Auto save every seconds")); - fileSizer2->Add(check,0,wxRIGHT | wxALIGN_CENTRE_VERTICAL,10); - fileSizer2->AddStretchSpacer(1); - fileSizer2->Add(new wxStaticText(filePage,-1,_("Auto-save every")),0,wxRIGHT | wxALIGN_CENTRE_VERTICAL,5); - fileSizer2->Add(edit,0,wxRIGHT,5); - fileSizer2->Add(new wxStaticText(filePage,-1,_("seconds.")),0,wxRIGHT | wxALIGN_CENTRE_VERTICAL,0); - - // Second static box - fileSizer4->Add(new wxStaticText(filePage,-1,_("Auto-save path:")),0,wxRIGHT | wxALIGN_CENTRE_VERTICAL,5); - edit = new wxTextCtrl(filePage,-1); - Bind(edit,_T("Auto save path")); - fileSizer4->Add(edit,1,wxEXPAND); - browse = new BrowseButton(filePage,-1,_T(""),BROWSE_FOLDER); - browse->Bind(edit); - fileSizer4->Add(browse,0,wxEXPAND); - - fileSizer4->Add(new wxStaticText(filePage,-1,_("Auto-backup path:")),0,wxRIGHT | wxALIGN_CENTRE_VERTICAL,5); - edit = new wxTextCtrl(filePage,-1); - Bind(edit,_T("Auto backup path")); - fileSizer4->Add(edit,1,wxEXPAND); - browse = new BrowseButton(filePage,-1,_T(""),BROWSE_FOLDER); - browse->Bind(edit); - fileSizer4->Add(browse,0,wxEXPAND); - fileSizer4->AddGrowableCol(1,1); - - // Third static box - fileSizer6->Add(new wxStaticText(filePage,-1,_("Auto-load linked files:")),0,wxRIGHT | wxALIGN_CENTRE_VERTICAL,5); - wxString choices[3] = { _("Never"), _("Always"), _("Ask") }; - wxComboBox *combo = new wxComboBox(filePage,-1,_T(""),wxDefaultPosition,wxDefaultSize,3,choices,wxCB_DROPDOWN | wxCB_READONLY); - Bind(combo,_T("Autoload linked files")); - fileSizer6->Add(combo,1,wxEXPAND); - fileSizer6->AddGrowableCol(1,1); - - // Sizers - fileSizer1->Add(fileSizer2,0,wxEXPAND | wxALL,5); - fileSizer3->Add(fileSizer4,1,wxEXPAND | wxALL,5); - fileSizer5->Add(fileSizer6,1,wxEXPAND | wxALL,5); - fileMainSizer->Add(fileSizer1,0,wxEXPAND | wxALL,0); - fileMainSizer->Add(fileSizer3,0,wxEXPAND | wxTOP,5); - fileMainSizer->Add(fileSizer5,0,wxEXPAND | wxTOP,5); - fileMainSizer->AddStretchSpacer(1); - filePage->SetSizerAndFit(fileMainSizer); - } - - // Edit box page - { - // Sizers - wxSizer *editMainSizer = new wxBoxSizer(wxVERTICAL); - wxSizer *editSizer1 = new wxStaticBoxSizer(wxVERTICAL,editPage,_("Options")); - wxSizer *editSizer6 = new wxBoxSizer(wxHORIZONTAL); - wxFlexGridSizer *editSizer2 = new wxFlexGridSizer(2,5,5); - wxSizer *editSizer3 = new wxStaticBoxSizer(wxVERTICAL,editPage,_("Style")); - wxFlexGridSizer *editSizer4 = new wxFlexGridSizer(2,2,2); - wxSizer *editSizer5 = new wxBoxSizer(wxHORIZONTAL); - - // First static box - wxString labels1[4] = { _("Enable call tips"), _("Enable syntax highlighting"), _("Link commiting of times"), _("Overwrite-Insertion in time boxes") }; - wxString options1[4] = { _T("Call Tips Enabled"), _T("Syntax Highlight Enabled"), _T("Link Time Boxes Commit"), _T("Insert Mode on Time Boxes") }; - for (int i=0;i<4;i++) { - wxCheckBox *control = new wxCheckBox(editPage,-1,labels1[i]); - Bind(control,options1[i]); - editSizer2->Add(control,1,wxEXPAND,0); - } - //editSizer2->AddGrowableCol(0,1); - editSizer2->AddGrowableCol(1,1); - editSizer6->Add(new wxStaticText(editPage,-1,_("Path to dictionary files:")),0,wxALIGN_CENTER_VERTICAL|wxRIGHT,5); - wxTextCtrl *edit = new wxTextCtrl(editPage,-1,_T("")); - Bind(edit,_T("Dictionaries path")); - editSizer6->Add(edit,1,wxEXPAND|wxALIGN_CENTER_VERTICAL|wxRIGHT,5); - browse = new BrowseButton(editPage,-1,_T(""),BROWSE_FOLDER); - browse->Bind(edit); - editSizer6->Add(browse,0,wxEXPAND); - - // Second static box - wxControl *control; - wxString labels2[10] = { _("Normal"), _("Brackets"), _("Slashes and Parentheses"), _("Tags"), _("Parameters") , - _("Error"), _("Error Background"), _("Line Break"), _("Karaoke templates"), _("Modified Background") }; - wxString options2[12] = { _T("Normal"), _T("Brackets"), _T("Slashes"), _T("Tags"), _T("Parameters") , - _T("Error"), _T("Error Background"), _T("Line Break"), _T("Karaoke Template"), _T("Edit box need enter background"), _T("Edit Font Face"), _T("Edit Font Size") }; - for (int i=0;i<10;i++) { - wxString caption = labels2[i]+_T(": "); - wxString option = options2[i]; - if (i < 9) { - caption = _("Syntax highlighter - ") + caption; - option = _T("Syntax highlight ") + option; - } - control = new ColourButton(editPage,-1,wxSize(40,10)); - Bind(control,option); - editSizer4->Add(new wxStaticText(editPage,-1,caption),0,wxALIGN_CENTER_VERTICAL|wxRIGHT,5); - editSizer4->Add(control,1,wxALIGN_RIGHT,0); - } - editSizer4->AddGrowableCol(1,1); - - // Third sizer - editSizer5->Add(new wxStaticText(editPage,-1,_("Font: ")),0,wxALIGN_CENTER_VERTICAL | wxRIGHT,10); - control = new wxTextCtrl(editPage,-1); - Bind(control,options2[10]); - browse = new BrowseButton(editPage,-1,_T(""),BROWSE_FONT); - browse->Bind((wxTextCtrl*)control); - editSizer5->Add(control,1,wxEXPAND | wxRIGHT,5); - control = new wxTextCtrl(editPage,-1,_T(""),wxDefaultPosition,wxSize(50,-1),0,NumValidator(NULL,false));; - Bind(control,options2[11]); - editSizer5->Add(control,0,wxEXPAND | wxRIGHT,5); - browse->Bind((wxTextCtrl*)control,1); - editSizer5->Add(browse,0,wxEXPAND); - - // Sizers - editSizer1->Add(editSizer2,1,wxEXPAND | wxALL,5); - editSizer1->Add(editSizer6,0,wxEXPAND | wxLEFT | wxRIGHT | wxBOTTOM,5); - editSizer3->Add(editSizer4,1,wxEXPAND | wxALL,5); - editSizer3->Add(editSizer5,0,wxEXPAND | wxALL,5); - editMainSizer->Add(editSizer1,0,wxEXPAND | wxALL,0); - editMainSizer->Add(editSizer3,0,wxEXPAND | wxTOP,5); - editMainSizer->AddStretchSpacer(1); - editPage->SetSizerAndFit(editMainSizer); - } - - // Grid page - { - // Sizers - wxSizer *gridMainSizer = new wxBoxSizer(wxVERTICAL); - wxSizer *gridSizer1 = new wxStaticBoxSizer(wxVERTICAL,gridPage,_("Options")); - wxSizer *gridSizer2 = new wxStaticBoxSizer(wxVERTICAL,gridPage,_("Style")); - wxFlexGridSizer *gridSizer3 = new wxFlexGridSizer(2,2,2); - wxSizer *gridSizer4 = new wxBoxSizer(wxHORIZONTAL); - wxSizer *gridSizer5 = new wxBoxSizer(wxHORIZONTAL); - - // First sizer - wxString labels1[2] = { _("Allow grid to take focus"), _("Highlight subtitles that are currently visible in video") }; - wxString options1[2] = { _T("Grid allow focus"), _T("Highlight subs in frame") }; - for (int i=0;i<2;i++) { - wxCheckBox *control = new wxCheckBox(gridPage,-1,labels1[i]); - Bind(control,options1[i]); - gridSizer1->Add(control,1,wxEXPAND | wxALL,5); - } - - // Second sizer - wxControl *control; - wxString labels2[12] = { _("Standard foreground"), _("Standard background"), _("Selection foreground"), - _("Selection background"), _("Comment background"), _("Selected comment background"), - _("Collision foreground"), _("Line in frame background"), _("Header"), - _("Left Column"), _("Active Line Border"), _("Lines") }; - wxString options2[12] = { _T("standard foreground"), _T("background"), _T("selection foreground"), - _T("selection background"), _T("comment background"), _T("selected comment background"), - _T("collision foreground") , _T("inframe background"), _T("header"), - _T("left column"), _T("active border"), _T("lines") }; - for (int i=0;i<12;i++) { - wxString caption = labels2[i] + _T(": "); - wxString option = _T("Grid ") + options2[i]; - control = new ColourButton(gridPage,-1,wxSize(40,10)); - Bind(control,option); - gridSizer3->Add(new wxStaticText(gridPage,-1,caption),0,wxALIGN_CENTER_VERTICAL|wxRIGHT,5); - gridSizer3->Add(control,1,wxALIGN_CENTER,0); - } - gridSizer3->AddGrowableCol(0,1); - - // Third sizer - gridSizer4->Add(new wxStaticText(gridPage,-1,_("Font: ")),0,wxALIGN_CENTER_VERTICAL | wxRIGHT,10); - control = new wxTextCtrl(gridPage,-1); - Bind(control,_T("Grid font face")); - browse = new BrowseButton(gridPage,-1,_T(""),BROWSE_FONT); - browse->Bind((wxTextCtrl*)control); - gridSizer4->Add(control,1,wxEXPAND | wxRIGHT,5); - control = new wxTextCtrl(gridPage,-1,_T(""),wxDefaultPosition,wxSize(50,-1),0,NumValidator(NULL,false));; - Bind(control,_T("Grid font size")); - browse->Bind((wxTextCtrl*)control,1); - gridSizer4->Add(control,0,wxEXPAND | wxRIGHT,5); - gridSizer4->Add(browse,0,wxEXPAND); - - // Fourth sizer - gridSizer5->Add(new wxStaticText(gridPage,-1,_("Replace override tags with: ")),0,wxALIGN_CENTER_VERTICAL | wxRIGHT,10); - control = new wxTextCtrl(gridPage,-1); - Bind(control,_T("Grid hide overrides char")); - gridSizer5->Add(control,1,wxEXPAND | wxRIGHT,5); - - // Sizers - gridSizer2->Add(gridSizer3,1,wxEXPAND | wxALL,5); - gridSizer2->Add(gridSizer4,0,wxEXPAND | wxALL,5); - gridSizer2->Add(gridSizer5,0,wxEXPAND | wxALL,5); - gridMainSizer->Add(gridSizer1,0,wxEXPAND | wxALL,0); - gridMainSizer->Add(gridSizer2,0,wxEXPAND | wxTOP,5); - gridMainSizer->AddStretchSpacer(1); - gridPage->SetSizerAndFit(gridMainSizer); - } - - // Video page - { - // Sizers - wxSizer *videoMainSizer = new wxBoxSizer(wxVERTICAL); - wxSizer *videoSizer1 = new wxStaticBoxSizer(wxVERTICAL,videoPage,_("Options")); - wxSizer *videoSizer2 = new wxStaticBoxSizer(wxVERTICAL,videoPage,_("Advanced - EXPERT USERS ONLY")); - wxFlexGridSizer *videoSizer3 = new wxFlexGridSizer(2,5,5); - wxFlexGridSizer *videoSizer4 = new wxFlexGridSizer(2,5,5); - wxControl *control; - - // First sizer - videoSizer3->Add(new wxStaticText(videoPage,-1,_("Match video resolution on open: ")),0,wxALIGN_CENTER_VERTICAL | wxRIGHT,10); - wxString choices1[3] = { _("Never"), _("Ask"), _("Always") }; - control = new wxComboBox(videoPage,-1,_T(""),wxDefaultPosition,wxDefaultSize,3,choices1,wxCB_READONLY | wxCB_DROPDOWN); - Bind(control,_T("Video check script res")); - videoSizer3->Add(control,1,wxEXPAND); - videoSizer3->Add(new wxStaticText(videoPage,-1,_("Default Zoom: ")),0,wxALIGN_CENTER_VERTICAL | wxRIGHT,10); - wxArrayString choices2; - for (int i=1;i<=16;i++) { - wxString toAdd = wxString::Format(_T("%i"),int(i*12.5)); - if (i%2) toAdd += _T(".5"); - toAdd += _T("%"); - choices2.Add(toAdd); - } - control = new wxComboBox(videoPage,-1,_T(""),wxDefaultPosition,wxDefaultSize,choices2,wxCB_READONLY | wxCB_DROPDOWN); - Bind(control,_T("Video Default Zoom")); - videoSizer3->Add(control,1,wxEXPAND); - videoSizer3->Add(new wxStaticText(videoPage,-1,_("Fast jump step in frames: ")),0,wxALIGN_CENTER_VERTICAL | wxRIGHT,10); - control = new wxTextCtrl(videoPage,-1,_T(""),wxDefaultPosition,wxDefaultSize,0,NumValidator()); - Bind(control,_T("Video fast jump step")); - videoSizer3->Add(control,1,wxEXPAND); - videoSizer3->Add(new wxStaticText(videoPage,-1,_("Screenshot save path: ")),0,wxALIGN_CENTER_VERTICAL | wxRIGHT,10); - wxString choices3[3] = { _T("?video"), _T("?script"), _T(".") }; - //control = new wxTextCtrl(videoPage,-1); - control = new wxComboBox(videoPage,-1,_T(""),wxDefaultPosition,wxDefaultSize,3,choices3,wxCB_DROPDOWN); - Bind(control,_T("Video screenshot path")); - videoSizer3->Add(control,1,wxEXPAND); - control = new wxCheckBox(videoPage,-1,_("Show keyframes in slider")); - Bind(control,_T("Show keyframes on video slider")); - videoSizer3->Add(control,0,wxEXPAND); - control = new wxCheckBox(videoPage,-1,_("Always show visual tools")); - Bind(control,_T("Always show visual tools")); - videoSizer3->Add(control,0,wxEXPAND); - videoSizer3->AddGrowableCol(1,1); - - // Second sizer - videoSizer4->Add(new wxStaticText(videoPage,-1,_("Video provider: ")),0,wxALIGN_CENTER_VERTICAL | wxRIGHT,10); - wxArrayString choices4 = VideoProviderFactoryManager::GetFactoryList(); - control = new wxComboBox(videoPage,-1,_T(""),wxDefaultPosition,wxDefaultSize,choices4,wxCB_DROPDOWN | wxCB_READONLY); - Bind(control,_T("Video provider"),1); - videoSizer4->Add(control,1,wxEXPAND); - videoSizer4->Add(new wxStaticText(videoPage,-1,_("Subtitles provider: ")),0,wxALIGN_CENTER_VERTICAL | wxRIGHT,10); - wxArrayString choices5 = SubtitlesProviderFactoryManager::GetFactoryList(); - control = new wxComboBox(videoPage,-1,_T(""),wxDefaultPosition,wxDefaultSize,choices5,wxCB_DROPDOWN | wxCB_READONLY); - Bind(control,_T("Subtitles provider"),1); - videoSizer4->Add(control,1,wxEXPAND); -#ifdef WIN32 - videoSizer4->Add(new wxStaticText(videoPage,-1,_("Avisynth memory limit: ")),0,wxALIGN_CENTER_VERTICAL | wxRIGHT,10); - control = new wxTextCtrl(videoPage,-1,_T(""),wxDefaultPosition,wxDefaultSize,0,NumValidator(NULL,false)); - Bind(control,_T("Avisynth memorymax")); - videoSizer4->Add(control,1,wxEXPAND); - //control = new wxCheckBox(videoPage,-1,_("Threaded video")); - //Bind(control,_T("Threaded video")); - //videoSizer4->Add(control,1,wxEXPAND); - control = new wxCheckBox(videoPage,-1,_("Allow pre-2.56a Avisynth")); - Bind(control,_T("Allow Ancient Avisynth")); - videoSizer4->Add(control,1,wxEXPAND); - videoSizer4->AddGrowableCol(1,1); -#endif - - // Sizers - videoSizer1->Add(videoSizer3,1,wxEXPAND | wxALL,5); - videoSizer2->Add(new wxStaticText(videoPage,-1,_("WARNING: Changing these settings might result in bugs,\ncrashes, glitches and/or movax.\nDon't touch these unless you know what you're doing.")),0,wxEXPAND | wxALL,5); - videoSizer2->Add(videoSizer4,1,wxEXPAND | wxALL,5); - videoMainSizer->Add(videoSizer1,0,wxEXPAND | wxALL,0); - videoMainSizer->Add(videoSizer2,0,wxEXPAND | wxTOP,5); - videoMainSizer->AddStretchSpacer(1); - videoPage->SetSizerAndFit(videoMainSizer); - } - - // Audio page - { - // Sizers - wxSizer *audioMainSizer = new wxBoxSizer(wxVERTICAL); - wxSizer *audioSizer1 = new wxStaticBoxSizer(wxVERTICAL,audioPage,_("Options")); - wxFlexGridSizer *audioSizer3 = new wxFlexGridSizer(2,5,5); - wxFlexGridSizer *audioSizer4 = new wxFlexGridSizer(2,5,5); - - // First sizer - AddCheckBox(audioPage,audioSizer3,_("Grab times from line upon selection"),_T("Audio grab times on select")); - AddCheckBox(audioPage,audioSizer3,_("Default mouse wheel to zoom"),_T("Audio Wheel Default To Zoom")); - AddCheckBox(audioPage,audioSizer3,_("Lock scroll on Cursor"),_T("Audio lock scroll on cursor")); - AddCheckBox(audioPage,audioSizer3,_("Snap to keyframes"),_T("Audio snap to keyframes")); - AddCheckBox(audioPage,audioSizer3,_("Snap to adjacent lines"),_T("Audio snap to other lines")); - AddCheckBox(audioPage,audioSizer3,_("Auto-focus on mouse over"),_T("Audio Autofocus")); - AddCheckBox(audioPage,audioSizer3,_("Play audio when stepping in video"),_T("Audio Plays When Stepping Video")); - audioSizer3->AddGrowableCol(1,1); - - // Second sizer - wxString choices1[3] = { _("Don't show"), _("Show previous"), _("Show all") }; - AddTextControl(audioPage,audioSizer4,_("Default timing length"),_T("Timing Default Duration"),TEXT_TYPE_NUMBER); - AddTextControl(audioPage,audioSizer4,_("Default lead-in length"),_T("Audio lead in"),TEXT_TYPE_NUMBER); - AddTextControl(audioPage,audioSizer4,_("Default lead-out length"),_T("Audio lead out"),TEXT_TYPE_NUMBER); - AddComboControl(audioPage,audioSizer4,_("Show inactive lines"),_T("Audio Inactive Lines Display Mode"),wxArrayString(3,choices1)); - AddTextControl(audioPage,audioSizer4,_("Start-marker drag sensitivity"),_T("Audio Start Drag Sensitivity"),TEXT_TYPE_NUMBER); - audioSizer4->AddGrowableCol(0,1); - - // Sizers - audioSizer1->Add(audioSizer3,0,wxEXPAND | wxALL,5); - audioSizer1->Add(audioSizer4,1,wxEXPAND | wxALL,5); - audioMainSizer->Add(audioSizer1,0,wxEXPAND | wxALL,0); - audioMainSizer->AddStretchSpacer(1); - audioPage->SetSizerAndFit(audioMainSizer); - } - - // Audio display page - { - // Sizers - wxSizer *displayMainSizer = new wxBoxSizer(wxVERTICAL); - wxSizer *displaySizer1 = new wxStaticBoxSizer(wxVERTICAL,displayPage,_("Options")); - wxSizer *displaySizer2 = new wxStaticBoxSizer(wxVERTICAL,displayPage,_("Style")); - wxFlexGridSizer *displaySizer3 = new wxFlexGridSizer(2,2,2); - wxFlexGridSizer *displaySizer4 = new wxFlexGridSizer(2,2,2); - - // First sizer - wxString labels1[6] = { _("Draw secondary lines"), _("Draw selection background"), _("Draw timeline"), - _("Draw cursor time"), _("Draw keyframes"), _("Draw video position") }; - wxString options1[6] = { _T("Draw Secondary Lines"), _T("Draw Selection Background") , _T("Draw Timeline"), - _T("Draw Cursor Time"), _T("Draw keyframes"), _T("Draw video position")}; - for (int i=0;i<6;i++) { - wxCheckBox *control = new wxCheckBox(displayPage,-1,labels1[i]); - Bind(control,_T("Audio ") + options1[i]); - displaySizer3->Add(control,1,wxEXPAND | wxALL,5); - } - - // Second sizer - wxControl *control; - wxString labels2[14] = { _("Play cursor"), _("Background"), _("Selection background"), - _("Selection background - modified"), _("Seconds boundary"), _("Waveform"), - _("Waveform - selection"), _("Waveform - modified"), _("Waveform - inactive"), - _("Boundary - start"), _("Boundary - end"), _("Boundary - inactive"), - _("Syllable text"), _("Syllable boundary") }; - wxString options2[14] = { _T("Play cursor"), _T("Background"), _T("Selection background"), - _T("Selection background modified"), _T("Seconds boundaries"), _T("Waveform"), - _T("Waveform selected"), _T("Waveform Modified"), _T("Waveform Inactive"), - _T("Line boundary start"), _T("Line boundary end"), _T("Line boundary inactive line"), - _T("Syllable text"), _T("Syllable boundaries") }; - for (int i=0;i<14;i++) { - wxString caption = labels2[i] + _T(": "); - wxString option = _T("Audio ") + options2[i]; - control = new ColourButton(displayPage,-1,wxSize(40,10)); - Bind(control,option); - displaySizer4->Add(new wxStaticText(displayPage,-1,caption),0,wxALIGN_CENTER_VERTICAL|wxRIGHT,5); - displaySizer4->Add(control,1,wxALIGN_CENTER,0); - } - displaySizer4->AddGrowableCol(0,1); - - // Sizers - displaySizer1->Add(displaySizer3,1,wxEXPAND | wxALL,5); - displaySizer2->Add(displaySizer4,1,wxEXPAND | wxALL,5); - displayMainSizer->Add(displaySizer1,0,wxEXPAND | wxALL,0); - displayMainSizer->Add(displaySizer2,0,wxEXPAND | wxTOP,5); - displayMainSizer->AddStretchSpacer(1); - displayPage->SetSizerAndFit(displayMainSizer); - } - - // Audio advanced page - { - // Sizers - wxFlexGridSizer *audioAdvSizer1 = new wxFlexGridSizer(2,5,5); - wxSizer *audioAdvSizer2 = new wxStaticBoxSizer(wxVERTICAL,audioAdvPage,_("Advanced - EXPERT USERS ONLY")); - wxSizer *audioAdvSizer3 = new wxBoxSizer(wxVERTICAL); - - // Controls - wxString choices2[3] = { _("None (NOT RECOMMENDED)"), _("RAM"), _("Hard Disk") }; -#ifdef WIN32 - wxString choices3[3] = { _T("ConvertToMono"), _T("GetLeftChannel"), _T("GetRightChannel") }; -#endif - - AddComboControl(audioAdvPage,audioAdvSizer1,_("Audio provider"),_T("Audio Provider"),AudioProviderFactoryManager::GetFactoryList(),true,1); - AddComboControl(audioAdvPage,audioAdvSizer1,_("Audio player"),_T("Audio Player"),AudioPlayerFactoryManager::GetFactoryList(),true,1); - AddComboControl(audioAdvPage,audioAdvSizer1,_("Cache type"),_T("Audio Cache"),wxArrayString(3,choices2),true); -#ifdef WIN32 - AddComboControl(audioAdvPage,audioAdvSizer1,_("Avisynth down-mixer"),_T("Audio Downmixer"),wxArrayString(3,choices3),false); -#endif - AddTextControl(audioAdvPage,audioAdvSizer1,_("HD cache path"),_T("Audio HD Cache Location"),TEXT_TYPE_FOLDER); - AddTextControl(audioAdvPage,audioAdvSizer1,_("HD cache name"),_T("Audio HD CAche Name")); - AddTextControl(audioAdvPage,audioAdvSizer1,_("Spectrum cutoff"),_T("Audio spectrum cutoff"),TEXT_TYPE_NUMBER); - wxString spectrum_quality_choices[] = { _("0 - Regular quality"), _("1 - Better quality"), _("2 - High quality"), _("3 - Insane quality") }; - AddComboControl(audioAdvPage,audioAdvSizer1,_("Spectrum quality"),_T("Audio spectrum quality"),wxArrayString(4,spectrum_quality_choices)); - AddTextControl(audioAdvPage,audioAdvSizer1,_("Spectrum cache memory max (MB)"),_T("Audio spectrum memory max"),TEXT_TYPE_NUMBER); - audioAdvSizer1->AddGrowableCol(0,1); - - // Main sizer - audioAdvSizer2->Add(new wxStaticText(audioAdvPage,-1,_("WARNING: Changing these settings might result in bugs,\ncrashes, glitches and/or movax.\nDon't touch these unless you know what you're doing.")),0,wxEXPAND | wxALL,5); - audioAdvSizer2->Add(audioAdvSizer1,1,wxEXPAND | wxALL,5); - audioAdvSizer3->Add(audioAdvSizer2,0,wxEXPAND); - audioAdvSizer3->AddStretchSpacer(1); - audioAdvPage->SetSizerAndFit(audioAdvSizer3); - } - - // Automation page - { - // Sizers - wxSizer *autoMainSizer = new wxBoxSizer(wxVERTICAL); - wxSizer *autoSizer1 = new wxStaticBoxSizer(wxVERTICAL,autoPage,_("Options")); - wxFlexGridSizer *autoSizer2 = new wxFlexGridSizer(2,5,5); - - // First sizer - AddTextControl(autoPage,autoSizer2,_("Base path"),_T("Automation Base Path")); - AddTextControl(autoPage,autoSizer2,_("Include path"),_T("Automation Include Path")); - AddTextControl(autoPage,autoSizer2,_("Auto-load path"),_T("Automation Autoload Path")); - wxString trace_choices[] = { _("0: Fatal"), _("1: Error"), _("2: Warning"), _("3: Hint"), _("4: Debug"), _("5: Trace") }; - wxString prio_choices[] = { _("Normal"), _("Below Normal (recommended)"), _("Lowest") }; - wxString reload_choices[] = { _("No scripts"), _("Subtitle-local scripts"), _("Global autoload scripts"), _("All scripts") }; - AddComboControl(autoPage,autoSizer2,_("Trace level"),_T("Automation Trace Level"),wxArrayString(6,trace_choices)); - AddComboControl(autoPage,autoSizer2,_("Thread priority"),_T("Automation Thread Priority"),wxArrayString(3,prio_choices)); - AddComboControl(autoPage,autoSizer2,_("Autoreload on Export"),_T("Automation Autoreload Mode"),wxArrayString(4,reload_choices)); - autoSizer2->AddGrowableCol(1,1); - - // Sizers - autoSizer1->Add(autoSizer2,1,wxEXPAND | wxALL,5); - autoMainSizer->Add(autoSizer1,0,wxEXPAND | wxALL,0); - autoMainSizer->AddStretchSpacer(1); - autoPage->SetSizerAndFit(autoMainSizer); - } - - // Hotkeys page - { - // Variables - hotkeysModified = false; - origKeys = Hotkeys.key; - - // List of shortcuts - Shortcuts = new wxListView(hotkeysPage,HOTKEY_LIST,wxDefaultPosition,wxDefaultSize,wxLC_REPORT | wxLC_SINGLE_SEL); - Shortcuts->InsertColumn(0,_("Function"),wxLIST_FORMAT_LEFT,200); - Shortcuts->InsertColumn(1,_("Key"),wxLIST_FORMAT_LEFT,120); - - // Populate list - std::map::iterator cur; - for (cur = Hotkeys.key.end();cur-- != Hotkeys.key.begin();) { - wxListItem item; - item.SetText(wxGetTranslation(cur->second.origName)); - item.SetData(&cur->second); - int pos = Shortcuts->InsertItem(item); - Shortcuts->SetItem(pos,1,cur->second.GetText()); - } - - // Create buttons - wxSizer *buttons = new wxBoxSizer(wxHORIZONTAL); - buttons->Add(new wxButton(hotkeysPage,BUTTON_HOTKEY_SET,_("Set Hotkey...")),1,wxEXPAND|wxRIGHT,5); - buttons->Add(new wxButton(hotkeysPage,BUTTON_HOTKEY_CLEAR,_("Clear Hotkey")),0,wxEXPAND|wxRIGHT,5); - buttons->Add(new wxButton(hotkeysPage,BUTTON_HOTKEY_DEFAULT,_("Default")),0,wxEXPAND|wxRIGHT,5); - buttons->Add(new wxButton(hotkeysPage,BUTTON_HOTKEY_DEFAULT_ALL,_("Default All")),0,wxEXPAND|wxRIGHT,0); - - // Main sizer - wxSizer *hotkeysSizer = new wxBoxSizer(wxVERTICAL); - hotkeysSizer->Add(Shortcuts,1,wxLEFT|wxRIGHT|wxTOP|wxEXPAND,5); - hotkeysSizer->Add(buttons,0,wxALL|wxEXPAND,5); - hotkeysPage->SetSizerAndFit(hotkeysSizer); - } - - // List book - book->AddPage(generalPage,_("General"),true); - book->AddSubPage(filePage,_("File save/load"),true); - book->AddSubPage(editPage,_("Subtitles edit box"),true); - book->AddSubPage(gridPage,_("Subtitles grid"),true); - book->AddPage(videoPage,_("Video"),true); - book->AddPage(audioPage,_("Audio"),true); - book->AddSubPage(displayPage,_("Display"),true); - book->AddSubPage(audioAdvPage,_("Advanced"),true); - book->AddPage(autoPage,_("Automation"),true); - book->AddPage(hotkeysPage,_("Hotkeys"),true); - #ifdef wxUSE_TREEBOOK - book->ChangeSelection(Options.AsInt(_T("Options page"))); - #endif - book->Fit(); - - // Buttons Sizer - wxStdDialogButtonSizer *stdButtonSizer = new wxStdDialogButtonSizer(); - stdButtonSizer->AddButton(new wxButton(this,wxID_OK)); - stdButtonSizer->AddButton(new wxButton(this,wxID_CANCEL)); - stdButtonSizer->AddButton(new wxButton(this,wxID_APPLY)); - stdButtonSizer->AddButton(new HelpButton(this,_T("Options"))); - stdButtonSizer->Realize(); - wxSizer *buttonSizer = new wxBoxSizer(wxHORIZONTAL); - wxButton *defaultButton = new wxButton(this,BUTTON_DEFAULTS,_("Restore Defaults")); - buttonSizer->Add(defaultButton,0,wxEXPAND); - buttonSizer->AddStretchSpacer(1); - buttonSizer->Add(stdButtonSizer,0,wxEXPAND); - - // Main Sizer - wxSizer *mainSizer = new wxBoxSizer(wxVERTICAL); - mainSizer->Add(book,1,wxEXPAND | wxALL,5); - mainSizer->Add(buttonSizer,0,wxEXPAND | wxLEFT | wxRIGHT | wxBOTTOM,5); - mainSizer->SetSizeHints(this); - SetSizerAndFit(mainSizer); - CenterOnParent(); - - // Read - ReadFromOptions(); -} - - - -/// @brief Destructor -/// -DialogOptions::~DialogOptions() { -} - - - -/// @brief Bind control to option -/// @param ctrl -/// @param option -/// @param param -/// -void DialogOptions::Bind(wxControl *ctrl, wxString option,int param) { - OptionsBind bind; - bind.ctrl = ctrl; - bind.option = option; - bind.param = param; - binds.push_back(bind); -} - - - -/// @brief Add a wxTextCtrl -/// @param parent -/// @param sizer -/// @param label -/// @param option -/// @param type -/// -void DialogOptions::AddTextControl(wxWindow *parent,wxSizer *sizer,wxString label,wxString option,TextType type) { - sizer->Add(new wxStaticText(parent,-1,label + wxString(_T(": "))),0,wxALIGN_CENTER_VERTICAL | wxRIGHT,10); - wxTextCtrl *control; - if (type == TEXT_TYPE_NUMBER) control = new wxTextCtrl(parent,-1,_T(""),wxDefaultPosition,wxDefaultSize,0,NumValidator()); - else control = new wxTextCtrl(parent,-1); - Bind(control,option); - sizer->Add(control,1,wxEXPAND); -} - - - -/// @brief Add a wxComboBox -/// @param parent -/// @param sizer -/// @param label -/// @param option -/// @param choices -/// @param readOnly -/// @param bindParam -/// -void DialogOptions::AddComboControl(wxWindow *parent,wxSizer *sizer,wxString label,wxString option,wxArrayString choices,bool readOnly,int bindParam) { - sizer->Add(new wxStaticText(parent,-1,label + wxString(_T(": "))),0,wxALIGN_CENTER_VERTICAL | wxRIGHT,10); - int flags = wxCB_DROPDOWN; - if (readOnly) flags |= wxCB_READONLY; - wxComboBox *control = new wxComboBox(parent,-1,_T(""),wxDefaultPosition,wxDefaultSize,choices,flags); - Bind(control,option,bindParam); - sizer->Add(control,1,wxEXPAND); -} - - - -/// @brief Add a checkbox -/// @param parent -/// @param sizer -/// @param label -/// @param option -/// -void DialogOptions::AddCheckBox(wxWindow *parent,wxSizer *sizer,wxString label,wxString option) { - wxControl *control = new wxCheckBox(parent,-1,label); - Bind(control,option); - sizer->Add(control,1,wxEXPAND,0); -} - - -/////////////// -// Event table -BEGIN_EVENT_TABLE(DialogOptions,wxDialog) - EVT_BUTTON(wxID_OK,DialogOptions::OnOK) - EVT_BUTTON(wxID_CANCEL,DialogOptions::OnCancel) - EVT_BUTTON(wxID_APPLY,DialogOptions::OnApply) - EVT_BUTTON(BUTTON_DEFAULTS,DialogOptions::OnDefaults) - EVT_BUTTON(BUTTON_HOTKEY_SET,DialogOptions::OnEditHotkey) - EVT_BUTTON(BUTTON_HOTKEY_CLEAR,DialogOptions::OnClearHotkey) - EVT_BUTTON(BUTTON_HOTKEY_DEFAULT,DialogOptions::OnDefaultHotkey) - EVT_BUTTON(BUTTON_HOTKEY_DEFAULT_ALL,DialogOptions::OnDefaultAllHotkey) -END_EVENT_TABLE() - - - -/// @brief OK -/// @param event -/// -void DialogOptions::OnOK(wxCommandEvent &event) { - Options.SetInt(_T("Options page"),book->GetSelection()); - WriteToOptions(); - EndModal(0); - - // Restart - if (needsRestart) { - int answer = wxMessageBox(_("Aegisub must restart for the changes to take effect. Restart now?"),_("Restart Aegisub"),wxYES_NO); - if (answer == wxYES) { - FrameMain *frame = (FrameMain*) GetParent(); - if (frame->Close()) { - RestartAegisub(); - //wxStandardPaths stand; - //wxExecute(stand.GetExecutablePath()); - } - } - } -} - - - -/// @brief Apply -/// @param event -/// -void DialogOptions::OnApply(wxCommandEvent &event) { - Options.SetInt(_T("Options page"),book->GetSelection()); - WriteToOptions(true); -} - - - -/// @brief Cancel -/// @param event -/// -void DialogOptions::OnCancel(wxCommandEvent &event) { - // Undo hotkeys - if (hotkeysModified) Hotkeys.key = origKeys; - - // Set options - Options.SetInt(_T("Options page"),book->GetSelection()); - Options.Save(); - EndModal(0); - - // Restart - if (needsRestart) { - int answer = wxMessageBox(_("Aegisub must restart for the changes to take effect. Restart now?"),_("Restart Aegisub"),wxYES_NO); - if (answer == wxYES) { - FrameMain *frame = (FrameMain*) GetParent(); - if (frame->Close()) { - RestartAegisub(); - //wxStandardPaths stand; - //wxExecute(stand.GetExecutablePath()); - } - } - } -} - - - -/// @brief Restore defaults -/// @param event -/// -void DialogOptions::OnDefaults(wxCommandEvent &event) { - int result = wxMessageBox(_("Are you sure that you want to restore the defaults? All your settings will be overriden."),_("Restore defaults?"),wxYES_NO); - if (result == wxYES) { - Options.LoadDefaults(true); - Options.Save(); - ReadFromOptions(); - } -} - - - -/// @brief Write to options -/// @param justApply -/// -void DialogOptions::WriteToOptions(bool justApply) { - // Flags - bool mustRestart = false; - bool editBox = false; - bool grid = false; - bool video = false; - bool audio = false; - bool videoReload = false; - bool audioReload = false; - - // For each bound item - for (unsigned int i=0;iIsKindOf(CLASSINFO(wxCheckBox))) { - wxCheckBox *check = (wxCheckBox*) binds[i].ctrl; - if (Options.AsBool(binds[i].option) != check->GetValue()) { - Options.SetBool(binds[i].option,check->GetValue()); - modified = true; - } - } - - // Spin control - if (binds[i].ctrl->IsKindOf(CLASSINFO(wxSpinCtrl))) { - wxSpinCtrl *spin = (wxSpinCtrl*) binds[i].ctrl; - if (spin->GetValue() != Options.AsInt(binds[i].option)) { - Options.SetInt(binds[i].option,spin->GetValue()); - modified = true; - } - } - - // Text control - if (binds[i].ctrl->IsKindOf(CLASSINFO(wxTextCtrl))) { - wxTextCtrl *text = (wxTextCtrl*) binds[i].ctrl; - if (text->GetValue() != Options.AsText(binds[i].option)) { - Options.ResetWith(binds[i].option,text->GetValue()); - modified = true; - } - } - - // Combo box - if (binds[i].ctrl->IsKindOf(CLASSINFO(wxComboBox))) { - wxComboBox *combo = (wxComboBox*) binds[i].ctrl; - int style = combo->GetWindowStyleFlag(); - - // Read-only, use as value - if (style & wxCB_READONLY && binds[i].param == 0) { - if (combo->GetSelection() != Options.AsInt(binds[i].option)) { - Options.SetInt(binds[i].option,combo->GetSelection()); - modified = true; - } - } - - // Editable, use as text - else { - if (!combo->GetValue().IsEmpty() && combo->GetValue() != Options.AsText(binds[i].option)) { - Options.SetText(binds[i].option,combo->GetValue()); - modified = true; - } - } - } - - // Colour button - if (binds[i].ctrl->IsKindOf(CLASSINFO(wxBitmapButton))) { - ColourButton *button = (ColourButton*) binds[i].ctrl; - if (button->GetColour() != Options.AsColour(binds[i].option)) { - Options.SetColour(binds[i].option,button->GetColour()); - modified = true; - } - } - - // Set modification type - if (modified) { - ModType type = Options.GetModType(binds[i].option); - if (type == MOD_RESTART) mustRestart = true; - if (type == MOD_EDIT_BOX) editBox = true; - if (type == MOD_GRID) grid = true; - if (type == MOD_VIDEO) video = true; - if (type == MOD_VIDEO_RELOAD) videoReload = true; - if (type == MOD_AUDIO) audio = true; - if (type == MOD_AUDIO_RELOAD) audioReload = true; - } - } - - // Apply hotkey changes if modified - if (hotkeysModified) { - // Save changes - Hotkeys.modified = true; - Hotkeys.Save(); - hotkeysModified = false; - origKeys = Hotkeys.key; - - // Rebuild menu - FrameMain *parent = (FrameMain*) GetParent(); - parent->InitMenu(); - - // Rebuild accelerator table - parent->SetAccelerators(); - - // Update tooltips - ToolTipManager::Update(); - } - - // Save options - Options.SetFile(StandardPaths::DecodePath(_T("?user/config.dat"))); - Options.Save(); - - // Need restart? - if (mustRestart) { - if (justApply) needsRestart = true; - else { - int answer = wxMessageBox(_("Aegisub must restart for the changes to take effect. Restart now?"),_("Restart Aegisub"),wxYES_NO); - if (answer == wxYES) { - FrameMain *frame = (FrameMain*) GetParent(); - if (frame->Close()) { - RestartAegisub(); - //wxStandardPaths stand; - //wxExecute(stand.GetExecutablePath()); - } - } - } - } - - // Other modifications - if (!mustRestart || justApply) { - // Edit box - if (editBox) { - FrameMain *frame = (FrameMain*) GetParent(); - frame->EditBox->TextEdit->SetStyles(); - frame->EditBox->TextEdit->UpdateStyle(); - } - - // Grid - if (grid) { - FrameMain *frame = (FrameMain*) GetParent(); - frame->SubsBox->UpdateStyle(); - } - - // Video - if (videoReload) { - VideoContext::Get()->Reload(); - } - else if (video) { - FrameMain *frame = (FrameMain*) GetParent(); - frame->videoBox->videoSlider->Refresh(); - } - - // Audio - if (audioReload) { - FrameMain *frame = (FrameMain*) GetParent(); - frame->audioBox->audioDisplay->Reload(); - } - else if (audio) { - FrameMain *frame = (FrameMain*) GetParent(); - frame->audioBox->audioDisplay->RecreateImage(); - frame->audioBox->audioDisplay->Refresh(); - } - } -} - - - -/// @brief Read form options -/// -void DialogOptions::ReadFromOptions() { - for (unsigned int i=0;iIsKindOf(CLASSINFO(wxCheckBox))) { - wxCheckBox *check = (wxCheckBox*) binds[i].ctrl; - check->SetValue(Options.AsBool(binds[i].option)); - } - - // Spin control - if (binds[i].ctrl->IsKindOf(CLASSINFO(wxSpinCtrl))) { - wxSpinCtrl *spin = (wxSpinCtrl*) binds[i].ctrl; - spin->SetValue(Options.AsInt(binds[i].option)); - } - - // Text control - if (binds[i].ctrl->IsKindOf(CLASSINFO(wxTextCtrl))) { - wxTextCtrl *text = (wxTextCtrl*) binds[i].ctrl; - text->SetValue(Options.AsText(binds[i].option)); - } - - // Combo box - if (binds[i].ctrl->IsKindOf(CLASSINFO(wxComboBox))) { - wxComboBox *combo = (wxComboBox*) binds[i].ctrl; - int style = combo->GetWindowStyleFlag(); - - // Read-only, use as value - if (style & wxCB_READONLY && binds[i].param == 0) { - combo->SetSelection(Options.AsInt(binds[i].option)); - } - - // Editable, set text - else { - wxString value = Options.AsText(binds[i].option); - if (!(style & wxCB_READONLY) && combo->FindString(value) == wxNOT_FOUND) combo->Append(value); - combo->SetValue(value); - } - } - - // Colour button - if (binds[i].ctrl->IsKindOf(CLASSINFO(wxBitmapButton))) { - ColourButton *button = (ColourButton*) binds[i].ctrl; - button->SetColour(Options.AsColour(binds[i].option)); - } - } -} - - - -/// @brief Edit a hotkey -/// @param event -/// @return -/// -void DialogOptions::OnEditHotkey(wxCommandEvent &event) { - // Get selection - int sel = Shortcuts->GetFirstSelected(); - if (sel == wxNOT_FOUND) return; - - // Get key and store old - HotkeyType *curKey = (HotkeyType *) wxUIntToPtr(Shortcuts->GetItemData(sel)); - int oldKeycode = curKey->keycode; - int oldFlags = curKey->flags; - - // Open dialog - DialogInputHotkey input(this, curKey, Shortcuts->GetItemText(sel), Shortcuts); - input.ShowModal(); - - // Update stuff if it changed - if (oldKeycode != curKey->keycode || oldFlags != curKey->flags) { - Shortcuts->SetItem(sel,1,curKey->GetText()); - hotkeysModified = true; - } -} - - - -/// @brief Clear a hotkey -/// @param event -/// -void DialogOptions::OnClearHotkey(wxCommandEvent &event) { - for (int item=-1;true;) { - item = Shortcuts->GetNextItem(item,wxLIST_NEXT_ALL,wxLIST_STATE_SELECTED); - if (item == -1) break; - - HotkeyType *curKey = (HotkeyType *) wxUIntToPtr(Shortcuts->GetItemData(item)); - if (curKey->keycode != 0 || curKey->flags != 0) { - hotkeysModified = true; - curKey->keycode = 0; - curKey->flags = 0; - Shortcuts->SetItem(item,1,curKey->GetText()); - } - } -} - - - -/// @brief Reset hotkey to default -/// @param event -/// -void DialogOptions::OnDefaultHotkey(wxCommandEvent &event) { - // Load defaults - HotkeyManager defs; - defs.LoadDefaults(); - - // Replace - for (int item=-1;true;) { - item = Shortcuts->GetNextItem(item,wxLIST_NEXT_ALL,wxLIST_STATE_SELECTED); - if (item == -1) break; - - HotkeyType *curKey = (HotkeyType *) wxUIntToPtr(Shortcuts->GetItemData(item)); - HotkeyType *origKey = &defs.key[curKey->origName.Lower()]; - if (origKey->keycode != curKey->keycode || origKey->flags != curKey->flags) { - hotkeysModified = true; - curKey->keycode = origKey->keycode; - curKey->flags = origKey->flags; - Shortcuts->SetItem(item,1,curKey->GetText()); - - // Unmap duplicate - HotkeyType *dup = Hotkeys.Find(origKey->keycode,origKey->flags); - if (dup) { - dup->keycode = 0; - dup->flags = 0; - int item = Shortcuts->FindItem(-1,wxPtrToUInt(dup)); - if (item != -1) Shortcuts->SetItem(item,1,dup->GetText()); - } - } - } -} - - - -/// @brief Reset all hotkeys to default -/// @param event -/// -void DialogOptions::OnDefaultAllHotkey(wxCommandEvent &event) { - Hotkeys.LoadDefaults(); - Shortcuts->Freeze(); - Shortcuts->ClearAll(); - Shortcuts->InsertColumn(0,_("Function"),wxLIST_FORMAT_LEFT,200); - Shortcuts->InsertColumn(1,_("Key"),wxLIST_FORMAT_LEFT,120); - - // Populate list - std::map::iterator cur; - for (cur = Hotkeys.key.end();cur-- != Hotkeys.key.begin();) { - wxListItem item; - item.SetText(wxGetTranslation(cur->second.origName)); - item.SetData(&cur->second); - int pos = Shortcuts->InsertItem(item); - Shortcuts->SetItem(pos,1,cur->second.GetText()); - } - hotkeysModified = true; - Shortcuts->Thaw(); -} - - - -/// @brief Input constructor -/// @param _key -/// @param name -/// @param shorts -/// -DialogInputHotkey::DialogInputHotkey(wxWindow *parent, HotkeyType *_key, wxString name, wxListView *shorts) -: wxDialog(parent, -1, _("Press Key"), wxDefaultPosition, wxDefaultSize, wxCAPTION | wxWANTS_CHARS) -{ - // Key - key = _key; - shortcuts = shorts; - - wxButton *cancel_button = new wxButton(this, wxID_CANCEL); - cancel_button->Connect(wxEVT_KEY_DOWN, (wxObjectEventFunction)&DialogInputHotkey::OnKeyDown, 0, this); - - // Main sizer - wxSizer *MainSizer = new wxBoxSizer(wxVERTICAL); - MainSizer->Add(new wxStaticText(this,-1,wxString::Format(_("Press key to bind to \"%s\" or Esc to cancel."), name.c_str())), 0, wxALL, 12); - MainSizer->Add(cancel_button, 0, wxALIGN_CENTER|wxALL&~wxTOP, 12); - MainSizer->SetSizeHints(this); - SetSizer(MainSizer); - CentreOnParent(); -} - - - -///////////////////// -// Input event table -BEGIN_EVENT_TABLE(DialogInputHotkey,wxDialog) - EVT_KEY_DOWN(DialogInputHotkey::OnKeyDown) -END_EVENT_TABLE() - - - -/// @brief On key down -/// @param event -/// @return -/// -void DialogInputHotkey::OnKeyDown(wxKeyEvent &event) { - // Get key - int keycode = event.GetKeyCode(); - if (keycode == WXK_ESCAPE) EndModal(0); - else if (keycode != WXK_SHIFT && keycode != WXK_CONTROL && keycode != WXK_ALT) { - // Get modifier - int mod = 0; - if (event.m_altDown) mod |= wxACCEL_ALT; -#ifdef __APPLE__ - if (event.m_metaDown) mod |= wxACCEL_CTRL; -#else - if (event.m_controlDown) mod |= wxACCEL_CTRL; -#endif - if (event.m_shiftDown) mod |= wxACCEL_SHIFT; - - // Check if keycode is free - HotkeyType *dup = Hotkeys.Find(keycode,mod); - if (dup) { - int result = wxMessageBox(wxString::Format(_("The hotkey %s is already mapped to %s. If you proceed, that hotkey will be cleared. Proceed?"),dup->GetText().c_str(),dup->origName.c_str()),_("Hotkey conflict"),wxYES_NO | wxICON_EXCLAMATION); - if (result == wxNO) { - EndModal(0); - return; - } - dup->keycode = 0; - dup->flags = 0; - int item = shortcuts->FindItem(-1,wxPtrToUInt(dup)); - if (item != -1) shortcuts->SetItem(item,1,dup->GetText()); - } - - // Set keycode - key->keycode = keycode; - key->flags = mod; - - // End dialogue - EndModal(0); - } - else event.Skip(); -} - diff --git a/aegisub/src/dialog_options.h b/aegisub/src/dialog_options.h deleted file mode 100644 index f933ad959..000000000 --- a/aegisub/src/dialog_options.h +++ /dev/null @@ -1,186 +0,0 @@ -// Copyright (c) 2006, Rodrigo Braz Monteiro -// All rights reserved. -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are met: -// -// * Redistributions of source code must retain the above copyright notice, -// this list of conditions and the following disclaimer. -// * Redistributions in binary form must reproduce the above copyright notice, -// this list of conditions and the following disclaimer in the documentation -// and/or other materials provided with the distribution. -// * Neither the name of the Aegisub Group nor the names of its contributors -// may be used to endorse or promote products derived from this software -// without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" -// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE -// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE -// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR -// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF -// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS -// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN -// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) -// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE -// POSSIBILITY OF SUCH DAMAGE. -// -// Aegisub Project http://www.aegisub.org/ -// -// $Id$ - -/// @file dialog_options.h -/// @see dialog_options.cpp -/// @ingroup configuration_ui -/// - - - - -//////////// -// Includes -#ifndef AGI_PRE -#include -#include - -#include -#include -#endif - -#include "hotkeys.h" -#include "options.h" - - -////////////// -// Prototypes -class FrameMain; -class DialogInputHotkey; -#if wxUSE_TREEBOOK -class wxTreebook; -#else -#include - -/// DOCME -typedef wxChoicebook wxTreebook; -#endif - - - -/// DOCME -/// @class OptionsBind -/// @brief DOCME -/// -/// DOCME -class OptionsBind { -public: - - /// DOCME - wxControl *ctrl; - - /// DOCME - wxString option; - - /// DOCME - int param; -}; - - - -/// DOCME -enum TextType { - - /// DOCME - TEXT_TYPE_PLAIN, - - /// DOCME - TEXT_TYPE_NUMBER, - - /// DOCME - TEXT_TYPE_FILE, - - /// DOCME - TEXT_TYPE_FOLDER, - - /// DOCME - TEXT_TYPE_FONT -}; - - -/// DOCME -/// @class DialogOptions -/// @brief DOCME -/// -/// DOCME -class DialogOptions: public wxDialog { -private: - - /// DOCME - bool needsRestart; - - - /// DOCME - wxTreebook *book; - - /// DOCME - std::vector binds; - - - /// DOCME - std::map origKeys; - - /// DOCME - wxListView *Shortcuts; - - /// DOCME - bool hotkeysModified; - - void Bind(wxControl *ctrl,wxString option,int param=0); - void WriteToOptions(bool justApply=false); - void ReadFromOptions(); - - void AddTextControl(wxWindow *parent,wxSizer *sizer,wxString label,wxString option,TextType type=TEXT_TYPE_PLAIN); - void AddComboControl(wxWindow *parent,wxSizer *sizer,wxString label,wxString option,wxArrayString choices,bool readOnly=true,int bindParam=0); - void AddCheckBox(wxWindow *parent,wxSizer *sizer,wxString label,wxString option); - - void OnOK(wxCommandEvent &event); - void OnCancel(wxCommandEvent &event); - void OnApply(wxCommandEvent &event); - void OnDefaults(wxCommandEvent &event); - - void OnEditHotkey(wxCommandEvent &event); - void OnClearHotkey(wxCommandEvent &event); - void OnDefaultHotkey(wxCommandEvent &event); - void OnDefaultAllHotkey(wxCommandEvent &event); - -public: - DialogOptions(wxWindow *parent); - ~DialogOptions(); - - DECLARE_EVENT_TABLE() -}; - - - - -/// DOCME -/// @class DialogInputHotkey -/// @brief DOCME -/// -/// DOCME -class DialogInputHotkey : public wxDialog { - - /// DOCME - HotkeyType *key; - - /// DOCME - wxListView *shortcuts; - - void OnKeyDown(wxKeyEvent &event); - -public: - DialogInputHotkey(wxWindow *parent, HotkeyType *key, wxString name, wxListView *Shortcuts); - - DECLARE_EVENT_TABLE() -}; - - diff --git a/aegisub/src/dialog_paste_over.cpp b/aegisub/src/dialog_paste_over.cpp index e746d332c..387f883fd 100644 --- a/aegisub/src/dialog_paste_over.cpp +++ b/aegisub/src/dialog_paste_over.cpp @@ -48,6 +48,7 @@ #include "dialog_paste_over.h" #include "help_button.h" +#include "main.h" #include "options.h" @@ -87,7 +88,10 @@ DialogPasteOver::DialogPasteOver (wxWindow *parent) ListSizer->Add(ListBox,0,wxEXPAND|wxTOP,5); // Load checked items - for (unsigned int i=0;iCheck(i,Options.AsBool(wxString::Format(_T("Paste Over #%i"),i))); + /// @todo This assumes a static set of fields. + std::vector choice_array; + OPT_GET("Tool/Paste Lines Over/Fields")->GetListBool(choice_array); + for (unsigned int i=0;iCheck(i,choice_array.at(i)); // Top buttons wxSizer *TopButtonSizer = new wxBoxSizer(wxHORIZONTAL); @@ -138,15 +142,13 @@ END_EVENT_TABLE() /// @param event /// void DialogPasteOver::OnOK(wxCommandEvent &event) { - // Set options - options.SetCount(10); - for (int i=0;i<10;i++) { - options[i] = ListBox->IsChecked(i) ? 1 : 0; - Options.SetBool(wxString::Format(_T("Paste Over #%i"),i),options[i]==1); - } - Options.Save(); - // End + std::vector map; + for (int i=0;i<10;i++) { + map[i] = ListBox->IsChecked(i); + } + OPT_SET("Tool/Paste Lines Over/Fields")->SetListBool(map); + EndModal(1); } diff --git a/aegisub/src/dialog_search_replace.cpp b/aegisub/src/dialog_search_replace.cpp index ae68a3e1e..6793041ed 100644 --- a/aegisub/src/dialog_search_replace.cpp +++ b/aegisub/src/dialog_search_replace.cpp @@ -44,6 +44,7 @@ #include #endif +#include "compat.h" #include "ass_dialogue.h" #include "ass_file.h" #include "dialog_search_replace.h" @@ -68,14 +69,14 @@ DialogSearchReplace::DialogSearchReplace (wxWindow *parent,bool _hasReplace,wxSt // Find sizer wxSizer *FindSizer = new wxFlexGridSizer(2,2,5,15); - wxArrayString FindHistory = Options.GetRecentList(_T("Recent find")); + wxArrayString FindHistory = lagi_MRU_wxAS("Find"); FindEdit = new wxComboBox(this,-1,_T(""),wxDefaultPosition,wxSize(300,-1),FindHistory,wxCB_DROPDOWN); //if (FindHistory.Count()) FindEdit->SetStringSelection(FindHistory[0]); FindEdit->SetSelection(0); FindSizer->Add(new wxStaticText(this,-1,_("Find what:")),0,wxRIGHT | wxALIGN_CENTER_VERTICAL,0); FindSizer->Add(FindEdit,0,wxRIGHT,0); if (hasReplace) { - wxArrayString ReplaceHistory = Options.GetRecentList(_T("Recent replace")); + wxArrayString ReplaceHistory = lagi_MRU_wxAS("Replace"); ReplaceEdit = new wxComboBox(this,-1,_T(""),wxDefaultPosition,wxSize(300,-1),ReplaceHistory,wxCB_DROPDOWN); FindSizer->Add(new wxStaticText(this,-1,_("Replace with:")),0,wxRIGHT | wxALIGN_CENTER_VERTICAL,0); FindSizer->Add(ReplaceEdit,0,wxRIGHT,0); @@ -87,10 +88,10 @@ DialogSearchReplace::DialogSearchReplace (wxWindow *parent,bool _hasReplace,wxSt CheckMatchCase = new wxCheckBox(this,CHECK_MATCH_CASE,_("Match case")); CheckRegExp = new wxCheckBox(this,CHECK_MATCH_CASE,_("Use regular expressions")); CheckUpdateVideo = new wxCheckBox(this,CHECK_UPDATE_VIDEO,_("Update Video (slow)")); - CheckMatchCase->SetValue(Options.AsBool(_T("Find Match Case"))); - CheckRegExp->SetValue(Options.AsBool(_T("Find RegExp"))); + CheckMatchCase->SetValue(OPT_GET("Tool/Search Replace/Match Case")->GetBool()); + CheckRegExp->SetValue(OPT_GET("Tool/Search Replace/RegExp")->GetBool()); //CheckRegExp->Enable(false); - CheckUpdateVideo->SetValue(Options.AsBool(_T("Find Update Video"))); + CheckUpdateVideo->SetValue(OPT_GET("Tool/Search Replace/Video Update")->GetBool()); // CheckUpdateVideo->Enable(Search.grid->video->loaded); OptionsSizer->Add(CheckMatchCase,0,wxBOTTOM,5); OptionsSizer->Add(CheckRegExp,0,wxBOTTOM,5); @@ -110,8 +111,8 @@ DialogSearchReplace::DialogSearchReplace (wxWindow *parent,bool _hasReplace,wxSt wxSizer *LimitSizer = new wxBoxSizer(wxHORIZONTAL); LimitSizer->Add(Field,1,wxEXPAND | wxRIGHT,5); LimitSizer->Add(Affect,0,wxEXPAND | wxRIGHT,0); - Field->SetSelection(Options.AsInt(_T("Find Field"))); - Affect->SetSelection(Options.AsInt(_T("Find Affect"))); + Field->SetSelection(OPT_GET("Tool/Search Replace/Field")->GetInt()); + Affect->SetSelection(OPT_GET("Tool/Search Replace/Affect")->GetInt()); // Left sizer wxSizer *LeftSizer = new wxBoxSizer(wxVERTICAL); @@ -160,12 +161,11 @@ void DialogSearchReplace::UpdateSettings() { Search.isReg = CheckRegExp->IsChecked() && CheckRegExp->IsEnabled(); Search.matchCase = CheckMatchCase->IsChecked(); Search.updateVideo = CheckUpdateVideo->IsChecked() && CheckUpdateVideo->IsEnabled(); - Options.SetBool(_T("Find Match Case"),CheckMatchCase->IsChecked()); - Options.SetBool(_T("Find RegExp"),CheckRegExp->IsChecked()); - Options.SetBool(_T("Find Update Video"),CheckUpdateVideo->IsChecked()); - Options.SetInt(_T("Find Field"),Field->GetSelection()); - Options.SetInt(_T("Find Affect"),Affect->GetSelection()); - Options.Save(); + OPT_SET("Tool/Search Replace/Match Case")->SetBool(CheckMatchCase->IsChecked()); + OPT_SET("Tool/Search Replace/RegExp")->SetBool(CheckRegExp->IsChecked()); + OPT_SET("Tool/Search Replace/Video Update")->SetBool(CheckUpdateVideo->IsChecked()); + OPT_SET("Tool/Search Replace/Field")->SetInt(Field->GetSelection()); + OPT_SET("Tool/Search Replace/Affect")->SetInt(Affect->GetSelection()); } @@ -234,7 +234,7 @@ void DialogSearchReplace::FindReplace(int mode) { if (hasReplace) { wxString ReplaceWith = ReplaceEdit->GetValue(); Search.ReplaceWith = ReplaceWith; - Options.AddToRecentList(ReplaceWith,_T("Recent replace")); + AegisubApp::Get()->mru->Add("Replace", STD_STR(ReplaceWith)); } } @@ -244,11 +244,11 @@ void DialogSearchReplace::FindReplace(int mode) { Search.ReplaceWith = ReplaceWith; if (mode == 1) Search.ReplaceNext(); else Search.ReplaceAll(); - Options.AddToRecentList(ReplaceWith,_T("Recent replace")); + AegisubApp::Get()->mru->Add("Replace", STD_STR(ReplaceWith)); } // Add to history - Options.AddToRecentList(LookFor,_T("Recent find")); + AegisubApp::Get()->mru->Add("Find", STD_STR(LookFor)); UpdateDropDowns(); } @@ -287,7 +287,7 @@ void DialogSearchReplace::UpdateDropDowns() { // Find FindEdit->Freeze(); FindEdit->Clear(); - FindEdit->Append(Options.GetRecentList(_T("Recent find"))); + FindEdit->Append(lagi_MRU_wxAS("Find")); FindEdit->SetSelection(0); FindEdit->Thaw(); @@ -295,7 +295,7 @@ void DialogSearchReplace::UpdateDropDowns() { if (hasReplace) { ReplaceEdit->Freeze(); ReplaceEdit->Clear(); - ReplaceEdit->Append(Options.GetRecentList(_T("Recent replace"))); + ReplaceEdit->Append(lagi_MRU_wxAS("Replace")); ReplaceEdit->SetSelection(0); ReplaceEdit->Thaw(); } diff --git a/aegisub/src/dialog_selection.cpp b/aegisub/src/dialog_selection.cpp index 7b9a39169..daccbc3b0 100644 --- a/aegisub/src/dialog_selection.cpp +++ b/aegisub/src/dialog_selection.cpp @@ -45,8 +45,10 @@ #endif #include "ass_dialogue.h" +#include "compat.h" #include "dialog_selection.h" #include "help_button.h" +#include "main.h" #include "options.h" #include "subs_grid.h" #include "subs_edit_box.h" @@ -70,7 +72,7 @@ wxDialog (parent,-1,_("Select"),wxDefaultPosition,wxDefaultSize,wxCAPTION) // Matches box Matches = new wxRadioButton(this,-1,_("Matches"),wxDefaultPosition,wxDefaultSize,wxRB_GROUP); DoesntMatch = new wxRadioButton(this,-1,_("Doesn't Match"),wxDefaultPosition,wxDefaultSize,0); - Match = new wxTextCtrl(this,-1,Options.AsText(_T("Select Text")),wxDefaultPosition,wxSize(200,-1)); + Match = new wxTextCtrl(this,-1,lagi_wxString(OPT_GET("Tool/Select Lines/Text")->GetString()),wxDefaultPosition,wxSize(200,-1)); MatchCase = new wxCheckBox(this,-1,_("Match case")); Exact = new wxRadioButton(this,-1,_("Exact match"),wxDefaultPosition,wxDefaultSize,wxRB_GROUP); Contains = new wxRadioButton(this,-1,_("Contains")); @@ -130,13 +132,13 @@ wxDialog (parent,-1,_("Select"),wxDefaultPosition,wxDefaultSize,wxCAPTION) CenterOnParent(); // Load settings - Field->SetSelection(Options.AsInt(_T("Select Field"))); - Action->SetSelection(Options.AsInt(_T("Select Action"))); - MatchCase->SetValue(Options.AsBool(_T("Select Match case"))); - MatchDialogues->SetValue(Options.AsBool(_T("Select Match dialogues"))); - MatchComments->SetValue(Options.AsBool(_T("Select Match comments"))); - int condition = Options.AsInt(_T("Select Condition")); - int mode = Options.AsInt(_T("Select Mode")); + Field->SetSelection(OPT_GET("Tool/Select/Field")->GetInt()); + Action->SetSelection(OPT_GET("Tool/Select/Action")->GetInt()); + MatchCase->SetValue(OPT_GET("Tool/Select Lines/Match/Case")->GetBool()); + MatchDialogues->SetValue(OPT_GET("Tool/Select Lines/Match/Dialogue")->GetBool()); + MatchComments->SetValue(OPT_GET("Tool/Select Lines/Match/Comment")->GetBool()); + int condition = OPT_GET("Tool/Select/Condition")->GetInt(); + int mode = OPT_GET("Tool/Select/Mode")->GetInt(); if (condition == 1) DoesntMatch->SetValue(true); if (mode == 1) Contains->SetValue(true); else if (mode == 2) RegExp->SetValue(true); @@ -303,14 +305,14 @@ void DialogSelection::SaveSettings() { else condition = 1; // Store - Options.SetText(_T("Select Text"),Match->GetValue()); - Options.SetInt(_T("Select Condition"),condition); - Options.SetInt(_T("Select Field"),field); - Options.SetInt(_T("Select Action"),action); - Options.SetInt(_T("Select Mode"),mode); - Options.SetBool(_T("Select Match case"),MatchCase->IsChecked()); - Options.SetBool(_T("Select Match dialogues"),MatchDialogues->IsChecked()); - Options.SetBool(_T("Select Match comments"),MatchComments->IsChecked()); + OPT_SET("Tool/Select Lines/Text")->SetString(STD_STR(Match->GetValue())); + OPT_SET("Tool/Select/Condition")->SetInt(condition); + OPT_SET("Tool/Select/Field")->SetInt(field); + OPT_SET("Tool/Select/Action")->SetInt(action); + OPT_SET("Tool/Select/Mode")->SetInt(mode); + OPT_SET("Tool/Select Lines/Match/Case")->SetBool(MatchCase->IsChecked()); + OPT_SET("Tool/Select Lines/Match/Dialogue")->SetBool(MatchDialogues->IsChecked()); + OPT_SET("Tool/Select Lines/Match/Comment")->SetBool(MatchComments->IsChecked()); } diff --git a/aegisub/src/dialog_shift_times.cpp b/aegisub/src/dialog_shift_times.cpp index 2d4be2eda..eea291599 100644 --- a/aegisub/src/dialog_shift_times.cpp +++ b/aegisub/src/dialog_shift_times.cpp @@ -55,6 +55,7 @@ #include "dialog_shift_times.h" #include "help_button.h" #include "libresrc/libresrc.h" +#include "main.h" #include "options.h" #include "standard_paths.h" #include "subs_edit_box.h" @@ -154,20 +155,20 @@ DialogShiftTimes::DialogShiftTimes (wxWindow *parent,SubtitlesGrid *_grid) CenterOnParent(); // Load values from options - if (!Options.AsBool(_T("Shift Times ByTime"))) { + if (!OPT_GET("Tools/Shift Times/ByTime")->GetBool()) { if (RadioFrames->IsEnabled()) { RadioFrames->SetValue(true); ShiftFrame->Enable(true); ShiftTime->Enable(false); - ShiftFrame->SetValue(Options.AsText(_T("Shift Times Length"))); + ShiftFrame->SetValue(AegiIntegerToString(OPT_GET("Tool/Shift Times/Length")->GetInt())); } } else { - ShiftTime->SetTime(Options.AsInt(_T("Shift Times Length"))); + ShiftTime->SetTime(OPT_GET("Tool/Shift Times/Length")->GetInt()); } - TimesChoice->SetSelection(Options.AsInt(_T("Shift Times Type"))); - SelChoice->SetSelection(Options.AsInt(_T("Shift Times Affect"))); - if (Options.AsBool(_T("Shift Times Direction"))) DirectionBackward->SetValue(true); + TimesChoice->SetSelection(OPT_GET("Tool/Shift Times/Type")->GetInt()); + SelChoice->SetSelection(OPT_GET("Tool/Shift Times/Affect")->GetInt()); + if (OPT_GET("Tools/Shift Times/Direction")->GetBool()) DirectionBackward->SetValue(true); // Has selection? wxArrayInt sel = grid->GetSelection(); @@ -304,12 +305,11 @@ void DialogShiftTimes::OnOK(wxCommandEvent &event) { } // Store modifications - Options.SetBool(_T("Shift Times ByTime"),byTime); - Options.SetInt(_T("Shift Times Type"),type); - Options.SetInt(_T("Shift Times Length"),len); - Options.SetInt(_T("Shift Times Affect"),affect); - Options.SetBool(_T("Shift Times Direction"),backward); - Options.Save(); + OPT_SET("Tools/Shift Times/ByTime")->SetBool(byTime); + OPT_SET("Tool/Shift Times/Type")->SetInt(type); + OPT_SET("Tool/Shift Times/Length")->SetInt(len); + OPT_SET("Tool/Shift Times/Affect")->SetInt(affect); + OPT_SET("Tools/Shift Times/Direction")->SetBool(backward); // End dialog grid->ass->FlagAsModified(_("shifting")); diff --git a/aegisub/src/dialog_spellchecker.cpp b/aegisub/src/dialog_spellchecker.cpp index 6408baab9..b9f5f9281 100644 --- a/aegisub/src/dialog_spellchecker.cpp +++ b/aegisub/src/dialog_spellchecker.cpp @@ -44,10 +44,12 @@ #include "ass_dialogue.h" #include "ass_file.h" +#include "compat.h" #include "dialog_spellchecker.h" #include "frame_main.h" #include "help_button.h" #include "libresrc/libresrc.h" +#include "main.h" #include "options.h" #include "spellchecker_manager.h" #include "subs_edit_box.h" @@ -114,7 +116,7 @@ DialogSpellChecker::DialogSpellChecker(wxFrame *parent) } // Get current language - wxString curLang = Options.AsText(_T("Spell checker language")); + wxString curLang = lagi_wxString(OPT_GET("Tool/Spell Checker/Language")->GetString()); int curLangPos = langCodes.Index(curLang); if (curLangPos == wxNOT_FOUND) { curLangPos = langCodes.Index(_T("en")); @@ -401,8 +403,7 @@ void DialogSpellChecker::OnChangeLanguage(wxCommandEvent &event) { // Change language code wxString code = langCodes[language->GetSelection()]; spellchecker->SetLanguage(code); - Options.SetText(_T("Spell checker language"),code); - Options.Save(); + OPT_SET("Tool/Spell Checker/Language")->SetString(STD_STR(code)); // Go back to first match GetFirstMatch(); diff --git a/aegisub/src/dialog_style_editor.cpp b/aegisub/src/dialog_style_editor.cpp index a29f35056..ef1e0a873 100644 --- a/aegisub/src/dialog_style_editor.cpp +++ b/aegisub/src/dialog_style_editor.cpp @@ -50,10 +50,12 @@ #include "ass_override.h" #include "ass_style.h" #include "ass_style_storage.h" +#include "compat.h" #include "dialog_colorpicker.h" #include "dialog_style_editor.h" #include "help_button.h" #include "libresrc/libresrc.h" +#include "main.h" #include "options.h" #include "subs_grid.h" #include "subs_preview.h" @@ -362,9 +364,9 @@ DialogStyleEditor::DialogStyleEditor (wxWindow *parent, AssStyle *_style, Subtit SubsPreview = NULL; PreviewText = NULL; if (SubtitlesProviderFactoryManager::ProviderAvailable()) { - PreviewText = new wxTextCtrl(this,TEXT_PREVIEW,Options.AsText(_T("Style editor preview text"))); - previewButton = new ColourButton(this,BUTTON_PREVIEW_COLOR,wxSize(45,16),Options.AsColour(_T("Style editor preview background"))); - SubsPreview = new SubtitlesPreview(this,-1,wxDefaultPosition,wxSize(100,60),wxSUNKEN_BORDER,Options.AsColour(_T("Style editor preview background"))); + PreviewText = new wxTextCtrl(this,TEXT_PREVIEW,lagi_wxString(OPT_GET("Tool/Style Editor/Preview Text")->GetString())); + previewButton = new ColourButton(this,BUTTON_PREVIEW_COLOR,wxSize(45,16),lagi_wxColour(OPT_GET("Colour/Style Editor/Background/Preview")->GetColour())); + SubsPreview = new SubtitlesPreview(this,-1,wxDefaultPosition,wxSize(100,60),wxSUNKEN_BORDER,lagi_wxColour(OPT_GET("Colour/Style Editor/Background/Preview")->GetColour())); SubsPreview->SetToolTip(_("Preview of current style.")); SubsPreview->SetStyle(style); @@ -588,8 +590,7 @@ void DialogStyleEditor::Apply (bool apply,bool close) { // Exit if (close) { EndModal(1); - if (PreviewText) Options.SetText(_T("Style editor preview text"),PreviewText->GetValue()); - Options.Save(); + if (PreviewText) OPT_SET("Tool/Style Editor/Preview Text")->SetString(STD_STR(PreviewText->GetValue())); } // Update preview @@ -600,8 +601,7 @@ void DialogStyleEditor::Apply (bool apply,bool close) { else { if (close) { EndModal(0); - if (PreviewText) Options.SetText(_T("Style editor preview text"),PreviewText->GetValue()); - Options.Save(); + if (PreviewText) OPT_SET("Tool/Style Editor/Preview Text")->SetString(STD_STR(PreviewText->GetValue())); } } } @@ -722,8 +722,7 @@ void DialogStyleEditor::OnPreviewTextChange (wxCommandEvent &event) { /// void DialogStyleEditor::OnPreviewColourChange (wxCommandEvent &event) { if (SubsPreview) SubsPreview->SetColour(previewButton->GetColour()); - Options.SetColour(_T("Style editor preview background"),previewButton->GetColour()); - Options.Save(); + OPT_SET("Colour/Style Editor/Background/Preview")->SetColour(STD_STR(previewButton->GetColour().GetAsString(wxC2S_CSS_SYNTAX))); } /// @brief Command event to update preview diff --git a/aegisub/src/dialog_style_manager.cpp b/aegisub/src/dialog_style_manager.cpp index bb40e02bc..555bee639 100644 --- a/aegisub/src/dialog_style_manager.cpp +++ b/aegisub/src/dialog_style_manager.cpp @@ -47,10 +47,12 @@ #include "ass_dialogue.h" #include "ass_file.h" #include "ass_style.h" +#include "compat.h" #include "dialog_style_editor.h" #include "dialog_style_manager.h" #include "help_button.h" #include "libresrc/libresrc.h" +#include "main.h" #include "options.h" #include "standard_paths.h" #include "subs_grid.h" @@ -829,14 +831,13 @@ void DialogStyleManager::OnCurrentDelete (wxCommandEvent &) { /// @brief Import styles from another script void DialogStyleManager::OnCurrentImport(wxCommandEvent &) { // Get file name - wxString path = Options.AsText(_T("Last open subtitles path")); + wxString path = lagi_wxString(OPT_GET("Path/Last/Subtitles")->GetString()); wxString filename = wxFileSelector(_("Open subtitles file"),path,_T(""),_T(""),AssFile::GetWildcardList(0),wxFD_OPEN | wxFD_FILE_MUST_EXIST); if (!filename.IsEmpty()) { // Save path wxFileName filepath(filename); - Options.SetText(_T("Last open subtitles path"), filepath.GetPath()); - Options.Save(); + OPT_SET("Path/Last/Subtitles")->SetString(STD_STR(filepath.GetPath())); try { // Load file diff --git a/aegisub/src/dialog_text_import.cpp b/aegisub/src/dialog_text_import.cpp index eddc6840d..1aeec8af1 100644 --- a/aegisub/src/dialog_text_import.cpp +++ b/aegisub/src/dialog_text_import.cpp @@ -44,7 +44,9 @@ #include #endif +#include "compat.h" #include "dialog_text_import.h" +#include "main.h" #include "options.h" @@ -56,8 +58,8 @@ DialogTextImport::DialogTextImport() // Main controls wxFlexGridSizer *fg = new wxFlexGridSizer(2, 5, 5); wxBoxSizer *main_sizer = new wxBoxSizer(wxVERTICAL); - edit_separator = new wxTextCtrl(this, EDIT_ACTOR_SEPARATOR, Options.AsText(_T("text actor separator"))); - edit_comment = new wxTextCtrl(this, EDIT_COMMENT_STARTER, Options.AsText(_T("text comment starter"))); + edit_separator = new wxTextCtrl(this, EDIT_ACTOR_SEPARATOR, lagi_wxString(OPT_GET("Tool/Import/Text/Actor Separator")->GetString())); + edit_comment = new wxTextCtrl(this, EDIT_COMMENT_STARTER, lagi_wxString(OPT_GET("Tool/Import/Text/Comment Starter")->GetString())); // Dialog layout fg->Add(new wxStaticText(this, -1, _("Actor separator:")), 0, wxALIGN_CENTRE_VERTICAL); @@ -85,9 +87,8 @@ DialogTextImport::~DialogTextImport() void DialogTextImport::OnOK(wxCommandEvent &event) { // Set options - Options.SetText(_T("text actor separator"), edit_separator->GetValue()); - Options.SetText(_T("text comment starter"), edit_comment->GetValue()); - Options.Save(); + OPT_SET("Tool/Import/Text/Actor Separator")->SetString(STD_STR(edit_separator->GetValue())); + OPT_SET("Tool/Import/Text/Comment Starter")->SetString(STD_STR(edit_comment->GetValue())); EndModal(wxID_OK); } diff --git a/aegisub/src/dialog_timing_processor.cpp b/aegisub/src/dialog_timing_processor.cpp index 2d95f5d2b..83d55a26a 100644 --- a/aegisub/src/dialog_timing_processor.cpp +++ b/aegisub/src/dialog_timing_processor.cpp @@ -44,6 +44,7 @@ #include "dialog_timing_processor.h" #include "help_button.h" #include "libresrc/libresrc.h" +#include "main.h" #include "options.h" #include "subs_grid.h" #include "utils.h" @@ -66,13 +67,14 @@ DialogTimingProcessor::DialogTimingProcessor(wxWindow *parent,SubtitlesGrid *_gr // Set variables grid = _grid; - leadInTime = Options.AsText(_T("Audio lead in")); - leadOutTime = Options.AsText(_T("Audio lead out")); - thresStartBefore = Options.AsText(_T("Timing processor key start before thres")); - thresStartAfter = Options.AsText(_T("Timing processor key start after thres")); - thresEndBefore = Options.AsText(_T("Timing processor key end before thres")); - thresEndAfter = Options.AsText(_T("Timing processor key end after thres")); - adjsThresTime = Options.AsText(_T("Timing processor adjacent thres")); + leadInTime = AegiIntegerToString(OPT_GET("Audio/Lead/IN")->GetInt()); + leadOutTime = AegiIntegerToString(OPT_GET("Audio/Lead/OUT")->GetInt()); + thresStartBefore = AegiIntegerToString(OPT_GET("Tool/Timing Post Processor/Threshold/Key Start Before")->GetInt()); + thresStartAfter = AegiIntegerToString(OPT_GET("Tool/Timing Post Processor/Threshold/Key Start After")->GetInt()); + thresEndBefore = AegiIntegerToString(OPT_GET("Tool/Timing Post Processor/Threshold/Key End Before")->GetInt()); + thresEndAfter = AegiIntegerToString(OPT_GET("Tool/Timing Post Processor/Threshold/Key End After")->GetInt()); + adjsThresTime = AegiIntegerToString(OPT_GET("Tool/Timing Post Processor/Threshold/Adjacent")->GetInt()); + // Styles box wxSizer *LeftSizer = new wxStaticBoxSizer(wxVERTICAL,this,_("Apply to styles")); @@ -87,19 +89,19 @@ DialogTimingProcessor::DialogTimingProcessor(wxWindow *parent,SubtitlesGrid *_gr // Options box wxSizer *optionsSizer = new wxStaticBoxSizer(wxHORIZONTAL,this,_("Options")); onlySelection = new wxCheckBox(this,-1,_("Affect selection only")); - onlySelection->SetValue(Options.AsBool(_T("Timing processor Only Selection"))); + onlySelection->SetValue(OPT_GET("Tool/Timing Post Processor/Only Selection")->GetBool()); optionsSizer->Add(onlySelection,1,wxALL,0); // Lead-in/out box wxSizer *LeadSizer = new wxStaticBoxSizer(wxHORIZONTAL,this,_("Lead-in/Lead-out")); hasLeadIn = new wxCheckBox(this,CHECK_ENABLE_LEADIN,_("Add lead in:")); hasLeadIn->SetToolTip(_("Enable adding of lead-ins to lines.")); - hasLeadIn->SetValue(Options.AsBool(_T("Timing processor Enable lead-in"))); + hasLeadIn->SetValue(OPT_GET("Tool/Timing Post Processor/Enable/Lead/IN")->GetBool()); leadIn = new wxTextCtrl(this,-1,_T(""),wxDefaultPosition,wxSize(80,-1),0,NumValidator(&leadInTime)); leadIn->SetToolTip(_("Lead in to be added, in milliseconds.")); hasLeadOut = new wxCheckBox(this,CHECK_ENABLE_LEADOUT,_("Add lead out:")); hasLeadOut->SetToolTip(_("Enable adding of lead-outs to lines.")); - hasLeadOut->SetValue(Options.AsBool(_T("Timing processor Enable lead-out"))); + hasLeadOut->SetValue(OPT_GET("Tool/Timing Post Processor/Enable/Lead/OUT")->GetBool()); leadOut = new wxTextCtrl(this,-1,_T(""),wxDefaultPosition,wxSize(80,-1),0,NumValidator(&leadOutTime)); leadOut->SetToolTip(_("Lead out to be added, in milliseconds.")); LeadSizer->Add(hasLeadIn,0,wxRIGHT|wxEXPAND,5); @@ -112,11 +114,11 @@ DialogTimingProcessor::DialogTimingProcessor(wxWindow *parent,SubtitlesGrid *_gr wxSizer *AdjacentSizer = new wxStaticBoxSizer(wxHORIZONTAL,this,_("Make adjacent subtitles continuous")); adjsEnable = new wxCheckBox(this,CHECK_ENABLE_ADJASCENT,_("Enable")); adjsEnable->SetToolTip(_("Enable snapping of subtitles together if they are within a certain distance of each other.")); - adjsEnable->SetValue(Options.AsBool(_T("Timing processor Enable adjacent"))); + adjsEnable->SetValue(OPT_GET("Tool/Timing Post Processor/Enable/Adjacent")->GetBool()); wxStaticText *adjsThresText = new wxStaticText(this,-1,_("Threshold:"),wxDefaultPosition,wxDefaultSize,wxALIGN_CENTRE); adjacentThres = new wxTextCtrl(this,-1,_T(""),wxDefaultPosition,wxSize(60,-1),0,NumValidator(&adjsThresTime)); adjacentThres->SetToolTip(_("Maximum difference between start and end time for two subtitles to be made continuous, in milliseconds.")); - adjacentBias = new wxSlider(this,-1,MID(0,int(Options.AsFloat(_T("Timing processor adjacent bias"))*100),100),0,100,wxDefaultPosition,wxSize(-1,20)); + adjacentBias = new wxSlider(this,-1,MID(0,int(OPT_GET("Tool/Timing Post Processor/Adjacent Bias")->GetDouble()*100),100),0,100,wxDefaultPosition,wxSize(-1,20)); adjacentBias->SetToolTip(_("Sets how to set the adjoining of lines. If set totally to left, it will extend start time of the second line; if totally to right, it will extend the end time of the first line.")); AdjacentSizer->Add(adjsEnable,0,wxRIGHT|wxEXPAND,10); AdjacentSizer->Add(adjsThresText,0,wxRIGHT|wxALIGN_CENTER,5); @@ -130,7 +132,7 @@ DialogTimingProcessor::DialogTimingProcessor(wxWindow *parent,SubtitlesGrid *_gr wxSizer *KeyframesFlexSizer = new wxFlexGridSizer(2,5,5,0); keysEnable = new wxCheckBox(this,CHECK_ENABLE_KEYFRAME,_("Enable")); keysEnable->SetToolTip(_("Enable snapping of subtitles to nearest keyframe, if distance is within threshold.")); - keysEnable->SetValue(Options.AsBool(_T("Timing processor Enable keyframe"))); + keysEnable->SetValue(OPT_GET("Tool/Timing Post Processor/Enable/Keyframe")->GetBool()); wxStaticText *textStartBefore = new wxStaticText(this,-1,_("Starts before thres.:"),wxDefaultPosition,wxDefaultSize,wxALIGN_CENTRE); keysStartBefore = new wxTextCtrl(this,-1,_T(""),wxDefaultPosition,wxSize(60,-1),0,NumValidator(&thresStartBefore)); keysStartBefore->SetToolTip(_("Threshold for 'before start' distance, that is, how many frames a subtitle must start before a keyframe to snap to it.")); @@ -293,26 +295,25 @@ void DialogTimingProcessor::OnApply(wxCommandEvent &event) { // Save settings long temp = 0; leadIn->GetValue().ToLong(&temp); - Options.SetInt(_T("Audio lead in"),temp); + OPT_SET("Audio/Lead/IN")->SetInt(temp); leadOut->GetValue().ToLong(&temp); - Options.SetInt(_T("Audio lead out"),temp); + OPT_SET("Audio/Lead/OUT")->SetInt(temp); keysStartBefore->GetValue().ToLong(&temp); - Options.SetInt(_T("Timing processor key start before thres"),temp); + OPT_SET("Tool/Timing Post Processor/Threshold/Key Start Before")->SetInt(temp); keysStartAfter->GetValue().ToLong(&temp); - Options.SetInt(_T("Timing processor key start after thres"),temp); + OPT_SET("Tool/Timing Post Processor/Threshold/Key Start After")->SetInt(temp); keysEndBefore->GetValue().ToLong(&temp); - Options.SetInt(_T("Timing processor key end before thres"),temp); + OPT_SET("Tool/Timing Post Processor/Threshold/Key End Before")->SetInt(temp); keysEndAfter->GetValue().ToLong(&temp); - Options.SetInt(_T("Timing processor key end after thres"),temp); + OPT_SET("Tool/Timing Post Processor/Threshold/Key End After")->SetInt(temp); adjacentThres->GetValue().ToLong(&temp); - Options.SetInt(_T("Timing processor adjacent thres"),temp); - Options.SetFloat(_T("Timing processor adjacent bias"),adjacentBias->GetValue() / 100.0); - Options.SetBool(_T("Timing processor Enable lead-in"),hasLeadIn->IsChecked()); - Options.SetBool(_T("Timing processor Enable lead-out"),hasLeadOut->IsChecked()); - if (keysEnable->IsEnabled()) Options.SetBool(_T("Timing processor Enable keyframe"),keysEnable->IsChecked()); - Options.SetBool(_T("Timing processor Enable adjacent"),adjsEnable->IsChecked()); - Options.SetBool(_T("Timing processor Only Selection"),onlySelection->IsChecked()); - Options.Save(); + OPT_SET("Tool/Timing Post Processor/Threshold/Adjacent")->SetInt(temp); + OPT_SET("Tool/Timing Post Processor/Adjacent Bias")->SetDouble(adjacentBias->GetValue() / 100.0); + OPT_SET("Tool/Timing Post Processor/Enable/Lead/IN")->SetBool(hasLeadIn->IsChecked()); + OPT_SET("Tool/Timing Post Processor/Enable/Lead/OUT")->SetBool(hasLeadOut->IsChecked()); + if (keysEnable->IsEnabled()) OPT_SET("Tool/Timing Post Processor/Enable/Keyframe")->SetBool(keysEnable->IsChecked()); + OPT_SET("Tool/Timing Post Processor/Enable/Adjacent")->SetBool(adjsEnable->IsChecked()); + OPT_SET("Tool/Timing Post Processor/Only Selection")->SetBool(onlySelection->IsChecked()); // Check if rows are valid bool valid = true; diff --git a/aegisub/src/dialog_tip.cpp b/aegisub/src/dialog_tip.cpp index 478b40084..060bf324c 100644 --- a/aegisub/src/dialog_tip.cpp +++ b/aegisub/src/dialog_tip.cpp @@ -45,6 +45,7 @@ #endif #include "dialog_tip.h" +#include "main.h" #include "options.h" @@ -99,12 +100,11 @@ wxString TipOfTheDay::GetTip() { /// void TipOfTheDay::Show(wxWindow *parent) { try { - if (Options.AsBool(_T("Tips enabled"))) { - TipOfTheDay *tip = new TipOfTheDay(Options.AsInt(_T("Tips current"))); + if (OPT_GET("App/Tips")->GetBool()) { + TipOfTheDay *tip = new TipOfTheDay(OPT_GET("Tool/Tip of the Day/Current")->GetInt()); bool show = wxShowTip(parent, tip, true); - if (!show) Options.SetBool(_T("Tips enabled"),false); - Options.SetInt(_T("Tips current"),tip->curTip); - Options.Save(); + if (!show) OPT_SET("App/Tips")->SetBool(false); + OPT_SET("Tool/Tip of the Day/Current")->SetInt(tip->curTip); delete tip; } } diff --git a/aegisub/src/dialog_version_check.cpp b/aegisub/src/dialog_version_check.cpp index 56c6ed580..f32af9780 100644 --- a/aegisub/src/dialog_version_check.cpp +++ b/aegisub/src/dialog_version_check.cpp @@ -64,12 +64,14 @@ #include #endif +#include "compat.h" #include "dialog_version_check.h" +#include "main.h" #include "options.h" -#include "include/aegisub/exception.h" #include "string_codec.h" #include "version.h" +#include /* *** Public API is implemented here *** */ @@ -138,7 +140,7 @@ public: }; -DEFINE_SIMPLE_EXCEPTION_NOINNER(VersionCheckError, Aegisub::Exception, "versioncheck") +DEFINE_SIMPLE_EXCEPTION_NOINNER(VersionCheckError, agi::Exception, "versioncheck") class AegisubVersionCheckEventHandler : public wxEvtHandler { @@ -169,11 +171,11 @@ wxThread::ExitCode AegisubVersionCheckerThread::Entry() if (!interactive) { // Automatic checking enabled? - if (!Options.AsBool(_T("auto check for updates"))) + if (!OPT_GET("App/Auto/Check For Updates")->GetInt()) return 0; // Is it actually time for a check? - time_t next_check = Options.AsInt(_T("Updates Next Check Time")); + time_t next_check = OPT_GET("Version/Next Check")->GetInt(); if ((time_t)next_check > wxDateTime::GetTimeNow()) return 0; } @@ -183,10 +185,10 @@ wxThread::ExitCode AegisubVersionCheckerThread::Entry() try { DoCheck(); } - catch (const Aegisub::Exception &e) { + catch (const agi::Exception &e) { PostErrorEvent(wxString::Format( _("There was an error checking for updates to Aegisub:\n%s\n\nIf other applications can access the Internet fine, this is probably a temporary server problem on our end."), - e.GetMessage().c_str())); + e.GetMessage())); } catch (...) { PostErrorEvent(_("An unknown error occurred while checking for updates to Aegisub.")); @@ -201,7 +203,7 @@ wxThread::ExitCode AegisubVersionCheckerThread::Entry() // because the tree only depends on the keys. // Lastly, writing options to disk only happens when Options.Save() is called. time_t new_next_check_time = wxDateTime::GetTimeNow() + 60*60; // in one hour - Options.SetInt(_T("Updates Next Check Time"), (int)new_next_check_time); + OPT_SET("Version/Next Check")->SetInt((int)new_next_check_time); return 0; } @@ -338,12 +340,14 @@ void AegisubVersionCheckerThread::DoCheck() http.SetFlags(wxSOCKET_WAITALL|wxSOCKET_BLOCK); if (!http.Connect(servername)) - throw VersionCheckError(_("Could not connect to updates server.")); + throw VersionCheckError(STD_STR(_("Could not connect to updates server."))); std::auto_ptr stream(http.GetInputStream(path)); - if (http.GetResponse() < 200 || http.GetResponse() >= 300) - throw VersionCheckError(wxString::Format(_("HTTP request failed, got HTTP response %d."), http.GetResponse())); + if (http.GetResponse() < 200 || http.GetResponse() >= 300) { + const std::string str_err = STD_STR(wxString::Format(_("HTTP request failed, got HTTP response %d."), http.GetResponse())); + throw VersionCheckError(str_err); + } wxTextInputStream text(*stream); @@ -485,7 +489,7 @@ VersionCheckerResultDialog::VersionCheckerResultDialog(const wxString &main_text } automatic_check_checkbox = new wxCheckBox(this, -1, _("Auto Check for Updates")); - automatic_check_checkbox->SetValue(Options.AsBool(_T("Auto check for updates"))); + automatic_check_checkbox->SetValue(!!OPT_GET("App/Auto/Check For Updates")->GetInt()); wxButton *remind_later_button = 0; if (updates.size() > 0) @@ -523,7 +527,7 @@ void VersionCheckerResultDialog::OnRemindMeLater(wxCommandEvent &evt) { // In one week time_t new_next_check_time = wxDateTime::Today().GetTicks() + 7*24*60*60; - Options.SetInt(_T("Updates Next Check Time"), (int)new_next_check_time); + OPT_SET("Version/Next Check")->SetInt((int)new_next_check_time); Close(); } @@ -531,7 +535,7 @@ void VersionCheckerResultDialog::OnRemindMeLater(wxCommandEvent &evt) void VersionCheckerResultDialog::OnClose(wxCloseEvent &evt) { - Options.SetBool(_T("Auto check for updates"), automatic_check_checkbox->GetValue()); + OPT_SET("App/Auto/Check For Updates")->SetBool(automatic_check_checkbox->GetValue()); Destroy(); } diff --git a/aegisub/src/ffmpegsource_common.cpp b/aegisub/src/ffmpegsource_common.cpp index 4313b08ce..eced81f7f 100644 --- a/aegisub/src/ffmpegsource_common.cpp +++ b/aegisub/src/ffmpegsource_common.cpp @@ -46,6 +46,7 @@ #include // Keep this last so wxUSE_CHOICEDLG is set. #endif +#include "compat.h" #include "ffmpegsource_common.h" #include "frame_main.h" #include "main.h" @@ -176,7 +177,7 @@ int FFmpegSourceProvider::AskForTrackSelection(const std::map &Tra /// @brief Set ffms2 log level according to setting in config.dat void FFmpegSourceProvider::SetLogLevel() { - wxString LogLevel = Options.AsText(_T("FFmpegSource log level")); + wxString LogLevel = lagi_wxString(OPT_GET("Provider/FFmpegSource/Log Level")->GetString()); if (!LogLevel.CmpNoCase(_T("panic"))) FFMS_SetLogLevel(FFMS_LOG_PANIC); @@ -198,7 +199,7 @@ void FFmpegSourceProvider::SetLogLevel() { FFMS_IndexErrorHandling FFmpegSourceProvider::GetErrorHandlingMode() { - wxString Mode = Options.AsText(_T("FFmpegSource audio decoding error handling")); + wxString Mode = lagi_wxString(OPT_GET("Provider/Audio/FFMpegSource/Decode Error Handling")->GetString()); if (!Mode.CmpNoCase(_T("ignore"))) return FFMS_IEH_IGNORE; @@ -310,9 +311,9 @@ wxThread::ExitCode FFmpegSourceCacheCleaner::Entry() { // the option is in megabytes, we need bytes // shift left by 20 is CLEARLY more efficient than multiplying by 1048576 - int64_t maxsize = Options.AsInt(_T("FFmpegSource max cache size")) << 20; + int64_t maxsize = OPT_GET("Provider/FFmpegSource/Cache/Size")->GetInt() << 20; int64_t cursize = wxDir::GetTotalSize(cachedirname).GetValue(); - int maxfiles = Options.AsInt(_T("FFmpegSource max cache files")); + int maxfiles = OPT_GET("Provider/FFmpegSource/Cache/Files")->GetInt(); if (!cachedir.HasFiles(_T("*.ffindex"))) { wxLogDebug(_T("FFmpegSourceCacheCleaner: no index files in cache folder, exiting")); diff --git a/aegisub/src/frame_main.cpp b/aegisub/src/frame_main.cpp index e7afabf8e..b4e8227ca 100644 --- a/aegisub/src/frame_main.cpp +++ b/aegisub/src/frame_main.cpp @@ -62,6 +62,7 @@ #include "avisynth_wrap.h" #endif #include "charset_conv.h" +#include "compat.h" #include "dialog_detached_video.h" #include "dialog_search_replace.h" #include "dialog_splash.h" @@ -145,7 +146,7 @@ FrameMain::FrameMain (wxArrayString args) // Create menu and tool bars StartupLog(_T("Apply saved Maximized state")); - if (Options.AsBool(_T("Maximized"))) Maximize(true); + if (OPT_GET("App/Maximized")->GetBool()) Maximize(true); StartupLog(_T("Initialize toolbar")); InitToolbar(); StartupLog(_T("Initialize menu bar")); @@ -179,7 +180,7 @@ FrameMain::FrameMain (wxArrayString args) // It doesn't work properly on wxMac, and the jumping dock icon // signals the same as the splash screen either way. #if !_DEBUG && !__WXMAC__ - if (Options.AsBool(_T("Show Splash"))) { + if (OPT_GET("App/Splash")->GetBool()) { SplashScreen *splash = new SplashScreen(this); splash->Show(true); splash->Update(); @@ -192,7 +193,7 @@ FrameMain::FrameMain (wxArrayString args) // Set autosave timer StartupLog(_T("Set up Auto Save")); AutoSave.SetOwner(this,AutoSave_Timer); - int time = Options.AsInt(_T("Auto save every seconds")); + int time = OPT_GET("App/Auto/Save Every Seconds")->GetInt(); if (time > 0) { AutoSave.Start(time*1000); } @@ -214,12 +215,11 @@ FrameMain::FrameMain (wxArrayString args) // Version checker StartupLog(_T("Possibly perform automatic updates check")); - int option = Options.AsInt(_T("Auto check for updates")); + int option = OPT_GET("App/Auto/Check For Updates")->GetInt(); if (option == -1) { int result = wxMessageBox(_("Do you want Aegisub to check for updates whenever it starts? You can still do it manually via the Help menu."),_("Check for updates?"),wxYES_NO); option = (result == wxYES); - Options.SetInt(_T("Auto check for updates"),option); - Options.Save(); + OPT_SET("App/Auto/Check For Updates")->SetInt(option); } PerformVersionCheck(false); @@ -609,7 +609,7 @@ void FrameMain::InitContents() { videoBox->videoSlider->grid = SubsBox; VideoContext::Get()->grid = SubsBox; StartupLog(_T("Reset video zoom")); - videoBox->videoDisplay->SetZoom(Options.AsInt(_T("Video Default Zoom")) * .125 + .125); + videoBox->videoDisplay->SetZoom(OPT_GET("Video/Default Zoom")->GetInt() * .125 + .125); Search.grid = SubsBox; // Audio area @@ -718,7 +718,7 @@ void FrameMain::LoadSubtitles (wxString filename,wxString charset) { wxString cur = testSubs.ReadLineFromFile(); if (cur.Left(10) == _T("# timecode")) { LoadVFR(filename); - Options.SetText(_T("Last open timecodes path"), fileCheck.GetPath()); + OPT_SET("Path/Last/Timecodes")->SetString(STD_STR(fileCheck.GetPath())); return; } } @@ -737,7 +737,7 @@ void FrameMain::LoadSubtitles (wxString filename,wxString charset) { SubsBox->LoadFromAss(AssFile::top,false,true); wxFileName fn(filename); StandardPaths::SetPathValue(_T("?script"),fn.GetPath()); - Options.SetText(_T("Last open subtitles path"), fn.GetPath()); + OPT_SET("Path/Last/Subtitles")->SetString(STD_STR(fn.GetPath())); } else { SubsBox->LoadDefault(AssFile::top); @@ -759,9 +759,9 @@ void FrameMain::LoadSubtitles (wxString filename,wxString charset) { // Save copy wxFileName origfile(filename); - if (!isBinary && Options.AsBool(_T("Auto backup")) && origfile.FileExists()) { + if (!isBinary && OPT_GET("App/Auto/Backup")->GetBool() && origfile.FileExists()) { // Get path - wxString path = Options.AsText(_T("Auto backup path")); + wxString path = lagi_wxString(OPT_GET("Path/Auto/Backup")->GetString()); if (path.IsEmpty()) path = origfile.GetPath(); wxFileName dstpath(path); if (!dstpath.IsAbsolute()) path = StandardPaths::DecodePathMaybeRelative(path, _T("?user/")); @@ -796,7 +796,7 @@ bool FrameMain::SaveSubtitles(bool saveas,bool withCharset) { // Failed, ask user if (filename.IsEmpty()) { VideoContext::Get()->Stop(); - wxString path = Options.AsText(_T("Last open subtitles path")); + wxString path = lagi_wxString(OPT_GET("Path/Last/Subtitles")->GetString()); wxFileName origPath(AssFile::top->filename); filename = wxFileSelector(_("Save subtitles file"),path,origPath.GetName() + _T(".ass"),_T("ass"),AssFile::GetWildcardList(1),wxFD_SAVE | wxFD_OVERWRITE_PROMPT,this); } @@ -805,7 +805,7 @@ bool FrameMain::SaveSubtitles(bool saveas,bool withCharset) { if (!filename.empty()) { // Store path wxFileName filepath(filename); - Options.SetText(_T("Last open subtitles path"), filepath.GetPath()); + OPT_SET("Path/Last/Subtitles")->SetString(STD_STR(filepath.GetPath())); // Fix me, ghetto hack for correct relative path generation in SynchronizeProject() AssFile::top->filename = filename; @@ -979,7 +979,7 @@ void FrameMain::SynchronizeProject(bool fromSubs) { wxString AutoScriptString = subs->GetScriptInfo(_T("Automation Scripts")); // Check if there is anything to change - int autoLoadMode = Options.AsInt(_T("Autoload linked files")); + int autoLoadMode = OPT_GET("App/Auto/Load Linked Files")->GetInt(); bool hasToLoad = false; if (curSubsAudio != audioBox->audioName || curSubsVFR != VFR_Output.GetFilename() || @@ -1034,7 +1034,7 @@ void FrameMain::SynchronizeProject(bool fromSubs) { local_scripts->RemoveAll(); wxStringTokenizer tok(AutoScriptString, _T("|"), wxTOKEN_STRTOK); wxFileName subsfn(subs->filename); - wxString autobasefn(Options.AsText(_T("Automation Base Path"))); + wxString autobasefn(lagi_wxString(OPT_GET("Path/Automation/Base")->GetString())); while (tok.HasMoreTokens()) { wxString sfnames = tok.GetNextToken().Trim(true).Trim(false); wxString sfnamel = sfnames.Left(1); @@ -1102,7 +1102,7 @@ void FrameMain::SynchronizeProject(bool fromSubs) { // 4. Otherwise, use path relative to subs ("~") #ifdef WITH_AUTOMATION wxString scripts_string; - wxString autobasefn(Options.AsText(_T("Automation Base Path"))); + wxString autobasefn(lagi_wxString(OPT_GET("Path/Automation/Base")->GetString())); const std::vector &scripts = local_scripts->GetScripts(); for (unsigned int i = 0; i < scripts.size(); i++) { @@ -1182,7 +1182,7 @@ void FrameMain::LoadVideo(wxString file,bool autoload) { int scriptx = SubsBox->ass->GetScriptInfoAsInt(_T("PlayResX")); int scripty = SubsBox->ass->GetScriptInfoAsInt(_T("PlayResY")); if (scriptx != vidx || scripty != vidy) { - switch (Options.AsInt(_T("Video Check Script Res"))) { + switch (OPT_GET("Video/Check Script Res")->GetInt()) { case 1: // Ask to change on mismatch if (wxMessageBox(wxString::Format(_("The resolution of the loaded video and the resolution specified for the subtitles don't match.\n\nVideo resolution:\t%d x %d\nScript resolution:\t%d x %d\n\nChange subtitles resolution to match video?"), vidx, vidy, scriptx, scripty), _("Resolution mismatch"), wxYES_NO, this) != wxYES) @@ -1207,7 +1207,7 @@ void FrameMain::LoadVideo(wxString file,bool autoload) { SetDisplayMode(1,-1); EditBox->UpdateFrameTiming(); - DetachVideo(VideoContext::Get()->IsLoaded() && Options.AsBool(_T("Detached Video"))); + DetachVideo(VideoContext::Get()->IsLoaded() && OPT_GET("Video/Detached/Enabled")->GetBool()); Thaw(); } @@ -1345,7 +1345,7 @@ void FrameMain::SetAccelerators() { entry.push_back(Hotkeys.GetAccelerator(_T("Edit box commit"),Edit_Box_Commit)); // Medusa - bool medusaPlay = Options.AsBool(_T("Audio Medusa Timing Hotkeys")); + bool medusaPlay = OPT_GET("Audio/Medusa Timing Hotkeys")->GetBool(); if (medusaPlay && audioBox->audioDisplay->loaded) { entry.push_back(Hotkeys.GetAccelerator(_T("Audio Medusa Play"),Medusa_Play)); entry.push_back(Hotkeys.GetAccelerator(_T("Audio Medusa Stop"),Medusa_Stop)); diff --git a/aegisub/src/frame_main.h b/aegisub/src/frame_main.h index bb029c3a7..fb4974585 100644 --- a/aegisub/src/frame_main.h +++ b/aegisub/src/frame_main.h @@ -295,7 +295,7 @@ private: void OnOpenVideoDetails (wxCommandEvent &event); void OnOpenASSDraw (wxCommandEvent &event); - void OnOpenOptions (wxCommandEvent &event); + void OnOpenPreferences (wxCommandEvent &event); void OnGridEvent (wxCommandEvent &event); void OnOpenAutomation (wxCommandEvent &event); diff --git a/aegisub/src/frame_main_events.cpp b/aegisub/src/frame_main_events.cpp index 5dbf9e8e9..e61edb241 100644 --- a/aegisub/src/frame_main_events.cpp +++ b/aegisub/src/frame_main_events.cpp @@ -57,6 +57,7 @@ #include "auto4_base.h" #endif #include "charset_conv.h" +#include "compat.h" #include "dialog_about.h" #include "dialog_attachments.h" #include "dialog_automation.h" @@ -65,7 +66,6 @@ #include "dialog_fonts_collector.h" #include "dialog_jumpto.h" #include "dialog_kara_timing_copy.h" -#include "dialog_options.h" #include "dialog_progress.h" #include "dialog_properties.h" #include "dialog_resample.h" @@ -80,10 +80,12 @@ #include "dialog_version_check.h" #include "dialog_video_details.h" #include "frame_main.h" +#include "hotkeys.h" #include "keyframe.h" #include "libresrc/libresrc.h" #include "main.h" #include "options.h" +#include "preferences.h" #include "standard_paths.h" #include "subs_edit_box.h" #include "subs_grid.h" @@ -192,7 +194,7 @@ BEGIN_EVENT_TABLE(FrameMain, wxFrame) EVT_MENU(Menu_Tools_Resample, FrameMain::OnOpenResample) EVT_MENU(Menu_Tools_Timing_Processor, FrameMain::OnOpenTimingProcessor) EVT_MENU(Menu_Tools_Kanji_Timer, FrameMain::OnOpenKanjiTimer) - EVT_MENU(Menu_Tools_Options, FrameMain::OnOpenOptions) + EVT_MENU(Menu_Tools_Options, FrameMain::OnOpenPreferences) EVT_MENU(Menu_Tools_ASSDraw, FrameMain::OnOpenASSDraw) EVT_MENU(Menu_Subs_Snap_Start_To_Video, FrameMain::OnSnapSubsStartToVid) @@ -272,7 +274,7 @@ void FrameMain::RebuildRecentList(wxString listName,wxMenu *menu,int startID) { // Rebuild int added = 0; wxString n; - wxArrayString entries = Options.GetRecentList(listName); + wxArrayString entries = lagi_MRU_wxAS(listName); for (size_t i=0;iEnable(Menu_File_Open_Subtitles_From_Video,VideoContext::Get()->HasSubtitles()); } @@ -321,7 +323,7 @@ void FrameMain::OnMenuOpen (wxMenuEvent &event) { else if (showAudio && showVideo) MenuBar->Check(Menu_View_Standard,true); else MenuBar->Check(Menu_View_Audio,true); - MenuBar->Check(Options.AsInt(L"Grid hide overrides") + Menu_View_FullTags, true); + MenuBar->Check(OPT_GET("Subtitle/Grid/Hide Overrides")->GetInt() + Menu_View_FullTags, true); } // Video menu @@ -368,12 +370,12 @@ void FrameMain::OnMenuOpen (wxMenuEvent &event) { } // Set overscan mask - MenuBar->Check(Menu_Video_Overscan,Options.AsBool(_T("Show Overscan Mask"))); + MenuBar->Check(Menu_Video_Overscan,OPT_GET("Video/Overscan Mask")->GetBool()); // Rebuild recent lists - RebuildRecentList(_T("Recent vid"),RecentVids,Menu_Video_Recent); - RebuildRecentList(_T("Recent timecodes"),RecentTimecodes,Menu_Timecodes_Recent); - RebuildRecentList(_T("Recent Keyframes"),RecentKeyframes,Menu_Keyframes_Recent); + RebuildRecentList(_T("Video"),RecentVids,Menu_Video_Recent); + RebuildRecentList(_T("Timecodes"),RecentTimecodes,Menu_Timecodes_Recent); + RebuildRecentList(_T("Keyframes"),RecentKeyframes,Menu_Keyframes_Recent); } // Audio menu @@ -385,7 +387,7 @@ void FrameMain::OnMenuOpen (wxMenuEvent &event) { MenuBar->Enable(Menu_Audio_Close,state); // Rebuild recent - RebuildRecentList(_T("Recent aud"),RecentAuds,Menu_Audio_Recent); + RebuildRecentList(_T("Audio"),RecentAuds,Menu_Audio_Recent); } // Subtitles menu @@ -534,8 +536,7 @@ int FrameMain::AddMacroMenuItems(wxMenu *menu, const std::vectormru->GetEntry("Subtitle", number)); } @@ -545,8 +546,7 @@ void FrameMain::OnOpenRecentSubs(wxCommandEvent &event) { /// void FrameMain::OnOpenRecentVideo(wxCommandEvent &event) { int number = event.GetId()-Menu_Video_Recent; - wxString key = _T("Recent vid #") + wxString::Format(_T("%i"),number+1); - LoadVideo(Options.AsText(key)); + LoadSubtitles(AegisubApp::Get()->mru->GetEntry("Video", number)); } @@ -556,8 +556,7 @@ void FrameMain::OnOpenRecentVideo(wxCommandEvent &event) { /// void FrameMain::OnOpenRecentTimecodes(wxCommandEvent &event) { int number = event.GetId()-Menu_Timecodes_Recent; - wxString key = _T("Recent timecodes #") + wxString::Format(_T("%i"),number+1); - LoadVFR(Options.AsText(key)); + LoadSubtitles(AegisubApp::Get()->mru->GetEntry("Timecodes", number)); } @@ -567,8 +566,7 @@ void FrameMain::OnOpenRecentTimecodes(wxCommandEvent &event) { /// void FrameMain::OnOpenRecentKeyframes(wxCommandEvent &event) { int number = event.GetId()-Menu_Keyframes_Recent; - wxString key = _T("Recent Keyframes #") + wxString::Format(_T("%i"),number+1); - KeyFrameFile::Load(Options.AsText(key)); + LoadSubtitles(AegisubApp::Get()->mru->GetEntry("Keyframes", number)); videoBox->videoSlider->Refresh(); audioBox->audioDisplay->Update(); Refresh(); @@ -581,8 +579,7 @@ void FrameMain::OnOpenRecentKeyframes(wxCommandEvent &event) { /// void FrameMain::OnOpenRecentAudio(wxCommandEvent &event) { int number = event.GetId()-Menu_Audio_Recent; - wxString key = _T("Recent aud #") + wxString::Format(_T("%i"),number+1); - LoadAudio(Options.AsText(key)); + LoadSubtitles(AegisubApp::Get()->mru->GetEntry("Audio", number)); } @@ -706,14 +703,13 @@ void FrameMain::OnVideoPlay(wxCommandEvent &event) { /// @param event /// void FrameMain::OnOpenVideo(wxCommandEvent& WXUNUSED(event)) { - wxString path = Options.AsText(_T("Last open video path")); + wxString path = lagi_wxString(OPT_GET("Path/Last/Video")->GetString()); wxString str = wxString(_("Video Formats")) + _T(" (*.avi,*.mkv,*.mp4,*.avs,*.d2v,*.ogm,*.mpeg,*.mpg,*.vob,*.mov)|*.avi;*.avs;*.d2v;*.mkv;*.ogm;*.mp4;*.mpeg;*.mpg;*.vob;*.mov|") + _("All Files") + _T(" (*.*)|*.*"); wxString filename = wxFileSelector(_("Open video file"),path,_T(""),_T(""),str,wxFD_OPEN | wxFD_FILE_MUST_EXIST); if (!filename.empty()) { LoadVideo(filename); - Options.SetText(_T("Last open video path"), filename); - Options.Save(); + OPT_SET("Path/Last/Video")->SetString(STD_STR(filename)); } } @@ -732,15 +728,14 @@ void FrameMain::OnCloseVideo(wxCommandEvent& WXUNUSED(event)) { /// @param event /// void FrameMain::OnOpenAudio (wxCommandEvent& WXUNUSED(event)) { - wxString path = Options.AsText(_T("Last open audio path")); + wxString path = lagi_wxString(OPT_GET("Path/Last/Audio")->GetString()); wxString str = wxString(_("Audio Formats")) + _T(" (*.wav,*.mp3,*.ogg,*.flac,*.mp4,*.ac3,*.aac,*.mka,*.m4a,*.w64)|*.wav;*.mp3;*.ogg;*.flac;*.mp4;*.ac3;*.aac;*.mka;*.m4a;*.w64|") + _("Video Formats") + _T(" (*.avi,*.mkv,*.ogm,*.mpg,*.mpeg)|*.avi;*.mkv;*.ogm;*.mp4;*.mpeg;*.mpg|") + _("All files") + _T(" (*.*)|*.*"); wxString filename = wxFileSelector(_("Open audio file"),path,_T(""),_T(""),str,wxFD_OPEN | wxFD_FILE_MUST_EXIST); if (!filename.empty()) { LoadAudio(filename); - Options.SetText(_T("Last open audio path"), filename); - Options.Save(); + OPT_SET("Path/Last/Audio")->SetString(STD_STR(filename)); } } @@ -785,13 +780,12 @@ void FrameMain::OnOpenDummyNoiseAudio (wxCommandEvent& WXUNUSED(event)) { /// @param event /// void FrameMain::OnOpenSubtitles(wxCommandEvent& WXUNUSED(event)) { - wxString path = Options.AsText(_T("Last open subtitles path")); + wxString path = lagi_wxString(OPT_GET("Path/Last/Subtitles")->GetString()); wxString filename = wxFileSelector(_("Open subtitles file"),path,_T(""),_T(""),AssFile::GetWildcardList(0),wxFD_OPEN | wxFD_FILE_MUST_EXIST); if (!filename.empty()) { LoadSubtitles(filename); wxFileName filepath(filename); - Options.SetText(_T("Last open subtitles path"), filepath.GetPath()); - Options.Save(); + OPT_SET("Path/Last/Subtitles")->SetString(STD_STR(filepath.GetPath())); } } @@ -803,7 +797,7 @@ void FrameMain::OnOpenSubtitles(wxCommandEvent& WXUNUSED(event)) { void FrameMain::OnOpenSubtitlesCharset(wxCommandEvent& WXUNUSED(event)) { // Initialize charsets wxArrayString choices = AegisubCSConv::GetEncodingsList(); - wxString path = Options.AsText(_T("Last open subtitles path")); + wxString path = lagi_wxString(OPT_GET("Path/Last/Subtitles")->GetString()); // Get options and load wxString filename = wxFileSelector(_("Open subtitles file"),path,_T(""),_T(""),AssFile::GetWildcardList(0),wxFD_OPEN | wxFD_FILE_MUST_EXIST); @@ -812,8 +806,7 @@ void FrameMain::OnOpenSubtitlesCharset(wxCommandEvent& WXUNUSED(event)) { if (!charset.empty()) { LoadSubtitles(filename,charset); } - Options.SetText(_T("Last open subtitles path"), filename); - Options.Save(); + OPT_SET("Path/Last/Subtitles")->SetString(STD_STR(filename)); } } @@ -865,7 +858,7 @@ void FrameMain::OnNewSubtitles(wxCommandEvent& WXUNUSED(event)) { /// void FrameMain::OnExportSubtitles(wxCommandEvent & WXUNUSED(event)) { #ifdef WITH_AUTOMATION - int autoreload = Options.AsInt(_T("Automation Autoreload Mode")); + int autoreload = OPT_GET("Automation/Autoreload Mode")->GetInt(); if (autoreload & 1) { // Local scripts const std::vector scripts = local_scripts->GetScripts(); @@ -897,14 +890,13 @@ void FrameMain::OnExportSubtitles(wxCommandEvent & WXUNUSED(event)) { /// @param event /// void FrameMain::OnOpenVFR(wxCommandEvent &event) { - wxString path = Options.AsText(_T("Last open timecodes path")); + wxString path = lagi_wxString(OPT_GET("Path/Last/Timecodes")->GetString()); wxString str = wxString(_("All Supported Types")) + _T("(*.txt)|*.txt|") + _("All Files") + _T(" (*.*)|*.*"); wxString filename = wxFileSelector(_("Open timecodes file"),path,_T(""),_T(""),str,wxFD_OPEN | wxFD_FILE_MUST_EXIST); if (!filename.empty()) { LoadVFR(filename); - Options.SetText(_T("Last open timecodes path"), filename); - Options.Save(); + OPT_SET("Path/Last/Timecodes")->SetString(STD_STR(filename)); } } @@ -914,14 +906,13 @@ void FrameMain::OnOpenVFR(wxCommandEvent &event) { /// @param event /// void FrameMain::OnSaveVFR(wxCommandEvent &event) { - wxString path = Options.AsText(_T("Last open timecodes path")); + wxString path = lagi_wxString(OPT_GET("Path/Last/Timecodes")->GetString()); wxString str = wxString(_("All Supported Types")) + _T("(*.txt)|*.txt|") + _("All Files") + _T(" (*.*)|*.*"); wxString filename = wxFileSelector(_("Save timecodes file"),path,_T(""),_T(""),str,wxFD_SAVE | wxFD_OVERWRITE_PROMPT); if (!filename.empty()) { SaveVFR(filename); - Options.SetText(_T("Last open timecodes path"), filename); - Options.Save(); + OPT_SET("Path/Last/Timecodes")->SetString(STD_STR(filename)); } } @@ -943,11 +934,10 @@ void FrameMain::OnCloseVFR(wxCommandEvent &event) { /// void FrameMain::OnOpenKeyframes (wxCommandEvent &event) { // Pick file - wxString path = Options.AsText(_T("Last open keyframes path")); + wxString path = lagi_wxString(OPT_GET("Path/Last/Keyframes")->GetString()); wxString filename = wxFileSelector(_T("Select the keyframes file to open"),path,_T(""),_T(".txt"),_T("All supported formats (*.txt, *.pass, *.stats, *.log)|*.txt;*.pass;*.stats;*.log|All files (*.*)|*.*"),wxFD_FILE_MUST_EXIST | wxFD_OPEN); if (filename.IsEmpty()) return; - Options.SetText(_T("Last open keyframes path"),filename); - Options.Save(); + OPT_SET("Path/Last/Keyframes")->SetString(STD_STR(filename)); // Load KeyFrameFile::Load(filename); @@ -976,11 +966,10 @@ void FrameMain::OnCloseKeyframes (wxCommandEvent &event) { /// void FrameMain::OnSaveKeyframes (wxCommandEvent &event) { // Pick file - wxString path = Options.AsText(_T("Last open keyframes path")); + wxString path = lagi_wxString(OPT_GET("Path/Last/Keyframes")->GetString()); wxString filename = wxFileSelector(_T("Select the Keyframes file to open"),path,_T(""),_T("*.key.txt"),_T("Text files (*.txt)|*.txt"),wxFD_OVERWRITE_PROMPT | wxFD_SAVE); if (filename.IsEmpty()) return; - Options.SetText(_T("Last open keyframes path"),filename); - Options.Save(); + OPT_SET("Path/Last/Keyframes")->SetString(STD_STR(filename)); // Save KeyFrameFile::Save(filename); @@ -1067,8 +1056,7 @@ void FrameMain::OnDummyVideo (wxCommandEvent &event) { /// @param event /// void FrameMain::OnOverscan (wxCommandEvent &event) { - Options.SetBool(_T("Show overscan mask"),event.IsChecked()); - Options.Save(); + OPT_SET("Video/Overscan Mask")->SetBool(event.IsChecked()); VideoContext::Get()->Stop(); videoBox->videoDisplay->Render(); } @@ -1217,13 +1205,13 @@ void FrameMain::OnOpenKanjiTimer (wxCommandEvent &event) { /// @brief Open Options dialog /// @param event /// -void FrameMain::OnOpenOptions (wxCommandEvent &event) { +void FrameMain::OnOpenPreferences (wxCommandEvent &event) { try { - DialogOptions options(this); - options.ShowModal(); - } - catch (const wxChar *e) { - wxLogError(e); + Preferences pref(this); + pref.ShowModal(); + + } catch (agi::Exception& e) { + wxPrintf("Caught agi::Exception: %s -> %s\n", e.GetName(), e.GetMessage()); } } @@ -1615,8 +1603,7 @@ void FrameMain::OnCloseWindow (wxCloseEvent &event) { int result = TryToCloseSubs(canVeto); // Store maximization state - Options.SetBool(_T("Maximized"),IsMaximized()); - Options.Save(); + OPT_SET("App/Maximized")->SetBool(IsMaximized()); // Abort/destroy if (canVeto) { @@ -1738,7 +1725,7 @@ void FrameMain::OnAutoSave(wxTimerEvent &event) { if (AssFile::top->loaded) { // Set path wxFileName origfile(AssFile::top->filename); - wxString path = Options.AsText(_T("Auto save path")); + wxString path = lagi_wxString(OPT_GET("Path/Auto/Save")->GetString()); if (path.IsEmpty()) path = origfile.GetPath(); wxFileName dstpath(path); if (!dstpath.IsAbsolute()) path = StandardPaths::DecodePathMaybeRelative(path, _T("?user/")); @@ -1848,7 +1835,7 @@ void FrameMain::OnNextLine(wxCommandEvent &event) { /// @brief Cycle through tag hiding modes void FrameMain::OnToggleTags(wxCommandEvent &) { - int tagMode = Options.AsInt(_T("Grid hide overrides")); + int tagMode = OPT_GET("Subtitle/Grid/Hide Overrides")->GetInt(); // Cycle to next tagMode = (tagMode+1)%3; @@ -1861,15 +1848,13 @@ void FrameMain::OnToggleTags(wxCommandEvent &) { StatusTimeout(message,10000); // Set option - Options.SetInt(_T("Grid hide overrides"),tagMode); - Options.Save(); + OPT_SET("Subtitle/Grid/Hide Overrides")->SetInt(tagMode); // Refresh grid SubsBox->Refresh(false); } void FrameMain::OnSetTags(wxCommandEvent &event) { - Options.SetInt(_T("Grid hide overrides"), event.GetId() - Menu_View_FullTags); - Options.Save(); + OPT_SET("Subtitle/Grid/Hide Overrides")->SetInt(event.GetId() - Menu_View_FullTags); SubsBox->Refresh(false); } @@ -1914,8 +1899,7 @@ void FrameMain::OnChooseLanguage (wxCommandEvent &event) { // Is OK? if (newCode != -1) { // Set code - Options.SetInt(_T("Locale Code"),newCode); - Options.Save(); + OPT_SET("App/Locale")->SetInt(newCode); // Language actually changed? if (newCode != old) { diff --git a/aegisub/src/hilimod_textctrl.cpp b/aegisub/src/hilimod_textctrl.cpp index b2fcf8f65..0d841317e 100644 --- a/aegisub/src/hilimod_textctrl.cpp +++ b/aegisub/src/hilimod_textctrl.cpp @@ -39,7 +39,9 @@ // Includes #include "config.h" +#include "compat.h" #include "hilimod_textctrl.h" +#include "main.h" #include "options.h" @@ -111,7 +113,7 @@ void HiliModTextCtrl::Modified() { // Different from original if (!isModified && !match) { isModified = true; - SetBackgroundColour(Options.AsColour(_T("Edit Box Need Enter Background"))); + SetBackgroundColour(lagi_wxColour(OPT_GET("Colour/Background/Modified")->GetColour())); Refresh(false); } diff --git a/aegisub/src/keyframe.cpp b/aegisub/src/keyframe.cpp index f4f4d2f27..300d81c12 100644 --- a/aegisub/src/keyframe.cpp +++ b/aegisub/src/keyframe.cpp @@ -42,7 +42,9 @@ #include #endif +#include "compat.h" #include "keyframe.h" +#include "main.h" #include "options.h" #include "text_file_reader.h" #include "text_file_writer.h" @@ -74,7 +76,7 @@ void KeyFrameFile::Load(wxString filename) { VideoContext::Get()->SetKeyFramesName(filename); // Add to recent - Options.AddToRecentList(filename,_T("Recent keyframes")); + AegisubApp::Get()->mru->Add("Keyframes", STD_STR(filename)); } // Fail catch (const wchar_t *error) { @@ -106,7 +108,7 @@ void KeyFrameFile::Save(wxString filename) { } // Add to recent - Options.AddToRecentList(filename,_T("Recent keyframes")); + AegisubApp::Get()->mru->Add("Keyframes", STD_STR(filename)); } diff --git a/aegisub/src/libresrc/Makefile.am b/aegisub/src/libresrc/Makefile.am index 67602640d..3b3711589 100644 --- a/aegisub/src/libresrc/Makefile.am +++ b/aegisub/src/libresrc/Makefile.am @@ -9,10 +9,10 @@ BUILT_SOURCES = bitmap.cpp default_config.cpp bitmap.cpp: ../../tools/common-respack ../../tools/common-respack bitmap.cpp ../bitmaps/16 ../bitmaps/24 ../bitmaps/misc/splash.png ../bitmaps/misc/wxicon.png -default_config.cpp: ../../tools/common-respack - ../../tools/common-respack default_config.cpp ./default_mru.json +default_config.cpp: ../../tools/common-respack *.json + ../../tools/common-respack default_config.cpp ./default_mru.json ./default_config.json -EXTRA_DIST = default_mru.json +EXTRA_DIST = *.json CLEANFILES= \ bitmap.cpp \ diff --git a/aegisub/src/libresrc/OLD_TO_NEW_OPTION_MAP.txt b/aegisub/src/libresrc/OLD_TO_NEW_OPTION_MAP.txt new file mode 100644 index 000000000..ff2edeac3 --- /dev/null +++ b/aegisub/src/libresrc/OLD_TO_NEW_OPTION_MAP.txt @@ -0,0 +1,191 @@ +Allow Ancient Avisynth Provider/Avisynth/Allow Ancient +Audio Alsa Device Player/Audio/ALSA/Device +Audio Autocommit Audio/Auto/Commit +Audio Autofocus Audio/Auto/Focus +Audio Autoscroll Audio/Auto/Scroll +Audio Background Colour/Audio Display/Background/Background +Audio Cache Audio/Cache/Type +Audio Disable PCM Provider Provider/Audio/PCM/Disable +Audio Display Height Audio/Display Height +Audio Downmixer Audio/Downmixer +Audio Draw Cursor Time Audio/Display/Draw/Cursor Time +Audio Draw Keyframes Audio/Display/Draw/Keyframes +Audio Draw Secondary Lines Audio/Display/Draw/Secondary Lines +Audio Draw Selection Background Audio/Display/Draw/Selection Background +Audio Draw Timeline Audio/Display/Draw/Timeline +Audio Draw Video Position Audio/Display/Draw/Video Position +Audio dsound buffer latency Player/Audio/DirectSound/Buffer Latency +Audio dsound buffer length Player/Audio/DirectSound/Buffer Length +Audio grab times on select Audio/Grab Times on Select +Audio HD Cache Location Audio/Cache/HD/Location +Audio HD Cache Name Audio/Cache/HD/Name +Audio Inactive Lines Display Mode Audio/Inactive Lines Display Mode +Audio Lead in Audio/Lead/IN +Audio Lead out Audio/Lead/OUT +Audio Line boundaries Thickness Audio/Line Boundaries Thickness +Audio Line boundary end Colour/Audio Display/Line boundary End +Audio Line boundary inactive line Colour/Audio Display/Line Boundary Inactive Line +Audio Line boundary start Colour/Audio Display/Line boundary Start +Audio Link Audio/Link +Audio lock scroll on cursor Audio/Lock Scroll on Cursor +Audio Medusa Timing Hotkeys Audio/Medusa Timing Hotkeys +Audio Next Line on Commit Audio/Next Line on Commit +Audio OSS Device Audio/OSS/Device +Audio Play Cursor Colour/Audio Display/Play Cursor +Audio player Audio/Player +Audio Plays When Stepping Video Audio/Plays When Stepping +Audio PortAudio Device Player/Audio/PortAudio/Device +Audio provider Audio/Provider +Audio Sample Rate Provider/Audio/AVS/Sample Rate +Audio Seconds Boundaries Colour/Audio Display/Seconds Boundaries +Audio Selection Background Colour/Audio Display/Background/Background +Audio Selection Background Modified Colour/Audio Display/Background/Selection Modified +Audio snap to keyframes Audio/Display/Snap/Keyframes +Audio snap to other lines Audio/Display/Snap/Other Lines +Audio Spectrum Audio/Spectrum +Audio Spectrum Cutoff Audio/Renderer/Spectrum/Cutoff +Audio Spectrum Memory Max Audio/Renderer/Spectrum/Memory Max +Audio Spectrum Quality Audio/Renderer/Spectrum/Quality +Audio Start Drag Sensitivity Audio/Start Drag Sensitivity +Audio Syllable boundaries Colour/Audio Display/Syllable Boundaries +Audio Syllable text Colour/Audio Display/Syllable Text +Audio Waveform Colour/Audio Display/Waveform +Audio Waveform Inactive Colour/Audio Display/Waveform Inactive +Audio Waveform Modified Colour/Audio Display/Waveform Modified +Audio Waveform Selected Colour/Audio Display/Waveform Selected +Audio Wheel Default To Zoom Audio/Wheel Default to Zoom +Auto backup App/Auto/Backup +Auto backup path Path/Auto/Backup +Auto check for updates App/Auto/Check For Updates +Auto save every seconds App/Auto/Save Every Seconds +Auto Save on Every Change App/Auto/Save on Every Change +Auto save path Path/Auto/Save +Autoload linked files App/Auto/Load Linked Files +Automation Autoload Path Path/Automation/Autoload +Automation Autoreload Mode Automation/Autoreload Mode +Automation Base Path Path/Automation/Base +Automation Include Path Path/Automation/Include +Automation Thread Priority Automation/Lua/Thread Priority +Automation Trace Level Automation/Trace Level +Avisynth MemoryMax Provider/Avisynth/Memory Max +Call tips enabled App/Call Tips +Color Picker Mode Tool/Colour Picker/Mode +Color Picker Recent Tool/Colour Picker/Recent +Colour/Subtitle/Syntax/Error Colour/Subtitle/Syntax/Background/Error +Detached Video Video/Detached/Enabled +Detached video last x Video/Detached/Last/X +Detached video last y Video/Detached/Last/Y +Detached video maximized Video/Detached/Maximized +Dictionaries path Path/Dictionary +Disable Dragging Times Audio/Display/Dragging Times +Edit Box Need Enter Background Color/Background/Modified +Edit Font Face Subtitle/Edit Box/Font Face +Edit Font Size Subtitle/Edit Box/Font Size +FFmpeg allow unsafe seeking Provider/Video/FFMpegSource/Unsafe Seeking +FFmpegSource always index all tracks Provider/FFmpegSource/Index All Tracks +FFmpegSource audio decoding error handling Provider/Audio/FFMpegSource/Decode Error Handling +FFmpegSource decoding threads Provider/Video/FFmpegSource/Decoding Threads +FFmpegSource log level Provider/FFmpegSource/Log Level +FFmpegSource max cache files Provider/FFmpegSource/Cache/Files +FFmpegSource max cache size Provider/FFmpegSource/Cache/Size +Find Affect Tool/Search Replace/Affect +Find Field Tool/Search Replace/Field +Find Match Case Tool/Search Replace/Match Case +Find RegExp Tool/Search Replace/RegExp +Find Update Video Tool/Search Replace/Video Update +Fonts Collector Action Tool/Fonts Collector/Action +Fonts Collector Destination Path/Fonts Collector Destination +Grid Active border Colour/Subtitle Grid/Active Border +Grid Allow Focus Subtitle/Grid/Focus Allow +Grid Background Colour/Subtitle Grid/Background/Background +Grid collision foreground Colour/Subtitle Grid/Collision +Grid Font Face Subtitle/Grid/Font Face +Grid font size Subtitle/Grid/Font Size +Grid Hide Overrides Subtitle/Grid/Hide Overrides +Grid hide overrides char Subtitle/Grid/Hide Overrides Char +Grid left column Colour/Subtitle Grid/Left Column +Grid lines Colour/Subtitle Grid/Lines +Grid selection background Colour/Subtitle Grid/Background/Selection +Grid selection foreground Colour/Subtitle Grid/Selection +Grid standard foreground Colour/Subtitle Grid/Standard +Highlight subs in frame Subtitle/Grid/Highlight Subtitles in Frame +Insert Mode on Time Boxes Subtitle/Time Edit/Insert Mode +kanji timer interpolation Tool/Kanji Timer/Interpolation +Last open audio path Path/Last/Audio +Last open automation path Path/Last/Automation +Last open keyframes path Path/Last/Keyframes +Last open subtitles path Path/Last/Subtitles +Last open timecodes path Path/Last/Timecodes +Last open video path Path/Last/Video +Link Time Boxes Commit Subtitle/Edit Box/Link Time Boxes Commit +Local config App/Local Config +Locale Code App/Locale +Maximized App/Maximized +Recent timecodes Timecodes +RGBAdjust Tool Tool/Colour Picker/RGBAdjust Tool +Save Charset App/Save Charset +Select Action Tool/Select/Action +Select Condition Tool/Select/Condition +Select Field Tool/Select/Field +Select Match case Tool/Select Lines/Match/Case +Select Match comments Tool/Select Lines/Match/Comment +Select Match dialogues Tool/Select Lines/Match/Dialogue +Select Mode Tool/Select/Mode +Select Text Tool/Select Lines/Text +Shift Times Affect Tool/Shift Times/Affect +Shift Times ByTime Tools/Shift Times/ByTime +Shift Times Direction Tools/Shift Times/Direction +Shift Times Length Tool/Shift Times/Length +Shift Times Type Tool/Shift Times/Type +Show keyframes on video slider Video/Slider/Show Keyframes +Show Overscan Mask Video/Overscan Mask +Show Splash App/Splash +Spell Checker Tool/Spell Checker/Backend +Spell checker Language Tool/Spell Checker/Language +Style editor preview background Colour/Style Editor/Background/Preview +Style editor preview text Tool/Style Editor/Preview Text +Subtitles provider Subtitle/Provider +Sync video with subs Video/Subtitle Sync + +Syntax Highlight Brackets Colour/Subtitle/Syntax/Brackets +Syntax Highlight Enabled Subtitle/Highlight/Syntax +Syntax Highlight Error Syntax Highlight Error Background +Syntax Highlight Karaoke Template Colour/Subtitle/Syntax/Karaoke Template +Syntax Highlight Line Break Colour/Subtitle/Syntax/Line Break +Syntax Highlight Normal Colour/Subtitle/Syntax/Normal +Syntax Highlight Parameters Colour/Subtitle/Syntax/Parameters +Syntax Highlight Slashes Colour/Subtitle/Syntax/Slashes +Syntax Highlight Tags Colour/Subtitle/Syntax/Highlight Tags +Text actor separator Tool/Import/Text/Actor Separator + +Text comment starter Tool/Import/Text/Comment Starter +Thesaurus Language Tool/Thesaurus/Language +Timing Default Duration Timing/Default Duration +Timing processor adjacent bias Tool/Timing Post Processor/Adjacent Bias +Timing processor adjacent thres Tool/Timing Post Processor/Threshold/Adjacent +Timing processor Enable adjacent Tool/Timing Post Processor/Enable/Adjacent +Timing processor Enable keyframe Tool/Timing Post Processor/Enable/Keyframe +Timing processor Enable lead-in Tool/Timing Post Processor/Enable/Lead/IN +Timing processor Enable lead-out Tool/Timing Post Processor/Enable/Lead/OUT +Timing processor key end after thres Tool/Timing Post Processor/Threshold/Key End After +Timing processor key end before thres Tool/Timing Post Processor/Threshold/Key End Before +Timing processor key start after thres Tool/Timing Post Processor/Threshold/Key Start After +Timing processor key start before thres Tool/Timing Post Processor/Threshold/Key Start Before +Timing processor Only Selection Tool/Timing Post Processor/Only Selection +Tips current Tool/Tip of the Day/Current +Tips enabled App/Tips +Undo levels Subtitle/Undo Levels +Updates Next Check Time Version/Next Check +Use nonstandard Milisecond Times App/Nonstandard Milisecond Times +Video Check Script Res Video/Check Script Res +Video Default Zoom Video/Default Zoom +Video Dummy Last Colour Colour/Video Dummy/Last Colour +Video Dummy Last FPS Video/Dummy/FPS +Video Dummy Last Height Video/Dummy/Last/Height +Video Dummy Last Length Video/Dummy/Last/Length +Video Dummy Last Width Video/Dummy/Last/Width +Video Dummy Pattern Video/Dummy/Pattern +Video Fast Jump Step Video/Slider/Fast Jump Step +Video provider Video/Provider +Video Screenshot Path Path/Screenshot +Video Visual Realtime Video/Visual Realtime diff --git a/aegisub/src/libresrc/default_config.json b/aegisub/src/libresrc/default_config.json new file mode 100644 index 000000000..b53ee7834 --- /dev/null +++ b/aegisub/src/libresrc/default_config.json @@ -0,0 +1,415 @@ +{ + "App" : { + "Auto" : { + "Backup" : true, + "Check For Updates" : -1, + "Load Linked Files" : 2, + "Save Every Seconds" : 60, + "Save on Every Change" : false + }, + "Call Tips" : false, + "Local Config" : false, + "Locale" : -1, + "Maximized" : false, + "Nonstandard Milisecond Times" : false, + "Save Charset" : "UTF-8", + "Splash" : true, + "Tips" : false + }, + + + "Audio" : { + "Auto" : { + "Commit" : false, + "Focus" : false, + "Scroll" : true + }, + "Cache" : { + "HD" : { + "Location" : "default", + "Name" : "audio%02i.tmp" + }, + "Type" : 1 + }, + "Display Height" : 200, + "Display" : { + "Dragging Times" : false, + "Draw" : { + "Cursor Time" : true, + "Keyframes" : true, + "Secondary Lines" : true, + "Selection Background" : true, + "Timeline" : true, + "Video Position" : false + }, + "Snap" : { + "Keyframes" : false, + "Other Lines" : false + } + }, + "Downmixer" : "ConvertToMono", + "Grab Times on Select" : true, + "Inactive Lines Display Mode" : 1, + "Lead" : { + "IN" : 200, + "OUT" : 300 + }, + "Line Boundaries Thickness" : 2, + "Line Boundary Inactive Line" : "grey", + "Link" : true, + "Lock Scroll on Cursor" : false, + "Medusa Timing Hotkeys" : false, + "Next Line on Commit" : true, + "Player" : "portaudio", + "Plays When Stepping Video" : false, + "Provider" : "ffmpegsource", + "Renderer" : { + "Spectrum" : { + "Cutoff" : 0, + "Memory Max" : 128, + "Quality" : 1 + } + }, + "Spectrum" : true, + "Start Drag Sensitivity" : 2, + "Wheel Default to Zoom" : false + }, + + + "Automation" : { + "Autoreload Mode" : 1, + "Lua" : { + "Thread Priority" : 1 + }, + "Trace Level" : 3 + }, + + + "Colour" : { + "Audio Display" : { + "Background" : { + "Background" : "rgb(0,0,0)", + "Selection" : "rgb(64, 64, 64)", + "Selection Modified" : "rgb(92, 0, 0)" + }, + "Line Boundary Inactive Line" : "rgb(190,190,190)", + "Line boundary End" : "rgb(230, 125, 0)", + "Line boundary Start" : "rgb(216, 0, 0)", + "Play Cursor" : "rgb(255,255,255)", + "Seconds Boundaries" : "rgb(0, 100, 255)", + "Syllable Boundaries" : "rgb(255,255,0)", + "Syllable Text" : "rgb(255,0,0)", + "Waveform" : "rgb(0, 200, 0)", + "Waveform Inactive" : "rgb(0, 80, 0)", + "Waveform Modified" : "rgb(255, 230, 230)", + "Waveform Selected" : "rgb(255,255,255)" + }, + "Background" : { + "Modified" : "rgb(192, 192, 255)" + }, + "Style Editor" : { + "Background" : { + "Preview" : "rgb(125, 153, 176)" + } + }, + "Subtitle Grid" : { + "Active Border" : "rgb(255, 91, 239)", + "Background" : { + "Background" : "rgb(255,255,255)", + "Comment" : "rgb(216, 222, 245)", + "Inframe" : "rgb(255, 253, 234)", + "Selected Comment" : "rgb(211, 238, 238)", + "Selection" : "rgb(206, 255, 231)" + }, + "Collision" : "rgb(255,0,0)", + "Header" : "rgb(165, 207, 231)", + "Left Column" : "rgb(196, 236, 201)", + "Lines" : "rgb(190,190,190)", + "Selection" : "rgb(0,0,0)", + "Standard" : "rgb(0,0,0)" + }, + "Subtitle" : { + "Syntax" : { + "Background" : { + "Error" : "rgb(255, 200, 200)" + }, + "Brackets" : "rgb(20, 50, 255)", + "Error" : "rgb(200, 0, 0)", + "Highlight Tags" : "rgb(90, 90, 90)", + "Karaoke Template" : "rgb(128, 0, 192)", + "Line Break" : "rgb(160, 160, 160)", + "Normal" : "rgb(0,0,0)", + "Parameters" : "rgb(40, 90, 40)", + "Slashes" : "rgb(255, 0, 200)" + } + }, + "Video Dummy" : { + "Last Colour" : "rgb(47, 163, 254)" + } + }, + + "Limits" : { + "Find Replace" : 16, + "MRU" : 16, + "Undo Levels" : 8 + }, + + "Path" : { + "Auto" : { + "Backup" : "?user/autoback", + "Save" : "?user/autosave" + }, + "Automation" : { + "Autoload" : "?user/automation/autoload/|?data/automation/autoload/", + "Base" : "?data/automation/", + "Include" : "?user/automation/include/|?data/automation/include/" + }, + "Dictionary" : "?user/dictionary", + "Fonts Collector Destination" : "?script", + "Last" : { + "Audio" : "", + "Automation" : "", + "Keyframes" : "", + "Subtitles" : "", + "Timecodes" : "", + "Video" : "" + }, + "Screenshot" : "?video" + }, + + + "Player" : { + "Audio" : { + "ALSA" : { + "Device" : "default" + }, + "DirectSound" : { + "Buffer Latency" : 100, + "Buffer Length" : 5 + }, + "OSS" : { + "Device" : "/dev/dsp" + }, + "PortAudio" : { + "Device" : -1 + } + } + }, + + + "Provider" : { + "Audio" : { + "AVS" : { + "Sample Rate" : 0 + }, + "FFMpegSource" : { + "Decode Error Handling" : "stop" + }, + "PCM" : { + "Disable" : false + } + }, + "Avisynth" : { + "Allow Ancient" : false, + "Memory Max" : 64 + }, + "FFmpegSource" : { + "Cache" : { + "Files" : 20, + "Size" : 42 + }, + "Index All Tracks" : true, + "Log Level" : "quiet" + }, + "Video" : { + "Cache" : { + "Size" : 32 + }, + "FFMpegSource" : { + "Decoding Threads" : 1, + "Unsafe Seeking" : false + } + } + }, + + + "Subtitle" : { + "Edit Box" : { + "Font Face" : "", + "Font Size" : 10, + "Link Time Boxes Commit" : true + }, + "Grid" : { + "Column" : [ + {"bool" : true}, + {"bool" : true}, + {"bool" : true}, + {"bool" : true}, + {"bool" : true}, + {"bool" : true}, + {"bool" : true}, + {"bool" : true}, + {"bool" : true}, + {"bool" : true} + ], + "Focus Allow" : true, + "Font Face" : "", + "Font Size" : 10, + "Hide Overrides" : 1, + "Hide Overrides Char" : "☀", + "Highlight Subtitles in Frame" : true + }, + "Highlight" : { + "Syntax" : true + }, + "Provider" : "libass", + "Time Edit" : { + "Insert Mode" : true + } + }, + + + "Timing" : { + "Default Duration" : 2000 + }, + + + "Tool" : { + "Colour Picker" : { + "Mode" : 4, + "RGBAdjust Tool" : false, + "Recent" : "&H000000& &H0000FF& &H00FFFF& &H00FF00& &HFFFF00& &HFF0000& &HFF00FF& &HFFFFFF&" + }, + "Fonts Collector" : { + "Action" : 0 + }, + "Import" : { + "Text" : { + "Actor Separator" : ":", + "Comment Starter" : "#" + } + }, + "Kanji Timer" : { + "Interpolation" : true + }, + "Paste Lines Over" : { + "Fields" : [ + {"bool" : false}, + {"bool" : false}, + {"bool" : false}, + {"bool" : false}, + {"bool" : false}, + {"bool" : false}, + {"bool" : false}, + {"bool" : false}, + {"bool" : false}, + {"bool" : true} + ] + }, + "Preferences" : { + "Page" : 0 + }, + "Search Replace" : { + "Affect" : 0, + "Field" : 0, + "Match Case" : false, + "RegExp" : false, + "Video Update" : false + }, + "Select Lines" : { + "Match" : { + "Case" : false, + "Comment" : false, + "Dialogue" : true + }, + "Text" : "" + }, + "Select" : { + "Action" : 0, + "Condition" : 0, + "Field" : 0, + "Mode" : 1 + }, + "Shift Times" : { + "Affect" : 0, + "ByTime" : true, + "Direction" : true, + "Length" : 0, + "Type" : 0 + }, + "Spell Checker" : { + "Backend" : "hunspell", + "Language" : "en_US" + }, + "Style Editor" : { + "Preview Text" : "Aegisub\\N0123 月語" + }, + "Thesaurus" : { + "Language" : "en_US" + }, + "Timing Post Processor" : { + "Adjacent Bias" : 0.9000000000000000222, + "Enable" : { + "Adjacent" : true, + "Keyframe" : true, + "Lead" : { + "IN" : true, + "OUT" : true + } + }, + "Only Selection" : false, + "Threshold" : { + "Adjacent" : 300, + "Key End After" : 6, + "Key End Before" : 5, + "Key Start After" : 4, + "Key Start Before" : 5 + } + }, + "Tip of the Day" : { + "Current" : 0 + }, + "Visual" : { + "Always Show": true + } + }, + + + "Version" : { + "Id" : "$Id$", + "Last Version" : 4040, + "Next Check" : 0 + }, + + + "Video" : { + "Check Script Res" : 0, + "Default Zoom" : 7, + "Detached" : { + "Enabled" : false, + "Last" : { + "X" : -1, + "Y" : -1 + }, + "Maximized" : false + }, + "Dummy" : { + "FPS" : 23.975999999999999091, + "Last" : { + "Height" : 480, + "Length" : 40000, + "Width" : 640 + }, + "Pattern" : false + }, + "Overscan Mask" : false, + "Provider" : "ffmpegsource", + "Slider" : { + "Fast Jump Step" : 10, + "Show Keyframes" : true + }, + "Subtitle Sync" : true, + "Threaded" : false, + "Visual Realtime" : true + } +} diff --git a/aegisub/src/libresrc/default_mru.json b/aegisub/src/libresrc/default_mru.json index 10bb3e2e2..96166d7b0 100644 --- a/aegisub/src/libresrc/default_mru.json +++ b/aegisub/src/libresrc/default_mru.json @@ -1,5 +1,9 @@ { "Audio" : [], - "Video" : [], - "Scripts" : [] + "Find" : [], + "Keyframes" : [], + "Replace" : [], + "Subtitle" : [], + "Timecodes" : [], + "Video" : [] } diff --git a/aegisub/src/main.cpp b/aegisub/src/main.cpp index 086cc085d..4df53dc6c 100644 --- a/aegisub/src/main.cpp +++ b/aegisub/src/main.cpp @@ -60,11 +60,12 @@ #include "auto4_base.h" #endif #include "charset_conv.h" +#include "compat.h" #include "export_framerate.h" #include "frame_main.h" #include "hotkeys.h" #include "main.h" -#include "options.h" +#include "libresrc/libresrc.h" #include "plugin_manager.h" #include "standard_paths.h" #include "subs_grid.h" @@ -72,6 +73,7 @@ #include "version.h" #include "video_context.h" +#include /////////////////// // wxWidgets macro @@ -140,6 +142,32 @@ bool AegisubApp::OnInit() { StartupLog(_T("Inside OnInit")); frame = NULL; try { + + const std::string conf_mru(StandardPaths::DecodePath(_T("?user/mru.json"))); + mru = new agi::MRUManager(conf_mru, GET_DEFAULT_CONFIG(default_mru)); + + // Set config file + StartupLog(_T("Load configuration")); + try { + const std::string conf_user(StandardPaths::DecodePath(_T("?user/config.json"))); + opt = new agi::Options(conf_user, GET_DEFAULT_CONFIG(default_config)); + opt->ConfigUser(); +/* +#ifdef _DEBUG + const std::string conf_default("default_config.json"); + std::istream *stream = agi::io::Open(conf_default); + opt->ConfigDefault(*stream); + delete stream; +#else + opt->ConfigDefault(GET_DEFAULT_CONFIG(default_config)); +#endif +*/ +// opt->ConfigDefault(GET_DEFAULT_CONFIG(default_config)); + + } catch (agi::Exception& e) { + wxPrintf("Caught agi::Exception: %s -> %s\n", e.GetName(), e.GetMessage()); + } + // Initialize randomizer StartupLog(_T("Initialize random generator")); srand(time(NULL)); @@ -166,36 +194,9 @@ bool AegisubApp::OnInit() { wxHandleFatalExceptions(true); #endif - // Set config file - StartupLog(_T("Load configuration")); - Options.LoadDefaults(); -#ifdef __WXMSW__ - // Try loading configuration from the install dir if one exists there - if (wxFileName::FileExists(StandardPaths::DecodePath(_T("?data/config.dat")))) { - Options.SetFile(StandardPaths::DecodePath(_T("?data/config.dat"))); - Options.Load(); - - if (Options.AsBool(_T("Local config"))) { - // Local config, make ?user mean ?data so all user settings are placed in install dir - StandardPaths::SetPathValue(_T("?user"), StandardPaths::DecodePath(_T("?data"))); - } - else { - // Not local config, we don't want that config.dat file here any more - // It might be a leftover from a really old install - wxRemoveFile(StandardPaths::DecodePath(_T("?data/config.dat"))); - } - } -#endif - // TODO: Check if we can write to config.dat and warn the user if we can't - // If we had local config, ?user now means ?data so this will still be loaded from the correct location - Options.SetFile(StandardPaths::DecodePath(_T("?user/config.dat"))); - Options.Load(); - StartupLog(_T("Store options back")); - Options.SetInt(_T("Last Version"),GetSVNRevision()); - Options.LoadDefaults(false,true); // Override options based on version number - Options.Save(); - AssTime::UseMSPrecision = Options.AsBool(_T("Use nonstandard Milisecond Times")); + OPT_SET("Version/Last Version")->SetInt(GetSVNRevision()); + AssTime::UseMSPrecision = OPT_GET("App/Nonstandard Milisecond Times")->GetBool(); // Set hotkeys file StartupLog(_T("Load hotkeys")); @@ -205,11 +206,10 @@ bool AegisubApp::OnInit() { StartupLog(_T("Initialize final locale")); // Set locale - int lang = Options.AsInt(_T("Locale Code")); + int lang = OPT_GET("App/Locale")->GetInt(); if (lang == -1) { lang = locale.PickLanguage(); - Options.SetInt(_T("Locale Code"),lang); - Options.Save(); + OPT_SET("App/Locale")->SetInt(lang); } locale.Init(lang); @@ -220,7 +220,7 @@ bool AegisubApp::OnInit() { // Load Automation scripts #ifdef WITH_AUTOMATION StartupLog(_T("Load global Automation scripts")); - global_scripts = new Automation4::AutoloadScriptManager(Options.AsText(_T("Automation Autoload Path"))); + global_scripts = new Automation4::AutoloadScriptManager(lagi_wxString(OPT_GET("Path/Automation/Autoload")->GetString())); #endif // Load export filters @@ -263,7 +263,8 @@ int AegisubApp::OnExit() { SubtitleFormat::DestroyFormats(); VideoContext::Clear(); delete plugins; - Options.Clear(); + delete opt; + delete mru; #ifdef WITH_AUTOMATION delete global_scripts; #endif @@ -461,7 +462,7 @@ void AegisubApp::MacOpenFile(const wxString &filename) { if (frame != NULL && !filename.empty()) { frame->LoadSubtitles(filename); wxFileName filepath(filename); - Options.SetText(_T("Last open subtitles path"), filepath.GetPath()); + OPT_SET("Path/Last/Subtitles")->SetString(STD_STR(filepath.GetPath())); } } #endif diff --git a/aegisub/src/main.h b/aegisub/src/main.h index eef8b70d2..496a82fe6 100644 --- a/aegisub/src/main.h +++ b/aegisub/src/main.h @@ -44,7 +44,8 @@ #endif #include "aegisublocale.h" - +#include +#include ////////////// // Prototypes @@ -54,7 +55,11 @@ class PluginManager; /// DOCME namespace Automation4 { class AutoloadScriptManager; } +/// Macro to get OptionValue object. +#define OPT_GET(x) AegisubApp::Get()->opt->Get(x) +/// Macro to set OptionValue object. +#define OPT_SET(x) AegisubApp::Get()->opt->Get(x) /// DOCME /// @class AegisubApp @@ -75,6 +80,9 @@ public: /// DOCME AegisubLocale locale; + agi::MRUManager *mru; + agi::Options *opt; + /// DOCME FrameMain *frame; #ifdef WITH_AUTOMATION diff --git a/aegisub/src/options.cpp b/aegisub/src/options.cpp index b7b8dfe27..09215c9a7 100644 --- a/aegisub/src/options.cpp +++ b/aegisub/src/options.cpp @@ -35,818 +35,3 @@ /// -//////////// -// Includes -#include "config.h" - -#ifndef AGI_PRE -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#endif - -#include "colorspace.h" -#include "options.h" -#include "text_file_reader.h" -#include "text_file_writer.h" -#include "utils.h" - - -/// @brief Constructor -/// -OptionsManager::OptionsManager() { - modified = false; - overriding = false; - lastVersion = -1; -} - - - -/// @brief Destructor -/// -OptionsManager::~OptionsManager() { - Clear(); -} - - - -/// @brief Clear -/// -void OptionsManager::Clear() { - opt.clear(); - optType.clear(); -} - - - -/// @brief Load default values -/// @param onlyDefaults -/// @param doOverride -/// -void OptionsManager::LoadDefaults(bool onlyDefaults,bool doOverride) { - ///// PUBLIC ////// - // Here go the options that can be edited by the options menu - - if (doOverride) overriding = true; - if (onlyDefaults) lastVersion = -1; - - // General - SetModificationType(MOD_AUTOMATIC); - -// Broken on OS X during startup only. - SetBool(_T("Tips enabled"),false); - SetBool(_T("Show splash"),true); - SetBool(_T("Local config"),false); - SetInt(_T("Undo levels"),8); - SetInt(_T("Recent timecodes max"),16); - SetInt(_T("Recent keyframes max"),16); - SetInt(_T("Recent sub max"),16); - SetInt(_T("Recent vid max"),16); - SetInt(_T("Recent aud max"),16); - SetInt(_T("Recent find max"),16); - SetInt(_T("Recent replace max"),16); - SetInt(_T("Auto check for updates"),-1); - - // File Save/Load - SetModificationType(MOD_RESTART); - SetInt(_T("Auto save every seconds"),60); // FIXME: this shouldn't need to require a restart - SetModificationType(MOD_AUTOMATIC); - SetText(_T("Auto save path"),_T("?user/autosave")); - SetBool(_T("Auto backup"),true); - SetText(_T("Auto backup path"),_T("?user/autoback")); - SetInt(_T("Autoload linked files"),2); - SetText(_T("Text actor separator"),_T(":")); - SetText(_T("Text comment starter"),_T("#")); - SetText(_T("Save charset"),_T("UTF-8")); - SetBool(_T("Use nonstandard milisecond times"),false); - SetBool(_T("Auto save on every change"),false); - - // Edit Box - SetModificationType(MOD_RESTART); -#if defined(__WINDOWS__) || defined(__APPLE__) - SetText(_T("Dictionaries path"),_T("?data/dictionaries")); -#else - SetText(_T("Dictionaries path"),wxString::Format(_T("%s/%s"), _T(INSTALL_PREFIX),_T("/share/myspell"))); -#endif - SetText(_T("Spell Checker"),_T("hunspell")); - SetModificationType(MOD_AUTOMATIC); - SetBool(_T("Link time boxes commit"),true); - SetBool(_T("Insert mode on time boxes"),true); - SetModificationType(MOD_EDIT_BOX); - SetBool(_T("Call tips enabled"),false,1700); - SetBool(_T("Syntax highlight enabled"),true); - - // Edit box cosmetic - SetColour(_T("Syntax Highlight Normal"),wxColour(0,0,0)); - SetColour(_T("Syntax Highlight Brackets"),wxColour(20,50,255)); - SetColour(_T("Syntax Highlight Slashes"),wxColour(255,0,200)); - SetColour(_T("Syntax Highlight Tags"),wxColour(90,90,90)); - SetColour(_T("Syntax Highlight Parameters"),wxColour(40,90,40)); - SetColour(_T("Syntax Highlight Error"),wxColour(200,0,0)); - SetColour(_T("Syntax Highlight Error Background"),wxColour(255,200,200)); - SetColour(_T("Syntax Highlight Line Break"),wxColour(160,160,160)); - SetColour(_T("Syntax Highlight Karaoke Template"), wxColour(128,0,192)); - SetColour(_T("Edit Box Need Enter Background"),wxColour(192,192,255)); -#if defined(__WINDOWS__) - SetInt(_T("Edit Font Size"),9); -#else - SetInt(_T("Edit Font Size"),11); -#endif - SetText(_T("Edit Font Face"),_T("")); - - // Video Options - SetModificationType(MOD_AUTOMATIC); - SetInt(_T("Video Check Script Res"), 0); - SetInt(_T("Video Default Zoom"), 7); - SetInt(_T("Video Fast Jump Step"), 10); - SetText(_T("Video Screenshot Path"),_T("?video"),1700); - SetModificationType(MOD_VIDEO); - SetBool(_T("Show keyframes on video slider"),true); - SetBool(_T("Show overscan mask"),false); - - // Video Provider (Advanced) - SetModificationType(MOD_VIDEO_RELOAD); - SetInt(_T("Avisynth MemoryMax"),64,1700); - SetBool(_T("Threaded Video"),false,1700); - #ifdef __WINDOWS__ - SetText(_T("Video Provider"),_T("ffmpegsource"),2416); - #else - SetText(_T("Video Provider"),_T(DEFAULT_PROVIDER_VIDEO),1945); - #endif - SetBool(_T("FFmpeg allow unsafe seeking"),false); - SetInt(_T("FFmpegSource decoding threads"),1); - SetBool(_T("Allow Ancient Avisynth"),false,1700); - #ifdef __WINDOWS__ - SetText(_T("Subtitles Provider"),_T("csri/vsfilter_textsub"),1700); - #else - SetText(_T("Subtitles Provider"),_T(DEFAULT_PROVIDER_SUBTITLE)); - #endif - SetInt(_T("Video cache size"), 32); - SetInt(_T("FFmpegSource max cache size"),42); - SetInt(_T("FFmpegSource max cache files"),20); - SetInt(_T("FFmpegSource always index all tracks"), true); - SetText(_T("FFmpegSource log level"), _T("quiet")); - SetText(_T("FFmpegSource audio decoding error handling"), _T("stop")); - - // Audio Options - SetModificationType(MOD_AUTOMATIC); - SetBool(_T("Audio grab times on select"),true); - SetBool(_T("Audio Autofocus"),false); - SetBool(_T("Audio Plays When Stepping Video"),false); - SetBool(_T("Audio Wheel Default To Zoom"),false); - SetBool(_T("Audio lock scroll on cursor"),false); - SetBool(_T("Audio snap to keyframes"),false); - SetBool(_T("Audio snap to other lines"),false); - SetInt(_T("Timing Default Duration"), 2000); - SetInt(_T("Audio lead in"),200); - SetInt(_T("Audio lead out"),300); - SetModificationType(MOD_AUDIO); - SetInt(_T("Audio Inactive Lines Display Mode"),1); - SetBool(_T("Disable Dragging Times"), false); - SetInt(_T("Audio Start Drag Sensitivity"), 2); - - // Audio Advanced - SetModificationType(MOD_AUDIO_RELOAD); - SetInt(_T("Audio Cache"),1,1700); - #if defined(__WINDOWS__) - SetText(_T("Audio Player"),_T("DirectSound"),1945); - SetText(_T("Audio Provider"),_T("ffmpegsource"),2416); - #else - SetText(_T("Audio Player"),_T(DEFAULT_PLAYER_AUDIO)); - SetText(_T("Audio Provider"),_T(DEFAULT_PROVIDER_AUDIO),1945); - #endif - SetText(_T("Audio Downmixer"),_T("ConvertToMono"),1700); - SetText(_T("Audio Alsa Device"), _T("default")); - SetInt(_T("Audio PortAudio Device"), -1); - SetText(_T("Audio OSS Device"), _T("/dev/dsp")); - SetText(_T("Audio HD Cache Location"),_T("default"),1700); - SetText(_T("Audio HD Cache Name"),_T("audio%02i.tmp"),1700); - SetBool(_T("Audio Disable PCM Provider"), false); - // Technically these can do with just the spectrum object being re-created - SetInt(_T("Audio Spectrum Cutoff"),0); - SetInt(_T("Audio Spectrum Quality"),1); - SetInt(_T("Audio Spectrum Memory Max"),128); // megabytes - // and this one could do with just reiniting the audio player - SetInt(_T("Audio dsound buffer latency"), 100); - SetInt(_T("Audio dsound buffer length"), 5); - - // Automation - // The path changes only take effect when a script is (re)loaded but Automatic should be good enough, it certainly doesn't warrart a restart - SetModificationType(MOD_AUTOMATIC); - SetText(_T("Automation Base Path"), _T("?data/automation/"),1700); - SetText(_T("Automation Include Path"), _T("?user/automation/include/|?data/automation/include/"),1700); - SetText(_T("Automation Autoload Path"), _T("?user/automation/autoload/|?data/automation/autoload/"),1700); - SetInt(_T("Automation Trace Level"), 3); - SetInt(_T("Automation Thread Priority"), 1); // "below normal" - SetInt(_T("Automation Autoreload Mode"), 1); // local only - - // Generate colors - // FIXME: Can't reliably store the system colour-based ones in the config file, the user might change colour scheme - wxColour tempCol = wxSystemSettings::GetColour(wxSYS_COLOUR_WINDOW); - wxColour textCol = wxSystemSettings::GetColour(wxSYS_COLOUR_WINDOWTEXT); - wxColour background = wxSystemSettings::GetColour(wxSYS_COLOUR_WINDOW); - wxColour comment = wxColour(216,222,245); - wxColour selection = wxColour(206,255,231); - wxColour selComment = wxColour(211,238,238); - wxColour header = wxColour(165,207,231); - wxColour labels = wxColour(196,236,201); - wxColour inframe = wxColour(255,253,234); - wxColour active = wxColour(255,91,239); - wxColour grid = wxColour(128,128,128); - wxColour collision = wxColour(255,0,0); - - // Grid - SetModificationType(MOD_GRID); - SetBool(_T("Grid allow focus"),true); - SetBool(_T("Highlight subs in frame"),true); - - // Grid cosmetic - SetColour(_T("Grid standard foreground"),textCol); - SetColour(_T("Grid selection background"),selection); - SetColour(_T("Grid selection foreground"),textCol); - SetColour(_T("Grid comment background"),comment); - SetColour(_T("Grid collision foreground"),collision); - SetColour(_T("Grid selected comment background"),selComment); - SetColour(_T("Grid inframe background"),inframe); - SetColour(_T("Grid background"),background); - SetColour(_T("Grid header"),header); - SetColour(_T("Grid left column"),labels); - SetColour(_T("Grid active border"),active); - SetColour(_T("Grid lines"),grid); -#if defined(__WINDOWS__) - SetInt(_T("Grid font size"),8); -#else - SetInt(_T("Grid font size"),10); -#endif - SetText(_T("Grid Font Face"),_T("")); - wchar_t temp = 0x2600; - SetText(_T("Grid hide overrides char"),temp); - SetModificationType(MOD_AUTOMATIC); - - // Audio Cosmetic - SetModificationType(MOD_AUDIO); - SetInt(_T("Audio Line boundaries Thickness"), 2); - SetBool(_T("Audio Draw Secondary Lines"), true); - SetBool(_T("Audio Draw Selection Background"), true); - SetBool(_T("Audio Draw Keyframes"), true); - SetBool(_T("Audio Draw Timeline"),true); - SetBool(_T("Audio Draw Cursor Time"),true); - SetBool(_T("Audio Draw Video Position"),false,1700); - SetColour(_T("Audio Selection Background Modified"),wxColour(92,0,0)); - SetColour(_T("Audio Selection Background"),wxColour(64,64,64)); - SetColour(_T("Audio Seconds Boundaries"),wxColour(0,100,255)); - SetColour(_T("Audio Waveform Modified"),wxColour(255,230,230)); - SetColour(_T("Audio Waveform Selected"),wxColour(255,255,255)); - SetColour(_T("Audio Waveform Inactive"),wxColour(0,80,0)); - SetColour(_T("Audio Waveform"),wxColour(0,200,0)); - SetColour(_T("Audio Line boundary start"),wxColour(216,0,0),1700); - SetColour(_T("Audio Line boundary end"),wxColour(230,125,0),1700); - SetColour(_T("Audio Line boundary inactive line"),wxColour(128,128,128)); - SetColour(_T("Audio Syllable boundaries"),wxColour(255,255,0)); - SetColour(_T("Audio Syllable text"),wxColour(255,0,0)); - SetColour(_T("Audio Play cursor"),wxColour(255,255,255)); - SetColour(_T("Audio Background"),wxColour(0,0,0)); - SetModificationType(MOD_OFF); - - // RGB Adjust tool - SetBool(_T("RGBAdjust Tool"),false); - - - // Only defaults? - if (!onlyDefaults) { - - ///// INTERNAL ////// - // Options that are set by the program itself - SetInt(_T("Video Dummy Last Width"), 640); - SetInt(_T("Video Dummy Last Height"), 480); - SetColour(_T("Video Dummy Last Colour"), wxColour(47, 163, 254)); - SetFloat(_T("Video Dummy Last FPS"), 23.976); - SetInt(_T("Video Dummy Last Length"), 40000); - SetBool(_T("Video Dummy Pattern"), false); - -// Broken on OS X during startup, so default to en_US -#ifdef __APPLE__ - SetInt(_T("Locale Code"),56,1700); -#else - SetInt(_T("Locale Code"),-1,1700); -#endif - SetBool(_T("Sync video with subs"),true); - SetText(_T("Spell checker language"),_T("en_US")); - SetText(_T("Thesaurus language"),_T("en_US")); - SetInt(_T("Options Page"),0); - - SetBool(_T("Audio Link"),true); - SetBool(_T("Audio Autocommit"),false); - SetBool(_T("Audio Autoscroll"),true); - SetBool(_T("Audio Medusa Timing Hotkeys"),false); - SetBool(_T("Audio Next Line on Commit"),true); - - SetBool(_T("Shift Times ByTime"),true); - SetInt(_T("Shift Times Type"),0); - SetInt(_T("Shift Times Length"),0); - SetInt(_T("Shift Times Affect"),0); - SetBool(_T("Shift Times Direction"),true); - - SetInt(_T("Tips current"),0); - SetBool(_T("Maximized"),false); - - SetBool(_T("Find Match Case"),false); - SetBool(_T("Find RegExp"),false); - SetBool(_T("Find Update Video"),false); - SetInt(_T("Find Affect"),0); - SetInt(_T("Find Field"),0); - - SetInt(_T("Grid hide overrides"),1); - for (int i=0;i<10;i++) SetBool(_T("Grid show column ") + AegiIntegerToString(i),true); - - for (int i=0;i<9;i++) SetBool(wxString::Format(_T("Paste Over #%i"),i),false); - SetBool(_T("Paste Over #9"),true); - - SetText(_T("Fonts Collector Destination"),_T("?script")); - SetInt(_T("Fonts Collector Action"),0); - - SetInt(_T("Audio Display Height"),200,1784); - SetBool(_T("Audio Spectrum"),true); - SetInt(_T("Audio Sample Rate"),0); - - SetBool(_T("Video Visual Realtime"),true); - SetBool(_T("Always show visual tools"),true); - SetBool(_T("Detached video"),false); - SetInt(_T("Detached video last x"),-1); - SetInt(_T("Detached video last y"),-1); - SetBool(_T("Detached video maximized"),false); - - SetInt(_T("Timing processor key start before thres"),5); - SetInt(_T("Timing processor key start after thres"),4); - SetInt(_T("Timing processor key end before thres"),5); - SetInt(_T("Timing processor key end after thres"),6); - SetInt(_T("Timing processor adjacent thres"),300); - SetBool(_T("Timing processor Enable lead-in"),true); - SetBool(_T("Timing processor Enable lead-out"),true); - SetBool(_T("Timing processor Enable keyframe"),true); - SetBool(_T("Timing processor Enable adjacent"),true); - SetBool(_T("Timing processor Only Selection"),false); - SetFloat(_T("Timing processor adjacent bias"),1.0); - - SetText(_T("Select Text"),_T("")); - SetInt(_T("Select Condition"),0); - SetInt(_T("Select Field"),0); - SetInt(_T("Select Action"),0); - SetInt(_T("Select Mode"),1); - SetBool(_T("Select Match case"),false); - SetBool(_T("Select Match dialogues"),true); - SetBool(_T("Select Match comments"),false); - - SetText(_T("Color Picker Recent"), _T("&H000000& &H0000FF& &H00FFFF& &H00FF00& &HFFFF00& &HFF0000& &HFF00FF& &HFFFFFF&")); - SetInt(_T("Color Picker Mode"), 4, 1700); - - SetText(_T("Last open subtitles path"),_T("")); - SetText(_T("Last open video path"),_T("")); - SetText(_T("Last open audio path"),_T("")); - SetText(_T("Last open timecodes path"),_T("")); - SetText(_T("Last open keyframes path"),_T("")); - SetText(_T("Last open automation path"),_T("")); - - SetBool(_T("kanji timer interpolation"),true); - - wxString previewText = _T("Aegisub\\N0123 "); - previewText += 0x6708; // kanji "moon" - previewText += 0x8a9e; // kanji "speak" - SetText(_T("Style editor preview text"),previewText); - SetColour(_T("Style editor preview background"),wxColour(125,153,176)); - - SetInt(_T("Updates Next Check Time"), 0); - } - - lastVersion = -1; - overriding = false; -} - - - -/// @brief Set filename -/// @param file -/// -void OptionsManager::SetFile(wxString file) { - filename = file; -} - - - -/// @brief Get filename -/// @return -/// -wxString OptionsManager::GetFile() const -{ - return filename; -} - - - -/// @brief Save -/// @return -/// -void OptionsManager::Save() { - // Check if it's actually modified - if (!modified) return; - - // Open file - TextFileWriter file(filename,_T("UTF-8")); - file.WriteLineToFile(_T("[Config]")); - - // Put variables in it - for (std::map::iterator cur=opt.begin();cur!=opt.end();cur++) { - file.WriteLineToFile((*cur).first + _T("=") + (*cur).second.AsText()); - } - - // Close - modified = false; -} - - - -/// @brief Load -/// @return -/// -void OptionsManager::Load() { - // Check if file exists - wxFileName path(filename); - if (!path.FileExists()) { - modified = true; - return; - } - - // Read header - TextFileReader file(filename); - wxString header; - try { - if (file.GetCurrentEncoding() != _T("binary")) - header = file.ReadLineFromFile(); - } - catch (wxString e) { - header = _T(""); - } - if (header != _T("[Config]")) { - wxMessageBox(_("Configuration file is either invalid or corrupt. The current file will be backed up and replaced with a default file."),_("Error"),wxCENTRE|wxICON_WARNING|wxOK); - wxRenameFile(filename,filename + wxString::Format(_T(".%i.backup"),wxGetUTCTime())); - modified = true; - return; - } - - // Get variables - std::map::iterator cur; - wxString curLine; - while (file.HasMoreLines()) { - // Parse line - try { - curLine = file.ReadLineFromFile(); - } - catch (wxString e) { - wxMessageBox(_("Configuration file is either invalid or corrupt. The current file will be backed up and replaced with a default file."),_("Error"),wxCENTRE|wxICON_WARNING|wxOK); - wxRenameFile(filename,filename + wxString::Format(_T(".%i.backup"),wxGetUTCTime())); - modified = true; - return; - } - if (curLine.IsEmpty()) continue; - size_t pos = curLine.Find(_T("=")); - if (pos == wxString::npos) continue; - wxString key = curLine.Left(pos); - wxString value = curLine.Mid(pos+1); - - // Find it - cur = opt.find(key); - if (cur != opt.end()) { - (*cur).second.ResetWith(value); - } - else SetText(key,value); - } - - // Get last version - if (IsDefined(_T("Last Version"))) { - long temp; - AsText(_T("Last Version")).ToLong(&temp); - lastVersion = temp; - } - else lastVersion = 1; // This was implemented in 1784, assume that anything before that is 1. -} - - - -/// @brief Write int -/// @param key -/// @param param -/// @param ifLastVersion -/// @return -/// -void OptionsManager::SetInt(wxString key,int param,int ifLastVersion) { - if (ifLastVersion == -1) { - if (overriding) ifLastVersion = 0; - else ifLastVersion = 0x7FFFFFFF; - } - if (lastVersion >= ifLastVersion) return; - opt[key.Lower()].SetInt(param); - if (curModType != MOD_OFF) optType[key.Lower()] = curModType; - modified = true; -} - - - -/// @brief Write float -/// @param key -/// @param param -/// @param ifLastVersion -/// @return -/// -void OptionsManager::SetFloat(wxString key,double param,int ifLastVersion) { - if (ifLastVersion == -1) { - if (overriding) ifLastVersion = 0; - else ifLastVersion = 0x7FFFFFFF; - } - if (lastVersion >= ifLastVersion) return; - opt[key.Lower()].SetFloat(param); - if (curModType != MOD_OFF) optType[key.Lower()] = curModType; - modified = true; -} - - - -/// @brief Write string -/// @param key -/// @param param -/// @param ifLastVersion -/// @return -/// -void OptionsManager::SetText(wxString key,wxString param,int ifLastVersion) { - if (ifLastVersion == -1) { - if (overriding) ifLastVersion = 0; - else ifLastVersion = 0x7FFFFFFF; - } - if (lastVersion >= ifLastVersion) return; - opt[key.Lower()].SetText(param); - if (curModType != MOD_OFF) optType[key.Lower()] = curModType; - modified = true; -} - - - -/// @brief Write boolean -/// @param key -/// @param param -/// @param ifLastVersion -/// @return -/// -void OptionsManager::SetBool(wxString key,bool param,int ifLastVersion) { - if (ifLastVersion == -1) { - if (overriding) ifLastVersion = 0; - else ifLastVersion = 0x7FFFFFFF; - } - if (lastVersion >= ifLastVersion) return; - opt[key.Lower()].SetBool(param); - if (curModType != MOD_OFF) optType[key.Lower()] = curModType; - modified = true; -} - - - -/// @brief Write colour -/// @param key -/// @param param -/// @param ifLastVersion -/// @return -/// -void OptionsManager::SetColour(wxString key,wxColour param,int ifLastVersion) { - if (ifLastVersion == -1) { - if (overriding) ifLastVersion = 0; - else ifLastVersion = 0x7FFFFFFF; - } - if (lastVersion >= ifLastVersion) return; - opt[key.Lower()].SetColour(param); - if (curModType != MOD_OFF) optType[key.Lower()] = curModType; - modified = true; -} - - - -/// @brief Reset with -/// @param key -/// @param param -/// -void OptionsManager::ResetWith(wxString key,wxString param) { - opt[key.Lower()].ResetWith(param); - modified = true; -} - - - -/// @brief As int -/// @param key -/// @return -/// -int OptionsManager::AsInt(wxString key) { - std::map::iterator cur; - cur = (opt.find(key.Lower())); - if (cur != opt.end()) { - return (*cur).second.AsInt(); - } - else throw key.c_str();//_T("Internal error: Attempted getting undefined configuration setting"); -} - - - -/// @brief As boolean -/// @param key -/// @return -/// -bool OptionsManager::AsBool(wxString key) { - std::map::iterator cur; - cur = (opt.find(key.Lower())); - if (cur != opt.end()) { - return (*cur).second.AsBool(); - } - else throw key.c_str();//_T("Internal error: Attempted getting undefined configuration setting"); -} - - - -/// @brief As float -/// @param key -/// @return -/// -double OptionsManager::AsFloat(wxString key) { - std::map::iterator cur; - cur = (opt.find(key.Lower())); - if (cur != opt.end()) { - return (*cur).second.AsFloat(); - } - else throw key.c_str();//_T("Internal error: Attempted getting undefined configuration setting"); -} - - - -/// @brief As string -/// @param key -/// @return -/// -wxString OptionsManager::AsText(wxString key) { - std::map::iterator cur; - cur = (opt.find(key.Lower())); - if (cur != opt.end()) { - return (*cur).second.AsText(); - } - else throw key.c_str();//_T("Internal error: Attempted getting undefined configuration setting"); -} - - - -/// @brief As colour -/// @param key -/// @return -/// -wxColour OptionsManager::AsColour(wxString key) { - std::map::iterator cur; - cur = (opt.find(key.Lower())); - if (cur != opt.end()) { - return (*cur).second.AsColour(); - } - else throw key.c_str();//_T("Internal error: Attempted getting undefined configuration setting"); -} - - - -/// @brief Modification type -/// @param key -/// @return -/// -ModType OptionsManager::GetModType(wxString key) { - std::map::iterator cur; - cur = (optType.find(key.Lower())); - if (cur != optType.end()) { - return (*cur).second; - } - else return MOD_AUTOMATIC; -} - - - -/// @brief Is defined? -/// @param key -/// @return -/// -bool OptionsManager::IsDefined(wxString key) { - std::map::iterator cur; - cur = (opt.find(key.Lower())); - return (cur != opt.end()); -} - - - -/// @brief Adds an item to a list of recents -/// @param entry -/// @param list -/// -void OptionsManager::AddToRecentList (wxString entry,wxString list) { - // Find strings already in recent list - wxArrayString orig; - wxString cur; - int recentMax = AsInt(list + _T(" max")); - int n = 0; - for (int i=0;i recentMax-1) n = recentMax-1; - for (int i=0;i recentMax-1) n = recentMax-1; - for (int i=0;i -#endif - -#include "variable_data.h" - -/// DOCME -enum ModType { - - /// DOCME - MOD_OFF = -1, - - /// DOCME - MOD_AUTOMATIC, - - /// DOCME - MOD_RESTART, - - /// DOCME - MOD_EDIT_BOX, - - /// DOCME - MOD_GRID, - - /// DOCME - MOD_VIDEO, - - /// DOCME - MOD_VIDEO_RELOAD, - - /// DOCME - MOD_AUDIO, - - /// DOCME - MOD_AUDIO_RELOAD -}; - - - -/// DOCME -/// @class OptionsManager -/// @brief DOCME -/// -/// DOCME -class OptionsManager { -private: - - /// DOCME - ModType curModType; - - /// DOCME - bool modified; - - /// DOCME - bool overriding; - - /// DOCME - wxString filename; - - /// DOCME - std::map opt; - - /// DOCME - std::map optType; - - /// DOCME - int lastVersion; - - void SetModificationType(ModType type); - -public: - OptionsManager(); - ~OptionsManager(); - - void Clear(); - void SetFile(wxString file); - wxString GetFile() const; - void Save(); - void Load(); - void LoadDefaults(bool onlyDefaults=false,bool versionOverride=false); - - void AddToRecentList (wxString entry,wxString list); - void RemoveFromRecentList (wxString entry,wxString list); - wxArrayString GetRecentList (wxString list); - - void SetInt(wxString key,int param,int ifLastVersion=-1); - void SetFloat(wxString key,double param,int ifLastVersion=-1); - void SetBool(wxString key,bool param,int ifLastVersion=-1); - void SetText(wxString key,wxString param,int ifLastVersion=-1); - void SetColour(wxString key,wxColour param,int ifLastVersion=-1); - void ResetWith(wxString key,wxString param); - - bool IsDefined(wxString key); - int AsInt(wxString key); - double AsFloat(wxString key); - bool AsBool(wxString key); - wxString AsText(wxString key); - wxColour AsColour(wxString key); - ModType GetModType(wxString key); -}; - - -/////////////////// -// Global instance -extern OptionsManager Options; diff --git a/aegisub/src/preferences.cpp b/aegisub/src/preferences.cpp new file mode 100644 index 000000000..9f6bc0d8f --- /dev/null +++ b/aegisub/src/preferences.cpp @@ -0,0 +1,566 @@ +// Copyright (c) 2010, Amar Takhar +// +// 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. +// +// $Id$ + +/// @file preferences.cpp +/// @brief Preferences dialogue +/// @ingroup configuration_ui + + +#ifndef AGI_PRE +#include +#include +#include +#include +#endif + +#include + +#include "colour_button.h" +#include "libresrc/libresrc.h" +#include "preferences.h" +#include "main.h" +#include "subtitles_provider_manager.h" +#include "video_provider_manager.h" +#include "audio_player_manager.h" +#include "audio_provider_manager.h" + +/// Define make all platform-specific options visible in a single view. +#define SHOW_ALL 1 + +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") + +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); + + General(book); + Subtitles(book); + Audio(book); + Video(book); + Interface(book); + Interface_Colours(book); + Interface_Hotkeys(book); + Paths(book); + File_Associations(book); + Backup(book); + Automation(book); + Advanced(book); + Advanced_Interface(book); + Advanced_Audio(book); + Advanced_Video(book); + + book->Fit(); + + /// @todo Save the last page and start with that page on next launch. + book->ChangeSelection(5); + + // Bottom Buttons + wxStdDialogButtonSizer *stdButtonSizer = new wxStdDialogButtonSizer(); + stdButtonSizer->AddButton(new wxButton(this,wxID_OK)); + stdButtonSizer->AddButton(new wxButton(this,wxID_CANCEL)); + stdButtonSizer->AddButton(new wxButton(this,wxID_APPLY)); + stdButtonSizer->Realize(); + wxSizer *buttonSizer = new wxBoxSizer(wxHORIZONTAL); + wxButton *defaultButton = new wxButton(this,2342,_("Restore Defaults")); + buttonSizer->Add(defaultButton,0,wxEXPAND); + buttonSizer->AddStretchSpacer(1); + buttonSizer->Add(stdButtonSizer,0,wxEXPAND); + + + // Main Sizer + wxSizer *mainSizer = new wxBoxSizer(wxVERTICAL); + mainSizer->Add(book, 1 ,wxEXPAND | wxALL, 5); + mainSizer->Add(buttonSizer,0,wxEXPAND | wxLEFT | wxRIGHT | wxBOTTOM,5); + SetSizerAndFit(mainSizer); + this->SetMinSize(wxSize(-1, 500)); + this->SetMaxSize(wxSize(-1, 500)); + CenterOnParent(); + + + +} + +void Preferences::OptionChoice(wxPanel *parent, wxFlexGridSizer *flex, const wxString &name, const wxArrayString &choices, const char *opt_name) { + agi::OptionValue *opt = OPT_GET(opt_name); + + int type = opt->GetType(); + wxString selection; + + switch (type) { + case agi::OptionValue::Type_Int: { + selection = choices.Item(opt->GetInt()); + break; + } + case agi::OptionValue::Type_String: { + selection.assign(opt->GetString()); + break; + } + + default: + throw PreferenceNotSupported("Unsupported type"); + } + + flex->Add(new wxStaticText(parent, wxID_ANY, name), 1, wxALIGN_CENTRE_VERTICAL); + wxComboBox *cb = new wxComboBox(parent, wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize, choices, wxCB_READONLY | wxCB_DROPDOWN); + cb->SetValue(selection); + flex->Add(cb, 1, wxEXPAND, 0); +} + + +void Preferences::OptionBrowse(wxPanel *parent, wxFlexGridSizer *flex, const wxString &name, BrowseType browse_type, const char *opt_name) { + + agi::OptionValue *opt = OPT_GET(opt_name); + + if (opt->GetType() != agi::OptionValue::Type_String) + throw PreferenceIncorrectType("Option must be agi::OptionValue::Type_String for BrowseButton."); + + flex->Add(new wxStaticText(parent, wxID_ANY, name), 1, wxALIGN_CENTRE_VERTICAL); + + wxFlexGridSizer *button_flex = new wxFlexGridSizer(2,5,5); + button_flex->AddGrowableCol(0,1); + flex->Add(button_flex, 1, wxEXPAND, 5); + + wxTextCtrl *text = new wxTextCtrl(parent, wxID_ANY , opt->GetString(), wxDefaultPosition, wxDefaultSize); + button_flex->Add(text, 1, wxEXPAND); + BrowseButton *browse = new BrowseButton(parent, wxID_ANY, wxEmptyString, browse_type); + browse->Bind(text); + button_flex->Add(browse, 1, wxEXPAND); + +} + + + +void Preferences::OptionAdd(wxPanel *parent, wxFlexGridSizer *flex, const wxString &name, const char *opt_name, double min, double max, double inc) { + + agi::OptionValue *opt = OPT_GET(opt_name); + + int type = opt->GetType(); + + switch (type) { + + case agi::OptionValue::Type_Bool: { + wxCheckBox *cb = new wxCheckBox(parent, wxID_ANY, name); + flex->Add(cb, 1, wxEXPAND, 0); + cb->SetValue(opt->GetBool()); + break; + } + + case agi::OptionValue::Type_Int: + case agi::OptionValue::Type_Double: { + flex->Add(new wxStaticText(parent, wxID_ANY, name), 1, wxALIGN_CENTRE_VERTICAL); + wxSpinCtrlDouble *scd = new wxSpinCtrlDouble(parent, wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize, wxSP_ARROW_KEYS, min, max, opt->GetInt(), inc); + flex->Add(scd); + + break; + } + + case agi::OptionValue::Type_String: { + flex->Add(new wxStaticText(parent, wxID_ANY, name), 1, wxALIGN_CENTRE_VERTICAL); + wxTextCtrl *text = new wxTextCtrl(parent, wxID_ANY , opt->GetString(), wxDefaultPosition, wxDefaultSize); + flex->Add(text, 1, wxEXPAND); + break; + } + + case agi::OptionValue::Type_Colour: { + flex->Add(new wxStaticText(parent, wxID_ANY, name), 1, wxALIGN_CENTRE_VERTICAL); + ColourButton *colour = new ColourButton(parent, wxID_ANY, wxSize(40,10)); + wxColour current(opt->GetColour()); + colour->SetColour(current); + flex->Add(colour); + break; + } + + default: + throw PreferenceNotSupported("Unsupported type"); + } + +} + +Preferences::~Preferences() { + +} + + +void Preferences::OnOK(wxCommandEvent &event) { + EndModal(0); +} + + +void Preferences::OnApply(wxCommandEvent &event) { +} + + +void Preferences::OnCancel(wxCommandEvent &event) { + EndModal(0); +} + + +#define PAGE_CREATE(name) \ + wxPanel *panel = new wxPanel(book, -1); \ + book->AddPage(panel, name, true); \ + wxSizer *sizer = new wxBoxSizer(wxVERTICAL); \ + +#define SUBPAGE_CREATE(name) \ + wxPanel *panel = new wxPanel(book, -1); \ + book->AddSubPage(panel, name, true); \ + wxSizer *sizer = new wxBoxSizer(wxVERTICAL); \ + + +#define PAGE_SIZER(name, name_value) \ + wxSizer *name_value##_sizer = new wxStaticBoxSizer(wxHORIZONTAL, panel, name); \ + sizer->Add(name_value##_sizer, 0,wxEXPAND, 5); \ + wxFlexGridSizer *name_value##_flex = new wxFlexGridSizer(2,5,5); \ + name_value##_flex->AddGrowableCol(0,1); \ + name_value##_sizer->Add(name_value##_flex, 1, wxEXPAND, 5); \ + sizer->AddSpacer(8); + +// name_value##_flex->SetFlexibleDirection(wxVERTICAL); \ + +#define PAGE_END() \ + panel->SetSizerAndFit(sizer); + +/// Skip a cell in a FlexGridSizer -- there's probably a better way to do this. +#define CELL_SKIP(flex) \ + flex->Add(new wxStaticText(panel, wxID_ANY , wxEmptyString), 0, wxALL, 5); + + + +void Preferences::Subtitles(wxTreebook *book) { + PAGE_CREATE(_("Subtitles")) + + PAGE_SIZER(_("Options"), general) + + OptionAdd(panel, general_flex, _("Enable call tips"), "App/Call Tips"); + OptionAdd(panel, general_flex, _("Enable syntax highlighting"), "Subtitle/Highlight/Syntax"); + OptionAdd(panel, general_flex, _("Link commiting of times"), "Subtitle/Edit Box/Link Time Boxes Commit"); + OptionAdd(panel, general_flex, _("Overwrite-Insertion in time boxes"), "Subtitle/Time Edit/Insert Mode"); + + PAGE_SIZER(_("Grid"), grid) + OptionAdd(panel, grid_flex, _("Allow grid to take focus"), "Subtitle/Grid/Focus Allow"); + OptionAdd(panel, grid_flex, _("Highlight visible subtitles"), "Subtitle/Grid/Highlight Subtitles in Frame"); + + PAGE_END() +} + + +void Preferences::General(wxTreebook *book) { + + PAGE_CREATE(_("General")) + + PAGE_SIZER(_("Startup"), startup) + OptionAdd(panel, startup_flex, _("Check for updates"), "App/Splash"); + OptionAdd(panel, startup_flex, _("Show Splash Screen"), "App/Splash"); + + PAGE_SIZER(_("Recently Used Lists"), recent) + OptionAdd(panel, recent_flex, _("Files"), "Limits/MRU"); + OptionAdd(panel, recent_flex, _("Find/Replace"), "Limits/Find Replace"); + sizer->AddSpacer(15); + + PAGE_SIZER(_("Undo / Redo Settings"), undo) + OptionAdd(panel, undo_flex, _("Undo Levels"), "Limits/MRU"); + + PAGE_END() +} + + +void Preferences::Audio(wxTreebook *book) { + PAGE_CREATE(_("Audio")) + + PAGE_SIZER(_("Options"), general) + OptionAdd(panel, general_flex, _("Grab times from line upon selection"), "Audio/Grab Times on Select"); + OptionAdd(panel, general_flex, _("Default mouse wheel to zoom"), "Audio/Wheel Default to Zoom"); + OptionAdd(panel, general_flex, _("Lock scroll on cursor"), "Audio/Lock Scroll on Cursor"); + OptionAdd(panel, general_flex, _("Snap to keyframes"), "Audio/Display/Snap/Keyframes"); + OptionAdd(panel, general_flex, _("Snap to adjacent lines"), "Audio/Display/Snap/Other Lines"); + OptionAdd(panel, general_flex, _("Auto-focus on mouse over"), "Audio/Auto/Focus"); + OptionAdd(panel, general_flex, _("Play audio when stepping in video"), "Audio/Plays When Stepping Video"); + + CELL_SKIP(general_flex) + + OptionAdd(panel, general_flex, _("Default timing length"), "Timing/Default Duration", 0, 36000); + OptionAdd(panel, general_flex, _("Default lead-in length"), "Audio/Lead/IN", 0, 36000); + OptionAdd(panel, general_flex, _("Default lead-out length"), "Audio/Lead/OUT", 0, 36000); + + const wxString dtl_arr[3] = { _("Don't show"), _("Show previous"), _("Show all") }; + wxArrayString choice_dtl(3, dtl_arr); + OptionChoice(panel, general_flex, _("Show inactive lines"), choice_dtl, "Audio/Inactive Lines Display Mode"); + + OptionAdd(panel, general_flex, _("Start-marker drag sensitivity"), "Audio/Start Drag Sensitivity", 1, 15); + + PAGE_SIZER(_("Display Visual Options"), display) + OptionAdd(panel, display_flex, _("Secondary lines"), "Audio/Display/Draw/Secondary Lines"); + OptionAdd(panel, display_flex, _("Selection background"), "Audio/Display/Draw/Selection Background"); + OptionAdd(panel, display_flex, _("Timeline"), "Audio/Display/Draw/Timeline"); + OptionAdd(panel, display_flex, _("Cursor time"), "Audio/Display/Draw/Cursor Time"); + OptionAdd(panel, display_flex, _("Keyframes"), "Audio/Display/Draw/Keyframes"); + OptionAdd(panel, display_flex, _("Video position"), "Audio/Display/Draw/Video Position"); + + PAGE_END() +} + + +void Preferences::Video(wxTreebook *book) { + + PAGE_CREATE(_("Video")) + + PAGE_SIZER(_("Options"), general) + + OptionAdd(panel, general_flex, _("Show keyframes in slider"), "Video/Slider/Show Keyframes"); + OptionAdd(panel, general_flex, _("Always show visual tools"), "Tool/Visual/Always Show"); + + const wxString cres_arr[3] = { _("Never"), _("Ask"), _("Always") }; + wxArrayString choice_res(3, cres_arr); + OptionChoice(panel, general_flex, _("Match video resolution on open"), choice_res, "Video/Check Script Res"); + + const wxString czoom_arr[24] = { _T("12.5%"), _T("25%"), _T("37.5%"), _T("50%"), _T("62.5%"), _T("75%"), _T("87.5%"), _T("100%"), _T("112.5%"), _T("125%"), _T("137.5%"), _T("150%"), _T("162.5%"), _T("175%"), _T("187.5%"), _T("200%"), _T("212.5%"), _T("225%"), _T("237.5%"), _T("250%"), _T("262.5%"), _T("275%"), _T("287.5%"), _T("300%") }; + wxArrayString choice_zoom(24, czoom_arr); + OptionChoice(panel, general_flex, _("Default Zoom"), choice_zoom, "Video/Default Zoom"); + + OptionAdd(panel, general_flex, _("Fast jump step in frames"), "Video/Slider/Fast Jump Step"); + + const wxString cscr_arr[3] = { _("?video"), _("?script"), _(".") }; + wxArrayString scr_res(3, cscr_arr); + OptionChoice(panel, general_flex, _("Screenshot save path"), scr_res, "Path/Screenshot"); + + + + panel->SetSizerAndFit(sizer); + + +} + + +void Preferences::Interface(wxTreebook *book) { + PAGE_CREATE(_("Interface")) + + PAGE_SIZER(_("Subtitle Grid"), grid) + OptionBrowse(panel, grid_flex, _("Font face"), BROWSE_FONT, "Subtitle/Grid/Font Face"); + OptionAdd(panel, grid_flex, _("Font size"), "Subtitle/Grid/Font Size", 3, 42); + + OptionAdd(panel, grid_flex, _("Hide overrides symbol"), "Subtitle/Grid/Hide Overrides Char"); + + PAGE_END() +} + +void Preferences::Interface_Colours(wxTreebook *book) { + + wxScrolled *panel = new wxScrolled(book, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxVSCROLL); + panel->SetScrollbars(0, 20, 0, 50); + book->AddSubPage(panel, _("Colours"), true); + wxSizer *sizer = new wxBoxSizer(wxVERTICAL); + + PAGE_SIZER(_("General"), general) + OptionAdd(panel, general_flex, _("Modified Background"), "Colour/Background/Modified"); + + PAGE_SIZER(_("Audio Display"), audio) + OptionAdd(panel, audio_flex, _("Play cursor"), "Colour/Audio Display/Play Cursor"); + OptionAdd(panel, audio_flex, _("Background"), "Colour/Audio Display/Background/Background"); + OptionAdd(panel, audio_flex, _("Selection background"), "Colour/Audio Display/Background/Selection"); + OptionAdd(panel, audio_flex, _("Selection background modified"), "Colour/Audio Display/Background/Selection Modified"); + OptionAdd(panel, audio_flex, _("Seconds boundaries"), "Colour/Audio Display/Seconds Boundaries"); + OptionAdd(panel, audio_flex, _("Waveform"), "Colour/Audio Display/Waveform"); + OptionAdd(panel, audio_flex, _("Waveform selected"), "Colour/Audio Display/Waveform Selected"); + OptionAdd(panel, audio_flex, _("Waveform Modified"), "Colour/Audio Display/Waveform Modified"); + OptionAdd(panel, audio_flex, _("Waveform Inactive"), "Colour/Audio Display/Waveform Inactive"); + OptionAdd(panel, audio_flex, _("Line boundary start"), "Colour/Audio Display/Line boundary Start"); + OptionAdd(panel, audio_flex, _("Line boundary end"), "Colour/Audio Display/Line boundary End"); + OptionAdd(panel, audio_flex, _("Line boundary inactive line"), "Colour/Audio Display/Line Boundary Inactive Line"); + OptionAdd(panel, audio_flex, _("Syllable text"), "Colour/Audio Display/Syllable Text"); + OptionAdd(panel, audio_flex, _("Syllable boundaries"), "Colour/Audio Display/Syllable Boundaries"); + + PAGE_SIZER(_("Syntax Highlighting"), syntax) + OptionAdd(panel, syntax_flex, _("Normal"), "Colour/Subtitle/Syntax/Normal"); + OptionAdd(panel, syntax_flex, _("Brackets"), "Colour/Subtitle/Syntax/Brackets"); + OptionAdd(panel, syntax_flex, _("Slashes and Parentheses"), "Colour/Subtitle/Syntax/Slashes"); + OptionAdd(panel, syntax_flex, _("Tags"), "Colour/Subtitle/Syntax/Highlight Tags"); + OptionAdd(panel, syntax_flex, _("Parameters"), "Colour/Subtitle/Syntax/Parameters"); + OptionAdd(panel, syntax_flex, _("Error"), "Colour/Subtitle/Syntax/Error"); + OptionAdd(panel, syntax_flex, _("Error Background"), "Colour/Subtitle/Syntax/Background/Error"); + OptionAdd(panel, syntax_flex, _("Line Break"), "Colour/Subtitle/Syntax/Line Break"); + OptionAdd(panel, syntax_flex, _("Karaoke templates"), "Colour/Subtitle/Syntax/Karaoke Template"); + + PAGE_SIZER(_("Subtitle Grid"), grid) + OptionAdd(panel, grid_flex, _("Standard foreground"), "Colour/Subtitle Grid/Standard"); + OptionAdd(panel, grid_flex, _("Standard background"), "Colour/Subtitle Grid/Background/Background"); + OptionAdd(panel, grid_flex, _("Selection foreground"), "Colour/Subtitle Grid/Selection"); + OptionAdd(panel, grid_flex, _("Selection background"), "Colour/Subtitle Grid/Background/Selection"); + OptionAdd(panel, grid_flex, _("Comment background"), "Colour/Subtitle Grid/Background/Comment"); + OptionAdd(panel, grid_flex, _("Selected comment background"), "Colour/Subtitle Grid/Background/Selected Comment"); + OptionAdd(panel, grid_flex, _("Left Column"), "Colour/Subtitle Grid/Left Column"); + OptionAdd(panel, grid_flex, _("Active Line Border"), "Colour/Subtitle Grid/Active Border"); + OptionAdd(panel, grid_flex, _("Lines"), "Colour/Subtitle Grid/Lines"); + PAGE_END() +} + +void Preferences::Interface_Hotkeys(wxTreebook *book) { + SUBPAGE_CREATE(_("Hotkeys")) + + PAGE_SIZER(_("Hotkeys"), hotkey) + hotkey_flex->Add(new wxStaticText(panel, wxID_ANY , _T("To be added after hotkey rewrite.")), 0, wxALL, 5); + + PAGE_END() +} + +void Preferences::Paths(wxTreebook *book) { + PAGE_CREATE(_("Paths")) + +// OptionBrowse(panel, general_flex, _("Dictionaries path"), BROWSE_FOLDER, "Path/Dictionary") + + PAGE_END() +} + +void Preferences::File_Associations(wxTreebook *book) { + PAGE_CREATE(_("File Assoc.")) + PAGE_END() +} + +void Preferences::Backup(wxTreebook *book) { + PAGE_CREATE(_("Backup")) + + + PAGE_SIZER(_("Automatic Save"), save) + OptionAdd(panel, save_flex, _("Enable"), "App/Auto/Backup"); + CELL_SKIP(save_flex) + OptionAdd(panel, save_flex, _("Interval in seconds."), "App/Auto/Save Every Seconds"); + OptionBrowse(panel, save_flex, _("Path"), BROWSE_FOLDER, "Path/Auto/Save"); + + PAGE_SIZER(_("Automatic Backup"), backup) + CELL_SKIP(backup_flex) + OptionAdd(panel, backup_flex, _("Enable"), "App/Auto/Backup"); + OptionBrowse(panel, backup_flex, _("Path"), BROWSE_FOLDER, "Path/Auto/Backup"); + + PAGE_END() +} + +void Preferences::Automation(wxTreebook *book) { + PAGE_CREATE(_("Automation")) + + PAGE_SIZER(_("Options"), general) + + OptionAdd(panel, general_flex, _("Base path"), "Path/Automation/Base"); + OptionAdd(panel, general_flex, _("Include path"), "Path/Automation/Include"); + OptionAdd(panel, general_flex, _("Auto-load path"), "Path/Automation/Autoload"); + + const wxString tl_arr[6] = { _("Fatal"), _("Error"), _("Warning"), _("Hint"), _("Debug"), _("Trace") }; + wxArrayString tl_choice(6, tl_arr); + OptionChoice(panel, general_flex, _("Trace level"), tl_choice, "Automation/Trace Level"); + + const wxString tp_arr[3] = { _("Normal"), _("Below Normal (recommended)"), _("Lowest") }; + wxArrayString tp_choice(3, tp_arr); + OptionChoice(panel, general_flex, _("Thread priority"), tp_choice, "Automation/Lua/Thread Priority"); + + const wxString ar_arr[4] = { _("No scripts"), _("Subtitle-local scripts"), _("Global autoload scripts"), _("All scripts") }; + wxArrayString ar_choice(4, ar_arr); + OptionChoice(panel, general_flex, _("Autoreload on Export"), ar_choice, "Automation/Autoreload Mode"); + + + PAGE_END() +} + + +void Preferences::Advanced(wxTreebook *book) { + PAGE_CREATE(_("Advanced")) + + wxStaticText *warning = new wxStaticText(panel, wxID_ANY ,_("Changing these settings might result in bugs and/or crashes. Do not touch these unless you know what you're doing.")); + warning->SetFont(wxFont(12, wxFONTFAMILY_SWISS, wxFONTSTYLE_NORMAL, wxFONTWEIGHT_BOLD)); + sizer->Fit(panel); + warning->Wrap(400); + sizer->Add(warning, 0, wxALL, 5); + + PAGE_END() +} + +void Preferences::Advanced_Interface(wxTreebook *book) { + SUBPAGE_CREATE(_("Interface")) + PAGE_END() +} + + +void Preferences::Advanced_Audio(wxTreebook *book) { + SUBPAGE_CREATE(_("Audio")) + + PAGE_SIZER(_("Options"), expert) + + wxArrayString ap_choice = AudioProviderFactoryManager::GetFactoryList(); + OptionChoice(panel, expert_flex, _("Audio provider"), ap_choice, "Audio/Provider"); + + wxArrayString apl_choice = AudioPlayerFactoryManager::GetFactoryList(); + OptionChoice(panel, expert_flex, _("Audio player"), apl_choice, "Audio/Player"); + + PAGE_SIZER(_("Cache"), cache) + const wxString ct_arr[3] = { _("None (NOT RECOMMENDED)"), _("RAM"), _("Hard Disk") }; + wxArrayString ct_choice(3, ct_arr); + OptionChoice(panel, cache_flex, _("Cache type"), ct_choice, "Audio/Cache/Type"); + + OptionBrowse(panel, cache_flex, _("Path"), BROWSE_FOLDER, "Audio/Cache/HD/Location"); + OptionAdd(panel, cache_flex, _("File name"), "Audio/Cache/HD/Name"); + + + PAGE_SIZER(_("Spectrum"), spectrum) + + OptionAdd(panel, spectrum_flex, _("Cutoff"), "Audio/Renderer/Spectrum/Cutoff"); + + const wxString sq_arr[4] = { _("Regular quality"), _("Better quality"), _("High quality"), _("Insane quality") }; + wxArrayString sq_choice(4, sq_arr); + OptionChoice(panel, spectrum_flex, _("Quality"), sq_choice, "Audio/Renderer/Spectrum/Quality"); + OptionAdd(panel, spectrum_flex, _("Cache memory max (MB)"), "Audio/Renderer/Spectrum/Memory Max", 2, 1024); + +#if defined(WIN32) || defined(SHOW_ALL) + PAGE_SIZER(_("Windows Only"), windows); + const wxString adm_arr[3] = { _T("ConvertToMono"), _T("GetLeftChannel"), _T("GetRightChannel") }; + wxArrayString adm_choice(3, adm_arr); + OptionChoice(panel, windows_flex, _("Avisynth down-mixer"), adm_choice, "Audio/Downmixer"); +#endif + + PAGE_END() +} + + +void Preferences::Advanced_Video(wxTreebook *book) { + SUBPAGE_CREATE(_("Video")) + + PAGE_SIZER(_("Options"), expert) + wxArrayString vp_choice = VideoProviderFactoryManager::GetFactoryList(); + OptionChoice(panel, expert_flex, _("Video provider"), vp_choice, "Video/Provider"); + + wxArrayString sp_choice = SubtitlesProviderFactoryManager::GetFactoryList(); + OptionChoice(panel, expert_flex, _("Subtitle provider"), sp_choice, "Subtitle/Provider"); + + + +#if defined(WIN32) || defined(SHOW_ALL) + PAGE_SIZER(_("Windows Only"), windows); + + OptionAdd(panel, windows_flex, _("Allow pre-2.56a Avisynth"), "Provider/Avisynth/Allow Ancient"); + CELL_SKIP(windows_flex) + OptionAdd(panel, windows_flex, _("Avisynth memory limit"), "Provider/Avisynth/Memory Max"); +#endif + + PAGE_END() +} + + + + +BEGIN_EVENT_TABLE(Preferences, wxDialog) + EVT_BUTTON(wxID_OK, Preferences::OnOK) + EVT_BUTTON(wxID_CANCEL, Preferences::OnCancel) + EVT_BUTTON(wxID_APPLY, Preferences::OnApply) +END_EVENT_TABLE() + diff --git a/aegisub/src/preferences.h b/aegisub/src/preferences.h new file mode 100644 index 000000000..ef1dd7ec1 --- /dev/null +++ b/aegisub/src/preferences.h @@ -0,0 +1,67 @@ +// Copyright (c) 2010, Amar Takhar +// +// 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. +// +// $Id$ + +/// @file preferences.h +/// @brief Preferences dialogue +/// @see preferences.cpp +/// @ingroup configuration_ui + +#ifndef AGI_PRE +#include +#include +#include +#include +#endif + +#include "browse_button.h" + +class Preferences: public wxDialog { + wxTreebook *book; + + void OnOK(wxCommandEvent &event); + void OnCancel(wxCommandEvent &event); + void OnApply(wxCommandEvent &event); + +// wxPanel *general; + +// void OptionAdd(wxPanel *parent, wxFlexGridSizer *flex, const wxString &name, const char *opt_name); + void OptionAdd(wxPanel *parent, wxFlexGridSizer *flex, const wxString &name, const char *opt_name, double min=0, double max=100, double inc=1); + void OptionChoice(wxPanel *parent, wxFlexGridSizer *flex, const wxString &name, const wxArrayString &choices, const char *opt_name); + void OptionBrowse(wxPanel *parent, wxFlexGridSizer *flex, const wxString &name, BrowseType browse_type, const char *opt_name); + + void General(wxTreebook *book); + void Subtitles(wxTreebook *book); + void Audio(wxTreebook *book); + void Video(wxTreebook *book); + void Interface(wxTreebook *book); + void Interface_Colours(wxTreebook *book); + void Interface_Hotkeys(wxTreebook *book); + void Paths(wxTreebook *book); + void File_Associations(wxTreebook *book); + void Backup(wxTreebook *book); + void Automation(wxTreebook *book); + void Advanced(wxTreebook *book); + void Advanced_Interface(wxTreebook *book); + void Advanced_Audio(wxTreebook *book); + void Advanced_Video(wxTreebook *book); + +public: + Preferences(wxWindow *parent); + ~Preferences(); + + DECLARE_EVENT_TABLE() +}; + diff --git a/aegisub/src/spellchecker.cpp b/aegisub/src/spellchecker.cpp index 898072657..a2723ac74 100644 --- a/aegisub/src/spellchecker.cpp +++ b/aegisub/src/spellchecker.cpp @@ -43,6 +43,8 @@ #include "spellchecker_hunspell.h" #endif +#include "compat.h" +#include "main.h" #include "options.h" #include "spellchecker_manager.h" @@ -53,7 +55,7 @@ /// SpellChecker *SpellCheckerFactoryManager::GetSpellChecker() { // List of providers - wxArrayString list = GetFactoryList(Options.AsText(_T("Spell Checker"))); + wxArrayString list = GetFactoryList(lagi_wxString(OPT_GET("Tool/Spell Checker/Backend")->GetString())); // None available if (list.Count() == 0) return 0; //throw _T("No spell checkers are available."); diff --git a/aegisub/src/spellchecker_hunspell.cpp b/aegisub/src/spellchecker_hunspell.cpp index d62c6a24c..4845cc386 100644 --- a/aegisub/src/spellchecker_hunspell.cpp +++ b/aegisub/src/spellchecker_hunspell.cpp @@ -53,6 +53,8 @@ #include #include "charset_conv.h" +#include "compat.h" +#include "main.h" #include "options.h" #include "spellchecker_hunspell.h" #include "standard_paths.h" @@ -63,7 +65,7 @@ HunspellSpellChecker::HunspellSpellChecker() { hunspell = NULL; conv = NULL; - SetLanguage(Options.AsText(_T("Spell checker Language"))); + SetLanguage(lagi_wxString(OPT_GET("Tool/Spell Checker/Language")->GetString())); } @@ -219,7 +221,7 @@ wxArrayString HunspellSpellChecker::GetSuggestions(wxString word) { /// wxArrayString HunspellSpellChecker::GetLanguageList() { // Get dir name - wxString path = StandardPaths::DecodePathMaybeRelative(Options.AsText(_T("Dictionaries path")), _T("?data")) + _T("/"); + wxString path = StandardPaths::DecodePathMaybeRelative(lagi_wxString(OPT_GET("Path/Dictionary")->GetString()), _T("?data")) + _T("/"); wxArrayString list; wxFileName folder(path); if (!folder.DirExists()) return list; @@ -259,7 +261,7 @@ void HunspellSpellChecker::SetLanguage(wxString language) { // Get dir name //FIXME: this should use ?user instead of ?data; however, since it apparently works already on win32, I'm not gonna mess with it right now :p - wxString path = StandardPaths::DecodePathMaybeRelative(Options.AsText(_T("Dictionaries path")), _T("?data")) + _T("/"); + wxString path = StandardPaths::DecodePathMaybeRelative(lagi_wxString(OPT_GET("Path/Dictionary")->GetString()), _T("?data")) + _T("/"); wxString userPath = StandardPaths::DecodePath(_T("?user/dictionaries/user_")); // Get affix and dictionary paths diff --git a/aegisub/src/subs_edit_box.cpp b/aegisub/src/subs_edit_box.cpp index 1825891c1..edb8786c4 100644 --- a/aegisub/src/subs_edit_box.cpp +++ b/aegisub/src/subs_edit_box.cpp @@ -373,11 +373,11 @@ void SubsEditBox::SetToLine(int n,bool weak) { // Set video if (VideoContext::Get()->IsLoaded() && !weak) { - wxString sync; - if (Search.hasFocus) sync = _T("Find update video"); - else sync = _T("Sync video with subs"); - - if (Options.AsBool(sync)) { + bool sync; + if (Search.hasFocus) sync = OPT_GET("Tool/Search Replace/Video Update")->GetBool(); + else sync = OPT_GET("Video/Subtitle Sync")->GetBool(); + + if (sync) { VideoContext::Get()->Stop(); AssDialogue *cur = grid->GetDialogue(n); if (cur) VideoContext::Get()->JumpToFrame(VFR_Output.GetFrameAtTime(cur->Start.GetMS(),true)); @@ -499,8 +499,7 @@ void SubsEditBox::OnKeyDown(wxStyledTextEvent &event) { /// void SubsEditBox::OnSyntaxBox(wxCommandEvent &event) { TextEdit->UpdateStyle(); - Options.SetBool(_T("Syntax Highlight Enabled"),SyntaxHighlight->GetValue()); - Options.Save(); + OPT_SET("Subtitle/Highlight/Syntax")->SetBool(SyntaxHighlight->GetValue()); event.Skip(); } @@ -724,7 +723,7 @@ void SubsEditBox::OnLayerEnter(wxCommandEvent &event) { /// void SubsEditBox::OnStartTimeChange(wxCommandEvent &event) { if (StartTime->time > EndTime->time) StartTime->SetTime(EndTime->time.GetMS()); - bool join = Options.AsBool(_T("Link Time Boxes Commit")) && EndTime->HasBeenModified(); + bool join = OPT_GET("Subtitle/Edit Box/Link Time Boxes Commit")->GetBool() && EndTime->HasBeenModified(); StartTime->Update(); Duration->Update(); if (join) EndTime->Update(); @@ -738,7 +737,7 @@ void SubsEditBox::OnStartTimeChange(wxCommandEvent &event) { /// void SubsEditBox::OnEndTimeChange(wxCommandEvent &event) { if (StartTime->time > EndTime->time) EndTime->SetTime(StartTime->time.GetMS()); - bool join = Options.AsBool(_T("Link Time Boxes Commit")) && StartTime->HasBeenModified(); + bool join = OPT_GET("Subtitle/Edit Box/Link Time Boxes Commit")->GetBool() && StartTime->HasBeenModified(); EndTime->Update(); Duration->Update(); if (join) StartTime->Update(); @@ -1015,7 +1014,7 @@ void SubsEditBox::Commit(bool stay) { if (next >= nrows) { AssDialogue *newline = new AssDialogue; newline->Start = cur->End; - newline->End.SetMS(cur->End.GetMS()+Options.AsInt(_T("Timing Default Duration"))); + newline->End.SetMS(cur->End.GetMS()+OPT_GET("Timing/Default Duration")->GetInt()); newline->Style = cur->Style; newline->UpdateData(); grid->InsertLine(newline,next-1,true,true); diff --git a/aegisub/src/subs_edit_ctrl.cpp b/aegisub/src/subs_edit_ctrl.cpp index b6b0d5c79..1215db372 100644 --- a/aegisub/src/subs_edit_ctrl.cpp +++ b/aegisub/src/subs_edit_ctrl.cpp @@ -44,6 +44,8 @@ #endif #include "ass_dialogue.h" +#include "compat.h" +#include "main.h" #include "options.h" #include "subs_edit_box.h" #include "subs_grid.h" @@ -201,54 +203,54 @@ void SubsTextEditCtrl::SetStyles() { // Styles wxFont font = wxSystemSettings::GetFont(wxSYS_DEFAULT_GUI_FONT); font.SetEncoding(wxFONTENCODING_DEFAULT); // this solves problems with some fonts not working properly - wxString fontname = Options.AsText(_T("Edit Font Face")); + wxString fontname = lagi_wxString(OPT_GET("Subtitle/Edit Box/Font Face")->GetString()); if (fontname != _T("")) font.SetFaceName(fontname); - int size = Options.AsInt(_T("Edit Font Size")); + int size = OPT_GET("Subtitle/Edit Box/Font Size")->GetInt(); // Normal style StyleSetFont(0,font); StyleSetSize(0,size); - StyleSetForeground(0,Options.AsColour(_T("Syntax Highlight Normal"))); + StyleSetForeground(0,lagi_wxColour(OPT_GET("Colour/Subtitle/Syntax/Normal")->GetColour())); // Brackets style StyleSetFont(1,font); StyleSetSize(1,size); - StyleSetForeground(1,Options.AsColour(_T("Syntax Highlight Brackets"))); + StyleSetForeground(1,lagi_wxColour(OPT_GET("Colour/Subtitle/Syntax/Brackets")->GetColour())); // Slashes/Parenthesis/Comma style StyleSetFont(2,font); StyleSetSize(2,size); - StyleSetForeground(2,Options.AsColour(_T("Syntax Highlight Slashes"))); + StyleSetForeground(2,lagi_wxColour(OPT_GET("Colour/Subtitle/Syntax/Slashes")->GetColour())); // Tags style StyleSetFont(3,font); StyleSetSize(3,size); StyleSetBold(3,true); - StyleSetForeground(3,Options.AsColour(_T("Syntax Highlight Tags"))); + StyleSetForeground(3,lagi_wxColour(OPT_GET("Colour/Subtitle/Syntax/Highlight Tags")->GetColour())); // Error style StyleSetFont(4,font); StyleSetSize(4,size); - StyleSetForeground(4,Options.AsColour(_T("Syntax Highlight Error"))); - StyleSetBackground(4,Options.AsColour(_T("Syntax Highlight Error Background"))); + StyleSetForeground(4,lagi_wxColour(OPT_GET("Colour/Subtitle/Syntax/Error")->GetColour())); + StyleSetBackground(4,lagi_wxColour(OPT_GET("Colour/Subtitle/Syntax/Background/Error")->GetColour())); // Tag Parameters style StyleSetFont(5,font); StyleSetSize(5,size); - StyleSetForeground(5,Options.AsColour(_T("Syntax Highlight Parameters"))); + StyleSetForeground(5,lagi_wxColour(OPT_GET("Colour/Subtitle/Syntax/Parameters")->GetColour())); // Line breaks style StyleSetFont(6,font); StyleSetSize(6,size); StyleSetBold(6,true); - StyleSetForeground(6,Options.AsColour(_T("Syntax Highlight Line Break"))); + StyleSetForeground(6,lagi_wxColour(OPT_GET("Colour/Subtitle/Syntax/Line Break")->GetColour())); // Karaoke template code block style StyleSetFont(7,font); StyleSetSize(7,size); StyleSetBold(7,true); //StyleSetItalic(7,true); - StyleSetForeground(7,Options.AsColour(_T("Syntax Highlight Karaoke Template"))); + StyleSetForeground(7,lagi_wxColour(OPT_GET("Colour/Subtitle/Syntax/Karaoke Template")->GetColour())); // Misspelling indicator IndicatorSetStyle(0,wxSTC_INDIC_SQUIGGLE); @@ -264,7 +266,7 @@ void SubsTextEditCtrl::SetStyles() { /// void SubsTextEditCtrl::UpdateStyle(int start, int _length) { // Styling enabled? - if (Options.AsBool(_T("Syntax Highlight Enabled")) == 0) return; + if (OPT_GET("Subtitle/Highlight/Syntax")->GetBool() == 0) return; // Check if it's a template line AssDialogue *diag = control->grid->GetDialogue(control->linen); @@ -483,7 +485,7 @@ void SubsTextEditCtrl::UpdateStyle(int start, int _length) { /// void SubsTextEditCtrl::UpdateCallTip() { // Enabled? - if (!Options.AsBool(_T("Call tips enabled"))) return; + if (!OPT_GET("App/Call Tips")->GetBool()) return; // Get position and text const unsigned int pos = GetReverseUnicodePosition(GetCurrentPos()); @@ -863,7 +865,7 @@ void SubsTextEditCtrl::ShowPopupMenu(int activePos) { wxArrayString langs = spellchecker->GetLanguageList(); // This probably should be cached... // Current language - wxString curLang = Options.AsText(_T("Spell checker language")); + wxString curLang = lagi_wxString(OPT_GET("Tool/Spell Checker/Language")->GetString()); // Languages wxMenu *languageMenu = new wxMenu(); @@ -949,7 +951,7 @@ void SubsTextEditCtrl::ShowPopupMenu(int activePos) { wxArrayString langs = thesaurus->GetLanguageList(); // This probably should be cached... // Current language - wxString curLang = Options.AsText(_T("Thesaurus language")); + wxString curLang = lagi_wxString(OPT_GET("Tool/Thesaurus/Language")->GetString()); // Languages wxMenu *languageMenu = new wxMenu(); @@ -1144,8 +1146,7 @@ void SubsTextEditCtrl::OnSetDicLanguage(wxCommandEvent &event) { wxString lang; if (index >= 0) lang = langs[index]; spellchecker->SetLanguage(lang); - Options.SetText(_T("Spell checker language"),lang); - Options.Save(); + OPT_SET("Tool/Spell Checker/Language")->SetString(STD_STR(lang)); // Update styling UpdateStyle(); @@ -1165,8 +1166,7 @@ void SubsTextEditCtrl::OnSetThesLanguage(wxCommandEvent &event) { wxString lang; if (index >= 0) lang = langs[index]; thesaurus->SetLanguage(lang); - Options.SetText(_T("Thesaurus language"),lang); - Options.Save(); + OPT_SET("Tool/Thesaurus/Language")->SetString(STD_STR(lang)); // Update styling UpdateStyle(); diff --git a/aegisub/src/subs_grid.cpp b/aegisub/src/subs_grid.cpp index f6bab0f18..bd5bd4f65 100644 --- a/aegisub/src/subs_grid.cpp +++ b/aegisub/src/subs_grid.cpp @@ -55,6 +55,7 @@ #include "dialog_paste_over.h" #include "frame_main.h" #include "hotkeys.h" +#include "main.h" #include "options.h" #include "subs_edit_box.h" #include "subs_grid.h" @@ -223,13 +224,11 @@ void SubtitlesGrid::OnPopupMenu(bool alternate) { /// @param event /// void SubtitlesGrid::OnShowColMenu(wxCommandEvent &event) { - // Set width int item = event.GetId()-MENU_SHOW_COL; showCol[item] = !showCol[item]; - // Save options - Options.SetBool(_T("Grid show column ") + AegiIntegerToString(item),showCol[item]); - Options.Save(); + std::vector map(showCol, showCol + sizeof(showCol) / sizeof(bool)); + OPT_SET("Subtitle/Grid/Column")->SetListBool(map); // Update SetColumnWidths(); @@ -456,14 +455,14 @@ void SubtitlesGrid::OnInsertBefore (wxCommandEvent &event) { def->End = GetDialogue(n)->Start; } else if (GetDialogue(n-1)->End.GetMS() > GetDialogue(n)->Start.GetMS()) { - def->Start.SetMS(GetDialogue(n)->Start.GetMS()-Options.AsInt(_T("Timing Default Duration"))); + def->Start.SetMS(GetDialogue(n)->Start.GetMS()-OPT_GET("Timing/Default Duration")->GetInt()); def->End = GetDialogue(n)->Start; } else { def->Start = GetDialogue(n-1)->End; def->End = GetDialogue(n)->Start; } - if (def->End.GetMS() < def->Start.GetMS()) def->End.SetMS(def->Start.GetMS()+Options.AsInt(_T("Timing Default Duration"))); + if (def->End.GetMS() < def->Start.GetMS()) def->End.SetMS(def->Start.GetMS()+OPT_GET("Timing/Default Duration")->GetInt()); def->Style = GetDialogue(n)->Style; // Insert it @@ -489,13 +488,13 @@ void SubtitlesGrid::OnInsertAfter (wxCommandEvent &event) { if (n == nrows-1) { def->Start = GetDialogue(n)->End; def->End = GetDialogue(n)->End; - def->End.SetMS(def->End.GetMS()+Options.AsInt(_T("Timing Default Duration"))); + def->End.SetMS(def->End.GetMS()+OPT_GET("Timing/Default Duration")->GetInt()); } else { def->Start = GetDialogue(n)->End; def->End = GetDialogue(n+1)->Start; } - if (def->End.GetMS() < def->Start.GetMS()) def->End.SetMS(def->Start.GetMS()+Options.AsInt(_T("Timing Default Duration"))); + if (def->End.GetMS() < def->Start.GetMS()) def->End.SetMS(def->Start.GetMS()+OPT_GET("Timing/Default Duration")->GetInt()); def->Style = GetDialogue(n)->Style; // Insert it @@ -519,7 +518,7 @@ void SubtitlesGrid::OnInsertBeforeVideo (wxCommandEvent &event) { AssDialogue *def = new AssDialogue; int video_ms = VFR_Output.GetTimeAtFrame(VideoContext::Get()->GetFrameN(),true); def->Start.SetMS(video_ms); - def->End.SetMS(video_ms+Options.AsInt(_T("Timing Default Duration"))); + def->End.SetMS(video_ms+OPT_GET("Timing/Default Duration")->GetInt()); def->Style = GetDialogue(n)->Style; // Insert it @@ -543,7 +542,7 @@ void SubtitlesGrid::OnInsertAfterVideo (wxCommandEvent &event) { AssDialogue *def = new AssDialogue; int video_ms = VFR_Output.GetTimeAtFrame(VideoContext::Get()->GetFrameN(),true); def->Start.SetMS(video_ms); - def->End.SetMS(video_ms+Options.AsInt(_T("Timing Default Duration"))); + def->End.SetMS(video_ms+OPT_GET("Timing/Default Duration")->GetInt()); def->Style = GetDialogue(n)->Style; // Insert it @@ -1490,7 +1489,7 @@ void SubtitlesGrid::CommitChanges(bool force,bool videoOnly) { if (!videoOnly) { // Autosave if option is enabled - if (Options.AsBool(_T("Auto Save on Every Change"))) { + if (OPT_GET("App/Auto/Save on Every Change")->GetBool()) { if (ass->IsModified() && !ass->filename.IsEmpty()) parentFrame->SaveSubtitles(false); } diff --git a/aegisub/src/subtitle_format_ttxt.cpp b/aegisub/src/subtitle_format_ttxt.cpp index 323d10fbb..6ca68c5bf 100644 --- a/aegisub/src/subtitle_format_ttxt.cpp +++ b/aegisub/src/subtitle_format_ttxt.cpp @@ -41,6 +41,8 @@ #include "ass_file.h" #include "ass_time.h" +#include "compat.h" +#include "main.h" #include "options.h" #include "subtitle_format_ttxt.h" @@ -369,7 +371,7 @@ void TTXTSubtitleFormat::ConvertToTTXT () { // Insert blank line at the end AssDialogue *diag = new AssDialogue(); diag->Start.SetMS(lastTime.GetMS()); - diag->End.SetMS(lastTime.GetMS()+Options.AsInt(_T("Timing Default Duration"))); + diag->End.SetMS(lastTime.GetMS()+OPT_GET("Timing/Default Duration")->GetInt()); diag->group = _T("[Events]"); diag->Style = _T("Default"); diag->Comment = false; diff --git a/aegisub/src/subtitle_format_txt.cpp b/aegisub/src/subtitle_format_txt.cpp index fc023335d..468d131ce 100644 --- a/aegisub/src/subtitle_format_txt.cpp +++ b/aegisub/src/subtitle_format_txt.cpp @@ -40,7 +40,9 @@ #include "config.h" #include "ass_dialogue.h" +#include "compat.h" #include "dialog_text_import.h" +#include "main.h" #include "options.h" #include "subtitle_format_txt.h" #include "text_file_reader.h" @@ -115,8 +117,8 @@ void TXTSubtitleFormat::ReadFile(wxString filename,wxString encoding) { using na // Data wxString actor; - wxString separator = Options.AsText(_T("Text actor separator")); - wxString comment = Options.AsText(_T("Text comment starter")); + wxString separator = lagi_wxString(OPT_GET("Tool/Import/Text/Actor Separator")->GetString()); + wxString comment = lagi_wxString(OPT_GET("Tool/Import/Text/Comment Starter")->GetString()); bool isComment = false; int lines = 0; @@ -184,7 +186,7 @@ void TXTSubtitleFormat::ReadFile(wxString filename,wxString encoding) { using na line->group = _T("[Events]"); line->Style = _T("Default"); line->Start.SetMS(0); - line->End.SetMS(Options.AsInt(_T("Timing Default Duration"))); + line->End.SetMS(OPT_GET("Timing/Default Duration")->GetInt()); Line->push_back(line); } } diff --git a/aegisub/src/subtitles_provider.cpp b/aegisub/src/subtitles_provider.cpp index e04861363..5ba4c0d26 100644 --- a/aegisub/src/subtitles_provider.cpp +++ b/aegisub/src/subtitles_provider.cpp @@ -39,6 +39,8 @@ // Headers #include "config.h" +#include "compat.h" +#include "main.h" #include "options.h" #ifdef WITH_CSRI #include "subtitles_provider_csri.h" @@ -61,7 +63,7 @@ SubtitlesProvider::~SubtitlesProvider() { /// bool SubtitlesProviderFactoryManager::ProviderAvailable() { // List of providers - wxArrayString list = GetFactoryList(Options.AsText(_T("Subtitles provider"))); + wxArrayString list = GetFactoryList(lagi_wxString(OPT_GET("Subtitle/Provider")->GetString())); // None available return (list.Count() > 0); @@ -74,7 +76,7 @@ bool SubtitlesProviderFactoryManager::ProviderAvailable() { /// SubtitlesProvider* SubtitlesProviderFactoryManager::GetProvider() { // List of providers - wxArrayString list = GetFactoryList(Options.AsText(_T("Subtitles provider"))); + wxArrayString list = GetFactoryList(lagi_wxString(OPT_GET("Subtitle/Provider")->GetString())); // None available if (list.Count() == 0) throw _T("No subtitle providers are available."); diff --git a/aegisub/src/text_file_writer.cpp b/aegisub/src/text_file_writer.cpp index 0659ef23b..bae68f22d 100644 --- a/aegisub/src/text_file_writer.cpp +++ b/aegisub/src/text_file_writer.cpp @@ -41,6 +41,8 @@ #endif #include "charset_conv.h" +#include "compat.h" +#include "main.h" #include "options.h" #include "text_file_writer.h" @@ -60,7 +62,7 @@ TextFileWriter::TextFileWriter(wxString filename, wxString encoding) throw _T("Failed opening file for writing."); } - if (encoding.IsEmpty()) encoding = Options.AsText(_T("Save Charset")); + if (encoding.IsEmpty()) encoding = lagi_wxString(OPT_GET("App/Save Charset")->GetString()); conv.reset(new AegisubCSConv(encoding, true)); // Write the BOM diff --git a/aegisub/src/thesaurus_myspell.cpp b/aegisub/src/thesaurus_myspell.cpp index 3deffc923..54542b882 100644 --- a/aegisub/src/thesaurus_myspell.cpp +++ b/aegisub/src/thesaurus_myspell.cpp @@ -45,7 +45,9 @@ #include #endif +#include "compat.h" #include "mythes.hxx" +#include "main.h" #include "options.h" #include "standard_paths.h" #include "thesaurus_myspell.h" @@ -57,7 +59,7 @@ MySpellThesaurus::MySpellThesaurus() { conv = NULL; mythes = NULL; - SetLanguage(Options.AsText(_T("Thesaurus Language"))); + SetLanguage(lagi_wxString(OPT_GET("Tool/Thesaurus/Language")->GetString())); } @@ -107,7 +109,7 @@ void MySpellThesaurus::Lookup(wxString word,ThesaurusEntryArray &result) { /// wxArrayString MySpellThesaurus::GetLanguageList() { // Get dir name - wxString path = StandardPaths::DecodePathMaybeRelative(Options.AsText(_T("Dictionaries path")), _T("?data")) + _T("/"); + wxString path = StandardPaths::DecodePathMaybeRelative(lagi_wxString(OPT_GET("Path/Dictionary")->GetString()), _T("?data")) + _T("/"); wxArrayString list; wxFileName folder(path); if (!folder.DirExists()) return list; @@ -153,7 +155,7 @@ void MySpellThesaurus::SetLanguage(wxString language) { if (language.IsEmpty()) return; // Get dir name - wxString path = StandardPaths::DecodePathMaybeRelative(Options.AsText(_T("Dictionaries path")), _T("?data")) + _T("/"); + wxString path = StandardPaths::DecodePathMaybeRelative(lagi_wxString(OPT_GET("Path/Dictionary")->GetString()), _T("?data")) + _T("/"); // Get affix and dictionary paths wxString idxpath = path + _T("th_") + language + _T(".idx"); diff --git a/aegisub/src/timeedit_ctrl.cpp b/aegisub/src/timeedit_ctrl.cpp index ede290124..e1b9e13b7 100644 --- a/aegisub/src/timeedit_ctrl.cpp +++ b/aegisub/src/timeedit_ctrl.cpp @@ -47,6 +47,8 @@ #endif #include "ass_time.h" +#include "compat.h" +#include "main.h" #include "options.h" #include "timeedit_ctrl.h" #include "vfr.h" @@ -151,7 +153,7 @@ void TimeEdit::Modified(bool byUser) { // Colour if (showModified && !modified) { - SetBackgroundColour(Options.AsColour(_T("Edit Box Need Enter Background"))); + SetBackgroundColour(lagi_wxColour(OPT_GET("Colour/Background/Modified")->GetColour())); } modified = true; @@ -223,7 +225,7 @@ void TimeEdit::Update() { } // Update time if not on insertion mode - else if (!Options.AsBool(_T("Insert Mode on Time Boxes"))) { + else if (!OPT_GET("Subtitle/Time Edit/Insert Mode")->GetBool()) { UpdateTime(); SetValue(time.GetASSFormated()); } @@ -242,7 +244,7 @@ void TimeEdit::Update() { /// @param byUser /// void TimeEdit::UpdateTime(bool byUser) { - bool insertion = Options.AsBool(_T("Insert Mode on Time Boxes")); + bool insertion = OPT_GET("Subtitle/Time Edit/Insert Mode")->GetBool(); wxString text = GetValue(); long start=0,end=0; if (insertion && byUser) { @@ -279,7 +281,7 @@ void TimeEdit::UpdateTime(bool byUser) { void TimeEdit::OnKeyDown(wxKeyEvent &event) { // Get key ID int key = event.GetKeyCode(); - bool insertMode = Options.AsBool(_T("Insert Mode on Time Boxes")); + bool insertMode = OPT_GET("Subtitle/Time Edit/Insert Mode")->GetBool(); Refresh(); // Check if it's an acceptable key @@ -320,7 +322,7 @@ void TimeEdit::OnKeyDown(wxKeyEvent &event) { /// @param event /// void TimeEdit::OnKillFocus(wxFocusEvent &event) { - if (!byFrame && !Options.AsBool(_T("Insert Mode on Time Boxes"))) { + if (!byFrame && !OPT_GET("Subtitle/Time Edit/Insert Mode")->GetBool()) { if (time.GetASSFormated() != GetValue()) { UpdateTime(); SetValue(time.GetASSFormated()); @@ -340,7 +342,7 @@ void TimeEdit::OnKillFocus(wxFocusEvent &event) { void TimeEdit::OnMouseEvent(wxMouseEvent &event) { // Right click context menu if (event.RightUp()) { - if (!byFrame && Options.AsBool(_T("Insert Mode on Time Boxes"))) { + if (!byFrame && OPT_GET("Subtitle/Time Edit/Insert Mode")->GetBool()) { wxMenu menu; menu.Append(Time_Edit_Copy,_("&Copy")); menu.Append(Time_Edit_Paste,_("&Paste")); diff --git a/aegisub/src/vfr.cpp b/aegisub/src/vfr.cpp index 812189e0d..56145db69 100644 --- a/aegisub/src/vfr.cpp +++ b/aegisub/src/vfr.cpp @@ -43,6 +43,8 @@ #include #endif +#include "compat.h" +#include "main.h" #include "options.h" #include "text_file_reader.h" #include "text_file_writer.h" @@ -236,7 +238,7 @@ void FrameRate::Load(wxString filename) { FrameRateType = VFR; // Add to recent - Options.AddToRecentList(filename,_T("Recent timecodes")); + AegisubApp::Get()->mru->Add("Timecodes", STD_STR(filename)); } diff --git a/aegisub/src/video_box.cpp b/aegisub/src/video_box.cpp index eae6c5d77..2b5f8ca92 100644 --- a/aegisub/src/video_box.cpp +++ b/aegisub/src/video_box.cpp @@ -52,6 +52,7 @@ #include "frame_main.h" #include "help_button.h" #include "libresrc/libresrc.h" +#include "main.h" #include "options.h" #include "subs_edit_box.h" #include "subs_grid.h" @@ -86,7 +87,7 @@ VideoBox::VideoBox(wxWindow *parent, bool isDetached) VideoStopButton->SetToolTip(_("Stop video playback")); AutoScroll = new ToggleBitmap(videoPage,Video_Auto_Scroll,GETIMAGE(toggle_video_autoscroll_24),wxSize(30,-1)); AutoScroll->SetToolTip(_("Toggle autoscroll of video")); - AutoScroll->SetValue(Options.AsBool(_T("Sync video with subs"))); + AutoScroll->SetValue(OPT_GET("Video/Subtitle Sync")->GetBool()); // Seek videoSlider = new VideoSlider(videoPage,-1); @@ -111,7 +112,7 @@ VideoBox::VideoBox(wxWindow *parent, bool isDetached) visualToolBar->AddTool(Video_Mode_Vector_Clip,_("Vector Clip"),GETIMAGE(visual_vector_clip_24),_("Clip subtitles to a vectorial area."),wxITEM_RADIO); visualToolBar->AddSeparator(); visualToolBar->AddTool(Video_Mode_Realtime,_("Realtime"),GETIMAGE(visual_realtime_24),_("Toggle realtime display of changes."),wxITEM_CHECK); - visualToolBar->ToggleTool(Video_Mode_Realtime,Options.AsBool(_T("Video Visual Realtime"))); + visualToolBar->ToggleTool(Video_Mode_Realtime,OPT_GET("Video/Visual Realtime")->GetBool()); visualToolBar->AddTool(Video_Mode_Help,_("Help"),GETIMAGE(visual_help_24),_("Open the manual page for Visual Typesetting.")); visualToolBar->Realize(); // Avoid ugly themed background on Vista and possibly also Win7 @@ -218,16 +219,14 @@ void VideoBox::OnVideoStop(wxCommandEvent &event) { /// @param event /// void VideoBox::OnVideoToggleScroll(wxCommandEvent &event) { - Options.SetBool(_T("Sync video with subs"),AutoScroll->GetValue()); - Options.Save(); + OPT_SET("Video/Subtitle Sync")->SetBool(AutoScroll->GetValue()); } /// @brief Realtime toggle /// @param event /// void VideoBox::OnToggleRealtime(wxCommandEvent &event) { - Options.SetBool(_T("Video Visual Realtime"),event.IsChecked()); - Options.Save(); + OPT_SET("Video/Visual Realtime")->SetBool(event.IsChecked()); } diff --git a/aegisub/src/video_context.cpp b/aegisub/src/video_context.cpp index 79728a5e9..50fd8f1f1 100644 --- a/aegisub/src/video_context.cpp +++ b/aegisub/src/video_context.cpp @@ -62,6 +62,8 @@ #include "ass_style.h" #include "ass_time.h" #include "audio_display.h" +#include "compat.h" +#include "main.h" #include "mkv_wrap.h" #include "options.h" #include "standard_paths.h" @@ -269,7 +271,7 @@ void VideoContext::SetVideo(const wxString &filename) { // Set filename videoName = filename; - Options.AddToRecentList(filename,_T("Recent vid")); + AegisubApp::Get()->mru->Add("Video", STD_STR(filename)); wxFileName fn(filename); StandardPaths::SetPathValue(_T("?video"),fn.GetPath()); @@ -329,7 +331,7 @@ void VideoContext::UpdateDisplays(bool full) { // Update audio display if (audio && audio->loaded && audio->IsShownOnScreen()) { - if (Options.AsBool(_T("Audio Draw Video Position"))) { + if (OPT_GET("Audio/Display/Draw/Video Position")->GetBool()) { audio->UpdateImage(false); } } @@ -374,7 +376,7 @@ void VideoContext::JumpToFrame(int n) { UpdateDisplays(false); // Update grid - if (!isPlaying && Options.AsBool(_T("Highlight subs in frame"))) grid->Refresh(false); + if (!isPlaying && OPT_GET("Subtitle/Grid/Highlight Subtitles in Frame")->GetBool()) grid->Refresh(false); } @@ -439,7 +441,7 @@ AegiVideoFrame VideoContext::GetFrame(int n,bool raw) { /// void VideoContext::SaveSnapshot(bool raw) { // Get folder - wxString option = Options.AsText(_T("Video Screenshot Path")); + wxString option = lagi_wxString(OPT_GET("Path/Screenshot")->GetString()); wxFileName videoFile(videoName); wxString basepath; // Is it a path specifier and not an actual fixed path? @@ -493,7 +495,7 @@ void VideoContext::PlayNextFrame() { int thisFrame = frame_n; JumpToFrame(frame_n + 1); // Start playing audio - if (Options.AsBool(_T("Audio Plays When Stepping Video"))) + if (OPT_GET("Audio/Plays When Stepping")->GetBool()) audio->Play(VFR_Output.GetTimeAtFrame(thisFrame),VFR_Output.GetTimeAtFrame(thisFrame + 1)); } @@ -507,7 +509,7 @@ void VideoContext::PlayPrevFrame() { int thisFrame = frame_n; JumpToFrame(frame_n -1); // Start playing audio - if (Options.AsBool(_T("Audio Plays When Stepping Video"))) + if (OPT_GET("Audio/Plays When Stepping")->GetBool()) audio->Play(VFR_Output.GetTimeAtFrame(thisFrame - 1),VFR_Output.GetTimeAtFrame(thisFrame)); } diff --git a/aegisub/src/video_display.cpp b/aegisub/src/video_display.cpp index 8749ae16c..395de508b 100644 --- a/aegisub/src/video_display.cpp +++ b/aegisub/src/video_display.cpp @@ -58,6 +58,7 @@ #include "ass_dialogue.h" #include "hotkeys.h" #include "options.h" +#include "main.h" #include "video_out_gl.h" #include "vfr.h" #include "video_box.h" @@ -107,12 +108,12 @@ int attribList[] = { WX_GL_RGBA , WX_GL_DOUBLEBUFFER, WX_GL_STENCIL_SIZE, 8, 0 } /// @class VideoOutRenderException /// @extends VideoOutException /// @brief An OpenGL error occured while uploading or displaying a frame -class OpenGlException : public Aegisub::Exception { +class OpenGlException : public agi::Exception { public: OpenGlException(const wxChar *func, int err) - : Aegisub::Exception(wxString::Format("%s failed with error code %d", func, err)) + : agi::Exception(STD_STR(wxString::Format("%s failed with error code %d", func, err))) { } - const wxChar * GetName() const { return L"video/opengl"; } + const char * GetName() const { return "video/opengl"; } Exception * Copy() const { return new OpenGlException(*this); } }; @@ -172,8 +173,8 @@ void VideoDisplay::SetFrame(int frameNumber) { PositionDisplay->SetValue(wxString::Format(L"%01i:%02i:%02i.%03i - %i", h, m, s, ms, frameNumber)); if (context->GetKeyFrames().Index(frameNumber) != wxNOT_FOUND) { // Set the background color to indicate this is a keyframe - PositionDisplay->SetBackgroundColour(Options.AsColour(L"Grid selection background")); - PositionDisplay->SetForegroundColour(Options.AsColour(L"Grid selection foreground")); + PositionDisplay->SetBackgroundColour(lagi_wxColour(OPT_GET("Colour/Subtitle Grid/Background/Selection")->GetColour())); + PositionDisplay->SetForegroundColour(lagi_wxColour(OPT_GET("Colour/Subtitle Grid/Selection")->GetColour())); } else { PositionDisplay->SetBackgroundColour(wxNullColour); @@ -260,7 +261,7 @@ void VideoDisplay::Render() try { E(glLoadIdentity()); E(glOrtho(0.0f, w, h, 0.0f, -1000.0f, 1000.0f)); - if (Options.AsBool(L"Show Overscan Mask")) { + if (OPT_GET("Video/Overscan Mask")->GetBool()) { double ar = context->GetAspectRatioValue(); // Based on BBC's guidelines: http://www.bbc.co.uk/guidelines/dq/pdf/tv/tv_standards_london.pdf @@ -279,7 +280,7 @@ void VideoDisplay::Render() try { if (video.x > INT_MIN || video.y > INT_MIN || - Options.AsBool(L"Always show visual tools")) { + OPT_GET("Tool/Visual/Always Show")->GetBool()) { tool->Draw(); } diff --git a/aegisub/src/video_out_gl.cpp b/aegisub/src/video_out_gl.cpp index b7dc585d8..c0ec1c7cc 100644 --- a/aegisub/src/video_out_gl.cpp +++ b/aegisub/src/video_out_gl.cpp @@ -58,8 +58,8 @@ using std::max; #include "utils.h" #include "video_frame.h" -#define CHECK_INIT_ERROR(cmd) cmd; if (GLenum err = glGetError()) throw VideoOutInitException(_T(#cmd), err) -#define CHECK_ERROR(cmd) cmd; if (GLenum err = glGetError()) throw VideoOutRenderException(_T(#cmd), err) +#define CHECK_INIT_ERROR(cmd) cmd; if (GLenum err = glGetError()) throw VideoOutInitException(#cmd, err) +#define CHECK_ERROR(cmd) cmd; if (GLenum err = glGetError()) throw VideoOutRenderException(#cmd, err) /// @brief Structure tracking all precomputable information about a subtexture struct VideoOutGL::TextureInfo { @@ -111,7 +111,7 @@ void VideoOutGL::DetectOpenGLCapabilities() { // Test for supported internalformats if (TestTexture(64, 64, GL_RGBA8)) internalFormat = GL_RGBA8; else if (TestTexture(64, 64, GL_RGBA)) internalFormat = GL_RGBA; - else throw VideoOutInitException(L"Could not create a 64x64 RGB texture in any format."); + else throw VideoOutInitException("Could not create a 64x64 RGB texture in any format."); // Test for the maximum supported texture size glGetIntegerv(GL_MAX_TEXTURE_SIZE, &maxTextureSize); @@ -256,7 +256,7 @@ void VideoOutGL::InitTextures(int width, int height, GLenum format, int bpp, boo glTexCoord2f(right, bottom); glVertex2f(x2, y2); glTexCoord2f(left, bottom); glVertex2f(x1, y2); glEnd(); - if (GLenum err = glGetError()) throw VideoOutRenderException(L"GL_QUADS", err); + if (GLenum err = glGetError()) throw VideoOutRenderException("GL_QUADS", err); } } CHECK_ERROR(glDisable(GL_TEXTURE_2D)); diff --git a/aegisub/src/video_out_gl.h b/aegisub/src/video_out_gl.h index c33144884..7bc7c2393 100644 --- a/aegisub/src/video_out_gl.h +++ b/aegisub/src/video_out_gl.h @@ -34,12 +34,14 @@ /// @ingroup video /// -#include "include/aegisub/exception.h" +#include #ifndef AGI_PRE #include #endif +#include "compat.h" + class AegiVideoFrame; /// @class VideoOutGL @@ -102,17 +104,17 @@ public: /// @class VideoOutException /// @extends Aegisub::Exception /// @brief Base class for all exceptions thrown by VideoOutGL -DEFINE_BASE_EXCEPTION_NOINNER(VideoOutException, Aegisub::Exception) +DEFINE_BASE_EXCEPTION_NOINNER(VideoOutException, agi::Exception) /// @class VideoOutRenderException /// @extends VideoOutException /// @brief An OpenGL error occured while uploading or displaying a frame class VideoOutRenderException : public VideoOutException { public: - VideoOutRenderException(const wxChar *func, int err) - : VideoOutException(wxString::Format("%s failed with error code %d", func, err)) + VideoOutRenderException(const char *func, int err) + : VideoOutException(STD_STR(wxString::Format("%s failed with error code %d", func, err))) { } - const wxChar * GetName() const { return L"videoout/opengl/render"; } + const char * GetName() const { return "videoout/opengl/render"; } Exception * Copy() const { return new VideoOutRenderException(*this); } }; /// @class VideoOutOpenGLException @@ -120,10 +122,10 @@ public: /// @brief An OpenGL error occured while setting up the video display class VideoOutInitException : public VideoOutException { public: - VideoOutInitException(const wxChar *func, int err) - : VideoOutException(wxString::Format("%s failed with error code %d", func, err)) + VideoOutInitException(const char *func, int err) + : VideoOutException(STD_STR(wxString::Format("%s failed with error code %d", func, err))) { } - VideoOutInitException(const wxChar *err) : VideoOutException(err) { } - const wxChar * GetName() const { return L"videoout/opengl/init"; } + VideoOutInitException(const char *err) : VideoOutException(err) { } + const char * GetName() const { return "videoout/opengl/init"; } Exception * Copy() const { return new VideoOutInitException(*this); } }; diff --git a/aegisub/src/video_provider_cache.cpp b/aegisub/src/video_provider_cache.cpp index 6778ed597..c0f94662d 100644 --- a/aegisub/src/video_provider_cache.cpp +++ b/aegisub/src/video_provider_cache.cpp @@ -38,6 +38,7 @@ /////////// // Headers #include "config.h" +#include "main.h" #include "options.h" #include "video_provider_cache.h" @@ -50,7 +51,7 @@ VideoProviderCache::VideoProviderCache(VideoProvider *parent) { master = parent; cacheMax = 0; if (parent->WantsCaching()) - cacheMax = Options.AsInt(_T("Video cache size")) << 20; // convert MB to bytes + cacheMax = OPT_GET("Provider/Video/Cache/Size")->GetInt() << 20; // convert MB to bytes else cacheMax = 0; } diff --git a/aegisub/src/video_provider_ffmpegsource.cpp b/aegisub/src/video_provider_ffmpegsource.cpp index ff329d298..32600b640 100644 --- a/aegisub/src/video_provider_ffmpegsource.cpp +++ b/aegisub/src/video_provider_ffmpegsource.cpp @@ -54,6 +54,7 @@ #include "aegisub_endian.h" #include "include/aegisub/aegisub.h" +#include "main.h" #include "options.h" #include "video_context.h" #include "video_provider_ffmpegsource.h" @@ -168,7 +169,7 @@ void FFmpegSourceVideoProvider::LoadVideo(wxString filename) { // moment of truth if (!IndexIsValid) { - int TrackMask = Options.AsBool(_T("FFmpegSource always index all tracks")) ? FFMS_TRACKMASK_ALL : FFMS_TRACKMASK_NONE; + int TrackMask = OPT_GET("Provider/FFmpegSource/Index All Tracks")->GetBool() ? FFMS_TRACKMASK_ALL : FFMS_TRACKMASK_NONE; try { // ignore audio decoding errors here, we don't care right now Index = DoIndexing(Indexer, CacheName, TrackMask, FFMS_IEH_IGNORE); @@ -201,14 +202,14 @@ void FFmpegSourceVideoProvider::LoadVideo(wxString filename) { } // set thread count - int Threads = Options.AsInt(_T("FFmpegSource decoding threads")); + int Threads = OPT_GET("Provider/Video/FFmpegSource/Decoding Threads")->GetInt(); if (Threads < 1) throw _T("FFmpegSource video provider: invalid decoding thread count"); // set seekmode // TODO: give this its own option? int SeekMode; - if (Options.AsBool(_T("FFmpeg allow unsafe seeking"))) + if (OPT_GET("Provider/Video/FFMpegSource/Unsafe Seeking")->GetBool()) SeekMode = FFMS_SEEK_UNSAFE; else SeekMode = FFMS_SEEK_NORMAL; diff --git a/aegisub/src/video_provider_manager.cpp b/aegisub/src/video_provider_manager.cpp index 884027196..95c9842fc 100644 --- a/aegisub/src/video_provider_manager.cpp +++ b/aegisub/src/video_provider_manager.cpp @@ -39,6 +39,8 @@ // Headers #include "config.h" +#include "compat.h" +#include "main.h" #include "options.h" #include "vfr.h" #ifdef WITH_AVISYNTH @@ -80,7 +82,7 @@ VideoProvider *VideoProviderFactoryManager::GetProvider(wxString video) { } // List of providers - wxArrayString list = GetFactoryList(Options.AsText(_T("Video provider"))); + wxArrayString list = GetFactoryList(lagi_wxString(OPT_GET("Video/Provider")->GetString())); // None available if (list.Count() == 0) throw _T("No video providers are available."); diff --git a/aegisub/src/video_slider.cpp b/aegisub/src/video_slider.cpp index 5983fb11d..c5da60382 100644 --- a/aegisub/src/video_slider.cpp +++ b/aegisub/src/video_slider.cpp @@ -44,6 +44,7 @@ #endif #include "ass_dialogue.h" +#include "main.h" #include "options.h" #include "subs_edit_box.h" #include "subs_grid.h" @@ -310,7 +311,7 @@ void VideoSlider::OnKeyDown(wxKeyEvent &event) { // Fast move if (!ctrl && !shift && alt) { if (VideoContext::Get()->IsPlaying()) return; - int target = MID(min,GetValue() + direction * Options.AsInt(_T("Video Fast Jump Step")),max); + int target = MID(min,GetValue() + direction * OPT_GET("Video/Slider/Fast Jump Step")->GetInt(),max); if (target != GetValue()) VideoContext::Get()->JumpToFrame(target); return; } @@ -478,7 +479,7 @@ void VideoSlider::DrawImage(wxDC &destdc) { // Draw keyframes int curX; - if (Display && Options.AsBool(_T("Show keyframes on video slider"))) { + if (Display && OPT_GET("Video/Slider/Show Keyframes")->GetBool()) { dc.SetPen(wxPen(shad)); wxArrayInt KeyFrames = VideoContext::Get()->GetKeyFrames(); int keys = KeyFrames.Count(); diff --git a/aegisub/src/visual_tool.cpp b/aegisub/src/visual_tool.cpp index c20c520c4..0c01c27f1 100644 --- a/aegisub/src/visual_tool.cpp +++ b/aegisub/src/visual_tool.cpp @@ -51,6 +51,7 @@ #include "ass_style.h" #include "ass_time.h" #include "export_visible_lines.h" +#include "main.h" #include "options.h" #include "subs_edit_box.h" #include "subs_grid.h" @@ -100,7 +101,7 @@ VisualTool::~VisualTool() { template void VisualTool::OnMouseEvent (wxMouseEvent &event) { - bool realTime = Options.AsBool(L"Video Visual Realtime"); + bool realTime = OPT_GET("Video/Visual Realtime")->GetBool(); if (event.Leaving()) { Update(); diff --git a/aegisub/tests/Makefile.am b/aegisub/tests/Makefile.am new file mode 100644 index 000000000..f15228a92 --- /dev/null +++ b/aegisub/tests/Makefile.am @@ -0,0 +1,18 @@ +# $Id$ + +bin_PROGRAMS = run + +run_LDFLAGS= -L../libaegisub -laegisub-2.2 -lgtest -rpath /mnt/free/aegisub/commit/libaegisub/.libs +run_CPPFLAGS= -I../src/include -I../libaegisub/include + + +run_SOURCES = \ + main.cpp \ + util.cpp \ + libaegisub_access.cpp \ + libaegisub_cajun.cpp \ + libaegisub_util.cpp \ + libaegisub_mru.cpp + +run_SOURCES += \ + *.h diff --git a/aegisub/tests/libaegisub_access.cpp b/aegisub/tests/libaegisub_access.cpp new file mode 100644 index 000000000..17a8b2f3e --- /dev/null +++ b/aegisub/tests/libaegisub_access.cpp @@ -0,0 +1,109 @@ +// Copyright (c) 2010, Amar Takhar +// +// 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. +// +// $Id$ + +/// @file libaegisub_access.cpp +/// @brief agi::acs tests. +/// @ingroup acs + +#include + +#include "main.h" + +using namespace agi::acs; + +class lagi_acs : public libagi { + +protected: + // place holder for future code placement +}; + + +// Yes, this is a horrifying use of macros, since these are all void static +// methods I couldn't think of a better way to test these without massive code +// duplication. +#define EX_AcsNotFound(func, pass) \ + TEST_F(lagi_acs, func##ExAcsNotFound) { \ + EXPECT_THROW(func("data/nonexistent"), AcsNotFound); \ + EXPECT_NO_THROW(func(pass)); \ + } + +#define EX_AcsAccess(func, fail, pass) \ + TEST_F(lagi_acs, func##ExAcsAccess) { \ + EXPECT_THROW(func(fail), AcsAccess); \ + EXPECT_NO_THROW(func(pass)); \ + } + +#define EX_AcsNotAFile(func, fail, pass) \ + TEST_F(lagi_acs, func##ExAcsNotAFile) { \ + EXPECT_THROW(func(fail), AcsNotAFile); \ + EXPECT_NO_THROW(func(pass)); \ + } + +#define EX_AcsNotADirectory(func, fail, pass) \ + TEST_F(lagi_acs, func##ExAcsNotADirectory) { \ + EXPECT_THROW(func(fail), AcsNotADirectory); \ + EXPECT_NO_THROW(func(pass)); \ + } + +#define EX_AcsRead(func, fail, pass) \ + TEST_F(lagi_acs, func##ExAcsRead) { \ + EXPECT_THROW(func(fail), AcsRead); \ + EXPECT_NO_THROW(func(pass)); \ + } + +#define EX_AcsWrite(func, fail, pass) \ + TEST_F(lagi_acs, func##ExAcsWrite) { \ + EXPECT_THROW(func(fail), AcsWrite); \ + EXPECT_NO_THROW(func(pass)); \ + } + + +/* +DEFINE_SIMPLE_EXCEPTION_NOINNER(AcsFatal, AcsError, "io/fatal") +DEFINE_SIMPLE_EXCEPTION_NOINNER(AcsAccessRead, AcsError, "io/read") +DEFINE_SIMPLE_EXCEPTION_NOINNER(AcsAccessWrite, AcsError, "io/write") +*/ + + +EX_AcsNotFound(CheckFileRead, "data/file") +EX_AcsAccess(CheckFileRead, "data/file_access_denied", "data/file") +EX_AcsNotAFile(CheckFileRead, "data/dir", "data/file") +TEST_F(lagi_acs, CheckFileRead) { + EXPECT_NO_THROW(CheckFileRead("data/file")); +} + +EX_AcsNotFound(CheckFileWrite, "data/file") +EX_AcsAccess(CheckFileWrite, "data/file_access_denied", "data/file") +EX_AcsNotAFile(CheckFileWrite, "data/dir", "data/file") +EX_AcsWrite(CheckFileWrite, "data/file_read_only", "data/file") +TEST_F(lagi_acs, CheckFileWrite) { + EXPECT_NO_THROW(CheckFileRead("data/file")); +} + +EX_AcsNotFound(CheckDirRead, "data/dir") +EX_AcsAccess(CheckDirRead, "data/dir_access_denied", "data/dir") +EX_AcsNotADirectory(CheckDirRead, "data/file", "data/dir") +TEST_F(lagi_acs, CheckDirRead) { + EXPECT_NO_THROW(CheckDirRead("data/dir")); +} + +EX_AcsNotFound(CheckDirWrite, "data/dir") +EX_AcsAccess(CheckDirWrite, "data/dir_access_denied", "data/dir") +EX_AcsNotADirectory(CheckDirWrite, "data/file", "data/dir") +EX_AcsWrite(CheckDirWrite, "data/dir_read_only", "data/dir") +TEST_F(lagi_acs, CheckDirWrite) { + EXPECT_NO_THROW(CheckDirWrite("data/dir")); +} diff --git a/aegisub/tests/libaegisub_cajun.cpp b/aegisub/tests/libaegisub_cajun.cpp new file mode 100644 index 000000000..61870517b --- /dev/null +++ b/aegisub/tests/libaegisub_cajun.cpp @@ -0,0 +1,159 @@ +// Copyright (c) 2010, Amar Takhar +// +// 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. +// +// $Id$ + +/// @file libaegisub_cajun.cpp +/// @brief Cajun/Json tests. +/// @ingroup cajun + +#include "main.h" + +#include +#include +#include +#include + +class lagi_cajun : public libagi { + +protected: + // place holder for future code placement +}; + + +TEST_F(lagi_cajun, ObjectCreateNumber) { + json::Object obj; + obj["Integer"] = json::Number(1); +} + + +TEST_F(lagi_cajun, ObjectCreateString) { + json::Object obj; + obj["String"] = json::String("test"); +} + + +TEST_F(lagi_cajun, ObjectCreateBoolean) { + json::Object obj; + obj["Boolean"] = json::Boolean(true); +} + + +TEST_F(lagi_cajun, ObjectCreateNull) { + json::Object obj; + obj["Null"] = json::Null(); +} + + +TEST_F(lagi_cajun, ObjectCreateArray) { + json::Object obj; + obj["Inside"] = json::String(); + json::Array array; + array.Insert(obj); +} + + +TEST_F(lagi_cajun, ObjectEquality) { + json::Object obj; + obj["Inside"] = json::String(); + json::Array array; + array.Insert(obj); + obj["Array"] = array; + json::Object obj_dupe = obj; + + EXPECT_TRUE(obj_dupe == obj); + + obj_dupe["NotEqual"] = array; + EXPECT_FALSE(obj_dupe == obj); + +} + +// Cajun doesn't have chained exceptions, so there's no real way to test the +// difference in the following exceptions. I'll try emailing the author to see +// If they'll add them, if not we'll do it ourselves. +TEST_F(lagi_cajun, ExExceptionArrayOutOfBounds) { + json::Object obj; + obj["Inside"] = json::String(); + json::Array array; + array.Insert(obj); + obj["Array"] = array; + const json::Array& const_array = obj["Array"]; + + EXPECT_THROW({ + const json::String& str = const_array[1]; + str.Value(); // avoid unused variable warning + }, json::Exception); +} + + +TEST_F(lagi_cajun, ExExceptionArrayObjNotFound) { + json::Object obj; + obj["Inside"] = json::String(); + json::Array array; + array.Insert(obj); + obj["Array"] = array; + const json::Array& const_array = obj["Array"]; + + EXPECT_THROW({ + const json::String& str = const_array[0]["Nothere"]; + str.Value(); // avoid unused variable warning + }, json::Exception); +} + + +TEST_F(lagi_cajun, ExExceptionArrayBadCast) { + json::Object obj; + obj["Inside"] = json::String(); + json::Array array; + array.Insert(obj); + obj["Array"] = array; + const json::Array& const_array = obj["Array"]; + const json::Object& arr_obj = const_array[0]; + + EXPECT_THROW({ + const json::UnknownElement& unkn = arr_obj["Array"]["BadCast"]; + unkn["Array"]; // avoid unused variable warning + }, json::Exception); +} + + +TEST_F(lagi_cajun, Read) { + json::Object obj; + std::istringstream doc("{\"String\" : \"This is a test\"}"); + EXPECT_NO_THROW(json::Reader::Read(obj, doc)); +} + + +TEST_F(lagi_cajun, Write) { + json::Object obj; + std::istringstream doc("{\"String\" : \"This is a test\"}"); + + std::stringstream stream; + EXPECT_NO_THROW(json::Writer::Write(obj, stream)); +} + +TEST_F(lagi_cajun, ReaderExParseException) { + json::Object obj; + std::istringstream doc("[1 2]"); + + EXPECT_THROW(json::Reader::Read(obj, doc), json::Reader::ParseException); +} + + +TEST_F(lagi_cajun, ReaderExScanException) { + json::Object obj; + std::istringstream doc("[true, false, thiswontwork]"); + + EXPECT_THROW(json::Reader::Read(obj, doc), json::Reader::ScanException); +} diff --git a/aegisub/tests/libaegisub_mru.cpp b/aegisub/tests/libaegisub_mru.cpp new file mode 100644 index 000000000..8ceae9a70 --- /dev/null +++ b/aegisub/tests/libaegisub_mru.cpp @@ -0,0 +1,84 @@ +// Copyright (c) 2010, Amar Takhar +// +// 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. +// +// $Id$ + +/// @file libaegisub_mru.cpp +/// @brief agi::mru (Most Recently Used) +/// @ingroup mru + +#include +#include "main.h" +#include "util.h" + +class lagi_mru : public libagi { +protected: + std::string default_mru; + std::string conf_ok; + + virtual void SetUp() { + default_mru = "{\"Valid_Int\" : []}"; + conf_ok = "./data/mru_ok.json"; + } +}; + + +TEST_F(lagi_mru, MRUConstructFromFile) { + agi::MRUManager mru(conf_ok, default_mru); +} + +TEST_F(lagi_mru, MRUConstructFromString) { + util::remove("data/mru_tmp"); + + const std::string nonexistent("data/mru_tmp"); + agi::MRUManager mru(nonexistent, default_mru); +} + + +TEST_F(lagi_mru, MRUConstructInvalid) { + util::copy("data/mru_invalid.json", "data/mru_tmp"); + + const std::string nonexistent("data/mru_tmp"); + agi::MRUManager mru(nonexistent, default_mru); + + // Make sure it didn't load from the file. + EXPECT_THROW(mru.Add("Invalid", "/path/to/file"), agi::MRUErrorInvalidKey); + EXPECT_NO_THROW(mru.Add("Valid_Int", "/path/to/file")); +} + +TEST_F(lagi_mru, MRUEntryAdd) { + util::copy("data/mru_ok.json", "data/mru_tmp"); + agi::MRUManager mru("data/mru_tmp", default_mru); + EXPECT_NO_THROW(mru.Add("Valid", "/path/to/file")); +} + +TEST_F(lagi_mru, MRUEntryRemove) { + util::copy("data/mru_ok.json", "data/mru_tmp"); + agi::MRUManager mru("data/mru_tmp", default_mru); + EXPECT_NO_THROW(mru.Add("Valid", "/path/to/file")); + EXPECT_NO_THROW(mru.Remove("Valid", "/path/to/file")); +} + +TEST_F(lagi_mru, MRUKeyInvalid) { + util::copy("data/mru_ok.json", "data/mru_tmp"); + agi::MRUManager mru("data/mru_tmp", default_mru); + EXPECT_THROW(mru.Add("Invalid", "/path/to/file"), agi::MRUErrorInvalidKey); +} + +TEST_F(lagi_mru, MRUKeyValid) { + util::copy("data/mru_ok.json", "data/mru_tmp"); + agi::MRUManager mru("data/mru_tmp", default_mru); + EXPECT_NO_THROW(mru.Add("Valid", "/path/to/file")); +} + diff --git a/aegisub/tests/libaegisub_option.cpp b/aegisub/tests/libaegisub_option.cpp new file mode 100644 index 000000000..0dd1bcf3b --- /dev/null +++ b/aegisub/tests/libaegisub_option.cpp @@ -0,0 +1,41 @@ + +// Copyright (c) 2010, Amar Takhar +// +// 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. +// +// $Id$ + +/// @file libaegisub_option.cpp +/// @brief Option class +/// @ingroup option + +#include +#include "main.h" +#include "util.h" + +class lagi_option : public libagi { +protected: + std::string default_opt; + std::string conf_ok; + + virtual void SetUp() { + default_opt = "{\"Valid\" : \"This is valid\"}"; + conf_ok = "./data/option_string.json"; + } +}; + + +TEST_F(lagi_option, OptionConstructFromFile) { + EXPECT_NO_THROW(agi::Options *opt = new agi::Options(conf_ok, default_opt)); +} + diff --git a/aegisub/tests/libaegisub_util.cpp b/aegisub/tests/libaegisub_util.cpp new file mode 100644 index 000000000..6c47fa81f --- /dev/null +++ b/aegisub/tests/libaegisub_util.cpp @@ -0,0 +1,70 @@ +// Copyright (c) 2010, Amar Takhar +// +// 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. +// +// $Id$ + +/// @file libaegisub_util.cpp +/// @brief agi::util (Utilities) +/// @ingroup util + +#include +#include +#include "main.h" + +class lagi_util : public libagi { +protected: +// placeholder +}; + + +namespace agi { + +TEST_F(lagi_util, UtilDirnameEmpty) { + EXPECT_STREQ(".", util::DirName("").c_str()); +} + +TEST_F(lagi_util, UtilDirnameNoTrailingSlash) { + EXPECT_STREQ(".", util::DirName("dot").c_str()); +} + +TEST_F(lagi_util, UtilDirnameRoot) { + EXPECT_STREQ("/", util::DirName("/").c_str()); +} + +TEST_F(lagi_util, UtilDirnameHeir) { + EXPECT_STREQ("/last/part/not_stripped/", util::DirName("/last/part/not_stripped/").c_str()); +} + +TEST_F(lagi_util, UtilDirnameHeirNoTrailingSlash) { + EXPECT_STREQ("/last/part/", util::DirName("/last/part/stripped").c_str()); +} + +TEST_F(lagi_util, UtilRenameOverwrite) { + util::Rename("./data/rename_me_overwrite", "./data/rename_me_overwrite_renamed"); + util::Rename("./data/rename_me_overwrite_renamed", "./data/rename_me_overwrite"); + std::ofstream fp_touch("./data/rename_me_overwrite_renamed"); +} + +TEST_F(lagi_util, UtilRenameNew) { + util::Rename("./data/rename_me", "./data/rename_me_renamed"); + util::Rename("./data/rename_me_renamed", "./data/rename_me"); +} + +TEST_F(lagi_util, UtilRenameExNotFound) { + EXPECT_THROW(util::Rename("./data/nonexistent", ""), acs::AcsNotFound); +} + + + +} // namespace agi diff --git a/aegisub/tests/main.cpp b/aegisub/tests/main.cpp new file mode 100644 index 000000000..54e935bd8 --- /dev/null +++ b/aegisub/tests/main.cpp @@ -0,0 +1,27 @@ +// Copyright (c) 2010, Amar Takhar +// +// 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. +// +// $Id$ + +/// @file main.cpp +/// @brief Main +/// @ingroup main + +#include + +int main(int argc, char **argv) { + ::testing::InitGoogleTest(&argc, argv); + return RUN_ALL_TESTS(); +} + diff --git a/aegisub/tests/main.h b/aegisub/tests/main.h new file mode 100644 index 000000000..078e231c9 --- /dev/null +++ b/aegisub/tests/main.h @@ -0,0 +1,34 @@ +// Copyright (c) 2010, Amar Takhar +// +// 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. +// +// $Id$ + +/// @file main.h +/// @brief Main header +/// @ingroup main + +#include + +/// A small macro to silence "unused variable" warnings. +#define unused(x) x = x + +namespace { + +class libagi : public ::testing::Test { +protected: + // place holder for future code placement +}; + +} // namespace + diff --git a/aegisub/tests/setup.sh b/aegisub/tests/setup.sh new file mode 100755 index 000000000..24fb6a980 --- /dev/null +++ b/aegisub/tests/setup.sh @@ -0,0 +1,40 @@ +chmod 664 data/* +rm -rf data +mkdir -p data + +touch data/file +mkdir data/dir + +touch data/file_access_denied +chmod 000 data/file_access_denied + +touch data/file_read_only +chmod 444 data/file_read_only + + +mkdir data/dir_access_denied +chmod 000 data/dir_access_denied + +mkdir data/dir_read_only +chmod 444 data/dir_read_only + +echo '{"Valid" : []}' > data/mru_ok.json + +echo '{"Invalid" : [1 3]}' > data/mru_invalid.json + +touch data/rename_me + +touch data/rename_me_overwrite +touch data/rename_me_overwrite_renamed + + +echo '{"String" : "This is a test"}' > data/option_string.json +echo '{"Integer" : 1}' > data/option_integer.json +echo '{"Double" : 2.1}' > data/option_double.json +echo '{"Bool" : true}' > data/option_bool.json +echo '{"Null" : null}' > data/option_null.json + +echo '{"String" : [{"string" : "This is a test"}, {"string" : "This is a test"}]}' > data/option_array_string +echo '{"Integer" : [{"int" : 1}, {"int" : 1}]}' > data/option_array_integer +echo '{"Double" : [{"double" : 2.1}, {"double" : 2.1}]}' > data/option_array_double +echo '{"Bool" : [{"bool" : true}, {"bool" : true}]}' > data/option_array_bool diff --git a/aegisub/tests/util.cpp b/aegisub/tests/util.cpp new file mode 100644 index 000000000..20a1285f8 --- /dev/null +++ b/aegisub/tests/util.cpp @@ -0,0 +1,39 @@ +// Copyright (c) 2010, Amar Takhar +// +// 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. +// +// $Id$ + +/// @file util.cpp +/// @brief Common utilities used in tests. +/// @ingroup util + +#include +#include + +namespace util { + +void copy(const std::string from, const std::string to) { + std::ifstream ifs(from.c_str(), std::ios::binary); + std::ofstream ofs(to.c_str(), std::ios::binary); + + ofs << ifs.rdbuf(); +} + +void remove(const std::string& file) { + unlink(file.c_str()); +} + +} // namespace util + + diff --git a/aegisub/tests/util.h b/aegisub/tests/util.h new file mode 100644 index 000000000..f57856edc --- /dev/null +++ b/aegisub/tests/util.h @@ -0,0 +1,28 @@ +// Copyright (c) 2010, Amar Takhar +// +// 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. +// +// $Id$ + +/// @file util.cpp +/// @brief Common utilities used in tests. +/// @ingroup util + +namespace util { + +void copy(const std::string from, const std::string to); +void remove(const std::string& file); + +} // namespace util + + diff --git a/aegisub/tinderbox/www/doxygen.sh b/aegisub/tinderbox/www/doxygen.sh index 63bd5e167..7c173b394 100755 --- a/aegisub/tinderbox/www/doxygen.sh +++ b/aegisub/tinderbox/www/doxygen.sh @@ -18,6 +18,9 @@ case "$1" in "reporter") OUTPUT="reporter" ;; + "libaegisub") + OUTPUT="libaegisub" + ;; esac cd docs/doxygen diff --git a/aegisub/tools/common_respack_packresources.vsprops b/aegisub/tools/common_respack_packresources.vsprops index 847119182..aa6b95dc5 100644 --- a/aegisub/tools/common_respack_packresources.vsprops +++ b/aegisub/tools/common_respack_packresources.vsprops @@ -6,6 +6,6 @@ >