Gui: Add standardized HintsTable for InputHints
Input hints in various DrawSketchHandler were implemented independently using declarative mechanism with searching over lookup table. This results in a lot of duplicated code, this commit will create generic mechanisms that can be used to replace them.
This commit is contained in:
@@ -253,6 +253,16 @@ struct InputHint
|
||||
InputSequence(const std::initializer_list<UserInput> keys)
|
||||
: keys(keys)
|
||||
{}
|
||||
|
||||
friend bool operator==(const InputSequence& lhs, const InputSequence& rhs)
|
||||
{
|
||||
return lhs.keys == rhs.keys;
|
||||
}
|
||||
|
||||
friend bool operator!=(const InputSequence& lhs, const InputSequence& rhs)
|
||||
{
|
||||
return !(lhs == rhs);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -270,8 +280,41 @@ struct InputHint
|
||||
* @brief List of sequences to be substituted.
|
||||
*/
|
||||
std::list<InputSequence> sequences;
|
||||
|
||||
friend bool operator==(const InputHint& lhs, const InputHint& rhs)
|
||||
{
|
||||
return lhs.message == rhs.message && lhs.sequences == rhs.sequences;
|
||||
}
|
||||
|
||||
friend bool operator!=(const InputHint& lhs, const InputHint& rhs)
|
||||
{
|
||||
return !(lhs == rhs);
|
||||
}
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
struct StateHints
|
||||
{
|
||||
T state;
|
||||
std::list<InputHint> hints;
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
using HintTable = std::vector<StateHints<T>>;
|
||||
|
||||
template <typename T>
|
||||
static std::list<InputHint> lookupHints(T state, HintTable<T> table, const std::list<InputHint>& fallback = {}) {
|
||||
const auto stateMatches = [&state](const StateHints<T>& entry) {
|
||||
return entry.state == state;
|
||||
};
|
||||
|
||||
if (auto it = std::ranges::find_if(table, stateMatches); it != table.end()) {
|
||||
return it->hints;
|
||||
}
|
||||
|
||||
return fallback;
|
||||
}
|
||||
|
||||
} // namespace Gui
|
||||
|
||||
#endif // GUI_INPUTHINT_H
|
||||
|
||||
@@ -5,12 +5,12 @@ add_executable(Gui_tests_run
|
||||
StyleParameters/StyleParametersApplicationTest.cpp
|
||||
StyleParameters/ParserTest.cpp
|
||||
StyleParameters/ParameterManagerTest.cpp
|
||||
InputHintTest.cpp
|
||||
)
|
||||
|
||||
# Qt tests
|
||||
setup_qt_test(QuantitySpinBox)
|
||||
|
||||
|
||||
target_link_libraries(Gui_tests_run PRIVATE
|
||||
GTest::gtest_main
|
||||
GTest::gmock_main
|
||||
|
||||
85
tests/src/Gui/InputHintTest.cpp
Normal file
85
tests/src/Gui/InputHintTest.cpp
Normal file
@@ -0,0 +1,85 @@
|
||||
#include <gtest/gtest.h>
|
||||
|
||||
#include "Gui/InputHint.h"
|
||||
|
||||
using namespace Gui;
|
||||
using enum InputHint::UserInput;
|
||||
|
||||
class InputHintTest: public ::testing::Test
|
||||
{
|
||||
protected:
|
||||
enum class State : std::uint8_t
|
||||
{
|
||||
SeekFirst,
|
||||
SeekSecond
|
||||
};
|
||||
|
||||
enum class Method : std::uint8_t
|
||||
{
|
||||
FirstMethod,
|
||||
SecondMethod
|
||||
};
|
||||
|
||||
using StateMethod = std::pair<State, Method>;
|
||||
|
||||
// Constants for hints
|
||||
static const InputHint firstHint;
|
||||
static const InputHint secondHint;
|
||||
static const InputHint firstMethodHint;
|
||||
static const InputHint secondMethodHint;
|
||||
static const InputHint thirdMethodHint;
|
||||
static const InputHint fourthMethodHint;
|
||||
};
|
||||
|
||||
// Define the constants
|
||||
const InputHint InputHintTest::firstHint = {QString("First hint"), {{KeySpace}}};
|
||||
const InputHint InputHintTest::secondHint = {QString("Second hint"), {{KeyEnter}}};
|
||||
const InputHint InputHintTest::firstMethodHint = {QString("First method hint"), {{KeyA}}};
|
||||
const InputHint InputHintTest::secondMethodHint = {QString("Second method hint"), {{KeyB}}};
|
||||
const InputHint InputHintTest::thirdMethodHint = {QString("Third method hint"), {{KeyC}}};
|
||||
const InputHint InputHintTest::fourthMethodHint = {QString("Fourth method hint"), {{KeyD}}};
|
||||
|
||||
TEST_F(InputHintTest, LookupHintsSimpleState)
|
||||
{
|
||||
// Arrange
|
||||
std::list<InputHint> hintsSeekFirst = {firstHint};
|
||||
std::list<InputHint> hintsSeekSecond = {secondHint};
|
||||
|
||||
HintTable<State> table = {{.state = State::SeekFirst, .hints = hintsSeekFirst},
|
||||
{.state = State::SeekSecond, .hints = hintsSeekSecond}};
|
||||
|
||||
// Act
|
||||
auto resultFirst = lookupHints(State::SeekFirst, table);
|
||||
auto resultSecond = lookupHints(State::SeekSecond, table);
|
||||
|
||||
// Assert
|
||||
EXPECT_EQ(resultFirst, hintsSeekFirst);
|
||||
EXPECT_EQ(resultSecond, hintsSeekSecond);
|
||||
}
|
||||
|
||||
TEST_F(InputHintTest, LookupHintsPairState)
|
||||
{
|
||||
// Arrange
|
||||
std::list<InputHint> firstFirstHints = {firstMethodHint};
|
||||
std::list<InputHint> firstSecondHints = {secondMethodHint};
|
||||
std::list<InputHint> secondFirstHints = {thirdMethodHint};
|
||||
std::list<InputHint> secondSecondHints = {fourthMethodHint};
|
||||
|
||||
HintTable<StateMethod> table = {
|
||||
{.state = {State::SeekFirst, Method::FirstMethod}, .hints = firstFirstHints},
|
||||
{.state = {State::SeekFirst, Method::SecondMethod}, .hints = firstSecondHints},
|
||||
{.state = {State::SeekSecond, Method::FirstMethod}, .hints = secondFirstHints},
|
||||
{.state = {State::SeekSecond, Method::SecondMethod}, .hints = secondSecondHints}};
|
||||
|
||||
// Act
|
||||
auto resultFirstFirst = lookupHints({State::SeekFirst, Method::FirstMethod}, table);
|
||||
auto resultFirstSecond = lookupHints({State::SeekFirst, Method::SecondMethod}, table);
|
||||
auto resultSecondFirst = lookupHints({State::SeekSecond, Method::FirstMethod}, table);
|
||||
auto resultSecondSecond = lookupHints({State::SeekSecond, Method::SecondMethod}, table);
|
||||
|
||||
// Assert
|
||||
EXPECT_EQ(resultFirstFirst, firstFirstHints);
|
||||
EXPECT_EQ(resultFirstSecond, firstSecondHints);
|
||||
EXPECT_EQ(resultSecondFirst, secondFirstHints);
|
||||
EXPECT_EQ(resultSecondSecond, secondSecondHints);
|
||||
}
|
||||
Reference in New Issue
Block a user