settings_objects.cpp
1 #include "pch.h" 2 #include "settings_objects.h" 3 #include "settings_helpers.h" 4 5 namespace PowerToysSettings 6 { 7 Settings::Settings(const HINSTANCE hinstance, std::wstring_view powertoy_name) 8 { 9 m_instance = hinstance; 10 m_json.SetNamedValue(L"version", json::value(L"1.0")); 11 m_json.SetNamedValue(L"name", json::value(powertoy_name)); 12 m_json.SetNamedValue(L"properties", json::JsonObject{}); 13 } 14 15 void Settings::set_description(UINT resource_id) 16 { 17 m_json.SetNamedValue(L"description", json::value(get_resource(resource_id))); 18 } 19 20 void Settings::set_description(std::wstring_view description) 21 { 22 m_json.SetNamedValue(L"description", json::value(description)); 23 } 24 25 void Settings::set_icon_key(std::wstring_view icon_key) 26 { 27 m_json.SetNamedValue(L"icon_key", json::value(icon_key)); 28 } 29 30 void Settings::set_overview_link(std::wstring_view overview_link) 31 { 32 m_json.SetNamedValue(L"overview_link", json::value(overview_link)); 33 } 34 35 void Settings::set_video_link(std::wstring_view video_link) 36 { 37 m_json.SetNamedValue(L"video_link", json::value(video_link)); 38 } 39 40 // add_bool_toggle overloads. 41 void Settings::add_bool_toggle(std::wstring_view name, UINT description_resource_id, bool value) 42 { 43 add_bool_toggle(name, get_resource(description_resource_id), value); 44 } 45 46 void Settings::add_bool_toggle(std::wstring_view name, std::wstring_view description, bool value) 47 { 48 json::JsonObject toggle; 49 toggle.SetNamedValue(L"display_name", json::value(description)); 50 toggle.SetNamedValue(L"editor_type", json::value(L"bool_toggle")); 51 toggle.SetNamedValue(L"value", json::value(value)); 52 toggle.SetNamedValue(L"order", json::value(++m_curr_priority)); 53 54 m_json.GetNamedObject(L"properties").SetNamedValue(name, toggle); 55 } 56 57 // add_int_spinner overloads. 58 void Settings::add_int_spinner(std::wstring_view name, UINT description_resource_id, int value, int min, int max, int step) 59 { 60 add_int_spinner(name, get_resource(description_resource_id), value, min, max, step); 61 } 62 63 void Settings::add_int_spinner(std::wstring_view name, std::wstring_view description, int value, int min, int max, int step) 64 { 65 json::JsonObject spinner; 66 spinner.SetNamedValue(L"display_name", json::value(description)); 67 spinner.SetNamedValue(L"editor_type", json::value(L"int_spinner")); 68 spinner.SetNamedValue(L"value", json::value(value)); 69 spinner.SetNamedValue(L"min", json::value(min)); 70 spinner.SetNamedValue(L"max", json::value(max)); 71 spinner.SetNamedValue(L"step", json::value(step)); 72 spinner.SetNamedValue(L"order", json::value(++m_curr_priority)); 73 74 m_json.GetNamedObject(L"properties").SetNamedValue(name, spinner); 75 } 76 77 // add_string overloads. 78 void Settings::add_string(std::wstring_view name, UINT description_resource_id, std::wstring_view value) 79 { 80 add_string(name, get_resource(description_resource_id), value); 81 } 82 83 void Settings::add_string(std::wstring_view name, std::wstring_view description, std::wstring_view value) 84 { 85 json::JsonObject string; 86 string.SetNamedValue(L"display_name", json::value(description)); 87 string.SetNamedValue(L"editor_type", json::value(L"string_text")); 88 string.SetNamedValue(L"value", json::value(value)); 89 string.SetNamedValue(L"order", json::value(++m_curr_priority)); 90 91 m_json.GetNamedObject(L"properties").SetNamedValue(name, string); 92 } 93 94 // add_multiline_string overloads. 95 void Settings::add_multiline_string(std::wstring_view name, UINT description_resource_id, std::wstring_view value) 96 { 97 add_multiline_string(name, get_resource(description_resource_id), value); 98 } 99 100 void Settings::add_multiline_string(std::wstring_view name, std::wstring_view description, std::wstring_view value) 101 { 102 json::JsonObject ml_string; 103 ml_string.SetNamedValue(L"display_name", json::value(description)); 104 ml_string.SetNamedValue(L"editor_type", json::value(L"string_text")); 105 ml_string.SetNamedValue(L"value", json::value(value)); 106 ml_string.SetNamedValue(L"order", json::value(++m_curr_priority)); 107 ml_string.SetNamedValue(L"multiline", json::value(true)); 108 109 m_json.GetNamedObject(L"properties").SetNamedValue(name, ml_string); 110 } 111 112 void Settings::add_header_szLarge(std::wstring_view name, std::wstring_view description, std::wstring_view value) 113 { 114 json::JsonObject string; 115 string.SetNamedValue(L"display_name", json::value(description)); 116 string.SetNamedValue(L"editor_type", json::value(L"header_large")); 117 string.SetNamedValue(L"value", json::value(value)); 118 string.SetNamedValue(L"order", json::value(++m_curr_priority)); 119 120 m_json.GetNamedObject(L"properties").SetNamedValue(name, string); 121 } 122 123 // add_color_picker overloads. 124 void Settings::add_color_picker(std::wstring_view name, UINT description_resource_id, std::wstring_view value) 125 { 126 add_color_picker(name, get_resource(description_resource_id), value); 127 } 128 129 void Settings::add_color_picker(std::wstring_view name, std::wstring_view description, std::wstring_view value) 130 { 131 json::JsonObject picker; 132 picker.SetNamedValue(L"display_name", json::value(description)); 133 picker.SetNamedValue(L"editor_type", json::value(L"color_picker")); 134 picker.SetNamedValue(L"value", json::value(value)); 135 picker.SetNamedValue(L"order", json::value(++m_curr_priority)); 136 137 m_json.GetNamedObject(L"properties").SetNamedValue(name, picker); 138 } 139 140 void Settings::add_hotkey(std::wstring_view name, UINT description_resource_id, const HotkeyObject& hotkey) 141 { 142 add_hotkey(name, get_resource(description_resource_id), hotkey); 143 } 144 145 void Settings::add_hotkey(std::wstring_view name, std::wstring_view description, const HotkeyObject& hotkey_obj) 146 { 147 json::JsonObject hotkey; 148 hotkey.SetNamedValue(L"display_name", json::value(description)); 149 hotkey.SetNamedValue(L"editor_type", json::value(L"hotkey")); 150 hotkey.SetNamedValue(L"value", hotkey_obj.get_json()); 151 hotkey.SetNamedValue(L"order", json::value(++m_curr_priority)); 152 153 m_json.GetNamedObject(L"properties").SetNamedValue(name, hotkey); 154 } 155 156 void Settings::add_choice_group(std::wstring_view name, UINT description_resource_id, std::wstring_view value, const std::vector<std::pair<std::wstring, UINT>>& keys_and_text_ids) 157 { 158 std::vector<std::pair<std::wstring, std::wstring>> keys_and_texts; 159 keys_and_texts.reserve(keys_and_text_ids.size()); 160 for (const auto& kv : keys_and_text_ids) 161 { 162 keys_and_texts.emplace_back(kv.first, get_resource(kv.second)); 163 } 164 add_choice_group(name, get_resource(description_resource_id), value, keys_and_texts); 165 } 166 167 void Settings::add_choice_group(std::wstring_view name, std::wstring_view description, std::wstring_view value, const std::vector<std::pair<std::wstring, std::wstring>>& keys_and_texts) 168 { 169 json::JsonObject choice_group; 170 choice_group.SetNamedValue(L"display_name", json::value(description)); 171 choice_group.SetNamedValue(L"editor_type", json::value(L"choice_group")); 172 json::JsonArray options; 173 for (const auto& [key, text] : keys_and_texts) 174 { 175 json::JsonObject entry; 176 entry.SetNamedValue(L"key", json::value(key)); 177 entry.SetNamedValue(L"text", json::value(text)); 178 options.Append(std::move(entry)); 179 } 180 choice_group.SetNamedValue(L"options", std::move(options)); 181 choice_group.SetNamedValue(L"value", json::value(value)); 182 choice_group.SetNamedValue(L"order", json::value(++m_curr_priority)); 183 184 m_json.GetNamedObject(L"properties").SetNamedValue(name, choice_group); 185 } 186 187 void Settings::add_dropdown(std::wstring_view name, UINT description_resource_id, std::wstring_view value, const std::vector<std::pair<std::wstring, UINT>>& keys_and_text_ids) 188 { 189 std::vector<std::pair<std::wstring, std::wstring>> keys_and_texts; 190 keys_and_texts.reserve(keys_and_text_ids.size()); 191 for (const auto& kv : keys_and_text_ids) 192 { 193 keys_and_texts.emplace_back(kv.first, get_resource(kv.second)); 194 } 195 add_dropdown(name, get_resource(description_resource_id), value, keys_and_texts); 196 } 197 198 void Settings::add_dropdown(std::wstring_view name, std::wstring_view description, std::wstring_view value, const std::vector<std::pair<std::wstring, std::wstring>>& keys_and_texts) 199 { 200 json::JsonObject dropdown; 201 dropdown.SetNamedValue(L"display_name", json::value(description)); 202 dropdown.SetNamedValue(L"editor_type", json::value(L"dropdown")); 203 json::JsonArray options; 204 for (const auto& [key, text] : keys_and_texts) 205 { 206 json::JsonObject entry; 207 entry.SetNamedValue(L"key", json::value(key)); 208 entry.SetNamedValue(L"text", json::value(text)); 209 options.Append(std::move(entry)); 210 } 211 dropdown.SetNamedValue(L"options", std::move(options)); 212 dropdown.SetNamedValue(L"value", json::value(value)); 213 dropdown.SetNamedValue(L"order", json::value(++m_curr_priority)); 214 215 m_json.GetNamedObject(L"properties").SetNamedValue(name, dropdown); 216 } 217 218 // add_custom_action overloads. 219 void Settings::add_custom_action(std::wstring_view name, UINT description_resource_id, UINT button_text_resource_id, UINT ext_description_resource_id) 220 { 221 add_custom_action(name, get_resource(description_resource_id), get_resource(button_text_resource_id), get_resource(ext_description_resource_id)); 222 } 223 224 void Settings::add_custom_action(std::wstring_view name, UINT description_resource_id, UINT button_text_resource_id, std::wstring_view value) 225 { 226 add_custom_action(name, get_resource(description_resource_id), get_resource(button_text_resource_id), value); 227 } 228 229 void Settings::add_custom_action(std::wstring_view name, std::wstring_view description, std::wstring_view button_text, std::wstring_view value) 230 { 231 json::JsonObject custom_action; 232 custom_action.SetNamedValue(L"display_name", json::value(description)); 233 custom_action.SetNamedValue(L"button_text", json::value(button_text)); 234 custom_action.SetNamedValue(L"editor_type", json::value(L"custom_action")); 235 custom_action.SetNamedValue(L"value", json::value(value)); 236 custom_action.SetNamedValue(L"order", json::value(++m_curr_priority)); 237 238 m_json.GetNamedObject(L"properties").SetNamedValue(name, custom_action); 239 } 240 241 // Serialization methods. 242 std::wstring Settings::serialize() 243 { 244 return m_json.Stringify().c_str(); 245 } 246 247 bool Settings::serialize_to_buffer(wchar_t* buffer, int* buffer_size) 248 { 249 auto result = m_json.Stringify(); 250 const int result_len = static_cast<int>(result.size() + 1); 251 252 if (buffer == nullptr || *buffer_size < result_len) 253 { 254 *buffer_size = result_len; 255 return false; 256 } 257 else 258 { 259 wcscpy_s(buffer, *buffer_size, result.c_str()); 260 return true; 261 } 262 } 263 264 // Resource helper. 265 std::wstring Settings::get_resource(UINT resource_id) 266 { 267 if (resource_id != 0) 268 { 269 wchar_t* res_ptr; 270 const size_t resource_length = LoadStringW(m_instance, resource_id, reinterpret_cast<wchar_t*>(&res_ptr), 0); 271 if (resource_length != 0) 272 { 273 return { *reinterpret_cast<wchar_t**>(&res_ptr), resource_length }; 274 } 275 } 276 277 return L"RESOURCE ID NOT FOUND: " + std::to_wstring(resource_id); 278 } 279 280 PowerToyValues::PowerToyValues(std::wstring_view powertoy_name, std::wstring_view powertoy_key) 281 { 282 _key = powertoy_key; 283 set_version(); 284 m_json.SetNamedValue(L"name", json::value(powertoy_name)); 285 m_json.SetNamedValue(L"properties", json::JsonObject{}); 286 } 287 288 PowerToyValues PowerToyValues::from_json_string(std::wstring_view json, std::wstring_view powertoy_key) 289 { 290 PowerToyValues result = PowerToyValues(); 291 json::JsonObject jsonObject = json::JsonValue::Parse(json).GetObjectW(); 292 if (!jsonObject.HasKey(L"name")) 293 { 294 throw winrt::hresult_error(E_NOT_SET, L"name field not set"); 295 } 296 297 result.m_json = json::JsonValue::Parse(json).GetObjectW(); 298 result._key = powertoy_key; 299 return result; 300 } 301 302 PowerToyValues PowerToyValues::load_from_settings_file(std::wstring_view powertoy_key) 303 { 304 PowerToyValues result = PowerToyValues(); 305 result.m_json = PTSettingsHelper::load_module_settings(powertoy_key); 306 result._key = powertoy_key; 307 return result; 308 } 309 310 inline bool has_property(const json::JsonObject& o, std::wstring_view name, const json::JsonValueType type) 311 { 312 const json::JsonObject props = o.GetNamedObject(L"properties", json::JsonObject{}); 313 return json::has(props, name) && json::has(props.GetNamedObject(name), L"value", type); 314 } 315 316 std::optional<bool> PowerToyValues::get_bool_value(std::wstring_view property_name) const 317 { 318 if (!has_property(m_json, property_name, json::JsonValueType::Boolean)) 319 { 320 return std::nullopt; 321 } 322 return m_json.GetNamedObject(L"properties").GetNamedObject(property_name).GetNamedBoolean(L"value"); 323 } 324 325 std::optional<int> PowerToyValues::get_int_value(std::wstring_view property_name) const 326 { 327 if (!has_property(m_json, property_name, json::JsonValueType::Number)) 328 { 329 return std::nullopt; 330 } 331 return static_cast<int>(m_json.GetNamedObject(L"properties").GetNamedObject(property_name).GetNamedNumber(L"value")); 332 } 333 334 std::optional<unsigned int> PowerToyValues::get_uint_value(std::wstring_view property_name) const 335 { 336 if (!has_property(m_json, property_name, json::JsonValueType::Number)) 337 { 338 return std::nullopt; 339 } 340 return static_cast<unsigned int>(m_json.GetNamedObject(L"properties").GetNamedObject(property_name).GetNamedNumber(L"value")); 341 } 342 343 std::optional<std::wstring> PowerToyValues::get_string_value(std::wstring_view property_name) const 344 { 345 if (!has_property(m_json, property_name, json::JsonValueType::String)) 346 { 347 return std::nullopt; 348 } 349 return m_json.GetNamedObject(L"properties").GetNamedObject(property_name).GetNamedString(L"value").c_str(); 350 } 351 352 std::optional<json::JsonObject> PowerToyValues::get_json(std::wstring_view property_name) const 353 { 354 if (!has_property(m_json, property_name, json::JsonValueType::Object)) 355 { 356 return std::nullopt; 357 } 358 return m_json.GetNamedObject(L"properties").GetNamedObject(property_name).GetNamedObject(L"value"); 359 } 360 361 json::JsonObject PowerToyValues::get_raw_json() 362 { 363 return m_json; 364 } 365 366 std::wstring PowerToyValues::serialize() 367 { 368 set_version(); 369 return m_json.Stringify().c_str(); 370 } 371 372 void PowerToyValues::save_to_settings_file() 373 { 374 set_version(); 375 PTSettingsHelper::save_module_settings(_key, m_json); 376 } 377 378 void PowerToyValues::set_version() 379 { 380 m_json.SetNamedValue(L"version", json::value(m_version)); 381 } 382 }