diff --git a/src/core/math_func.hpp b/src/core/math_func.hpp index 254496a733..a9784dee51 100644 --- a/src/core/math_func.hpp +++ b/src/core/math_func.hpp @@ -83,6 +83,32 @@ static inline T Clamp(const T a, const T min, const T max) return a; } +/** + * Clamp a value between an interval. + * + * This function returns a value which is between the given interval of + * min and max. If the given value is in this interval the value itself + * is returned otherwise the border of the interval is returned, according + * which side of the interval was 'left'. + * + * @note If the min value is greater than the max, return value is the average of the min and max. + * @param a The value to clamp/truncate. + * @param min The minimum of the interval. + * @param max the maximum of the interval. + * @returns A value between min and max which is closest to a. + */ +template +static inline T SoftClamp(const T a, const T min, const T max) +{ + if (min > max) { + using U = std::make_unsigned_t; + return min - (U(min) - max) / 2; + } + if (a <= min) return min; + if (a >= max) return max; + return a; +} + /** * Clamp an integer between an interval. * diff --git a/src/misc_gui.cpp b/src/misc_gui.cpp index 802d67edd3..69475fdfd4 100644 --- a/src/misc_gui.cpp +++ b/src/misc_gui.cpp @@ -1140,8 +1140,8 @@ struct QueryWindow : public Window { void FindWindowPlacementAndResize(int def_width, int def_height) override { /* Position query window over the calling window, ensuring it's within screen bounds. */ - this->left = Clamp(parent->left + (parent->width / 2) - (this->width / 2), 0, _screen.width - this->width); - this->top = Clamp(parent->top + (parent->height / 2) - (this->height / 2), 0, _screen.height - this->height); + this->left = SoftClamp(parent->left + (parent->width / 2) - (this->width / 2), 0, _screen.width - this->width); + this->top = SoftClamp(parent->top + (parent->height / 2) - (this->height / 2), 0, _screen.height - this->height); this->SetDirty(); } diff --git a/src/tests/math_func.cpp b/src/tests/math_func.cpp index 8db813c105..25abb1838e 100644 --- a/src/tests/math_func.cpp +++ b/src/tests/math_func.cpp @@ -120,3 +120,13 @@ TEST_CASE("ClampTo") /* max uint64_t gets clamped to max int64_t. */ CHECK(std::numeric_limits::max() == ClampTo(std::numeric_limits::max())); } + + +TEST_CASE("SoftClamp") +{ + /* Special behaviour of soft clamp returning the average of min/max when min is higher than max. */ + CHECK(1250 == SoftClamp(0, 1500, 1000)); + int million = 1000 * 1000; + CHECK(1250 * million == SoftClamp(0, 1500 * million, 1000 * million)); + CHECK(0 == SoftClamp(0, 1500 * million, -1500 * million)); +}