mirror of
https://github.com/pound-emu/pound.git
synced 2025-12-23 16:37:00 +00:00
a
This commit is contained in:
parent
bc0f05735c
commit
824f59de3b
7 changed files with 2515 additions and 3 deletions
530
common/polyfill_ranges.h
Executable file
530
common/polyfill_ranges.h
Executable file
|
|
@ -0,0 +1,530 @@
|
||||||
|
// SPDX-FileCopyrightText: 2022 yuzu Emulator Project
|
||||||
|
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||||
|
|
||||||
|
//
|
||||||
|
// TODO: remove this file when ranges are supported by all compilation targets
|
||||||
|
//
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <algorithm>
|
||||||
|
#include <utility>
|
||||||
|
#include <version>
|
||||||
|
|
||||||
|
#ifndef __cpp_lib_ranges
|
||||||
|
|
||||||
|
namespace std {
|
||||||
|
namespace ranges {
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
concept range = requires(T& t) {
|
||||||
|
begin(t);
|
||||||
|
end(t);
|
||||||
|
};
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
concept input_range = range<T>;
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
concept output_range = range<T>;
|
||||||
|
|
||||||
|
template <range R>
|
||||||
|
using range_difference_t = ptrdiff_t;
|
||||||
|
|
||||||
|
//
|
||||||
|
// find, find_if, find_if_not
|
||||||
|
//
|
||||||
|
|
||||||
|
struct find_fn {
|
||||||
|
template <typename Iterator, typename T, typename Proj = std::identity>
|
||||||
|
constexpr Iterator operator()(Iterator first, Iterator last, const T& value,
|
||||||
|
Proj proj = {}) const {
|
||||||
|
for (; first != last; ++first) {
|
||||||
|
if (std::invoke(proj, *first) == value) {
|
||||||
|
return first;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return first;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <ranges::input_range R, typename T, typename Proj = std::identity>
|
||||||
|
constexpr ranges::iterator_t<R> operator()(R&& r, const T& value, Proj proj = {}) const {
|
||||||
|
return operator()(ranges::begin(r), ranges::end(r), value, std::ref(proj));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
struct find_if_fn {
|
||||||
|
template <typename Iterator, typename Proj = std::identity, typename Pred>
|
||||||
|
constexpr Iterator operator()(Iterator first, Iterator last, Pred pred, Proj proj = {}) const {
|
||||||
|
for (; first != last; ++first) {
|
||||||
|
if (std::invoke(pred, std::invoke(proj, *first))) {
|
||||||
|
return first;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return first;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <ranges::input_range R, typename Proj = std::identity, typename Pred>
|
||||||
|
constexpr ranges::iterator_t<R> operator()(R&& r, Pred pred, Proj proj = {}) const {
|
||||||
|
return operator()(ranges::begin(r), ranges::end(r), std::ref(pred), std::ref(proj));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
struct find_if_not_fn {
|
||||||
|
template <typename Iterator, typename Proj = std::identity, typename Pred>
|
||||||
|
constexpr Iterator operator()(Iterator first, Iterator last, Pred pred, Proj proj = {}) const {
|
||||||
|
for (; first != last; ++first) {
|
||||||
|
if (!std::invoke(pred, std::invoke(proj, *first))) {
|
||||||
|
return first;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return first;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <ranges::input_range R, typename Proj = std::identity, typename Pred>
|
||||||
|
constexpr ranges::iterator_t<R> operator()(R&& r, Pred pred, Proj proj = {}) const {
|
||||||
|
return operator()(ranges::begin(r), ranges::end(r), std::ref(pred), std::ref(proj));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
inline constexpr find_fn find;
|
||||||
|
inline constexpr find_if_fn find_if;
|
||||||
|
inline constexpr find_if_not_fn find_if_not;
|
||||||
|
|
||||||
|
//
|
||||||
|
// any_of, all_of, none_of
|
||||||
|
//
|
||||||
|
|
||||||
|
struct all_of_fn {
|
||||||
|
template <typename Iterator, typename Proj = std::identity, typename Pred>
|
||||||
|
constexpr bool operator()(Iterator first, Iterator last, Pred pred, Proj proj = {}) const {
|
||||||
|
return ranges::find_if_not(first, last, std::ref(pred), std::ref(proj)) == last;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <ranges::input_range R, typename Proj = std::identity, typename Pred>
|
||||||
|
constexpr bool operator()(R&& r, Pred pred, Proj proj = {}) const {
|
||||||
|
return operator()(ranges::begin(r), ranges::end(r), std::ref(pred), std::ref(proj));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
struct any_of_fn {
|
||||||
|
template <typename Iterator, typename Proj = std::identity, typename Pred>
|
||||||
|
constexpr bool operator()(Iterator first, Iterator last, Pred pred, Proj proj = {}) const {
|
||||||
|
return ranges::find_if(first, last, std::ref(pred), std::ref(proj)) != last;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <ranges::input_range R, typename Proj = std::identity, typename Pred>
|
||||||
|
constexpr bool operator()(R&& r, Pred pred, Proj proj = {}) const {
|
||||||
|
return operator()(ranges::begin(r), ranges::end(r), std::ref(pred), std::ref(proj));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
struct none_of_fn {
|
||||||
|
template <typename Iterator, typename Proj = std::identity, typename Pred>
|
||||||
|
constexpr bool operator()(Iterator first, Iterator last, Pred pred, Proj proj = {}) const {
|
||||||
|
return ranges::find_if(first, last, std::ref(pred), std::ref(proj)) == last;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <ranges::input_range R, typename Proj = std::identity, typename Pred>
|
||||||
|
constexpr bool operator()(R&& r, Pred pred, Proj proj = {}) const {
|
||||||
|
return operator()(ranges::begin(r), ranges::end(r), std::ref(pred), std::ref(proj));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
inline constexpr any_of_fn any_of;
|
||||||
|
inline constexpr all_of_fn all_of;
|
||||||
|
inline constexpr none_of_fn none_of;
|
||||||
|
|
||||||
|
//
|
||||||
|
// count, count_if
|
||||||
|
//
|
||||||
|
|
||||||
|
struct count_fn {
|
||||||
|
template <typename Iterator, typename T, typename Proj = std::identity>
|
||||||
|
constexpr ptrdiff_t operator()(Iterator first, Iterator last, const T& value,
|
||||||
|
Proj proj = {}) const {
|
||||||
|
ptrdiff_t counter = 0;
|
||||||
|
for (; first != last; ++first)
|
||||||
|
if (std::invoke(proj, *first) == value)
|
||||||
|
++counter;
|
||||||
|
return counter;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <ranges::input_range R, typename T, typename Proj = std::identity>
|
||||||
|
constexpr ptrdiff_t operator()(R&& r, const T& value, Proj proj = {}) const {
|
||||||
|
return operator()(ranges::begin(r), ranges::end(r), value, std::ref(proj));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
struct count_if_fn {
|
||||||
|
template <typename Iterator, typename Proj = std::identity, typename Pred>
|
||||||
|
constexpr ptrdiff_t operator()(Iterator first, Iterator last, Pred pred, Proj proj = {}) const {
|
||||||
|
ptrdiff_t counter = 0;
|
||||||
|
for (; first != last; ++first)
|
||||||
|
if (std::invoke(pred, std::invoke(proj, *first)))
|
||||||
|
++counter;
|
||||||
|
return counter;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <ranges::input_range R, typename Proj = std::identity, typename Pred>
|
||||||
|
constexpr ptrdiff_t operator()(R&& r, Pred pred, Proj proj = {}) const {
|
||||||
|
return operator()(ranges::begin(r), ranges::end(r), std::ref(pred), std::ref(proj));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
inline constexpr count_fn count;
|
||||||
|
inline constexpr count_if_fn count_if;
|
||||||
|
|
||||||
|
//
|
||||||
|
// transform
|
||||||
|
//
|
||||||
|
|
||||||
|
struct transform_fn {
|
||||||
|
template <typename InputIterator, typename OutputIterator, typename F,
|
||||||
|
typename Proj = std::identity>
|
||||||
|
constexpr void operator()(InputIterator first1, InputIterator last1, OutputIterator result,
|
||||||
|
F op, Proj proj = {}) const {
|
||||||
|
for (; first1 != last1; ++first1, (void)++result) {
|
||||||
|
*result = std::invoke(op, std::invoke(proj, *first1));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
template <ranges::input_range R, typename OutputIterator, typename F,
|
||||||
|
typename Proj = std::identity>
|
||||||
|
constexpr void operator()(R&& r, OutputIterator result, F op, Proj proj = {}) const {
|
||||||
|
return operator()(ranges::begin(r), ranges::end(r), result, std::ref(op), std::ref(proj));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
inline constexpr transform_fn transform;
|
||||||
|
|
||||||
|
//
|
||||||
|
// sort
|
||||||
|
//
|
||||||
|
|
||||||
|
struct sort_fn {
|
||||||
|
template <typename Iterator, typename Comp = ranges::less, typename Proj = std::identity>
|
||||||
|
constexpr void operator()(Iterator first, Iterator last, Comp comp = {}, Proj proj = {}) const {
|
||||||
|
if (first == last)
|
||||||
|
return;
|
||||||
|
|
||||||
|
Iterator last_iter = ranges::next(first, last);
|
||||||
|
std::sort(first, last_iter,
|
||||||
|
[&](auto& lhs, auto& rhs) { return comp(proj(lhs), proj(rhs)); });
|
||||||
|
}
|
||||||
|
|
||||||
|
template <ranges::input_range R, typename Comp = ranges::less, typename Proj = std::identity>
|
||||||
|
constexpr void operator()(R&& r, Comp comp = {}, Proj proj = {}) const {
|
||||||
|
return operator()(ranges::begin(r), ranges::end(r), std::move(comp), std::move(proj));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
inline constexpr sort_fn sort;
|
||||||
|
|
||||||
|
//
|
||||||
|
// fill
|
||||||
|
//
|
||||||
|
|
||||||
|
struct fill_fn {
|
||||||
|
template <typename T, typename OutputIterator>
|
||||||
|
constexpr OutputIterator operator()(OutputIterator first, OutputIterator last,
|
||||||
|
const T& value) const {
|
||||||
|
while (first != last) {
|
||||||
|
*first++ = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
return first;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T, ranges::output_range R>
|
||||||
|
constexpr ranges::iterator_t<R> operator()(R&& r, const T& value) const {
|
||||||
|
return operator()(ranges::begin(r), ranges::end(r), value);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
inline constexpr fill_fn fill;
|
||||||
|
|
||||||
|
//
|
||||||
|
// for_each
|
||||||
|
//
|
||||||
|
|
||||||
|
struct for_each_fn {
|
||||||
|
template <typename Iterator, typename Proj = std::identity, typename Fun>
|
||||||
|
constexpr void operator()(Iterator first, Iterator last, Fun f, Proj proj = {}) const {
|
||||||
|
for (; first != last; ++first) {
|
||||||
|
std::invoke(f, std::invoke(proj, *first));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
template <ranges::input_range R, typename Proj = std::identity, typename Fun>
|
||||||
|
constexpr void operator()(R&& r, Fun f, Proj proj = {}) const {
|
||||||
|
return operator()(ranges::begin(r), ranges::end(r), std::move(f), std::ref(proj));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
inline constexpr for_each_fn for_each;
|
||||||
|
|
||||||
|
//
|
||||||
|
// min_element, max_element
|
||||||
|
//
|
||||||
|
|
||||||
|
struct min_element_fn {
|
||||||
|
template <typename Iterator, typename Proj = std::identity, typename Comp = ranges::less>
|
||||||
|
constexpr Iterator operator()(Iterator first, Iterator last, Comp comp = {},
|
||||||
|
Proj proj = {}) const {
|
||||||
|
if (first == last) {
|
||||||
|
return last;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto smallest = first;
|
||||||
|
++first;
|
||||||
|
for (; first != last; ++first) {
|
||||||
|
if (!std::invoke(comp, std::invoke(proj, *smallest), std::invoke(proj, *first))) {
|
||||||
|
smallest = first;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return smallest;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <ranges::input_range R, typename Proj = std::identity, typename Comp = ranges::less>
|
||||||
|
constexpr ranges::iterator_t<R> operator()(R&& r, Comp comp = {}, Proj proj = {}) const {
|
||||||
|
return operator()(ranges::begin(r), ranges::end(r), std::ref(comp), std::ref(proj));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
struct max_element_fn {
|
||||||
|
template <typename Iterator, typename Proj = std::identity, typename Comp = ranges::less>
|
||||||
|
constexpr Iterator operator()(Iterator first, Iterator last, Comp comp = {},
|
||||||
|
Proj proj = {}) const {
|
||||||
|
if (first == last) {
|
||||||
|
return last;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto largest = first;
|
||||||
|
++first;
|
||||||
|
for (; first != last; ++first) {
|
||||||
|
if (std::invoke(comp, std::invoke(proj, *largest), std::invoke(proj, *first))) {
|
||||||
|
largest = first;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return largest;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <ranges::input_range R, typename Proj = std::identity, typename Comp = ranges::less>
|
||||||
|
constexpr ranges::iterator_t<R> operator()(R&& r, Comp comp = {}, Proj proj = {}) const {
|
||||||
|
return operator()(ranges::begin(r), ranges::end(r), std::ref(comp), std::ref(proj));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
inline constexpr min_element_fn min_element;
|
||||||
|
inline constexpr max_element_fn max_element;
|
||||||
|
|
||||||
|
//
|
||||||
|
// replace, replace_if
|
||||||
|
//
|
||||||
|
|
||||||
|
struct replace_fn {
|
||||||
|
template <typename Iterator, typename T1, typename T2, typename Proj = std::identity>
|
||||||
|
constexpr Iterator operator()(Iterator first, Iterator last, const T1& old_value,
|
||||||
|
const T2& new_value, Proj proj = {}) const {
|
||||||
|
for (; first != last; ++first) {
|
||||||
|
if (old_value == std::invoke(proj, *first)) {
|
||||||
|
*first = new_value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return first;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <ranges::input_range R, typename T1, typename T2, typename Proj = std::identity>
|
||||||
|
constexpr ranges::iterator_t<R> operator()(R&& r, const T1& old_value, const T2& new_value,
|
||||||
|
Proj proj = {}) const {
|
||||||
|
return operator()(ranges::begin(r), ranges::end(r), old_value, new_value, std::move(proj));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
struct replace_if_fn {
|
||||||
|
template <typename Iterator, typename T, typename Proj = std::identity, typename Pred>
|
||||||
|
constexpr Iterator operator()(Iterator first, Iterator last, Pred pred, const T& new_value,
|
||||||
|
Proj proj = {}) const {
|
||||||
|
for (; first != last; ++first) {
|
||||||
|
if (!!std::invoke(pred, std::invoke(proj, *first))) {
|
||||||
|
*first = new_value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return std::move(first);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <ranges::input_range R, typename T, typename Proj = std::identity, typename Pred>
|
||||||
|
constexpr ranges::iterator_t<R> operator()(R&& r, Pred pred, const T& new_value,
|
||||||
|
Proj proj = {}) const {
|
||||||
|
return operator()(ranges::begin(r), ranges::end(r), std::move(pred), new_value,
|
||||||
|
std::move(proj));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
inline constexpr replace_fn replace;
|
||||||
|
inline constexpr replace_if_fn replace_if;
|
||||||
|
|
||||||
|
//
|
||||||
|
// copy, copy_if
|
||||||
|
//
|
||||||
|
|
||||||
|
struct copy_fn {
|
||||||
|
template <typename InputIterator, typename OutputIterator>
|
||||||
|
constexpr void operator()(InputIterator first, InputIterator last,
|
||||||
|
OutputIterator result) const {
|
||||||
|
for (; first != last; ++first, (void)++result) {
|
||||||
|
*result = *first;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
template <ranges::input_range R, typename OutputIterator>
|
||||||
|
constexpr void operator()(R&& r, OutputIterator result) const {
|
||||||
|
return operator()(ranges::begin(r), ranges::end(r), std::move(result));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
struct copy_if_fn {
|
||||||
|
template <typename InputIterator, typename OutputIterator, typename Proj = std::identity,
|
||||||
|
typename Pred>
|
||||||
|
constexpr void operator()(InputIterator first, InputIterator last, OutputIterator result,
|
||||||
|
Pred pred, Proj proj = {}) const {
|
||||||
|
for (; first != last; ++first) {
|
||||||
|
if (std::invoke(pred, std::invoke(proj, *first))) {
|
||||||
|
*result = *first;
|
||||||
|
++result;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
template <ranges::input_range R, typename OutputIterator, typename Proj = std::identity,
|
||||||
|
typename Pred>
|
||||||
|
constexpr void operator()(R&& r, OutputIterator result, Pred pred, Proj proj = {}) const {
|
||||||
|
return operator()(ranges::begin(r), ranges::end(r), std::move(result), std::ref(pred),
|
||||||
|
std::ref(proj));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
inline constexpr copy_fn copy;
|
||||||
|
inline constexpr copy_if_fn copy_if;
|
||||||
|
|
||||||
|
//
|
||||||
|
// generate
|
||||||
|
//
|
||||||
|
|
||||||
|
struct generate_fn {
|
||||||
|
template <typename Iterator, typename F>
|
||||||
|
constexpr Iterator operator()(Iterator first, Iterator last, F gen) const {
|
||||||
|
for (; first != last; *first = std::invoke(gen), ++first)
|
||||||
|
;
|
||||||
|
return first;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename R, std::copy_constructible F>
|
||||||
|
requires std::invocable<F&> && ranges::output_range<R>
|
||||||
|
constexpr ranges::iterator_t<R> operator()(R&& r, F gen) const {
|
||||||
|
return operator()(ranges::begin(r), ranges::end(r), std::move(gen));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
inline constexpr generate_fn generate;
|
||||||
|
|
||||||
|
//
|
||||||
|
// lower_bound, upper_bound
|
||||||
|
//
|
||||||
|
|
||||||
|
struct lower_bound_fn {
|
||||||
|
template <typename Iterator, typename T, typename Proj = std::identity,
|
||||||
|
typename Comp = ranges::less>
|
||||||
|
constexpr Iterator operator()(Iterator first, Iterator last, const T& value, Comp comp = {},
|
||||||
|
Proj proj = {}) const {
|
||||||
|
Iterator it;
|
||||||
|
std::ptrdiff_t _count, _step;
|
||||||
|
_count = std::distance(first, last);
|
||||||
|
|
||||||
|
while (_count > 0) {
|
||||||
|
it = first;
|
||||||
|
_step = _count / 2;
|
||||||
|
ranges::advance(it, _step, last);
|
||||||
|
if (comp(std::invoke(proj, *it), value)) {
|
||||||
|
first = ++it;
|
||||||
|
_count -= _step + 1;
|
||||||
|
} else {
|
||||||
|
_count = _step;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return first;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <ranges::input_range R, typename T, typename Proj = std::identity,
|
||||||
|
typename Comp = ranges::less>
|
||||||
|
constexpr ranges::iterator_t<R> operator()(R&& r, const T& value, Comp comp = {},
|
||||||
|
Proj proj = {}) const {
|
||||||
|
return operator()(ranges::begin(r), ranges::end(r), value, std::ref(comp), std::ref(proj));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
struct upper_bound_fn {
|
||||||
|
template <typename Iterator, typename T, typename Proj = std::identity,
|
||||||
|
typename Comp = ranges::less>
|
||||||
|
constexpr Iterator operator()(Iterator first, Iterator last, const T& value, Comp comp = {},
|
||||||
|
Proj proj = {}) const {
|
||||||
|
Iterator it;
|
||||||
|
std::ptrdiff_t _count, _step;
|
||||||
|
_count = std::distance(first, last);
|
||||||
|
|
||||||
|
while (_count > 0) {
|
||||||
|
it = first;
|
||||||
|
_step = _count / 2;
|
||||||
|
ranges::advance(it, _step, last);
|
||||||
|
if (!comp(value, std::invoke(proj, *it))) {
|
||||||
|
first = ++it;
|
||||||
|
_count -= _step + 1;
|
||||||
|
} else {
|
||||||
|
_count = _step;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return first;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <ranges::input_range R, typename T, typename Proj = std::identity,
|
||||||
|
typename Comp = ranges::less>
|
||||||
|
constexpr ranges::iterator_t<R> operator()(R&& r, const T& value, Comp comp = {},
|
||||||
|
Proj proj = {}) const {
|
||||||
|
return operator()(ranges::begin(r), ranges::end(r), value, std::ref(comp), std::ref(proj));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
inline constexpr lower_bound_fn lower_bound;
|
||||||
|
inline constexpr upper_bound_fn upper_bound;
|
||||||
|
|
||||||
|
//
|
||||||
|
// adjacent_find
|
||||||
|
//
|
||||||
|
|
||||||
|
struct adjacent_find_fn {
|
||||||
|
template <typename Iterator, typename Proj = std::identity, typename Pred = ranges::equal_to>
|
||||||
|
constexpr Iterator operator()(Iterator first, Iterator last, Pred pred = {},
|
||||||
|
Proj proj = {}) const {
|
||||||
|
if (first == last)
|
||||||
|
return first;
|
||||||
|
auto _next = ranges::next(first);
|
||||||
|
for (; _next != last; ++_next, ++first)
|
||||||
|
if (std::invoke(pred, std::invoke(proj, *first), std::invoke(proj, *_next)))
|
||||||
|
return first;
|
||||||
|
return _next;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <ranges::input_range R, typename Proj = std::identity,
|
||||||
|
typename Pred = ranges::equal_to>
|
||||||
|
constexpr ranges::iterator_t<R> operator()(R&& r, Pred pred = {}, Proj proj = {}) const {
|
||||||
|
return operator()(ranges::begin(r), ranges::end(r), std::ref(pred), std::ref(proj));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
inline constexpr adjacent_find_fn adjacent_find;
|
||||||
|
|
||||||
|
} // namespace ranges
|
||||||
|
} // namespace std
|
||||||
|
|
||||||
|
#endif
|
||||||
650
common/settings.h
Executable file
650
common/settings.h
Executable file
|
|
@ -0,0 +1,650 @@
|
||||||
|
// SPDX-FileCopyrightText: Copyright 2021 yuzu Emulator Project
|
||||||
|
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <algorithm>
|
||||||
|
#include <array>
|
||||||
|
#include <map>
|
||||||
|
#include <memory>
|
||||||
|
#include <stdexcept>
|
||||||
|
#include <string>
|
||||||
|
#include <utility>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
#include "common_types.h"
|
||||||
|
#include "settings_common.h"
|
||||||
|
#include "settings_enums.h"
|
||||||
|
#include "settings_input.h"
|
||||||
|
#include "settings_setting.h"
|
||||||
|
|
||||||
|
namespace Settings {
|
||||||
|
|
||||||
|
const char* TranslateCategory(Settings::Category category);
|
||||||
|
|
||||||
|
struct ResolutionScalingInfo {
|
||||||
|
u32 up_scale{1};
|
||||||
|
u32 down_shift{0};
|
||||||
|
f32 up_factor{1.0f};
|
||||||
|
f32 down_factor{1.0f};
|
||||||
|
bool active{};
|
||||||
|
bool downscale{};
|
||||||
|
|
||||||
|
s32 ScaleUp(s32 value) const {
|
||||||
|
if (value == 0) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
return std::max((value * static_cast<s32>(up_scale)) >> static_cast<s32>(down_shift), 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
u32 ScaleUp(u32 value) const {
|
||||||
|
if (value == 0U) {
|
||||||
|
return 0U;
|
||||||
|
}
|
||||||
|
return std::max((value * up_scale) >> down_shift, 1U);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
#ifndef CANNOT_EXPLICITLY_INSTANTIATE
|
||||||
|
// Instantiate the classes elsewhere (settings.cpp) to reduce compiler/linker work
|
||||||
|
#define SETTING(TYPE, RANGED) extern template class Setting<TYPE, RANGED>
|
||||||
|
#define SWITCHABLE(TYPE, RANGED) extern template class SwitchableSetting<TYPE, RANGED>
|
||||||
|
|
||||||
|
SETTING(AudioEngine, false);
|
||||||
|
SETTING(bool, false);
|
||||||
|
SETTING(int, false);
|
||||||
|
SETTING(s32, false);
|
||||||
|
SETTING(std::string, false);
|
||||||
|
SETTING(std::string, false);
|
||||||
|
SETTING(u16, false);
|
||||||
|
SWITCHABLE(AnisotropyMode, true);
|
||||||
|
SWITCHABLE(AntiAliasing, false);
|
||||||
|
SWITCHABLE(AspectRatio, true);
|
||||||
|
SWITCHABLE(AstcDecodeMode, true);
|
||||||
|
SWITCHABLE(AstcRecompression, true);
|
||||||
|
SWITCHABLE(AudioMode, true);
|
||||||
|
SWITCHABLE(CpuBackend, true);
|
||||||
|
SWITCHABLE(CpuAccuracy, true);
|
||||||
|
SWITCHABLE(FullscreenMode, true);
|
||||||
|
SWITCHABLE(GpuAccuracy, true);
|
||||||
|
SWITCHABLE(Language, true);
|
||||||
|
SWITCHABLE(MemoryLayout, true);
|
||||||
|
SWITCHABLE(NvdecEmulation, false);
|
||||||
|
SWITCHABLE(Region, true);
|
||||||
|
SWITCHABLE(RendererBackend, true);
|
||||||
|
SWITCHABLE(ScalingFilter, false);
|
||||||
|
SWITCHABLE(ShaderBackend, true);
|
||||||
|
SWITCHABLE(TimeZone, true);
|
||||||
|
SETTING(VSyncMode, true);
|
||||||
|
SWITCHABLE(bool, false);
|
||||||
|
SWITCHABLE(int, false);
|
||||||
|
SWITCHABLE(int, true);
|
||||||
|
SWITCHABLE(s64, false);
|
||||||
|
SWITCHABLE(u16, true);
|
||||||
|
SWITCHABLE(u32, false);
|
||||||
|
SWITCHABLE(u8, false);
|
||||||
|
SWITCHABLE(u8, true);
|
||||||
|
|
||||||
|
// Used in UISettings
|
||||||
|
// TODO see if we can move this to uisettings.h
|
||||||
|
SWITCHABLE(ConfirmStop, true);
|
||||||
|
|
||||||
|
#undef SETTING
|
||||||
|
#undef SWITCHABLE
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The InputSetting class allows for getting a reference to either the global or custom members.
|
||||||
|
* This is required as we cannot easily modify the values of user-defined types within containers
|
||||||
|
* using the SetValue() member function found in the Setting class. The primary purpose of this
|
||||||
|
* class is to store an array of 10 PlayerInput structs for both the global and custom setting and
|
||||||
|
* allows for easily accessing and modifying both settings.
|
||||||
|
*/
|
||||||
|
template <typename Type>
|
||||||
|
class InputSetting final {
|
||||||
|
public:
|
||||||
|
InputSetting() = default;
|
||||||
|
explicit InputSetting(Type val) : Setting<Type>(val) {}
|
||||||
|
~InputSetting() = default;
|
||||||
|
void SetGlobal(bool to_global) {
|
||||||
|
use_global = to_global;
|
||||||
|
}
|
||||||
|
[[nodiscard]] bool UsingGlobal() const {
|
||||||
|
return use_global;
|
||||||
|
}
|
||||||
|
[[nodiscard]] Type& GetValue(bool need_global = false) {
|
||||||
|
if (use_global || need_global) {
|
||||||
|
return global;
|
||||||
|
}
|
||||||
|
return custom;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
bool use_global{true}; ///< The setting's global state
|
||||||
|
Type global{}; ///< The setting
|
||||||
|
Type custom{}; ///< The custom setting value
|
||||||
|
};
|
||||||
|
|
||||||
|
struct TouchFromButtonMap {
|
||||||
|
std::string name;
|
||||||
|
std::vector<std::string> buttons;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct Values {
|
||||||
|
Linkage linkage{};
|
||||||
|
|
||||||
|
// Applet
|
||||||
|
Setting<AppletMode> cabinet_applet_mode{linkage, AppletMode::LLE, "cabinet_applet_mode",
|
||||||
|
Category::LibraryApplet};
|
||||||
|
Setting<AppletMode> controller_applet_mode{linkage, AppletMode::HLE, "controller_applet_mode",
|
||||||
|
Category::LibraryApplet};
|
||||||
|
Setting<AppletMode> data_erase_applet_mode{linkage, AppletMode::HLE, "data_erase_applet_mode",
|
||||||
|
Category::LibraryApplet};
|
||||||
|
Setting<AppletMode> error_applet_mode{linkage, AppletMode::LLE, "error_applet_mode",
|
||||||
|
Category::LibraryApplet};
|
||||||
|
Setting<AppletMode> net_connect_applet_mode{linkage, AppletMode::HLE, "net_connect_applet_mode",
|
||||||
|
Category::LibraryApplet};
|
||||||
|
Setting<AppletMode> player_select_applet_mode{
|
||||||
|
linkage, AppletMode::HLE, "player_select_applet_mode", Category::LibraryApplet};
|
||||||
|
Setting<AppletMode> swkbd_applet_mode{linkage, AppletMode::LLE, "swkbd_applet_mode",
|
||||||
|
Category::LibraryApplet};
|
||||||
|
Setting<AppletMode> mii_edit_applet_mode{linkage, AppletMode::LLE, "mii_edit_applet_mode",
|
||||||
|
Category::LibraryApplet};
|
||||||
|
Setting<AppletMode> web_applet_mode{linkage, AppletMode::HLE, "web_applet_mode",
|
||||||
|
Category::LibraryApplet};
|
||||||
|
Setting<AppletMode> shop_applet_mode{linkage, AppletMode::HLE, "shop_applet_mode",
|
||||||
|
Category::LibraryApplet};
|
||||||
|
Setting<AppletMode> photo_viewer_applet_mode{
|
||||||
|
linkage, AppletMode::LLE, "photo_viewer_applet_mode", Category::LibraryApplet};
|
||||||
|
Setting<AppletMode> offline_web_applet_mode{linkage, AppletMode::LLE, "offline_web_applet_mode",
|
||||||
|
Category::LibraryApplet};
|
||||||
|
Setting<AppletMode> login_share_applet_mode{linkage, AppletMode::HLE, "login_share_applet_mode",
|
||||||
|
Category::LibraryApplet};
|
||||||
|
Setting<AppletMode> wifi_web_auth_applet_mode{
|
||||||
|
linkage, AppletMode::HLE, "wifi_web_auth_applet_mode", Category::LibraryApplet};
|
||||||
|
Setting<AppletMode> my_page_applet_mode{linkage, AppletMode::LLE, "my_page_applet_mode",
|
||||||
|
Category::LibraryApplet};
|
||||||
|
|
||||||
|
// Audio
|
||||||
|
SwitchableSetting<AudioEngine> sink_id{linkage, AudioEngine::Auto, "output_engine",
|
||||||
|
Category::Audio, Specialization::RuntimeList};
|
||||||
|
SwitchableSetting<std::string> audio_output_device_id{
|
||||||
|
linkage, "auto", "output_device", Category::Audio, Specialization::RuntimeList};
|
||||||
|
SwitchableSetting<std::string> audio_input_device_id{
|
||||||
|
linkage, "auto", "input_device", Category::Audio, Specialization::RuntimeList};
|
||||||
|
SwitchableSetting<AudioMode, true> sound_index{
|
||||||
|
linkage, AudioMode::Stereo, AudioMode::Mono, AudioMode::Surround,
|
||||||
|
"sound_index", Category::SystemAudio, Specialization::Default, true,
|
||||||
|
true};
|
||||||
|
SwitchableSetting<u8, true> volume{linkage,
|
||||||
|
100,
|
||||||
|
0,
|
||||||
|
200,
|
||||||
|
"volume",
|
||||||
|
Category::Audio,
|
||||||
|
Specialization::Scalar | Specialization::Percentage,
|
||||||
|
true,
|
||||||
|
true};
|
||||||
|
Setting<bool, false> audio_muted{
|
||||||
|
linkage, false, "audio_muted", Category::Audio, Specialization::Default, true, true};
|
||||||
|
Setting<bool, false> dump_audio_commands{
|
||||||
|
linkage, false, "dump_audio_commands", Category::Audio, Specialization::Default, false};
|
||||||
|
|
||||||
|
// Core
|
||||||
|
SwitchableSetting<bool> use_multi_core{linkage, true, "use_multi_core", Category::Core};
|
||||||
|
SwitchableSetting<MemoryLayout, true> memory_layout_mode{linkage,
|
||||||
|
MemoryLayout::Memory_4Gb,
|
||||||
|
MemoryLayout::Memory_4Gb,
|
||||||
|
MemoryLayout::Memory_8Gb,
|
||||||
|
"memory_layout_mode",
|
||||||
|
Category::Core};
|
||||||
|
SwitchableSetting<bool> use_speed_limit{
|
||||||
|
linkage, true, "use_speed_limit", Category::Core, Specialization::Paired, false, true};
|
||||||
|
SwitchableSetting<u16, true> speed_limit{linkage,
|
||||||
|
100,
|
||||||
|
0,
|
||||||
|
9999,
|
||||||
|
"speed_limit",
|
||||||
|
Category::Core,
|
||||||
|
Specialization::Countable | Specialization::Percentage,
|
||||||
|
true,
|
||||||
|
true,
|
||||||
|
&use_speed_limit};
|
||||||
|
|
||||||
|
// Cpu
|
||||||
|
SwitchableSetting<CpuBackend, true> cpu_backend{linkage,
|
||||||
|
#ifdef HAS_NCE
|
||||||
|
CpuBackend::Nce,
|
||||||
|
#else
|
||||||
|
CpuBackend::Dynarmic,
|
||||||
|
#endif
|
||||||
|
CpuBackend::Dynarmic,
|
||||||
|
#ifdef HAS_NCE
|
||||||
|
CpuBackend::Nce,
|
||||||
|
#else
|
||||||
|
CpuBackend::Dynarmic,
|
||||||
|
#endif
|
||||||
|
"cpu_backend",
|
||||||
|
Category::Cpu};
|
||||||
|
SwitchableSetting<CpuAccuracy, true> cpu_accuracy{linkage, CpuAccuracy::Auto,
|
||||||
|
CpuAccuracy::Auto, CpuAccuracy::Paranoid,
|
||||||
|
"cpu_accuracy", Category::Cpu};
|
||||||
|
SwitchableSetting<bool> cpu_debug_mode{linkage, false, "cpu_debug_mode", Category::CpuDebug};
|
||||||
|
|
||||||
|
Setting<bool> cpuopt_page_tables{linkage, true, "cpuopt_page_tables", Category::CpuDebug};
|
||||||
|
Setting<bool> cpuopt_block_linking{linkage, true, "cpuopt_block_linking", Category::CpuDebug};
|
||||||
|
Setting<bool> cpuopt_return_stack_buffer{linkage, true, "cpuopt_return_stack_buffer",
|
||||||
|
Category::CpuDebug};
|
||||||
|
Setting<bool> cpuopt_fast_dispatcher{linkage, true, "cpuopt_fast_dispatcher",
|
||||||
|
Category::CpuDebug};
|
||||||
|
Setting<bool> cpuopt_context_elimination{linkage, true, "cpuopt_context_elimination",
|
||||||
|
Category::CpuDebug};
|
||||||
|
Setting<bool> cpuopt_const_prop{linkage, true, "cpuopt_const_prop", Category::CpuDebug};
|
||||||
|
Setting<bool> cpuopt_misc_ir{linkage, true, "cpuopt_misc_ir", Category::CpuDebug};
|
||||||
|
Setting<bool> cpuopt_reduce_misalign_checks{linkage, true, "cpuopt_reduce_misalign_checks",
|
||||||
|
Category::CpuDebug};
|
||||||
|
SwitchableSetting<bool> cpuopt_fastmem{linkage, true, "cpuopt_fastmem", Category::CpuDebug};
|
||||||
|
SwitchableSetting<bool> cpuopt_fastmem_exclusives{linkage, true, "cpuopt_fastmem_exclusives",
|
||||||
|
Category::CpuDebug};
|
||||||
|
Setting<bool> cpuopt_recompile_exclusives{linkage, true, "cpuopt_recompile_exclusives",
|
||||||
|
Category::CpuDebug};
|
||||||
|
Setting<bool> cpuopt_ignore_memory_aborts{linkage, true, "cpuopt_ignore_memory_aborts",
|
||||||
|
Category::CpuDebug};
|
||||||
|
|
||||||
|
SwitchableSetting<bool> cpuopt_unsafe_unfuse_fma{linkage, true, "cpuopt_unsafe_unfuse_fma",
|
||||||
|
Category::CpuUnsafe};
|
||||||
|
SwitchableSetting<bool> cpuopt_unsafe_reduce_fp_error{
|
||||||
|
linkage, true, "cpuopt_unsafe_reduce_fp_error", Category::CpuUnsafe};
|
||||||
|
SwitchableSetting<bool> cpuopt_unsafe_ignore_standard_fpcr{
|
||||||
|
linkage, true, "cpuopt_unsafe_ignore_standard_fpcr", Category::CpuUnsafe};
|
||||||
|
SwitchableSetting<bool> cpuopt_unsafe_inaccurate_nan{
|
||||||
|
linkage, true, "cpuopt_unsafe_inaccurate_nan", Category::CpuUnsafe};
|
||||||
|
SwitchableSetting<bool> cpuopt_unsafe_fastmem_check{
|
||||||
|
linkage, true, "cpuopt_unsafe_fastmem_check", Category::CpuUnsafe};
|
||||||
|
SwitchableSetting<bool> cpuopt_unsafe_ignore_global_monitor{
|
||||||
|
linkage, true, "cpuopt_unsafe_ignore_global_monitor", Category::CpuUnsafe};
|
||||||
|
|
||||||
|
// Renderer
|
||||||
|
SwitchableSetting<RendererBackend, true> renderer_backend{
|
||||||
|
linkage, RendererBackend::Vulkan, RendererBackend::OpenGL, RendererBackend::Null,
|
||||||
|
"backend", Category::Renderer};
|
||||||
|
SwitchableSetting<ShaderBackend, true> shader_backend{
|
||||||
|
linkage, ShaderBackend::Glsl, ShaderBackend::Glsl, ShaderBackend::SpirV,
|
||||||
|
"shader_backend", Category::Renderer, Specialization::RuntimeList};
|
||||||
|
SwitchableSetting<int> vulkan_device{linkage, 0, "vulkan_device", Category::Renderer,
|
||||||
|
Specialization::RuntimeList};
|
||||||
|
|
||||||
|
SwitchableSetting<bool> use_disk_shader_cache{linkage, true, "use_disk_shader_cache",
|
||||||
|
Category::Renderer};
|
||||||
|
SwitchableSetting<bool> use_asynchronous_gpu_emulation{
|
||||||
|
linkage, true, "use_asynchronous_gpu_emulation", Category::Renderer};
|
||||||
|
SwitchableSetting<AstcDecodeMode, true> accelerate_astc{linkage,
|
||||||
|
#ifdef ANDROID
|
||||||
|
AstcDecodeMode::Cpu,
|
||||||
|
#else
|
||||||
|
AstcDecodeMode::Gpu,
|
||||||
|
#endif
|
||||||
|
AstcDecodeMode::Cpu,
|
||||||
|
AstcDecodeMode::CpuAsynchronous,
|
||||||
|
"accelerate_astc",
|
||||||
|
Category::Renderer};
|
||||||
|
SwitchableSetting<VSyncMode, true> vsync_mode{
|
||||||
|
linkage, VSyncMode::Fifo, VSyncMode::Immediate, VSyncMode::FifoRelaxed,
|
||||||
|
"use_vsync", Category::Renderer, Specialization::RuntimeList, true,
|
||||||
|
true};
|
||||||
|
SwitchableSetting<NvdecEmulation> nvdec_emulation{linkage, NvdecEmulation::Gpu,
|
||||||
|
"nvdec_emulation", Category::Renderer};
|
||||||
|
// *nix platforms may have issues with the borderless windowed fullscreen mode.
|
||||||
|
// Default to exclusive fullscreen on these platforms for now.
|
||||||
|
SwitchableSetting<FullscreenMode, true> fullscreen_mode{linkage,
|
||||||
|
#ifdef _WIN32
|
||||||
|
FullscreenMode::Borderless,
|
||||||
|
#else
|
||||||
|
FullscreenMode::Exclusive,
|
||||||
|
#endif
|
||||||
|
FullscreenMode::Borderless,
|
||||||
|
FullscreenMode::Exclusive,
|
||||||
|
"fullscreen_mode",
|
||||||
|
Category::Renderer,
|
||||||
|
Specialization::Default,
|
||||||
|
true,
|
||||||
|
true};
|
||||||
|
SwitchableSetting<AspectRatio, true> aspect_ratio{linkage,
|
||||||
|
AspectRatio::R16_9,
|
||||||
|
AspectRatio::R16_9,
|
||||||
|
AspectRatio::Stretch,
|
||||||
|
"aspect_ratio",
|
||||||
|
Category::Renderer,
|
||||||
|
Specialization::Default,
|
||||||
|
true,
|
||||||
|
true};
|
||||||
|
|
||||||
|
ResolutionScalingInfo resolution_info{};
|
||||||
|
SwitchableSetting<ResolutionSetup> resolution_setup{linkage, ResolutionSetup::Res1X,
|
||||||
|
"resolution_setup", Category::Renderer};
|
||||||
|
SwitchableSetting<ScalingFilter> scaling_filter{linkage,
|
||||||
|
ScalingFilter::Bilinear,
|
||||||
|
"scaling_filter",
|
||||||
|
Category::Renderer,
|
||||||
|
Specialization::Default,
|
||||||
|
true,
|
||||||
|
true};
|
||||||
|
SwitchableSetting<AntiAliasing> anti_aliasing{linkage,
|
||||||
|
AntiAliasing::None,
|
||||||
|
"anti_aliasing",
|
||||||
|
Category::Renderer,
|
||||||
|
Specialization::Default,
|
||||||
|
true,
|
||||||
|
true};
|
||||||
|
SwitchableSetting<int, true> fsr_sharpening_slider{linkage,
|
||||||
|
25,
|
||||||
|
0,
|
||||||
|
200,
|
||||||
|
"fsr_sharpening_slider",
|
||||||
|
Category::Renderer,
|
||||||
|
Specialization::Scalar |
|
||||||
|
Specialization::Percentage,
|
||||||
|
true,
|
||||||
|
true};
|
||||||
|
|
||||||
|
SwitchableSetting<u8, false> bg_red{
|
||||||
|
linkage, 0, "bg_red", Category::Renderer, Specialization::Default, true, true};
|
||||||
|
SwitchableSetting<u8, false> bg_green{
|
||||||
|
linkage, 0, "bg_green", Category::Renderer, Specialization::Default, true, true};
|
||||||
|
SwitchableSetting<u8, false> bg_blue{
|
||||||
|
linkage, 0, "bg_blue", Category::Renderer, Specialization::Default, true, true};
|
||||||
|
|
||||||
|
SwitchableSetting<GpuAccuracy, true> gpu_accuracy{linkage,
|
||||||
|
#ifdef ANDROID
|
||||||
|
GpuAccuracy::Normal,
|
||||||
|
#else
|
||||||
|
GpuAccuracy::High,
|
||||||
|
#endif
|
||||||
|
GpuAccuracy::Normal,
|
||||||
|
GpuAccuracy::Extreme,
|
||||||
|
"gpu_accuracy",
|
||||||
|
Category::RendererAdvanced,
|
||||||
|
Specialization::Default,
|
||||||
|
true,
|
||||||
|
true};
|
||||||
|
GpuAccuracy current_gpu_accuracy{GpuAccuracy::High};
|
||||||
|
SwitchableSetting<AnisotropyMode, true> max_anisotropy{linkage,
|
||||||
|
#ifdef ANDROID
|
||||||
|
AnisotropyMode::Default,
|
||||||
|
#else
|
||||||
|
AnisotropyMode::Automatic,
|
||||||
|
#endif
|
||||||
|
AnisotropyMode::Automatic,
|
||||||
|
AnisotropyMode::X16,
|
||||||
|
"max_anisotropy",
|
||||||
|
Category::RendererAdvanced};
|
||||||
|
SwitchableSetting<AstcRecompression, true> astc_recompression{linkage,
|
||||||
|
AstcRecompression::Uncompressed,
|
||||||
|
AstcRecompression::Uncompressed,
|
||||||
|
AstcRecompression::Bc3,
|
||||||
|
"astc_recompression",
|
||||||
|
Category::RendererAdvanced};
|
||||||
|
SwitchableSetting<VramUsageMode, true> vram_usage_mode{linkage,
|
||||||
|
VramUsageMode::Conservative,
|
||||||
|
VramUsageMode::Conservative,
|
||||||
|
VramUsageMode::Aggressive,
|
||||||
|
"vram_usage_mode",
|
||||||
|
Category::RendererAdvanced};
|
||||||
|
SwitchableSetting<bool> async_presentation{linkage,
|
||||||
|
#ifdef ANDROID
|
||||||
|
true,
|
||||||
|
#else
|
||||||
|
false,
|
||||||
|
#endif
|
||||||
|
"async_presentation", Category::RendererAdvanced};
|
||||||
|
SwitchableSetting<bool> renderer_force_max_clock{linkage, false, "force_max_clock",
|
||||||
|
Category::RendererAdvanced};
|
||||||
|
SwitchableSetting<bool> use_reactive_flushing{linkage,
|
||||||
|
#ifdef ANDROID
|
||||||
|
false,
|
||||||
|
#else
|
||||||
|
true,
|
||||||
|
#endif
|
||||||
|
"use_reactive_flushing",
|
||||||
|
Category::RendererAdvanced};
|
||||||
|
SwitchableSetting<bool> use_asynchronous_shaders{linkage, false, "use_asynchronous_shaders",
|
||||||
|
Category::RendererAdvanced};
|
||||||
|
SwitchableSetting<bool> use_fast_gpu_time{
|
||||||
|
linkage, true, "use_fast_gpu_time", Category::RendererAdvanced, Specialization::Default,
|
||||||
|
true, true};
|
||||||
|
SwitchableSetting<bool> use_vulkan_driver_pipeline_cache{linkage,
|
||||||
|
true,
|
||||||
|
"use_vulkan_driver_pipeline_cache",
|
||||||
|
Category::RendererAdvanced,
|
||||||
|
Specialization::Default,
|
||||||
|
true,
|
||||||
|
true};
|
||||||
|
SwitchableSetting<bool> enable_compute_pipelines{linkage, false, "enable_compute_pipelines",
|
||||||
|
Category::RendererAdvanced};
|
||||||
|
SwitchableSetting<bool> use_video_framerate{linkage, false, "use_video_framerate",
|
||||||
|
Category::RendererAdvanced};
|
||||||
|
SwitchableSetting<bool> barrier_feedback_loops{linkage, true, "barrier_feedback_loops",
|
||||||
|
Category::RendererAdvanced};
|
||||||
|
|
||||||
|
Setting<bool> renderer_debug{linkage, false, "debug", Category::RendererDebug};
|
||||||
|
Setting<bool> renderer_shader_feedback{linkage, false, "shader_feedback",
|
||||||
|
Category::RendererDebug};
|
||||||
|
Setting<bool> enable_nsight_aftermath{linkage, false, "nsight_aftermath",
|
||||||
|
Category::RendererDebug};
|
||||||
|
Setting<bool> disable_shader_loop_safety_checks{
|
||||||
|
linkage, false, "disable_shader_loop_safety_checks", Category::RendererDebug};
|
||||||
|
Setting<bool> enable_renderdoc_hotkey{linkage, false, "renderdoc_hotkey",
|
||||||
|
Category::RendererDebug};
|
||||||
|
Setting<bool> disable_buffer_reorder{linkage, false, "disable_buffer_reorder",
|
||||||
|
Category::RendererDebug};
|
||||||
|
|
||||||
|
// System
|
||||||
|
SwitchableSetting<Language, true> language_index{linkage,
|
||||||
|
Language::EnglishAmerican,
|
||||||
|
Language::Japanese,
|
||||||
|
Language::PortugueseBrazilian,
|
||||||
|
"language_index",
|
||||||
|
Category::System};
|
||||||
|
SwitchableSetting<Region, true> region_index{linkage, Region::Usa, Region::Japan,
|
||||||
|
Region::Taiwan, "region_index", Category::System};
|
||||||
|
SwitchableSetting<TimeZone, true> time_zone_index{linkage, TimeZone::Auto,
|
||||||
|
TimeZone::Auto, TimeZone::Zulu,
|
||||||
|
"time_zone_index", Category::System};
|
||||||
|
// Measured in seconds since epoch
|
||||||
|
SwitchableSetting<bool> custom_rtc_enabled{
|
||||||
|
linkage, false, "custom_rtc_enabled", Category::System, Specialization::Paired, true, true};
|
||||||
|
SwitchableSetting<s64> custom_rtc{
|
||||||
|
linkage, 0, "custom_rtc", Category::System, Specialization::Time,
|
||||||
|
false, true, &custom_rtc_enabled};
|
||||||
|
SwitchableSetting<s64, true> custom_rtc_offset{linkage,
|
||||||
|
0,
|
||||||
|
std::numeric_limits<int>::min(),
|
||||||
|
std::numeric_limits<int>::max(),
|
||||||
|
"custom_rtc_offset",
|
||||||
|
Category::System,
|
||||||
|
Specialization::Countable,
|
||||||
|
true,
|
||||||
|
true};
|
||||||
|
SwitchableSetting<bool> rng_seed_enabled{
|
||||||
|
linkage, false, "rng_seed_enabled", Category::System, Specialization::Paired, true, true};
|
||||||
|
SwitchableSetting<u32> rng_seed{
|
||||||
|
linkage, 0, "rng_seed", Category::System, Specialization::Hex,
|
||||||
|
true, true, &rng_seed_enabled};
|
||||||
|
Setting<std::string> device_name{
|
||||||
|
linkage, "yuzu", "device_name", Category::System, Specialization::Default, true, true};
|
||||||
|
|
||||||
|
Setting<s32> current_user{linkage, 0, "current_user", Category::System};
|
||||||
|
|
||||||
|
SwitchableSetting<ConsoleMode> use_docked_mode{linkage,
|
||||||
|
#ifdef ANDROID
|
||||||
|
ConsoleMode::Handheld,
|
||||||
|
#else
|
||||||
|
ConsoleMode::Docked,
|
||||||
|
#endif
|
||||||
|
"use_docked_mode",
|
||||||
|
Category::System,
|
||||||
|
Specialization::Radio,
|
||||||
|
true,
|
||||||
|
true};
|
||||||
|
|
||||||
|
// Linux
|
||||||
|
SwitchableSetting<bool> enable_gamemode{linkage, true, "enable_gamemode", Category::Linux};
|
||||||
|
|
||||||
|
// Controls
|
||||||
|
InputSetting<std::array<PlayerInput, 10>> players;
|
||||||
|
|
||||||
|
Setting<bool> enable_raw_input{
|
||||||
|
linkage, false, "enable_raw_input", Category::Controls, Specialization::Default,
|
||||||
|
// Only read/write enable_raw_input on Windows platforms
|
||||||
|
#ifdef _WIN32
|
||||||
|
true
|
||||||
|
#else
|
||||||
|
false
|
||||||
|
#endif
|
||||||
|
};
|
||||||
|
Setting<bool> controller_navigation{linkage, true, "controller_navigation", Category::Controls};
|
||||||
|
Setting<bool> enable_joycon_driver{linkage, true, "enable_joycon_driver", Category::Controls};
|
||||||
|
Setting<bool> enable_procon_driver{linkage, false, "enable_procon_driver", Category::Controls};
|
||||||
|
|
||||||
|
SwitchableSetting<bool> vibration_enabled{linkage, true, "vibration_enabled",
|
||||||
|
Category::Controls};
|
||||||
|
SwitchableSetting<bool> enable_accurate_vibrations{linkage, false, "enable_accurate_vibrations",
|
||||||
|
Category::Controls};
|
||||||
|
|
||||||
|
SwitchableSetting<bool> motion_enabled{linkage, true, "motion_enabled", Category::Controls};
|
||||||
|
Setting<std::string> udp_input_servers{linkage, "127.0.0.1:26760", "udp_input_servers",
|
||||||
|
Category::Controls};
|
||||||
|
Setting<bool> enable_udp_controller{linkage, false, "enable_udp_controller",
|
||||||
|
Category::Controls};
|
||||||
|
|
||||||
|
Setting<bool> pause_tas_on_load{linkage, true, "pause_tas_on_load", Category::Controls};
|
||||||
|
Setting<bool> tas_enable{linkage, false, "tas_enable", Category::Controls};
|
||||||
|
Setting<bool> tas_loop{linkage, false, "tas_loop", Category::Controls};
|
||||||
|
|
||||||
|
Setting<bool> mouse_panning{
|
||||||
|
linkage, false, "mouse_panning", Category::Controls, Specialization::Default, false};
|
||||||
|
Setting<u8, true> mouse_panning_sensitivity{
|
||||||
|
linkage, 50, 1, 100, "mouse_panning_sensitivity", Category::Controls};
|
||||||
|
Setting<bool> mouse_enabled{linkage, false, "mouse_enabled", Category::Controls};
|
||||||
|
|
||||||
|
Setting<u8, true> mouse_panning_x_sensitivity{
|
||||||
|
linkage, 50, 1, 100, "mouse_panning_x_sensitivity", Category::Controls};
|
||||||
|
Setting<u8, true> mouse_panning_y_sensitivity{
|
||||||
|
linkage, 50, 1, 100, "mouse_panning_y_sensitivity", Category::Controls};
|
||||||
|
Setting<u8, true> mouse_panning_deadzone_counterweight{
|
||||||
|
linkage, 20, 0, 100, "mouse_panning_deadzone_counterweight", Category::Controls};
|
||||||
|
Setting<u8, true> mouse_panning_decay_strength{
|
||||||
|
linkage, 18, 0, 100, "mouse_panning_decay_strength", Category::Controls};
|
||||||
|
Setting<u8, true> mouse_panning_min_decay{
|
||||||
|
linkage, 6, 0, 100, "mouse_panning_min_decay", Category::Controls};
|
||||||
|
|
||||||
|
Setting<bool> emulate_analog_keyboard{linkage, false, "emulate_analog_keyboard",
|
||||||
|
Category::Controls};
|
||||||
|
Setting<bool> keyboard_enabled{linkage, false, "keyboard_enabled", Category::Controls};
|
||||||
|
|
||||||
|
Setting<bool> debug_pad_enabled{linkage, false, "debug_pad_enabled", Category::Controls};
|
||||||
|
ButtonsRaw debug_pad_buttons;
|
||||||
|
AnalogsRaw debug_pad_analogs;
|
||||||
|
|
||||||
|
TouchscreenInput touchscreen;
|
||||||
|
|
||||||
|
Setting<std::string> touch_device{linkage, "min_x:100,min_y:50,max_x:1800,max_y:850",
|
||||||
|
"touch_device", Category::Controls};
|
||||||
|
Setting<int> touch_from_button_map_index{linkage, 0, "touch_from_button_map",
|
||||||
|
Category::Controls};
|
||||||
|
std::vector<TouchFromButtonMap> touch_from_button_maps;
|
||||||
|
|
||||||
|
Setting<bool> enable_ring_controller{linkage, true, "enable_ring_controller",
|
||||||
|
Category::Controls};
|
||||||
|
RingconRaw ringcon_analogs;
|
||||||
|
|
||||||
|
Setting<bool> enable_ir_sensor{linkage, false, "enable_ir_sensor", Category::Controls};
|
||||||
|
Setting<std::string> ir_sensor_device{linkage, "auto", "ir_sensor_device", Category::Controls};
|
||||||
|
|
||||||
|
Setting<bool> random_amiibo_id{linkage, false, "random_amiibo_id", Category::Controls};
|
||||||
|
|
||||||
|
// Data Storage
|
||||||
|
Setting<bool> use_virtual_sd{linkage, true, "use_virtual_sd", Category::DataStorage};
|
||||||
|
Setting<bool> gamecard_inserted{linkage, false, "gamecard_inserted", Category::DataStorage};
|
||||||
|
Setting<bool> gamecard_current_game{linkage, false, "gamecard_current_game",
|
||||||
|
Category::DataStorage};
|
||||||
|
Setting<std::string> gamecard_path{linkage, std::string(), "gamecard_path",
|
||||||
|
Category::DataStorage};
|
||||||
|
|
||||||
|
// Debugging
|
||||||
|
bool record_frame_times;
|
||||||
|
Setting<bool> use_gdbstub{linkage, false, "use_gdbstub", Category::Debugging};
|
||||||
|
Setting<u16> gdbstub_port{linkage, 6543, "gdbstub_port", Category::Debugging};
|
||||||
|
Setting<std::string> program_args{linkage, std::string(), "program_args", Category::Debugging};
|
||||||
|
Setting<bool> dump_exefs{linkage, false, "dump_exefs", Category::Debugging};
|
||||||
|
Setting<bool> dump_nso{linkage, false, "dump_nso", Category::Debugging};
|
||||||
|
Setting<bool> dump_shaders{
|
||||||
|
linkage, false, "dump_shaders", Category::DebuggingGraphics, Specialization::Default,
|
||||||
|
false};
|
||||||
|
Setting<bool> dump_macros{
|
||||||
|
linkage, false, "dump_macros", Category::DebuggingGraphics, Specialization::Default, false};
|
||||||
|
Setting<bool> enable_fs_access_log{linkage, false, "enable_fs_access_log", Category::Debugging};
|
||||||
|
Setting<bool> reporting_services{
|
||||||
|
linkage, false, "reporting_services", Category::Debugging, Specialization::Default, false};
|
||||||
|
Setting<bool> quest_flag{linkage, false, "quest_flag", Category::Debugging};
|
||||||
|
Setting<bool> disable_macro_jit{linkage, false, "disable_macro_jit",
|
||||||
|
Category::DebuggingGraphics};
|
||||||
|
Setting<bool> disable_macro_hle{linkage, false, "disable_macro_hle",
|
||||||
|
Category::DebuggingGraphics};
|
||||||
|
Setting<bool> extended_logging{
|
||||||
|
linkage, false, "extended_logging", Category::Debugging, Specialization::Default, false};
|
||||||
|
Setting<bool> use_debug_asserts{linkage, false, "use_debug_asserts", Category::Debugging};
|
||||||
|
Setting<bool> use_auto_stub{
|
||||||
|
linkage, false, "use_auto_stub", Category::Debugging, Specialization::Default, false};
|
||||||
|
Setting<bool> enable_all_controllers{linkage, false, "enable_all_controllers",
|
||||||
|
Category::Debugging};
|
||||||
|
Setting<bool> perform_vulkan_check{linkage, true, "perform_vulkan_check", Category::Debugging};
|
||||||
|
|
||||||
|
// Miscellaneous
|
||||||
|
Setting<std::string> log_filter{linkage, "*:Info", "log_filter", Category::Miscellaneous};
|
||||||
|
Setting<bool> use_dev_keys{linkage, false, "use_dev_keys", Category::Miscellaneous};
|
||||||
|
|
||||||
|
// Network
|
||||||
|
Setting<std::string> network_interface{linkage, std::string(), "network_interface",
|
||||||
|
Category::Network};
|
||||||
|
|
||||||
|
// WebService
|
||||||
|
Setting<bool> enable_telemetry{linkage, true, "enable_telemetry", Category::WebService};
|
||||||
|
Setting<std::string> web_api_url{linkage, "https://api.yuzu-emu.org", "web_api_url",
|
||||||
|
Category::WebService};
|
||||||
|
Setting<std::string> yuzu_username{linkage, std::string(), "yuzu_username",
|
||||||
|
Category::WebService};
|
||||||
|
Setting<std::string> yuzu_token{linkage, std::string(), "yuzu_token", Category::WebService};
|
||||||
|
|
||||||
|
// Add-Ons
|
||||||
|
std::map<u64, std::vector<std::string>> disabled_addons;
|
||||||
|
};
|
||||||
|
|
||||||
|
extern Values values;
|
||||||
|
|
||||||
|
void UpdateGPUAccuracy();
|
||||||
|
bool IsGPULevelExtreme();
|
||||||
|
bool IsGPULevelHigh();
|
||||||
|
|
||||||
|
bool IsFastmemEnabled();
|
||||||
|
void SetNceEnabled(bool is_64bit);
|
||||||
|
bool IsNceEnabled();
|
||||||
|
|
||||||
|
bool IsDockedMode();
|
||||||
|
|
||||||
|
float Volume();
|
||||||
|
|
||||||
|
std::string GetTimeZoneString(TimeZone time_zone);
|
||||||
|
|
||||||
|
void LogSettings();
|
||||||
|
|
||||||
|
void TranslateResolutionInfo(ResolutionSetup setup, ResolutionScalingInfo& info);
|
||||||
|
void UpdateRescalingInfo();
|
||||||
|
|
||||||
|
// Restore the global state of all applicable settings in the Values struct
|
||||||
|
void RestoreGlobalState(bool is_powered_on);
|
||||||
|
|
||||||
|
bool IsConfiguringGlobal();
|
||||||
|
void SetConfiguringGlobal(bool is_global);
|
||||||
|
|
||||||
|
} // namespace Settings
|
||||||
274
common/settings_common.h
Executable file
274
common/settings_common.h
Executable file
|
|
@ -0,0 +1,274 @@
|
||||||
|
// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
|
||||||
|
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <functional>
|
||||||
|
#include <map>
|
||||||
|
#include <string>
|
||||||
|
#include <typeindex>
|
||||||
|
#include "common_types.h"
|
||||||
|
|
||||||
|
namespace Settings {
|
||||||
|
|
||||||
|
enum class Category : u32 {
|
||||||
|
Android,
|
||||||
|
Audio,
|
||||||
|
Core,
|
||||||
|
Cpu,
|
||||||
|
CpuDebug,
|
||||||
|
CpuUnsafe,
|
||||||
|
Overlay,
|
||||||
|
Renderer,
|
||||||
|
RendererAdvanced,
|
||||||
|
RendererDebug,
|
||||||
|
System,
|
||||||
|
SystemAudio,
|
||||||
|
DataStorage,
|
||||||
|
Debugging,
|
||||||
|
DebuggingGraphics,
|
||||||
|
GpuDriver,
|
||||||
|
Miscellaneous,
|
||||||
|
Network,
|
||||||
|
WebService,
|
||||||
|
AddOns,
|
||||||
|
Controls,
|
||||||
|
Ui,
|
||||||
|
UiAudio,
|
||||||
|
UiGeneral,
|
||||||
|
UiLayout,
|
||||||
|
UiGameList,
|
||||||
|
Screenshots,
|
||||||
|
Shortcuts,
|
||||||
|
Multiplayer,
|
||||||
|
Services,
|
||||||
|
Paths,
|
||||||
|
Linux,
|
||||||
|
LibraryApplet,
|
||||||
|
MaxEnum,
|
||||||
|
};
|
||||||
|
|
||||||
|
constexpr u8 SpecializationTypeMask = 0xf;
|
||||||
|
constexpr u8 SpecializationAttributeMask = 0xf0;
|
||||||
|
constexpr u8 SpecializationAttributeOffset = 4;
|
||||||
|
|
||||||
|
// Scalar and countable could have better names
|
||||||
|
enum Specialization : u8 {
|
||||||
|
Default = 0,
|
||||||
|
Time = 1, // Duration or specific moment in time
|
||||||
|
Hex = 2, // Hexadecimal number
|
||||||
|
List = 3, // Setting has specific members
|
||||||
|
RuntimeList = 4, // Members of the list are determined during runtime
|
||||||
|
Scalar = 5, // Values are continuous
|
||||||
|
Countable = 6, // Can be stepped through
|
||||||
|
Paired = 7, // Another setting is associated with this setting
|
||||||
|
Radio = 8, // Setting should be presented in a radio group
|
||||||
|
|
||||||
|
Percentage = (1 << SpecializationAttributeOffset), // Should be represented as a percentage
|
||||||
|
};
|
||||||
|
|
||||||
|
class BasicSetting;
|
||||||
|
|
||||||
|
class Linkage {
|
||||||
|
public:
|
||||||
|
explicit Linkage(u32 initial_count = 0);
|
||||||
|
~Linkage();
|
||||||
|
std::map<Category, std::vector<BasicSetting*>> by_category{};
|
||||||
|
std::map<std::string, Settings::BasicSetting*> by_key{};
|
||||||
|
std::vector<std::function<void()>> restore_functions{};
|
||||||
|
u32 count;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* BasicSetting is an abstract class that only keeps track of metadata. The string methods are
|
||||||
|
* available to get data values out.
|
||||||
|
*/
|
||||||
|
class BasicSetting {
|
||||||
|
protected:
|
||||||
|
explicit BasicSetting(Linkage& linkage, const std::string& name, Category category_, bool save_,
|
||||||
|
bool runtime_modifiable_, u32 specialization,
|
||||||
|
BasicSetting* other_setting);
|
||||||
|
|
||||||
|
public:
|
||||||
|
virtual ~BasicSetting();
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Data retrieval
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns a string representation of the internal data. If the Setting is Switchable, it
|
||||||
|
* respects the internal global state: it is based on GetValue().
|
||||||
|
*
|
||||||
|
* @returns A string representation of the internal data.
|
||||||
|
*/
|
||||||
|
[[nodiscard]] virtual std::string ToString() const = 0;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns a string representation of the global version of internal data. If the Setting is
|
||||||
|
* not Switchable, it behaves like ToString.
|
||||||
|
*
|
||||||
|
* @returns A string representation of the global version of internal data.
|
||||||
|
*/
|
||||||
|
[[nodiscard]] virtual std::string ToStringGlobal() const;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @returns A string representation of the Setting's default value.
|
||||||
|
*/
|
||||||
|
[[nodiscard]] virtual std::string DefaultToString() const = 0;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns a string representation of the minimum value of the setting. If the Setting is not
|
||||||
|
* ranged, the string represents the default initialization of the data type.
|
||||||
|
*
|
||||||
|
* @returns A string representation of the minimum value of the setting.
|
||||||
|
*/
|
||||||
|
[[nodiscard]] virtual std::string MinVal() const = 0;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns a string representation of the maximum value of the setting. If the Setting is not
|
||||||
|
* ranged, the string represents the default initialization of the data type.
|
||||||
|
*
|
||||||
|
* @returns A string representation of the maximum value of the setting.
|
||||||
|
*/
|
||||||
|
[[nodiscard]] virtual std::string MaxVal() const = 0;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Takes a string input, converts it to the internal data type if necessary, and then runs
|
||||||
|
* SetValue with it.
|
||||||
|
*
|
||||||
|
* @param load String of the input data.
|
||||||
|
*/
|
||||||
|
virtual void LoadString(const std::string& load) = 0;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns a string representation of the data. If the data is an enum, it returns a string of
|
||||||
|
* the enum value. If the internal data type is not an enum, this is equivalent to ToString.
|
||||||
|
*
|
||||||
|
* e.g. renderer_backend.Canonicalize() == "OpenGL"
|
||||||
|
*
|
||||||
|
* @returns Canonicalized string representation of the internal data
|
||||||
|
*/
|
||||||
|
[[nodiscard]] virtual std::string Canonicalize() const = 0;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Metadata
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @returns A unique identifier for the Setting's internal data type.
|
||||||
|
*/
|
||||||
|
[[nodiscard]] virtual std::type_index TypeId() const = 0;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns true if the Setting's internal data type is an enum.
|
||||||
|
*
|
||||||
|
* @returns True if the Setting's internal data type is an enum
|
||||||
|
*/
|
||||||
|
[[nodiscard]] virtual constexpr bool IsEnum() const = 0;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns true if the current setting is Switchable.
|
||||||
|
*
|
||||||
|
* @returns If the setting is a SwitchableSetting
|
||||||
|
*/
|
||||||
|
[[nodiscard]] virtual constexpr bool Switchable() const {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns true to suggest that a frontend can read or write the setting to a configuration
|
||||||
|
* file.
|
||||||
|
*
|
||||||
|
* @returns The save preference
|
||||||
|
*/
|
||||||
|
[[nodiscard]] bool Save() const;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @returns true if the current setting can be changed while the guest is running.
|
||||||
|
*/
|
||||||
|
[[nodiscard]] bool RuntimeModifiable() const;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @returns A unique number corresponding to the setting.
|
||||||
|
*/
|
||||||
|
[[nodiscard]] constexpr u32 Id() const {
|
||||||
|
return id;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the setting's category AKA INI group.
|
||||||
|
*
|
||||||
|
* @returns The setting's category
|
||||||
|
*/
|
||||||
|
[[nodiscard]] Category GetCategory() const;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @returns Extra metadata for data representation in frontend implementations.
|
||||||
|
*/
|
||||||
|
[[nodiscard]] u32 Specialization() const;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @returns Another BasicSetting if one is paired, or nullptr otherwise.
|
||||||
|
*/
|
||||||
|
[[nodiscard]] BasicSetting* PairedSetting() const;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the label this setting was created with.
|
||||||
|
*
|
||||||
|
* @returns A reference to the label
|
||||||
|
*/
|
||||||
|
[[nodiscard]] const std::string& GetLabel() const;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @returns If the Setting checks input values for valid ranges.
|
||||||
|
*/
|
||||||
|
[[nodiscard]] virtual constexpr bool Ranged() const = 0;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @returns The index of the enum if the underlying setting type is an enum, else max of u32.
|
||||||
|
*/
|
||||||
|
[[nodiscard]] virtual constexpr u32 EnumIndex() const = 0;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @returns True if the underlying type is a floating point storage
|
||||||
|
*/
|
||||||
|
[[nodiscard]] virtual constexpr bool IsFloatingPoint() const = 0;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @returns True if the underlying type is an integer storage
|
||||||
|
*/
|
||||||
|
[[nodiscard]] virtual constexpr bool IsIntegral() const = 0;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Switchable settings
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets a setting's global state. True means use the normal setting, false to use a custom
|
||||||
|
* value. Has no effect if the Setting is not Switchable.
|
||||||
|
*
|
||||||
|
* @param global The desired state
|
||||||
|
*/
|
||||||
|
virtual void SetGlobal(bool global);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns true if the setting is using the normal setting value. Always true if the setting is
|
||||||
|
* not Switchable.
|
||||||
|
*
|
||||||
|
* @returns The Setting's global state
|
||||||
|
*/
|
||||||
|
[[nodiscard]] virtual bool UsingGlobal() const;
|
||||||
|
|
||||||
|
private:
|
||||||
|
const std::string label; ///< The setting's label
|
||||||
|
const Category category; ///< The setting's category AKA INI group
|
||||||
|
const u32 id; ///< Unique integer for the setting
|
||||||
|
const bool save; ///< Suggests if the setting should be saved and read to a frontend config
|
||||||
|
const bool
|
||||||
|
runtime_modifiable; ///< Suggests if the setting can be modified while a guest is running
|
||||||
|
const u32 specialization; ///< Extra data to identify representation of a setting
|
||||||
|
BasicSetting* const other_setting; ///< A paired setting
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace Settings
|
||||||
223
common/settings_enums.h
Executable file
223
common/settings_enums.h
Executable file
|
|
@ -0,0 +1,223 @@
|
||||||
|
// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
|
||||||
|
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
#include <utility>
|
||||||
|
#include <vector>
|
||||||
|
#include "common_types.h"
|
||||||
|
|
||||||
|
namespace Settings {
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
struct EnumMetadata {
|
||||||
|
static std::vector<std::pair<std::string, T>> Canonicalizations();
|
||||||
|
static u32 Index();
|
||||||
|
};
|
||||||
|
|
||||||
|
#define PAIR_45(N, X, ...) {#X, N::X} __VA_OPT__(, PAIR_46(N, __VA_ARGS__))
|
||||||
|
#define PAIR_44(N, X, ...) {#X, N::X} __VA_OPT__(, PAIR_45(N, __VA_ARGS__))
|
||||||
|
#define PAIR_43(N, X, ...) {#X, N::X} __VA_OPT__(, PAIR_44(N, __VA_ARGS__))
|
||||||
|
#define PAIR_42(N, X, ...) {#X, N::X} __VA_OPT__(, PAIR_43(N, __VA_ARGS__))
|
||||||
|
#define PAIR_41(N, X, ...) {#X, N::X} __VA_OPT__(, PAIR_42(N, __VA_ARGS__))
|
||||||
|
#define PAIR_40(N, X, ...) {#X, N::X} __VA_OPT__(, PAIR_41(N, __VA_ARGS__))
|
||||||
|
#define PAIR_39(N, X, ...) {#X, N::X} __VA_OPT__(, PAIR_40(N, __VA_ARGS__))
|
||||||
|
#define PAIR_38(N, X, ...) {#X, N::X} __VA_OPT__(, PAIR_39(N, __VA_ARGS__))
|
||||||
|
#define PAIR_37(N, X, ...) {#X, N::X} __VA_OPT__(, PAIR_38(N, __VA_ARGS__))
|
||||||
|
#define PAIR_36(N, X, ...) {#X, N::X} __VA_OPT__(, PAIR_37(N, __VA_ARGS__))
|
||||||
|
#define PAIR_35(N, X, ...) {#X, N::X} __VA_OPT__(, PAIR_36(N, __VA_ARGS__))
|
||||||
|
#define PAIR_34(N, X, ...) {#X, N::X} __VA_OPT__(, PAIR_35(N, __VA_ARGS__))
|
||||||
|
#define PAIR_33(N, X, ...) {#X, N::X} __VA_OPT__(, PAIR_34(N, __VA_ARGS__))
|
||||||
|
#define PAIR_32(N, X, ...) {#X, N::X} __VA_OPT__(, PAIR_33(N, __VA_ARGS__))
|
||||||
|
#define PAIR_31(N, X, ...) {#X, N::X} __VA_OPT__(, PAIR_32(N, __VA_ARGS__))
|
||||||
|
#define PAIR_30(N, X, ...) {#X, N::X} __VA_OPT__(, PAIR_31(N, __VA_ARGS__))
|
||||||
|
#define PAIR_29(N, X, ...) {#X, N::X} __VA_OPT__(, PAIR_30(N, __VA_ARGS__))
|
||||||
|
#define PAIR_28(N, X, ...) {#X, N::X} __VA_OPT__(, PAIR_29(N, __VA_ARGS__))
|
||||||
|
#define PAIR_27(N, X, ...) {#X, N::X} __VA_OPT__(, PAIR_28(N, __VA_ARGS__))
|
||||||
|
#define PAIR_26(N, X, ...) {#X, N::X} __VA_OPT__(, PAIR_27(N, __VA_ARGS__))
|
||||||
|
#define PAIR_25(N, X, ...) {#X, N::X} __VA_OPT__(, PAIR_26(N, __VA_ARGS__))
|
||||||
|
#define PAIR_24(N, X, ...) {#X, N::X} __VA_OPT__(, PAIR_25(N, __VA_ARGS__))
|
||||||
|
#define PAIR_23(N, X, ...) {#X, N::X} __VA_OPT__(, PAIR_24(N, __VA_ARGS__))
|
||||||
|
#define PAIR_22(N, X, ...) {#X, N::X} __VA_OPT__(, PAIR_23(N, __VA_ARGS__))
|
||||||
|
#define PAIR_21(N, X, ...) {#X, N::X} __VA_OPT__(, PAIR_22(N, __VA_ARGS__))
|
||||||
|
#define PAIR_20(N, X, ...) {#X, N::X} __VA_OPT__(, PAIR_21(N, __VA_ARGS__))
|
||||||
|
#define PAIR_19(N, X, ...) {#X, N::X} __VA_OPT__(, PAIR_20(N, __VA_ARGS__))
|
||||||
|
#define PAIR_18(N, X, ...) {#X, N::X} __VA_OPT__(, PAIR_19(N, __VA_ARGS__))
|
||||||
|
#define PAIR_17(N, X, ...) {#X, N::X} __VA_OPT__(, PAIR_18(N, __VA_ARGS__))
|
||||||
|
#define PAIR_16(N, X, ...) {#X, N::X} __VA_OPT__(, PAIR_17(N, __VA_ARGS__))
|
||||||
|
#define PAIR_15(N, X, ...) {#X, N::X} __VA_OPT__(, PAIR_16(N, __VA_ARGS__))
|
||||||
|
#define PAIR_14(N, X, ...) {#X, N::X} __VA_OPT__(, PAIR_15(N, __VA_ARGS__))
|
||||||
|
#define PAIR_13(N, X, ...) {#X, N::X} __VA_OPT__(, PAIR_14(N, __VA_ARGS__))
|
||||||
|
#define PAIR_12(N, X, ...) {#X, N::X} __VA_OPT__(, PAIR_13(N, __VA_ARGS__))
|
||||||
|
#define PAIR_11(N, X, ...) {#X, N::X} __VA_OPT__(, PAIR_12(N, __VA_ARGS__))
|
||||||
|
#define PAIR_10(N, X, ...) {#X, N::X} __VA_OPT__(, PAIR_11(N, __VA_ARGS__))
|
||||||
|
#define PAIR_9(N, X, ...) {#X, N::X} __VA_OPT__(, PAIR_10(N, __VA_ARGS__))
|
||||||
|
#define PAIR_8(N, X, ...) {#X, N::X} __VA_OPT__(, PAIR_9(N, __VA_ARGS__))
|
||||||
|
#define PAIR_7(N, X, ...) {#X, N::X} __VA_OPT__(, PAIR_8(N, __VA_ARGS__))
|
||||||
|
#define PAIR_6(N, X, ...) {#X, N::X} __VA_OPT__(, PAIR_7(N, __VA_ARGS__))
|
||||||
|
#define PAIR_5(N, X, ...) {#X, N::X} __VA_OPT__(, PAIR_6(N, __VA_ARGS__))
|
||||||
|
#define PAIR_4(N, X, ...) {#X, N::X} __VA_OPT__(, PAIR_5(N, __VA_ARGS__))
|
||||||
|
#define PAIR_3(N, X, ...) {#X, N::X} __VA_OPT__(, PAIR_4(N, __VA_ARGS__))
|
||||||
|
#define PAIR_2(N, X, ...) {#X, N::X} __VA_OPT__(, PAIR_3(N, __VA_ARGS__))
|
||||||
|
#define PAIR_1(N, X, ...) {#X, N::X} __VA_OPT__(, PAIR_2(N, __VA_ARGS__))
|
||||||
|
#define PAIR(N, X, ...) {#X, N::X} __VA_OPT__(, PAIR_1(N, __VA_ARGS__))
|
||||||
|
|
||||||
|
#define ENUM(NAME, ...) \
|
||||||
|
enum class NAME : u32 { __VA_ARGS__ }; \
|
||||||
|
template <> \
|
||||||
|
inline std::vector<std::pair<std::string, NAME>> EnumMetadata<NAME>::Canonicalizations() { \
|
||||||
|
return {PAIR(NAME, __VA_ARGS__)}; \
|
||||||
|
} \
|
||||||
|
template <> \
|
||||||
|
inline u32 EnumMetadata<NAME>::Index() { \
|
||||||
|
return __COUNTER__; \
|
||||||
|
}
|
||||||
|
|
||||||
|
// AudioEngine must be specified discretely due to having existing but slightly different
|
||||||
|
// canonicalizations
|
||||||
|
// TODO (lat9nq): Remove explicit definition of AudioEngine/sink_id
|
||||||
|
enum class AudioEngine : u32 {
|
||||||
|
Auto,
|
||||||
|
Cubeb,
|
||||||
|
Sdl2,
|
||||||
|
Null,
|
||||||
|
Oboe,
|
||||||
|
};
|
||||||
|
|
||||||
|
template <>
|
||||||
|
inline std::vector<std::pair<std::string, AudioEngine>>
|
||||||
|
EnumMetadata<AudioEngine>::Canonicalizations() {
|
||||||
|
return {
|
||||||
|
{"auto", AudioEngine::Auto}, {"cubeb", AudioEngine::Cubeb}, {"sdl2", AudioEngine::Sdl2},
|
||||||
|
{"null", AudioEngine::Null}, {"oboe", AudioEngine::Oboe},
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
template <>
|
||||||
|
inline u32 EnumMetadata<AudioEngine>::Index() {
|
||||||
|
// This is just a sufficiently large number that is more than the number of other enums declared
|
||||||
|
// here
|
||||||
|
return 100;
|
||||||
|
}
|
||||||
|
|
||||||
|
ENUM(AudioMode, Mono, Stereo, Surround);
|
||||||
|
|
||||||
|
ENUM(Language, Japanese, EnglishAmerican, French, German, Italian, Spanish, Chinese, Korean, Dutch,
|
||||||
|
Portuguese, Russian, Taiwanese, EnglishBritish, FrenchCanadian, SpanishLatin,
|
||||||
|
ChineseSimplified, ChineseTraditional, PortugueseBrazilian);
|
||||||
|
|
||||||
|
ENUM(Region, Japan, Usa, Europe, Australia, China, Korea, Taiwan);
|
||||||
|
|
||||||
|
ENUM(TimeZone, Auto, Default, Cet, Cst6Cdt, Cuba, Eet, Egypt, Eire, Est, Est5Edt, Gb, GbEire, Gmt,
|
||||||
|
GmtPlusZero, GmtMinusZero, GmtZero, Greenwich, Hongkong, Hst, Iceland, Iran, Israel, Jamaica,
|
||||||
|
Japan, Kwajalein, Libya, Met, Mst, Mst7Mdt, Navajo, Nz, NzChat, Poland, Portugal, Prc, Pst8Pdt,
|
||||||
|
Roc, Rok, Singapore, Turkey, Uct, Universal, Utc, WSu, Wet, Zulu);
|
||||||
|
|
||||||
|
ENUM(AnisotropyMode, Automatic, Default, X2, X4, X8, X16);
|
||||||
|
|
||||||
|
ENUM(AstcDecodeMode, Cpu, Gpu, CpuAsynchronous);
|
||||||
|
|
||||||
|
ENUM(AstcRecompression, Uncompressed, Bc1, Bc3);
|
||||||
|
|
||||||
|
ENUM(VSyncMode, Immediate, Mailbox, Fifo, FifoRelaxed);
|
||||||
|
|
||||||
|
ENUM(VramUsageMode, Conservative, Aggressive);
|
||||||
|
|
||||||
|
ENUM(RendererBackend, OpenGL, Vulkan, Null);
|
||||||
|
|
||||||
|
ENUM(ShaderBackend, Glsl, Glasm, SpirV);
|
||||||
|
|
||||||
|
ENUM(GpuAccuracy, Normal, High, Extreme);
|
||||||
|
|
||||||
|
ENUM(CpuBackend, Dynarmic, Nce);
|
||||||
|
|
||||||
|
ENUM(CpuAccuracy, Auto, Accurate, Unsafe, Paranoid);
|
||||||
|
|
||||||
|
ENUM(MemoryLayout, Memory_4Gb, Memory_6Gb, Memory_8Gb);
|
||||||
|
|
||||||
|
ENUM(ConfirmStop, Ask_Always, Ask_Based_On_Game, Ask_Never);
|
||||||
|
|
||||||
|
ENUM(FullscreenMode, Borderless, Exclusive);
|
||||||
|
|
||||||
|
ENUM(NvdecEmulation, Off, Cpu, Gpu);
|
||||||
|
|
||||||
|
ENUM(ResolutionSetup, Res1_2X, Res3_4X, Res1X, Res3_2X, Res2X, Res3X, Res4X, Res5X, Res6X, Res7X,
|
||||||
|
Res8X);
|
||||||
|
|
||||||
|
ENUM(ScalingFilter, NearestNeighbor, Bilinear, Bicubic, Gaussian, ScaleForce, Fsr, MaxEnum);
|
||||||
|
|
||||||
|
ENUM(AntiAliasing, None, Fxaa, Smaa, MaxEnum);
|
||||||
|
|
||||||
|
ENUM(AspectRatio, R16_9, R4_3, R21_9, R16_10, Stretch);
|
||||||
|
|
||||||
|
ENUM(ConsoleMode, Handheld, Docked);
|
||||||
|
|
||||||
|
ENUM(AppletMode, HLE, LLE);
|
||||||
|
|
||||||
|
template <typename Type>
|
||||||
|
inline std::string CanonicalizeEnum(Type id) {
|
||||||
|
const auto group = EnumMetadata<Type>::Canonicalizations();
|
||||||
|
for (auto& [name, value] : group) {
|
||||||
|
if (value == id) {
|
||||||
|
return name;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return "unknown";
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename Type>
|
||||||
|
inline Type ToEnum(const std::string& canonicalization) {
|
||||||
|
const auto group = EnumMetadata<Type>::Canonicalizations();
|
||||||
|
for (auto& [name, value] : group) {
|
||||||
|
if (name == canonicalization) {
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
} // namespace Settings
|
||||||
|
|
||||||
|
#undef ENUM
|
||||||
|
#undef PAIR
|
||||||
|
#undef PAIR_1
|
||||||
|
#undef PAIR_2
|
||||||
|
#undef PAIR_3
|
||||||
|
#undef PAIR_4
|
||||||
|
#undef PAIR_5
|
||||||
|
#undef PAIR_6
|
||||||
|
#undef PAIR_7
|
||||||
|
#undef PAIR_8
|
||||||
|
#undef PAIR_9
|
||||||
|
#undef PAIR_10
|
||||||
|
#undef PAIR_12
|
||||||
|
#undef PAIR_13
|
||||||
|
#undef PAIR_14
|
||||||
|
#undef PAIR_15
|
||||||
|
#undef PAIR_16
|
||||||
|
#undef PAIR_17
|
||||||
|
#undef PAIR_18
|
||||||
|
#undef PAIR_19
|
||||||
|
#undef PAIR_20
|
||||||
|
#undef PAIR_22
|
||||||
|
#undef PAIR_23
|
||||||
|
#undef PAIR_24
|
||||||
|
#undef PAIR_25
|
||||||
|
#undef PAIR_26
|
||||||
|
#undef PAIR_27
|
||||||
|
#undef PAIR_28
|
||||||
|
#undef PAIR_29
|
||||||
|
#undef PAIR_30
|
||||||
|
#undef PAIR_32
|
||||||
|
#undef PAIR_33
|
||||||
|
#undef PAIR_34
|
||||||
|
#undef PAIR_35
|
||||||
|
#undef PAIR_36
|
||||||
|
#undef PAIR_37
|
||||||
|
#undef PAIR_38
|
||||||
|
#undef PAIR_39
|
||||||
|
#undef PAIR_40
|
||||||
|
#undef PAIR_42
|
||||||
|
#undef PAIR_43
|
||||||
|
#undef PAIR_44
|
||||||
|
#undef PAIR_45
|
||||||
413
common/settings_input.h
Executable file
413
common/settings_input.h
Executable file
|
|
@ -0,0 +1,413 @@
|
||||||
|
// SPDX-FileCopyrightText: Copyright 2020 yuzu Emulator Project
|
||||||
|
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <array>
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
#include "common_types.h"
|
||||||
|
|
||||||
|
namespace Settings {
|
||||||
|
namespace NativeButton {
|
||||||
|
enum Values : int {
|
||||||
|
A,
|
||||||
|
B,
|
||||||
|
X,
|
||||||
|
Y,
|
||||||
|
LStick,
|
||||||
|
RStick,
|
||||||
|
L,
|
||||||
|
R,
|
||||||
|
ZL,
|
||||||
|
ZR,
|
||||||
|
Plus,
|
||||||
|
Minus,
|
||||||
|
|
||||||
|
DLeft,
|
||||||
|
DUp,
|
||||||
|
DRight,
|
||||||
|
DDown,
|
||||||
|
|
||||||
|
SLLeft,
|
||||||
|
SRLeft,
|
||||||
|
|
||||||
|
Home,
|
||||||
|
Screenshot,
|
||||||
|
|
||||||
|
SLRight,
|
||||||
|
SRRight,
|
||||||
|
|
||||||
|
NumButtons,
|
||||||
|
};
|
||||||
|
|
||||||
|
constexpr int BUTTON_HID_BEGIN = A;
|
||||||
|
constexpr int BUTTON_NS_BEGIN = Home;
|
||||||
|
|
||||||
|
constexpr int BUTTON_HID_END = BUTTON_NS_BEGIN;
|
||||||
|
constexpr int BUTTON_NS_END = NumButtons;
|
||||||
|
|
||||||
|
constexpr int NUM_BUTTONS_HID = BUTTON_HID_END - BUTTON_HID_BEGIN;
|
||||||
|
constexpr int NUM_BUTTONS_NS = BUTTON_NS_END - BUTTON_NS_BEGIN;
|
||||||
|
|
||||||
|
extern const std::array<const char*, NumButtons> mapping;
|
||||||
|
|
||||||
|
} // namespace NativeButton
|
||||||
|
|
||||||
|
namespace NativeAnalog {
|
||||||
|
enum Values : int {
|
||||||
|
LStick,
|
||||||
|
RStick,
|
||||||
|
|
||||||
|
NumAnalogs,
|
||||||
|
};
|
||||||
|
|
||||||
|
constexpr int STICK_HID_BEGIN = LStick;
|
||||||
|
constexpr int STICK_HID_END = NumAnalogs;
|
||||||
|
|
||||||
|
extern const std::array<const char*, NumAnalogs> mapping;
|
||||||
|
} // namespace NativeAnalog
|
||||||
|
|
||||||
|
namespace NativeTrigger {
|
||||||
|
enum Values : int {
|
||||||
|
LTrigger,
|
||||||
|
RTrigger,
|
||||||
|
|
||||||
|
NumTriggers,
|
||||||
|
};
|
||||||
|
|
||||||
|
constexpr int TRIGGER_HID_BEGIN = LTrigger;
|
||||||
|
constexpr int TRIGGER_HID_END = NumTriggers;
|
||||||
|
} // namespace NativeTrigger
|
||||||
|
|
||||||
|
namespace NativeVibration {
|
||||||
|
enum Values : int {
|
||||||
|
LeftVibrationDevice,
|
||||||
|
RightVibrationDevice,
|
||||||
|
|
||||||
|
NumVibrations,
|
||||||
|
};
|
||||||
|
|
||||||
|
constexpr int VIBRATION_HID_BEGIN = LeftVibrationDevice;
|
||||||
|
constexpr int VIBRATION_HID_END = NumVibrations;
|
||||||
|
constexpr int NUM_VIBRATIONS_HID = NumVibrations;
|
||||||
|
|
||||||
|
extern const std::array<const char*, NumVibrations> mapping;
|
||||||
|
}; // namespace NativeVibration
|
||||||
|
|
||||||
|
namespace NativeMotion {
|
||||||
|
enum Values : int {
|
||||||
|
MotionLeft,
|
||||||
|
MotionRight,
|
||||||
|
|
||||||
|
NumMotions,
|
||||||
|
};
|
||||||
|
|
||||||
|
constexpr int MOTION_HID_BEGIN = MotionLeft;
|
||||||
|
constexpr int MOTION_HID_END = NumMotions;
|
||||||
|
constexpr int NUM_MOTIONS_HID = NumMotions;
|
||||||
|
|
||||||
|
extern const std::array<const char*, NumMotions> mapping;
|
||||||
|
} // namespace NativeMotion
|
||||||
|
|
||||||
|
namespace NativeMouseButton {
|
||||||
|
enum Values {
|
||||||
|
Left,
|
||||||
|
Right,
|
||||||
|
Middle,
|
||||||
|
Forward,
|
||||||
|
Back,
|
||||||
|
|
||||||
|
NumMouseButtons,
|
||||||
|
};
|
||||||
|
|
||||||
|
constexpr int MOUSE_HID_BEGIN = Left;
|
||||||
|
constexpr int MOUSE_HID_END = NumMouseButtons;
|
||||||
|
constexpr int NUM_MOUSE_HID = NumMouseButtons;
|
||||||
|
|
||||||
|
extern const std::array<const char*, NumMouseButtons> mapping;
|
||||||
|
} // namespace NativeMouseButton
|
||||||
|
|
||||||
|
namespace NativeMouseWheel {
|
||||||
|
enum Values {
|
||||||
|
X,
|
||||||
|
Y,
|
||||||
|
|
||||||
|
NumMouseWheels,
|
||||||
|
};
|
||||||
|
|
||||||
|
extern const std::array<const char*, NumMouseWheels> mapping;
|
||||||
|
} // namespace NativeMouseWheel
|
||||||
|
|
||||||
|
namespace NativeKeyboard {
|
||||||
|
enum Keys {
|
||||||
|
None,
|
||||||
|
|
||||||
|
A = 4,
|
||||||
|
B,
|
||||||
|
C,
|
||||||
|
D,
|
||||||
|
E,
|
||||||
|
F,
|
||||||
|
G,
|
||||||
|
H,
|
||||||
|
I,
|
||||||
|
J,
|
||||||
|
K,
|
||||||
|
L,
|
||||||
|
M,
|
||||||
|
N,
|
||||||
|
O,
|
||||||
|
P,
|
||||||
|
Q,
|
||||||
|
R,
|
||||||
|
S,
|
||||||
|
T,
|
||||||
|
U,
|
||||||
|
V,
|
||||||
|
W,
|
||||||
|
X,
|
||||||
|
Y,
|
||||||
|
Z,
|
||||||
|
N1,
|
||||||
|
N2,
|
||||||
|
N3,
|
||||||
|
N4,
|
||||||
|
N5,
|
||||||
|
N6,
|
||||||
|
N7,
|
||||||
|
N8,
|
||||||
|
N9,
|
||||||
|
N0,
|
||||||
|
Return,
|
||||||
|
Escape,
|
||||||
|
Backspace,
|
||||||
|
Tab,
|
||||||
|
Space,
|
||||||
|
Minus,
|
||||||
|
Plus,
|
||||||
|
OpenBracket,
|
||||||
|
CloseBracket,
|
||||||
|
Pipe,
|
||||||
|
Tilde,
|
||||||
|
Semicolon,
|
||||||
|
Quote,
|
||||||
|
Backquote,
|
||||||
|
Comma,
|
||||||
|
Period,
|
||||||
|
Slash,
|
||||||
|
CapsLockKey,
|
||||||
|
|
||||||
|
F1,
|
||||||
|
F2,
|
||||||
|
F3,
|
||||||
|
F4,
|
||||||
|
F5,
|
||||||
|
F6,
|
||||||
|
F7,
|
||||||
|
F8,
|
||||||
|
F9,
|
||||||
|
F10,
|
||||||
|
F11,
|
||||||
|
F12,
|
||||||
|
|
||||||
|
PrintScreen,
|
||||||
|
ScrollLockKey,
|
||||||
|
Pause,
|
||||||
|
Insert,
|
||||||
|
Home,
|
||||||
|
PageUp,
|
||||||
|
Delete,
|
||||||
|
End,
|
||||||
|
PageDown,
|
||||||
|
Right,
|
||||||
|
Left,
|
||||||
|
Down,
|
||||||
|
Up,
|
||||||
|
|
||||||
|
NumLockKey,
|
||||||
|
KPSlash,
|
||||||
|
KPAsterisk,
|
||||||
|
KPMinus,
|
||||||
|
KPPlus,
|
||||||
|
KPEnter,
|
||||||
|
KP1,
|
||||||
|
KP2,
|
||||||
|
KP3,
|
||||||
|
KP4,
|
||||||
|
KP5,
|
||||||
|
KP6,
|
||||||
|
KP7,
|
||||||
|
KP8,
|
||||||
|
KP9,
|
||||||
|
KP0,
|
||||||
|
KPDot,
|
||||||
|
|
||||||
|
Key102,
|
||||||
|
Compose,
|
||||||
|
Power,
|
||||||
|
KPEqual,
|
||||||
|
|
||||||
|
F13,
|
||||||
|
F14,
|
||||||
|
F15,
|
||||||
|
F16,
|
||||||
|
F17,
|
||||||
|
F18,
|
||||||
|
F19,
|
||||||
|
F20,
|
||||||
|
F21,
|
||||||
|
F22,
|
||||||
|
F23,
|
||||||
|
F24,
|
||||||
|
|
||||||
|
Open,
|
||||||
|
Help,
|
||||||
|
Properties,
|
||||||
|
Front,
|
||||||
|
Stop,
|
||||||
|
Repeat,
|
||||||
|
Undo,
|
||||||
|
Cut,
|
||||||
|
Copy,
|
||||||
|
Paste,
|
||||||
|
Find,
|
||||||
|
Mute,
|
||||||
|
VolumeUp,
|
||||||
|
VolumeDown,
|
||||||
|
CapsLockActive,
|
||||||
|
NumLockActive,
|
||||||
|
ScrollLockActive,
|
||||||
|
KPComma,
|
||||||
|
|
||||||
|
Ro = 0x87,
|
||||||
|
KatakanaHiragana,
|
||||||
|
Yen,
|
||||||
|
Henkan,
|
||||||
|
Muhenkan,
|
||||||
|
NumPadCommaPc98,
|
||||||
|
|
||||||
|
HangulEnglish = 0x90,
|
||||||
|
Hanja,
|
||||||
|
KatakanaKey,
|
||||||
|
HiraganaKey,
|
||||||
|
ZenkakuHankaku,
|
||||||
|
|
||||||
|
LeftControlKey = 0xE0,
|
||||||
|
LeftShiftKey,
|
||||||
|
LeftAltKey,
|
||||||
|
LeftMetaKey,
|
||||||
|
RightControlKey,
|
||||||
|
RightShiftKey,
|
||||||
|
RightAltKey,
|
||||||
|
RightMetaKey,
|
||||||
|
|
||||||
|
MediaPlayPause,
|
||||||
|
MediaStopCD,
|
||||||
|
MediaPrevious,
|
||||||
|
MediaNext,
|
||||||
|
MediaEject,
|
||||||
|
MediaVolumeUp,
|
||||||
|
MediaVolumeDown,
|
||||||
|
MediaMute,
|
||||||
|
MediaWebsite,
|
||||||
|
MediaBack,
|
||||||
|
MediaForward,
|
||||||
|
MediaStop,
|
||||||
|
MediaFind,
|
||||||
|
MediaScrollUp,
|
||||||
|
MediaScrollDown,
|
||||||
|
MediaEdit,
|
||||||
|
MediaSleep,
|
||||||
|
MediaCoffee,
|
||||||
|
MediaRefresh,
|
||||||
|
MediaCalculator,
|
||||||
|
|
||||||
|
NumKeyboardKeys,
|
||||||
|
};
|
||||||
|
|
||||||
|
static_assert(NumKeyboardKeys == 0xFC, "Incorrect number of keyboard keys.");
|
||||||
|
|
||||||
|
enum Modifiers {
|
||||||
|
LeftControl,
|
||||||
|
LeftShift,
|
||||||
|
LeftAlt,
|
||||||
|
LeftMeta,
|
||||||
|
RightControl,
|
||||||
|
RightShift,
|
||||||
|
RightAlt,
|
||||||
|
RightMeta,
|
||||||
|
CapsLock,
|
||||||
|
ScrollLock,
|
||||||
|
NumLock,
|
||||||
|
Katakana,
|
||||||
|
Hiragana,
|
||||||
|
|
||||||
|
NumKeyboardMods,
|
||||||
|
};
|
||||||
|
|
||||||
|
constexpr int KEYBOARD_KEYS_HID_BEGIN = None;
|
||||||
|
constexpr int KEYBOARD_KEYS_HID_END = NumKeyboardKeys;
|
||||||
|
constexpr int NUM_KEYBOARD_KEYS_HID = NumKeyboardKeys;
|
||||||
|
|
||||||
|
constexpr int KEYBOARD_MODS_HID_BEGIN = LeftControl;
|
||||||
|
constexpr int KEYBOARD_MODS_HID_END = NumKeyboardMods;
|
||||||
|
constexpr int NUM_KEYBOARD_MODS_HID = NumKeyboardMods;
|
||||||
|
|
||||||
|
} // namespace NativeKeyboard
|
||||||
|
|
||||||
|
using AnalogsRaw = std::array<std::string, NativeAnalog::NumAnalogs>;
|
||||||
|
using ButtonsRaw = std::array<std::string, NativeButton::NumButtons>;
|
||||||
|
using MotionsRaw = std::array<std::string, NativeMotion::NumMotions>;
|
||||||
|
using RingconRaw = std::string;
|
||||||
|
|
||||||
|
constexpr u32 JOYCON_BODY_NEON_RED = 0xFF3C28;
|
||||||
|
constexpr u32 JOYCON_BUTTONS_NEON_RED = 0x1E0A0A;
|
||||||
|
constexpr u32 JOYCON_BODY_NEON_BLUE = 0x0AB9E6;
|
||||||
|
constexpr u32 JOYCON_BUTTONS_NEON_BLUE = 0x001E1E;
|
||||||
|
|
||||||
|
enum class ControllerType {
|
||||||
|
ProController,
|
||||||
|
DualJoyconDetached,
|
||||||
|
LeftJoycon,
|
||||||
|
RightJoycon,
|
||||||
|
Handheld,
|
||||||
|
GameCube,
|
||||||
|
Pokeball,
|
||||||
|
NES,
|
||||||
|
SNES,
|
||||||
|
N64,
|
||||||
|
SegaGenesis,
|
||||||
|
};
|
||||||
|
|
||||||
|
struct PlayerInput {
|
||||||
|
bool connected;
|
||||||
|
ControllerType controller_type;
|
||||||
|
ButtonsRaw buttons;
|
||||||
|
AnalogsRaw analogs;
|
||||||
|
MotionsRaw motions;
|
||||||
|
|
||||||
|
bool vibration_enabled;
|
||||||
|
int vibration_strength;
|
||||||
|
|
||||||
|
u32 body_color_left;
|
||||||
|
u32 body_color_right;
|
||||||
|
u32 button_color_left;
|
||||||
|
u32 button_color_right;
|
||||||
|
std::string profile_name;
|
||||||
|
|
||||||
|
// This is meant to tell the Android frontend whether to use a device's built-in vibration
|
||||||
|
// motor or a controller's vibrations.
|
||||||
|
bool use_system_vibrator;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct TouchscreenInput {
|
||||||
|
bool enabled;
|
||||||
|
std::string device;
|
||||||
|
|
||||||
|
u32 finger;
|
||||||
|
u32 diameter_x;
|
||||||
|
u32 diameter_y;
|
||||||
|
u32 rotation_angle;
|
||||||
|
};
|
||||||
|
} // namespace Settings
|
||||||
422
common/settings_setting.h
Executable file
422
common/settings_setting.h
Executable file
|
|
@ -0,0 +1,422 @@
|
||||||
|
// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
|
||||||
|
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <limits>
|
||||||
|
#include <map>
|
||||||
|
#include <optional>
|
||||||
|
#include <stdexcept>
|
||||||
|
#include <string>
|
||||||
|
#include <typeindex>
|
||||||
|
#include <typeinfo>
|
||||||
|
#include <fmt/core.h>
|
||||||
|
#include "common_types.h"
|
||||||
|
#include "settings_common.h"
|
||||||
|
#include "settings_enums.h"
|
||||||
|
|
||||||
|
namespace Settings {
|
||||||
|
|
||||||
|
/** The Setting class is a simple resource manager. It defines a label and default value
|
||||||
|
* alongside the actual value of the setting for simpler and less-error prone use with frontend
|
||||||
|
* configurations. Specifying a default value and label is required. A minimum and maximum range
|
||||||
|
* can be specified for sanitization.
|
||||||
|
*/
|
||||||
|
template <typename Type, bool ranged = false>
|
||||||
|
class Setting : public BasicSetting {
|
||||||
|
protected:
|
||||||
|
Setting() = default;
|
||||||
|
|
||||||
|
public:
|
||||||
|
/**
|
||||||
|
* Sets a default value, label, and setting value.
|
||||||
|
*
|
||||||
|
* @param linkage Setting registry
|
||||||
|
* @param default_val Initial value of the setting, and default value of the setting
|
||||||
|
* @param name Label for the setting
|
||||||
|
* @param category_ Category of the setting AKA INI group
|
||||||
|
* @param specialization_ Suggestion for how frontend implementations represent this in a config
|
||||||
|
* @param save_ Suggests that this should or should not be saved to a frontend config file
|
||||||
|
* @param runtime_modifiable_ Suggests whether this is modifiable while a guest is loaded
|
||||||
|
* @param other_setting_ A second Setting to associate to this one in metadata
|
||||||
|
*/
|
||||||
|
explicit Setting(Linkage& linkage, const Type& default_val, const std::string& name,
|
||||||
|
Category category_, u32 specialization_ = Specialization::Default,
|
||||||
|
bool save_ = true, bool runtime_modifiable_ = false,
|
||||||
|
BasicSetting* other_setting_ = nullptr)
|
||||||
|
requires(!ranged)
|
||||||
|
: BasicSetting(linkage, name, category_, save_, runtime_modifiable_, specialization_,
|
||||||
|
other_setting_),
|
||||||
|
value{default_val}, default_value{default_val} {}
|
||||||
|
virtual ~Setting() = default;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets a default value, minimum value, maximum value, and label.
|
||||||
|
*
|
||||||
|
* @param linkage Setting registry
|
||||||
|
* @param default_val Initial value of the setting, and default value of the setting
|
||||||
|
* @param min_val Sets the minimum allowed value of the setting
|
||||||
|
* @param max_val Sets the maximum allowed value of the setting
|
||||||
|
* @param name Label for the setting
|
||||||
|
* @param category_ Category of the setting AKA INI group
|
||||||
|
* @param specialization_ Suggestion for how frontend implementations represent this in a config
|
||||||
|
* @param save_ Suggests that this should or should not be saved to a frontend config file
|
||||||
|
* @param runtime_modifiable_ Suggests whether this is modifiable while a guest is loaded
|
||||||
|
* @param other_setting_ A second Setting to associate to this one in metadata
|
||||||
|
*/
|
||||||
|
explicit Setting(Linkage& linkage, const Type& default_val, const Type& min_val,
|
||||||
|
const Type& max_val, const std::string& name, Category category_,
|
||||||
|
u32 specialization_ = Specialization::Default, bool save_ = true,
|
||||||
|
bool runtime_modifiable_ = false, BasicSetting* other_setting_ = nullptr)
|
||||||
|
requires(ranged)
|
||||||
|
: BasicSetting(linkage, name, category_, save_, runtime_modifiable_, specialization_,
|
||||||
|
other_setting_),
|
||||||
|
value{default_val}, default_value{default_val}, maximum{max_val}, minimum{min_val} {}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns a reference to the setting's value.
|
||||||
|
*
|
||||||
|
* @returns A reference to the setting
|
||||||
|
*/
|
||||||
|
[[nodiscard]] virtual const Type& GetValue() const {
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
[[nodiscard]] virtual const Type& GetValue(bool need_global) const {
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the setting to the given value.
|
||||||
|
*
|
||||||
|
* @param val The desired value
|
||||||
|
*/
|
||||||
|
virtual void SetValue(const Type& val) {
|
||||||
|
Type temp{ranged ? std::clamp(val, minimum, maximum) : val};
|
||||||
|
std::swap(value, temp);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the value that this setting was created with.
|
||||||
|
*
|
||||||
|
* @returns A reference to the default value
|
||||||
|
*/
|
||||||
|
[[nodiscard]] const Type& GetDefault() const {
|
||||||
|
return default_value;
|
||||||
|
}
|
||||||
|
|
||||||
|
[[nodiscard]] constexpr bool IsEnum() const override {
|
||||||
|
return std::is_enum_v<Type>;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected:
|
||||||
|
[[nodiscard]] std::string ToString(const Type& value_) const {
|
||||||
|
if constexpr (std::is_same_v<Type, std::string>) {
|
||||||
|
return value_;
|
||||||
|
} else if constexpr (std::is_same_v<Type, std::optional<u32>>) {
|
||||||
|
return value_.has_value() ? std::to_string(*value_) : "none";
|
||||||
|
} else if constexpr (std::is_same_v<Type, bool>) {
|
||||||
|
return value_ ? "true" : "false";
|
||||||
|
} else if constexpr (std::is_same_v<Type, AudioEngine>) {
|
||||||
|
// Compatibility with old AudioEngine setting being a string
|
||||||
|
return CanonicalizeEnum(value_);
|
||||||
|
} else if constexpr (std::is_floating_point_v<Type>) {
|
||||||
|
return fmt::format("{:f}", value_);
|
||||||
|
} else if constexpr (std::is_enum_v<Type>) {
|
||||||
|
return std::to_string(static_cast<u32>(value_));
|
||||||
|
} else {
|
||||||
|
return std::to_string(value_);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public:
|
||||||
|
/**
|
||||||
|
* Converts the value of the setting to a std::string. Respects the global state if the setting
|
||||||
|
* has one.
|
||||||
|
*
|
||||||
|
* @returns The current setting as a std::string
|
||||||
|
*/
|
||||||
|
[[nodiscard]] std::string ToString() const override {
|
||||||
|
return ToString(this->GetValue());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the default value of the setting as a std::string.
|
||||||
|
*
|
||||||
|
* @returns The default value as a string.
|
||||||
|
*/
|
||||||
|
[[nodiscard]] std::string DefaultToString() const override {
|
||||||
|
return ToString(default_value);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Assigns a value to the setting.
|
||||||
|
*
|
||||||
|
* @param val The desired setting value
|
||||||
|
*
|
||||||
|
* @returns A reference to the setting
|
||||||
|
*/
|
||||||
|
virtual const Type& operator=(const Type& val) {
|
||||||
|
Type temp{ranged ? std::clamp(val, minimum, maximum) : val};
|
||||||
|
std::swap(value, temp);
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns a reference to the setting.
|
||||||
|
*
|
||||||
|
* @returns A reference to the setting
|
||||||
|
*/
|
||||||
|
explicit virtual operator const Type&() const {
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Converts the given value to the Setting's type of value. Uses SetValue to enter the setting,
|
||||||
|
* thus respecting its constraints.
|
||||||
|
*
|
||||||
|
* @param input The desired value
|
||||||
|
*/
|
||||||
|
void LoadString(const std::string& input) override final {
|
||||||
|
if (input.empty()) {
|
||||||
|
this->SetValue(this->GetDefault());
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
if constexpr (std::is_same_v<Type, std::string>) {
|
||||||
|
this->SetValue(input);
|
||||||
|
} else if constexpr (std::is_same_v<Type, std::optional<u32>>) {
|
||||||
|
this->SetValue(static_cast<u32>(std::stoul(input)));
|
||||||
|
} else if constexpr (std::is_same_v<Type, bool>) {
|
||||||
|
this->SetValue(input == "true");
|
||||||
|
} else if constexpr (std::is_same_v<Type, float>) {
|
||||||
|
this->SetValue(std::stof(input));
|
||||||
|
} else if constexpr (std::is_same_v<Type, AudioEngine>) {
|
||||||
|
this->SetValue(ToEnum<AudioEngine>(input));
|
||||||
|
} else {
|
||||||
|
this->SetValue(static_cast<Type>(std::stoll(input)));
|
||||||
|
}
|
||||||
|
} catch (std::invalid_argument&) {
|
||||||
|
this->SetValue(this->GetDefault());
|
||||||
|
} catch (std::out_of_range&) {
|
||||||
|
this->SetValue(this->GetDefault());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[[nodiscard]] std::string Canonicalize() const override final {
|
||||||
|
if constexpr (std::is_enum_v<Type>) {
|
||||||
|
return CanonicalizeEnum(this->GetValue());
|
||||||
|
} else {
|
||||||
|
return ToString(this->GetValue());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gives us another way to identify the setting without having to go through a string.
|
||||||
|
*
|
||||||
|
* @returns the type_index of the setting's type
|
||||||
|
*/
|
||||||
|
[[nodiscard]] std::type_index TypeId() const override final {
|
||||||
|
return std::type_index(typeid(Type));
|
||||||
|
}
|
||||||
|
|
||||||
|
[[nodiscard]] constexpr u32 EnumIndex() const override final {
|
||||||
|
if constexpr (std::is_enum_v<Type>) {
|
||||||
|
return EnumMetadata<Type>::Index();
|
||||||
|
} else {
|
||||||
|
return std::numeric_limits<u32>::max();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[[nodiscard]] constexpr bool IsFloatingPoint() const final {
|
||||||
|
return std::is_floating_point_v<Type>;
|
||||||
|
}
|
||||||
|
|
||||||
|
[[nodiscard]] constexpr bool IsIntegral() const final {
|
||||||
|
return std::is_integral_v<Type>;
|
||||||
|
}
|
||||||
|
|
||||||
|
[[nodiscard]] std::string MinVal() const override final {
|
||||||
|
if constexpr (std::is_arithmetic_v<Type> && !ranged) {
|
||||||
|
return this->ToString(std::numeric_limits<Type>::min());
|
||||||
|
} else {
|
||||||
|
return this->ToString(minimum);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
[[nodiscard]] std::string MaxVal() const override final {
|
||||||
|
if constexpr (std::is_arithmetic_v<Type> && !ranged) {
|
||||||
|
return this->ToString(std::numeric_limits<Type>::max());
|
||||||
|
} else {
|
||||||
|
return this->ToString(maximum);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[[nodiscard]] constexpr bool Ranged() const override {
|
||||||
|
return ranged;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected:
|
||||||
|
Type value{}; ///< The setting
|
||||||
|
const Type default_value{}; ///< The default value
|
||||||
|
const Type maximum{}; ///< Maximum allowed value of the setting
|
||||||
|
const Type minimum{}; ///< Minimum allowed value of the setting
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The SwitchableSetting class is a slightly more complex version of the Setting class. This adds a
|
||||||
|
* custom setting to switch to when a guest application specifically requires it. The effect is that
|
||||||
|
* other components of the emulator can access the setting's intended value without any need for the
|
||||||
|
* component to ask whether the custom or global setting is needed at the moment.
|
||||||
|
*
|
||||||
|
* By default, the global setting is used.
|
||||||
|
*/
|
||||||
|
template <typename Type, bool ranged = false>
|
||||||
|
class SwitchableSetting : virtual public Setting<Type, ranged> {
|
||||||
|
public:
|
||||||
|
/**
|
||||||
|
* Sets a default value, label, and setting value.
|
||||||
|
*
|
||||||
|
* @param linkage Setting registry
|
||||||
|
* @param default_val Initial value of the setting, and default value of the setting
|
||||||
|
* @param name Label for the setting
|
||||||
|
* @param category_ Category of the setting AKA INI group
|
||||||
|
* @param specialization_ Suggestion for how frontend implementations represent this in a config
|
||||||
|
* @param save_ Suggests that this should or should not be saved to a frontend config file
|
||||||
|
* @param runtime_modifiable_ Suggests whether this is modifiable while a guest is loaded
|
||||||
|
* @param other_setting_ A second Setting to associate to this one in metadata
|
||||||
|
*/
|
||||||
|
template <typename T = BasicSetting>
|
||||||
|
explicit SwitchableSetting(Linkage& linkage, const Type& default_val, const std::string& name,
|
||||||
|
Category category_, u32 specialization_ = Specialization::Default,
|
||||||
|
bool save_ = true, bool runtime_modifiable_ = false,
|
||||||
|
typename std::enable_if<!ranged, T*>::type other_setting_ = nullptr)
|
||||||
|
: Setting<Type, false>{
|
||||||
|
linkage, default_val, name, category_, specialization_,
|
||||||
|
save_, runtime_modifiable_, other_setting_} {
|
||||||
|
linkage.restore_functions.emplace_back([this]() { this->SetGlobal(true); });
|
||||||
|
}
|
||||||
|
virtual ~SwitchableSetting() = default;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets a default value, minimum value, maximum value, and label.
|
||||||
|
*
|
||||||
|
* @param linkage Setting registry
|
||||||
|
* @param default_val Initial value of the setting, and default value of the setting
|
||||||
|
* @param min_val Sets the minimum allowed value of the setting
|
||||||
|
* @param max_val Sets the maximum allowed value of the setting
|
||||||
|
* @param name Label for the setting
|
||||||
|
* @param category_ Category of the setting AKA INI group
|
||||||
|
* @param specialization_ Suggestion for how frontend implementations represent this in a config
|
||||||
|
* @param save_ Suggests that this should or should not be saved to a frontend config file
|
||||||
|
* @param runtime_modifiable_ Suggests whether this is modifiable while a guest is loaded
|
||||||
|
* @param other_setting_ A second Setting to associate to this one in metadata
|
||||||
|
*/
|
||||||
|
template <typename T = BasicSetting>
|
||||||
|
explicit SwitchableSetting(Linkage& linkage, const Type& default_val, const Type& min_val,
|
||||||
|
const Type& max_val, const std::string& name, Category category_,
|
||||||
|
u32 specialization_ = Specialization::Default, bool save_ = true,
|
||||||
|
bool runtime_modifiable_ = false,
|
||||||
|
typename std::enable_if<ranged, T*>::type other_setting_ = nullptr)
|
||||||
|
: Setting<Type, true>{linkage, default_val, min_val,
|
||||||
|
max_val, name, category_,
|
||||||
|
specialization_, save_, runtime_modifiable_,
|
||||||
|
other_setting_} {
|
||||||
|
linkage.restore_functions.emplace_back([this]() { this->SetGlobal(true); });
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Tells this setting to represent either the global or custom setting when other member
|
||||||
|
* functions are used.
|
||||||
|
*
|
||||||
|
* @param to_global Whether to use the global or custom setting.
|
||||||
|
*/
|
||||||
|
void SetGlobal(bool to_global) override final {
|
||||||
|
use_global = to_global;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns whether this setting is using the global setting or not.
|
||||||
|
*
|
||||||
|
* @returns The global state
|
||||||
|
*/
|
||||||
|
[[nodiscard]] bool UsingGlobal() const override final {
|
||||||
|
return use_global;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns either the global or custom setting depending on the values of this setting's global
|
||||||
|
* state or if the global value was specifically requested.
|
||||||
|
*
|
||||||
|
* @param need_global Request global value regardless of setting's state; defaults to false
|
||||||
|
*
|
||||||
|
* @returns The required value of the setting
|
||||||
|
*/
|
||||||
|
[[nodiscard]] const Type& GetValue() const override final {
|
||||||
|
if (use_global) {
|
||||||
|
return this->value;
|
||||||
|
}
|
||||||
|
return custom;
|
||||||
|
}
|
||||||
|
[[nodiscard]] const Type& GetValue(bool need_global) const override final {
|
||||||
|
if (use_global || need_global) {
|
||||||
|
return this->value;
|
||||||
|
}
|
||||||
|
return custom;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the current setting value depending on the global state.
|
||||||
|
*
|
||||||
|
* @param val The new value
|
||||||
|
*/
|
||||||
|
void SetValue(const Type& val) override final {
|
||||||
|
Type temp{ranged ? std::clamp(val, this->minimum, this->maximum) : val};
|
||||||
|
if (use_global) {
|
||||||
|
std::swap(this->value, temp);
|
||||||
|
} else {
|
||||||
|
std::swap(custom, temp);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[[nodiscard]] constexpr bool Switchable() const override final {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
[[nodiscard]] std::string ToStringGlobal() const override final {
|
||||||
|
return this->ToString(this->value);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Assigns the current setting value depending on the global state.
|
||||||
|
*
|
||||||
|
* @param val The new value
|
||||||
|
*
|
||||||
|
* @returns A reference to the current setting value
|
||||||
|
*/
|
||||||
|
const Type& operator=(const Type& val) override final {
|
||||||
|
Type temp{ranged ? std::clamp(val, this->minimum, this->maximum) : val};
|
||||||
|
if (use_global) {
|
||||||
|
std::swap(this->value, temp);
|
||||||
|
return this->value;
|
||||||
|
}
|
||||||
|
std::swap(custom, temp);
|
||||||
|
return custom;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the current setting value depending on the global state.
|
||||||
|
*
|
||||||
|
* @returns A reference to the current setting value
|
||||||
|
*/
|
||||||
|
explicit operator const Type&() const override final {
|
||||||
|
if (use_global) {
|
||||||
|
return this->value;
|
||||||
|
}
|
||||||
|
return custom;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected:
|
||||||
|
bool use_global{true}; ///< The setting's global state
|
||||||
|
Type custom{}; ///< The custom value of the setting
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace Settings
|
||||||
|
|
@ -7,9 +7,9 @@
|
||||||
#include <memory>
|
#include <memory>
|
||||||
#include <set>
|
#include <set>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
#include "common/common_types.h"
|
#include "../common/common_types.h"
|
||||||
#include "core/file_sys/nca_metadata.h"
|
#include "nca_metadata.h"
|
||||||
#include "core/file_sys/vfs/vfs.h"
|
#include "../core/fs/vfs/vfs.h"
|
||||||
|
|
||||||
namespace Core::Crypto {
|
namespace Core::Crypto {
|
||||||
class KeyManager;
|
class KeyManager;
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue