From 6ca78038e5789e1a0a45db9f75526e68557ecb9c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=B1=85=E6=88=8E=E6=B0=8F?= Date: Fri, 24 Jun 2022 00:15:14 +0800 Subject: [PATCH] feat(key_binder): toggle the switch defined at index `toggle: '@n'` Closes #554 --- src/rime/gear/key_binder.cc | 23 ++++++++- src/rime/switches.cc | 93 ++++++++++++++++++++++--------------- src/rime/switches.h | 10 +++- 3 files changed, 86 insertions(+), 40 deletions(-) diff --git a/src/rime/gear/key_binder.cc b/src/rime/gear/key_binder.cc index 93ebc18fa..b5000fa53 100644 --- a/src/rime/gear/key_binder.cc +++ b/src/rime/gear/key_binder.cc @@ -5,6 +5,7 @@ // 2011-11-23 GONG Chen // #include +#include #include #include #include @@ -77,12 +78,27 @@ static void radio_select_option(Context* ctx, }); } +inline static bool is_switch_index(const string& option) { + return !option.empty() && option.front() == '@'; +} + +static Switches::SwitchOption switch_by_index(Switches& switches, + const string& option) { + try { + size_t index = boost::lexical_cast(option.substr(1)); + return switches.ByIndex(index); + } catch (...) {} + return {}; +} + static void toggle_option(Engine* engine, const string& option) { if (!engine) return; Context* ctx = engine->context(); Switches switches(engine->schema()->config()); - auto the_option = switches.OptionByName(option); + auto the_option = is_switch_index(option) + ? switch_by_index(switches, option) + : switches.OptionByName(option); if (the_option.found() && the_option.type == Switches::kRadioGroup) { auto selected_option = switches.FindRadioGroupOption( the_option.the_switch, @@ -102,7 +118,10 @@ static void toggle_option(Engine* engine, const string& option) { radio_select_option(ctx, next_option); } } else { // toggle - ctx->set_option(option, !ctx->get_option(option)); + // option can be an index. use the found option name, or an arbitrary + // option name specified by caller. + auto option_name = the_option.found() ? the_option.option_name : option; + ctx->set_option(option_name, !ctx->get_option(option_name)); } } diff --git a/src/rime/switches.cc b/src/rime/switches.cc index b023c8105..d7406b884 100644 --- a/src/rime/switches.cc +++ b/src/rime/switches.cc @@ -3,64 +3,83 @@ namespace rime { -Switches::SwitchOption Switches::FindOption( +inline static int reset_value(ConfigItemRef& item) { + auto reset = item["reset"]; + return reset.IsValue() ? reset.ToInt() : -1; +} + +Switches::SwitchOption Switches::FindOptionFromConfigItem( + ConfigItemRef& item, + size_t switch_index, function callback) { - auto switches = (*config_)["switches"]; - if (!switches.IsList()) - return {}; - for (size_t i = 0; i < switches.size(); ++i) { - auto item = switches[i]; - if (!item.IsMap()) - continue; - auto the_switch = As(*item); - auto reset = item["reset"]; - int reset_value = reset.IsValue() ? reset.ToInt() : -1; - auto name = item["name"]; - if (name.IsValue()) { + auto the_switch = As(*item); + auto name = item["name"]; + auto options = item["options"]; + if (name.IsValue()) { + SwitchOption option{ + the_switch, + kToggleOption, + name.ToString(), + reset_value(item), + switch_index, + }; + if (callback(option) == kFound) + return option; + } else if (options.IsList()) { + for (size_t option_index = 0; option_index < options.size(); + ++option_index) { SwitchOption option{ the_switch, - kToggleOption, - name.ToString(), - reset_value, - i, + kRadioGroup, + options[option_index].ToString(), + reset_value(item), + switch_index, + option_index, }; if (callback(option) == kFound) return option; - continue; - } - auto options = item["options"]; - if (options.IsList()) { - for (size_t j = 0; j < options.size(); ++j) { - SwitchOption option{ - the_switch, - kRadioGroup, - options[j].ToString(), - reset_value, - i, - j, - }; - if (callback(option) == kFound) - return option; - } } } return {}; } +Switches::SwitchOption Switches::FindOption( + function callback) { + auto switches = (*config_)["switches"]; + if (!switches.IsList()) + return {}; + for (size_t switch_index = 0; switch_index < switches.size(); + ++switch_index) { + auto item = switches[switch_index]; + if (!item.IsMap()) + continue; + auto option = FindOptionFromConfigItem(item, switch_index, callback); + if (option.found()) + return option; + } + return {}; +} + Switches::SwitchOption Switches::OptionByName(const string& option_name) { return FindOption([&option_name](SwitchOption option) { return option.option_name == option_name ? kFound : kContinue; }); } -an Switches::ByIndex(size_t switch_index) { +Switches::SwitchOption Switches::ByIndex(size_t switch_index) { auto switches = (*config_)["switches"]; if (!switches.IsList()) - return nullptr; + return {}; if (switches.size() <= switch_index) - return nullptr; + return {}; auto item = switches[switch_index]; - return As(*item); + return FindOptionFromConfigItem( + item, + switch_index, + // return the very first found option. + [](SwitchOption option) { + return kFound; + }); } Switches::SwitchOption Switches::Cycle(const SwitchOption& current) { diff --git a/src/rime/switches.h b/src/rime/switches.h index a17dd3e74..8b1dda5df 100644 --- a/src/rime/switches.h +++ b/src/rime/switches.h @@ -6,6 +6,7 @@ namespace rime { class Config; +class ConfigItemRef; class ConfigMap; class ConfigValue; @@ -43,7 +44,9 @@ class Switches { SwitchOption OptionByName(const string& option_name); - an ByIndex(size_t switch_index); + // Returns the switch option defined at switch_index. + // If the swtich is a radio group, return the first option in the group. + SwitchOption ByIndex(size_t switch_index); static SwitchOption Cycle(const SwitchOption& option); @@ -59,6 +62,11 @@ class Switches { an GetStateLabel(const string& option_name, int state); private: + SwitchOption FindOptionFromConfigItem( + ConfigItemRef& item, + size_t switch_index, + function callback); + Config* config_; };