Remove legacy string enum comparisons from InputState/Key/MouseButton, closes #306
Removed custom __eq__/__ne__ that allowed comparing enums to legacy string names (e.g., Key.ESCAPE == "Escape"). Removed _legacy_names dicts and to_legacy_string() functions. Kept from_legacy_string() in PyKey.cpp as it's used by C++ event dispatch. Updated ~50 Python test/demo/cookbook files to use enum members instead of string comparisons. Also updates grid.position -> grid.pos in files that had both types of changes. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
parent
354faca838
commit
6d5e99a114
52 changed files with 372 additions and 533 deletions
|
|
@ -4,24 +4,19 @@
|
|||
// Static storage for cached enum class reference
|
||||
PyObject* PyInputState::input_state_enum_class = nullptr;
|
||||
|
||||
// InputState entries - maps enum name to value and legacy string
|
||||
// InputState entries - maps enum name to value
|
||||
struct InputStateEntry {
|
||||
const char* name; // Python enum name (UPPER_SNAKE_CASE)
|
||||
int value; // Integer value
|
||||
const char* legacy; // Legacy string name for backwards compatibility
|
||||
};
|
||||
|
||||
static const InputStateEntry input_state_table[] = {
|
||||
{"PRESSED", 0, "start"},
|
||||
{"RELEASED", 1, "end"},
|
||||
{"PRESSED", 0},
|
||||
{"RELEASED", 1},
|
||||
};
|
||||
|
||||
static const int NUM_INPUT_STATE_ENTRIES = sizeof(input_state_table) / sizeof(input_state_table[0]);
|
||||
|
||||
const char* PyInputState::to_legacy_string(bool pressed) {
|
||||
return pressed ? "start" : "end";
|
||||
}
|
||||
|
||||
PyObject* PyInputState::create_enum_class(PyObject* module) {
|
||||
// Build the enum definition dynamically from the table
|
||||
std::ostringstream code;
|
||||
|
|
@ -31,13 +26,8 @@ PyObject* PyInputState::create_enum_class(PyObject* module) {
|
|||
code << " \"\"\"Enum representing input event states (pressed/released).\n";
|
||||
code << " \n";
|
||||
code << " Values:\n";
|
||||
code << " PRESSED: Key or button was pressed (legacy: 'start')\n";
|
||||
code << " RELEASED: Key or button was released (legacy: 'end')\n";
|
||||
code << " \n";
|
||||
code << " These enum values compare equal to their legacy string equivalents\n";
|
||||
code << " for backwards compatibility:\n";
|
||||
code << " InputState.PRESSED == 'start' # True\n";
|
||||
code << " InputState.RELEASED == 'end' # True\n";
|
||||
code << " PRESSED: Key or button was pressed\n";
|
||||
code << " RELEASED: Key or button was released\n";
|
||||
code << " \"\"\"\n";
|
||||
|
||||
// Add enum members
|
||||
|
|
@ -45,42 +35,10 @@ PyObject* PyInputState::create_enum_class(PyObject* module) {
|
|||
code << " " << input_state_table[i].name << " = " << input_state_table[i].value << "\n";
|
||||
}
|
||||
|
||||
// Add legacy names and custom methods AFTER class creation
|
||||
// (IntEnum doesn't allow dict attributes during class definition)
|
||||
code << "\n# Add legacy name mapping after class creation\n";
|
||||
code << "InputState._legacy_names = {\n";
|
||||
for (int i = 0; i < NUM_INPUT_STATE_ENTRIES; i++) {
|
||||
code << " " << input_state_table[i].value << ": \"" << input_state_table[i].legacy << "\",\n";
|
||||
}
|
||||
code << "}\n\n";
|
||||
|
||||
code << R"(
|
||||
def _InputState_eq(self, other):
|
||||
if isinstance(other, str):
|
||||
# Check enum name match (e.g., "PRESSED")
|
||||
if self.name == other:
|
||||
return True
|
||||
# Check legacy name match (e.g., "start")
|
||||
legacy = type(self)._legacy_names.get(self.value)
|
||||
if legacy and legacy == other:
|
||||
return True
|
||||
return False
|
||||
# Fall back to int comparison for IntEnum
|
||||
return int.__eq__(int(self), other)
|
||||
|
||||
InputState.__eq__ = _InputState_eq
|
||||
|
||||
def _InputState_ne(self, other):
|
||||
result = type(self).__eq__(self, other)
|
||||
if result is NotImplemented:
|
||||
return result
|
||||
return not result
|
||||
|
||||
InputState.__ne__ = _InputState_ne
|
||||
InputState.__hash__ = lambda self: hash(int(self))
|
||||
InputState.__repr__ = lambda self: f"{type(self).__name__}.{self.name}"
|
||||
InputState.__str__ = lambda self: self.name
|
||||
)";
|
||||
code << "\n";
|
||||
code << "InputState.__hash__ = lambda self: hash(int(self))\n";
|
||||
code << "InputState.__repr__ = lambda self: f\"{type(self).__name__}.{self.name}\"\n";
|
||||
code << "InputState.__str__ = lambda self: self.name\n";
|
||||
|
||||
std::string code_str = code.str();
|
||||
|
||||
|
|
@ -167,25 +125,22 @@ int PyInputState::from_arg(PyObject* arg, bool* out_pressed) {
|
|||
return 0;
|
||||
}
|
||||
|
||||
// Accept string (both new and legacy names)
|
||||
// Accept string (enum name only)
|
||||
if (PyUnicode_Check(arg)) {
|
||||
const char* name = PyUnicode_AsUTF8(arg);
|
||||
if (!name) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Check all entries for both name and legacy match
|
||||
for (int i = 0; i < NUM_INPUT_STATE_ENTRIES; i++) {
|
||||
if (strcmp(name, input_state_table[i].name) == 0 ||
|
||||
strcmp(name, input_state_table[i].legacy) == 0) {
|
||||
if (strcmp(name, input_state_table[i].name) == 0) {
|
||||
*out_pressed = (input_state_table[i].value == 0);
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
PyErr_Format(PyExc_ValueError,
|
||||
"Unknown InputState: '%s'. Use InputState.PRESSED, InputState.RELEASED, "
|
||||
"or legacy strings 'start', 'end'.", name);
|
||||
"Unknown InputState: '%s'. Use InputState.PRESSED or InputState.RELEASED.", name);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -6,10 +6,8 @@
|
|||
// Stored as a module attribute: mcrfpy.InputState
|
||||
//
|
||||
// Values:
|
||||
// PRESSED = 0 (corresponds to "start" in legacy API)
|
||||
// RELEASED = 1 (corresponds to "end" in legacy API)
|
||||
//
|
||||
// The enum compares equal to both its name ("PRESSED") and legacy string ("start")
|
||||
// PRESSED = 0
|
||||
// RELEASED = 1
|
||||
|
||||
class PyInputState {
|
||||
public:
|
||||
|
|
@ -18,14 +16,11 @@ public:
|
|||
static PyObject* create_enum_class(PyObject* module);
|
||||
|
||||
// Helper to extract input state from Python arg
|
||||
// Accepts InputState enum, string (for backwards compatibility), int, or None
|
||||
// Accepts InputState enum, string (enum name), or int
|
||||
// Returns 1 on success, 0 on error (with exception set)
|
||||
// out_pressed is set to true for PRESSED/start, false for RELEASED/end
|
||||
// out_pressed is set to true for PRESSED, false for RELEASED
|
||||
static int from_arg(PyObject* arg, bool* out_pressed);
|
||||
|
||||
// Convert bool to legacy string name (for passing to callbacks)
|
||||
static const char* to_legacy_string(bool pressed);
|
||||
|
||||
// Cached reference to the InputState enum class for fast type checking
|
||||
static PyObject* input_state_enum_class;
|
||||
|
||||
|
|
|
|||
|
|
@ -143,15 +143,6 @@ static const KeyEntry key_table[] = {
|
|||
|
||||
static const int NUM_KEY_ENTRIES = sizeof(key_table) / sizeof(key_table[0]);
|
||||
|
||||
const char* PyKey::to_legacy_string(sf::Keyboard::Key key) {
|
||||
for (int i = 0; i < NUM_KEY_ENTRIES; i++) {
|
||||
if (key_table[i].value == static_cast<int>(key)) {
|
||||
return key_table[i].legacy;
|
||||
}
|
||||
}
|
||||
return "Unknown";
|
||||
}
|
||||
|
||||
sf::Keyboard::Key PyKey::from_legacy_string(const char* name) {
|
||||
for (int i = 0; i < NUM_KEY_ENTRIES; i++) {
|
||||
if (strcmp(key_table[i].legacy, name) == 0 ||
|
||||
|
|
@ -181,11 +172,6 @@ PyObject* PyKey::create_enum_class(PyObject* module) {
|
|||
code << " Navigation: LEFT, RIGHT, UP, DOWN, HOME, END, PAGE_UP, PAGE_DOWN\n";
|
||||
code << " Editing: ENTER, BACKSPACE, DELETE, INSERT, TAB, SPACE\n";
|
||||
code << " Symbols: COMMA, PERIOD, SLASH, SEMICOLON, etc.\n";
|
||||
code << " \n";
|
||||
code << " These enum values compare equal to their legacy string equivalents\n";
|
||||
code << " for backwards compatibility:\n";
|
||||
code << " Key.ESCAPE == 'Escape' # True\n";
|
||||
code << " Key.LEFT_SHIFT == 'LShift' # True\n";
|
||||
code << " \"\"\"\n";
|
||||
|
||||
// Add enum members
|
||||
|
|
@ -193,42 +179,10 @@ PyObject* PyKey::create_enum_class(PyObject* module) {
|
|||
code << " " << key_table[i].name << " = " << key_table[i].value << "\n";
|
||||
}
|
||||
|
||||
// Add legacy names and custom methods AFTER class creation
|
||||
// (IntEnum doesn't allow dict attributes during class definition)
|
||||
code << "\n# Add legacy name mapping after class creation\n";
|
||||
code << "Key._legacy_names = {\n";
|
||||
for (int i = 0; i < NUM_KEY_ENTRIES; i++) {
|
||||
code << " " << key_table[i].value << ": \"" << key_table[i].legacy << "\",\n";
|
||||
}
|
||||
code << "}\n\n";
|
||||
|
||||
code << R"(
|
||||
def _Key_eq(self, other):
|
||||
if isinstance(other, str):
|
||||
# Check enum name match (e.g., "ESCAPE")
|
||||
if self.name == other:
|
||||
return True
|
||||
# Check legacy name match (e.g., "Escape")
|
||||
legacy = type(self)._legacy_names.get(self.value)
|
||||
if legacy and legacy == other:
|
||||
return True
|
||||
return False
|
||||
# Fall back to int comparison for IntEnum
|
||||
return int.__eq__(int(self), other)
|
||||
|
||||
Key.__eq__ = _Key_eq
|
||||
|
||||
def _Key_ne(self, other):
|
||||
result = type(self).__eq__(self, other)
|
||||
if result is NotImplemented:
|
||||
return result
|
||||
return not result
|
||||
|
||||
Key.__ne__ = _Key_ne
|
||||
Key.__hash__ = lambda self: hash(int(self))
|
||||
Key.__repr__ = lambda self: f"{type(self).__name__}.{self.name}"
|
||||
Key.__str__ = lambda self: self.name
|
||||
)";
|
||||
code << "\n";
|
||||
code << "Key.__hash__ = lambda self: hash(int(self))\n";
|
||||
code << "Key.__repr__ = lambda self: f\"{type(self).__name__}.{self.name}\"\n";
|
||||
code << "Key.__str__ = lambda self: self.name\n";
|
||||
|
||||
std::string code_str = code.str();
|
||||
|
||||
|
|
@ -315,25 +269,22 @@ int PyKey::from_arg(PyObject* arg, sf::Keyboard::Key* out_key) {
|
|||
return 0;
|
||||
}
|
||||
|
||||
// Accept string (both new and legacy names)
|
||||
// Accept string (enum name only)
|
||||
if (PyUnicode_Check(arg)) {
|
||||
const char* name = PyUnicode_AsUTF8(arg);
|
||||
if (!name) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Check all entries for both name and legacy match
|
||||
for (int i = 0; i < NUM_KEY_ENTRIES; i++) {
|
||||
if (strcmp(name, key_table[i].name) == 0 ||
|
||||
strcmp(name, key_table[i].legacy) == 0) {
|
||||
if (strcmp(name, key_table[i].name) == 0) {
|
||||
*out_key = static_cast<sf::Keyboard::Key>(key_table[i].value);
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
PyErr_Format(PyExc_ValueError,
|
||||
"Unknown Key: '%s'. Use Key enum members (e.g., Key.ESCAPE, Key.A) "
|
||||
"or legacy strings (e.g., 'Escape', 'A').", name);
|
||||
"Unknown Key: '%s'. Use Key enum members (e.g., Key.ESCAPE, Key.A).", name);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -6,7 +6,6 @@
|
|||
// Stored as a module attribute: mcrfpy.Key
|
||||
//
|
||||
// Values map to sf::Keyboard::Key enum values.
|
||||
// The enum compares equal to both its name ("ESCAPE") and legacy string ("Escape")
|
||||
//
|
||||
// Naming convention:
|
||||
// - Letters: A, B, C, ... Z
|
||||
|
|
@ -24,14 +23,11 @@ public:
|
|||
static PyObject* create_enum_class(PyObject* module);
|
||||
|
||||
// Helper to extract key from Python arg
|
||||
// Accepts Key enum, string (for backwards compatibility), int, or None
|
||||
// Accepts Key enum, string (enum name), or int
|
||||
// Returns 1 on success, 0 on error (with exception set)
|
||||
static int from_arg(PyObject* arg, sf::Keyboard::Key* out_key);
|
||||
|
||||
// Convert sf::Keyboard::Key to legacy string name (for passing to callbacks)
|
||||
static const char* to_legacy_string(sf::Keyboard::Key key);
|
||||
|
||||
// Convert legacy string to sf::Keyboard::Key
|
||||
// Convert string name to sf::Keyboard::Key (used by C++ event dispatch)
|
||||
// Returns sf::Keyboard::Unknown if not found
|
||||
static sf::Keyboard::Key from_legacy_string(const char* name);
|
||||
|
||||
|
|
|
|||
|
|
@ -4,11 +4,10 @@
|
|||
// Static storage for cached enum class reference
|
||||
PyObject* PyMouseButton::mouse_button_enum_class = nullptr;
|
||||
|
||||
// MouseButton entries - maps enum name to value and legacy string
|
||||
// MouseButton entries - maps enum name to value
|
||||
struct MouseButtonEntry {
|
||||
const char* name; // Python enum name (UPPER_SNAKE_CASE)
|
||||
int value; // Integer value (matches sf::Mouse::Button)
|
||||
const char* legacy; // Legacy string name for backwards compatibility
|
||||
};
|
||||
|
||||
// Custom values for scroll wheel (beyond sf::Mouse::Button range)
|
||||
|
|
@ -16,26 +15,17 @@ static const int SCROLL_UP_VALUE = 10;
|
|||
static const int SCROLL_DOWN_VALUE = 11;
|
||||
|
||||
static const MouseButtonEntry mouse_button_table[] = {
|
||||
{"LEFT", sf::Mouse::Left, "left"},
|
||||
{"RIGHT", sf::Mouse::Right, "right"},
|
||||
{"MIDDLE", sf::Mouse::Middle, "middle"},
|
||||
{"X1", sf::Mouse::XButton1, "x1"},
|
||||
{"X2", sf::Mouse::XButton2, "x2"},
|
||||
{"SCROLL_UP", SCROLL_UP_VALUE, "wheel_up"},
|
||||
{"SCROLL_DOWN", SCROLL_DOWN_VALUE, "wheel_down"},
|
||||
{"LEFT", sf::Mouse::Left},
|
||||
{"RIGHT", sf::Mouse::Right},
|
||||
{"MIDDLE", sf::Mouse::Middle},
|
||||
{"X1", sf::Mouse::XButton1},
|
||||
{"X2", sf::Mouse::XButton2},
|
||||
{"SCROLL_UP", SCROLL_UP_VALUE},
|
||||
{"SCROLL_DOWN", SCROLL_DOWN_VALUE},
|
||||
};
|
||||
|
||||
static const int NUM_MOUSE_BUTTON_ENTRIES = sizeof(mouse_button_table) / sizeof(mouse_button_table[0]);
|
||||
|
||||
const char* PyMouseButton::to_legacy_string(sf::Mouse::Button button) {
|
||||
for (int i = 0; i < NUM_MOUSE_BUTTON_ENTRIES; i++) {
|
||||
if (mouse_button_table[i].value == static_cast<int>(button)) {
|
||||
return mouse_button_table[i].legacy;
|
||||
}
|
||||
}
|
||||
return "left"; // Default fallback
|
||||
}
|
||||
|
||||
PyObject* PyMouseButton::create_enum_class(PyObject* module) {
|
||||
// Build the enum definition dynamically from the table
|
||||
std::ostringstream code;
|
||||
|
|
@ -45,19 +35,13 @@ PyObject* PyMouseButton::create_enum_class(PyObject* module) {
|
|||
code << " \"\"\"Enum representing mouse buttons and scroll wheel.\n";
|
||||
code << " \n";
|
||||
code << " Values:\n";
|
||||
code << " LEFT: Left mouse button (legacy: 'left')\n";
|
||||
code << " RIGHT: Right mouse button (legacy: 'right')\n";
|
||||
code << " MIDDLE: Middle mouse button / scroll wheel click (legacy: 'middle')\n";
|
||||
code << " X1: Extra mouse button 1 (legacy: 'x1')\n";
|
||||
code << " X2: Extra mouse button 2 (legacy: 'x2')\n";
|
||||
code << " SCROLL_UP: Scroll wheel up (legacy: 'wheel_up')\n";
|
||||
code << " SCROLL_DOWN: Scroll wheel down (legacy: 'wheel_down')\n";
|
||||
code << " \n";
|
||||
code << " These enum values compare equal to their legacy string equivalents\n";
|
||||
code << " for backwards compatibility:\n";
|
||||
code << " MouseButton.LEFT == 'left' # True\n";
|
||||
code << " MouseButton.RIGHT == 'right' # True\n";
|
||||
code << " MouseButton.SCROLL_UP == 'wheel_up' # True\n";
|
||||
code << " LEFT: Left mouse button\n";
|
||||
code << " RIGHT: Right mouse button\n";
|
||||
code << " MIDDLE: Middle mouse button / scroll wheel click\n";
|
||||
code << " X1: Extra mouse button 1\n";
|
||||
code << " X2: Extra mouse button 2\n";
|
||||
code << " SCROLL_UP: Scroll wheel up\n";
|
||||
code << " SCROLL_DOWN: Scroll wheel down\n";
|
||||
code << " \"\"\"\n";
|
||||
|
||||
// Add enum members
|
||||
|
|
@ -65,42 +49,10 @@ PyObject* PyMouseButton::create_enum_class(PyObject* module) {
|
|||
code << " " << mouse_button_table[i].name << " = " << mouse_button_table[i].value << "\n";
|
||||
}
|
||||
|
||||
// Add legacy names and custom methods AFTER class creation
|
||||
// (IntEnum doesn't allow dict attributes during class definition)
|
||||
code << "\n# Add legacy name mapping after class creation\n";
|
||||
code << "MouseButton._legacy_names = {\n";
|
||||
for (int i = 0; i < NUM_MOUSE_BUTTON_ENTRIES; i++) {
|
||||
code << " " << mouse_button_table[i].value << ": \"" << mouse_button_table[i].legacy << "\",\n";
|
||||
}
|
||||
code << "}\n\n";
|
||||
|
||||
code << R"(
|
||||
def _MouseButton_eq(self, other):
|
||||
if isinstance(other, str):
|
||||
# Check enum name match (e.g., "LEFT")
|
||||
if self.name == other:
|
||||
return True
|
||||
# Check legacy name match (e.g., "left")
|
||||
legacy = type(self)._legacy_names.get(self.value)
|
||||
if legacy and legacy == other:
|
||||
return True
|
||||
return False
|
||||
# Fall back to int comparison for IntEnum
|
||||
return int.__eq__(int(self), other)
|
||||
|
||||
MouseButton.__eq__ = _MouseButton_eq
|
||||
|
||||
def _MouseButton_ne(self, other):
|
||||
result = type(self).__eq__(self, other)
|
||||
if result is NotImplemented:
|
||||
return result
|
||||
return not result
|
||||
|
||||
MouseButton.__ne__ = _MouseButton_ne
|
||||
MouseButton.__hash__ = lambda self: hash(int(self))
|
||||
MouseButton.__repr__ = lambda self: f"{type(self).__name__}.{self.name}"
|
||||
MouseButton.__str__ = lambda self: self.name
|
||||
)";
|
||||
code << "\n";
|
||||
code << "MouseButton.__hash__ = lambda self: hash(int(self))\n";
|
||||
code << "MouseButton.__repr__ = lambda self: f\"{type(self).__name__}.{self.name}\"\n";
|
||||
code << "MouseButton.__str__ = lambda self: self.name\n";
|
||||
|
||||
std::string code_str = code.str();
|
||||
|
||||
|
|
@ -195,17 +147,15 @@ int PyMouseButton::from_arg(PyObject* arg, sf::Mouse::Button* out_button) {
|
|||
return 0;
|
||||
}
|
||||
|
||||
// Accept string (both new and legacy names)
|
||||
// Accept string (enum name only)
|
||||
if (PyUnicode_Check(arg)) {
|
||||
const char* name = PyUnicode_AsUTF8(arg);
|
||||
if (!name) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Check all entries for both name and legacy match
|
||||
for (int i = 0; i < NUM_MOUSE_BUTTON_ENTRIES; i++) {
|
||||
if (strcmp(name, mouse_button_table[i].name) == 0 ||
|
||||
strcmp(name, mouse_button_table[i].legacy) == 0) {
|
||||
if (strcmp(name, mouse_button_table[i].name) == 0) {
|
||||
*out_button = static_cast<sf::Mouse::Button>(mouse_button_table[i].value);
|
||||
return 1;
|
||||
}
|
||||
|
|
@ -213,8 +163,7 @@ int PyMouseButton::from_arg(PyObject* arg, sf::Mouse::Button* out_button) {
|
|||
|
||||
PyErr_Format(PyExc_ValueError,
|
||||
"Unknown MouseButton: '%s'. Use MouseButton.LEFT, MouseButton.RIGHT, "
|
||||
"MouseButton.MIDDLE, MouseButton.X1, MouseButton.X2, "
|
||||
"or legacy strings 'left', 'right', 'middle', 'x1', 'x2'.", name);
|
||||
"MouseButton.MIDDLE, MouseButton.X1, MouseButton.X2.", name);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -6,13 +6,11 @@
|
|||
// Stored as a module attribute: mcrfpy.MouseButton
|
||||
//
|
||||
// Values map to sf::Mouse::Button:
|
||||
// LEFT = 0 (corresponds to "left" in legacy API)
|
||||
// RIGHT = 1 (corresponds to "right" in legacy API)
|
||||
// MIDDLE = 2 (corresponds to "middle" in legacy API)
|
||||
// X1 = 3 (extra button 1)
|
||||
// X2 = 4 (extra button 2)
|
||||
//
|
||||
// The enum compares equal to both its name ("LEFT") and legacy string ("left")
|
||||
// LEFT = 0
|
||||
// RIGHT = 1
|
||||
// MIDDLE = 2
|
||||
// X1 = 3
|
||||
// X2 = 4
|
||||
|
||||
class PyMouseButton {
|
||||
public:
|
||||
|
|
@ -21,13 +19,10 @@ public:
|
|||
static PyObject* create_enum_class(PyObject* module);
|
||||
|
||||
// Helper to extract mouse button from Python arg
|
||||
// Accepts MouseButton enum, string (for backwards compatibility), int, or None
|
||||
// Accepts MouseButton enum, string (enum name), or int
|
||||
// Returns 1 on success, 0 on error (with exception set)
|
||||
static int from_arg(PyObject* arg, sf::Mouse::Button* out_button);
|
||||
|
||||
// Convert sf::Mouse::Button to legacy string name (for passing to callbacks)
|
||||
static const char* to_legacy_string(sf::Mouse::Button button);
|
||||
|
||||
// Cached reference to the MouseButton enum class for fast type checking
|
||||
static PyObject* mouse_button_enum_class;
|
||||
|
||||
|
|
|
|||
|
|
@ -90,7 +90,7 @@ print("=" * 60)
|
|||
|
||||
# Exit handler
|
||||
def handle_key(key, state):
|
||||
if key == "Escape" and state:
|
||||
if key == mcrfpy.Key.ESCAPE and state == mcrfpy.InputState.PRESSED:
|
||||
print("\nBenchmark ended by user")
|
||||
sys.exit(0)
|
||||
|
||||
|
|
|
|||
|
|
@ -183,24 +183,23 @@ class Calculator:
|
|||
|
||||
def on_key(self, key, state):
|
||||
"""Handle keyboard input."""
|
||||
if state != "start":
|
||||
if state != mcrfpy.InputState.PRESSED:
|
||||
return
|
||||
|
||||
if key == "Escape":
|
||||
if key == mcrfpy.Key.ESCAPE:
|
||||
# Switch to game scene
|
||||
mcrfpy.current_scene = game_scene
|
||||
return
|
||||
|
||||
# Map keys to buttons
|
||||
key_map = {
|
||||
"Num0": "0", "Num1": "1", "Num2": "2", "Num3": "3",
|
||||
"Num4": "4", "Num5": "5", "Num6": "6", "Num7": "7",
|
||||
"Num8": "8", "Num9": "9",
|
||||
"Period": ".", "Add": "+", "Subtract": "-",
|
||||
"Multiply": "*", "Divide": "/",
|
||||
"Enter": "=", "Return": "=",
|
||||
"C": "C", "Backspace": "DEL",
|
||||
"LParen": "(", "RParen": ")",
|
||||
mcrfpy.Key.NUM_0: "0", mcrfpy.Key.NUM_1: "1", mcrfpy.Key.NUM_2: "2", mcrfpy.Key.NUM_3: "3",
|
||||
mcrfpy.Key.NUM_4: "4", mcrfpy.Key.NUM_5: "5", mcrfpy.Key.NUM_6: "6", mcrfpy.Key.NUM_7: "7",
|
||||
mcrfpy.Key.NUM_8: "8", mcrfpy.Key.NUM_9: "9",
|
||||
mcrfpy.Key.PERIOD: ".", mcrfpy.Key.ADD: "+", mcrfpy.Key.SUBTRACT: "-",
|
||||
mcrfpy.Key.MULTIPLY: "*", mcrfpy.Key.DIVIDE: "/",
|
||||
mcrfpy.Key.ENTER: "=",
|
||||
mcrfpy.Key.C: "C", mcrfpy.Key.BACKSPACE: "DEL",
|
||||
}
|
||||
|
||||
if key in key_map:
|
||||
|
|
@ -271,10 +270,10 @@ class GamePlaceholder:
|
|||
|
||||
def on_key(self, key, state):
|
||||
"""Handle keyboard input."""
|
||||
if state != "start":
|
||||
if state != mcrfpy.InputState.PRESSED:
|
||||
return
|
||||
|
||||
if key == "Escape":
|
||||
if key == mcrfpy.Key.ESCAPE:
|
||||
# Switch to calculator
|
||||
calculator.activate()
|
||||
|
||||
|
|
|
|||
|
|
@ -444,25 +444,26 @@ class DialogueSystem:
|
|||
|
||||
def on_key(self, key, state):
|
||||
"""Handle keyboard input."""
|
||||
if state != "start":
|
||||
if state != mcrfpy.InputState.PRESSED:
|
||||
return
|
||||
|
||||
if key == "Escape":
|
||||
if key == mcrfpy.Key.ESCAPE:
|
||||
sys.exit(0)
|
||||
elif key in ("Num1", "Num2", "Num3", "Num4"):
|
||||
idx = int(key[-1]) - 1
|
||||
elif key in (mcrfpy.Key.NUM_1, mcrfpy.Key.NUM_2, mcrfpy.Key.NUM_3, mcrfpy.Key.NUM_4):
|
||||
_num_idx = {mcrfpy.Key.NUM_1: 0, mcrfpy.Key.NUM_2: 1, mcrfpy.Key.NUM_3: 2, mcrfpy.Key.NUM_4: 3}
|
||||
idx = _num_idx[key]
|
||||
if idx < len(self.choice_list.choices):
|
||||
self.choice_list.set_selected(idx)
|
||||
self.choice_list.confirm()
|
||||
elif key == "Up":
|
||||
elif key == mcrfpy.Key.UP:
|
||||
self.choice_list.navigate(-1)
|
||||
elif key == "Down":
|
||||
elif key == mcrfpy.Key.DOWN:
|
||||
self.choice_list.navigate(1)
|
||||
elif key == "Enter":
|
||||
elif key == mcrfpy.Key.ENTER:
|
||||
self.choice_list.confirm()
|
||||
elif key == "Space":
|
||||
elif key == mcrfpy.Key.SPACE:
|
||||
self.dialogue_box.skip_animation()
|
||||
elif key == "R":
|
||||
elif key == mcrfpy.Key.R:
|
||||
# Restart
|
||||
self.npc.mood = "neutral"
|
||||
self.npc.trust = 50
|
||||
|
|
|
|||
|
|
@ -396,10 +396,10 @@ class ShopDemo:
|
|||
|
||||
def on_key(self, key, state):
|
||||
"""Handle keyboard input."""
|
||||
if state != "start":
|
||||
if state != mcrfpy.InputState.PRESSED:
|
||||
return
|
||||
|
||||
if key == "Escape":
|
||||
if key == mcrfpy.Key.ESCAPE:
|
||||
if self.manager.held_item:
|
||||
self.manager.cancel_pickup()
|
||||
self.tooltip.text = "Cancelled"
|
||||
|
|
|
|||
|
|
@ -206,7 +206,7 @@ class CookbookLauncher:
|
|||
|
||||
def on_key(self, key, state):
|
||||
"""Handle keyboard input."""
|
||||
if state != "start":
|
||||
if state != mcrfpy.InputState.PRESSED:
|
||||
return
|
||||
|
||||
category = self.categories[self.selected_category]
|
||||
|
|
|
|||
|
|
@ -377,22 +377,22 @@ class AnimationDemo:
|
|||
|
||||
def on_key(self, key, state):
|
||||
"""Handle keyboard input."""
|
||||
if state != "start":
|
||||
if state != mcrfpy.InputState.PRESSED:
|
||||
return
|
||||
|
||||
if key == "Escape":
|
||||
if key == mcrfpy.Key.ESCAPE:
|
||||
sys.exit(0)
|
||||
elif key == "Num1":
|
||||
elif key == mcrfpy.Key.NUM_1:
|
||||
self.run_chain_demo()
|
||||
elif key == "Num2":
|
||||
elif key == mcrfpy.Key.NUM_2:
|
||||
self.run_group_demo()
|
||||
elif key == "Num3":
|
||||
elif key == mcrfpy.Key.NUM_3:
|
||||
self.run_callback_demo()
|
||||
elif key == "Num4":
|
||||
elif key == mcrfpy.Key.NUM_4:
|
||||
self.run_loop_demo()
|
||||
elif key == "Num5":
|
||||
elif key == mcrfpy.Key.NUM_5:
|
||||
self.run_combined_demo()
|
||||
elif key == "R":
|
||||
elif key == mcrfpy.Key.R:
|
||||
self.reset_all()
|
||||
|
||||
def activate(self):
|
||||
|
|
|
|||
|
|
@ -365,38 +365,39 @@ class RotationDemo:
|
|||
|
||||
def on_key(self, key, state):
|
||||
"""Handle keyboard input."""
|
||||
if state != "start":
|
||||
if state != mcrfpy.InputState.PRESSED:
|
||||
return
|
||||
|
||||
if key == "Escape":
|
||||
if key == mcrfpy.Key.ESCAPE:
|
||||
sys.exit(0)
|
||||
elif key == "Left":
|
||||
elif key == mcrfpy.Key.LEFT:
|
||||
# Rotate left (counter-clockwise)
|
||||
name, element = self.elements[self.selected]
|
||||
try:
|
||||
element.rotation = (element.rotation - 15) % 360
|
||||
except AttributeError:
|
||||
pass
|
||||
elif key == "Right":
|
||||
elif key == mcrfpy.Key.RIGHT:
|
||||
# Rotate right (clockwise)
|
||||
name, element = self.elements[self.selected]
|
||||
try:
|
||||
element.rotation = (element.rotation + 15) % 360
|
||||
except AttributeError:
|
||||
pass
|
||||
elif key == "Up":
|
||||
elif key == mcrfpy.Key.UP:
|
||||
self.rotation_speed = min(180, self.rotation_speed + 15)
|
||||
self.speed_label.text = f"Speed: {self.rotation_speed}°/sec"
|
||||
elif key == "Down":
|
||||
elif key == mcrfpy.Key.DOWN:
|
||||
self.rotation_speed = max(15, self.rotation_speed - 15)
|
||||
self.speed_label.text = f"Speed: {self.rotation_speed}°/sec"
|
||||
elif key in ("Num1", "Num2", "Num3", "Num4"):
|
||||
self.selected = int(key[-1]) - 1
|
||||
elif key in (mcrfpy.Key.NUM_1, mcrfpy.Key.NUM_2, mcrfpy.Key.NUM_3, mcrfpy.Key.NUM_4):
|
||||
_num_idx = {mcrfpy.Key.NUM_1: 0, mcrfpy.Key.NUM_2: 1, mcrfpy.Key.NUM_3: 2, mcrfpy.Key.NUM_4: 3}
|
||||
self.selected = _num_idx[key]
|
||||
if self.selected < len(self.elements):
|
||||
self.selected_label.text = f"Selected: {self.elements[self.selected][0]}"
|
||||
elif key == "O":
|
||||
elif key == mcrfpy.Key.O:
|
||||
self._cycle_origin()
|
||||
elif key == "A":
|
||||
elif key == mcrfpy.Key.A:
|
||||
self.auto_rotate = not self.auto_rotate
|
||||
if self.auto_rotate:
|
||||
self.auto_label.text = "Auto-rotate: On"
|
||||
|
|
@ -404,7 +405,7 @@ class RotationDemo:
|
|||
else:
|
||||
self.auto_label.text = "Auto-rotate: Off"
|
||||
self.auto_label.fill_color = mcrfpy.Color(200, 100, 100)
|
||||
elif key == "R":
|
||||
elif key == mcrfpy.Key.R:
|
||||
# Reset all rotations
|
||||
for name, element in self.elements:
|
||||
try:
|
||||
|
|
|
|||
|
|
@ -296,20 +296,21 @@ class ShaderDemo:
|
|||
|
||||
def on_key(self, key, state):
|
||||
"""Handle keyboard input."""
|
||||
if state != "start":
|
||||
if state != mcrfpy.InputState.PRESSED:
|
||||
return
|
||||
|
||||
if key == "Escape":
|
||||
if key == mcrfpy.Key.ESCAPE:
|
||||
sys.exit(0)
|
||||
elif key == "Space":
|
||||
elif key == mcrfpy.Key.SPACE:
|
||||
self.toggle_shaders()
|
||||
elif key == "R":
|
||||
elif key == mcrfpy.Key.R:
|
||||
# Re-enable all shaders
|
||||
self.shaders_enabled = False
|
||||
self.toggle_shaders()
|
||||
elif key in ("Num1", "Num2", "Num3", "Num4"):
|
||||
elif key in (mcrfpy.Key.NUM_1, mcrfpy.Key.NUM_2, mcrfpy.Key.NUM_3, mcrfpy.Key.NUM_4):
|
||||
# Focus on specific shader (could zoom in)
|
||||
idx = int(key[-1]) - 1
|
||||
_num_idx = {mcrfpy.Key.NUM_1: 0, mcrfpy.Key.NUM_2: 1, mcrfpy.Key.NUM_3: 2, mcrfpy.Key.NUM_4: 3}
|
||||
idx = _num_idx[key]
|
||||
if idx < len(self.shader_frames):
|
||||
self.status.text = f"Focused: Shader {idx + 1}"
|
||||
|
||||
|
|
|
|||
|
|
@ -102,13 +102,13 @@ class Button:
|
|||
if not self._enabled:
|
||||
return
|
||||
|
||||
if button == "left":
|
||||
if action == "start":
|
||||
if button == mcrfpy.MouseButton.LEFT:
|
||||
if action == mcrfpy.InputState.PRESSED:
|
||||
self.is_pressed = True
|
||||
self.frame.fill_color = self.press_color
|
||||
# Animate a subtle press effect
|
||||
self._animate_press()
|
||||
elif action == "end":
|
||||
elif action == mcrfpy.InputState.RELEASED:
|
||||
self.is_pressed = False
|
||||
# Restore hover or normal state
|
||||
if self.is_hovered:
|
||||
|
|
|
|||
|
|
@ -123,7 +123,7 @@ class ChoiceList:
|
|||
idx = i # Capture index in closure
|
||||
def make_click_handler(index):
|
||||
def handler(pos, button, action):
|
||||
if button == "left" and action == "end":
|
||||
if button == mcrfpy.MouseButton.LEFT and action == mcrfpy.InputState.RELEASED:
|
||||
self.set_selected(index)
|
||||
if self.on_select:
|
||||
self.on_select(index, self._choices[index])
|
||||
|
|
|
|||
|
|
@ -114,7 +114,7 @@ class GridContainer:
|
|||
# Set up event handlers
|
||||
def make_click(cx, cy):
|
||||
def handler(pos, button, action):
|
||||
if button == "left" and action == "end":
|
||||
if button == mcrfpy.MouseButton.LEFT and action == mcrfpy.InputState.RELEASED:
|
||||
self._on_cell_clicked(cx, cy)
|
||||
return handler
|
||||
|
||||
|
|
|
|||
|
|
@ -138,7 +138,7 @@ class ItemSlot(mcrfpy.Frame):
|
|||
return item.slot_type == self.slot_type
|
||||
|
||||
def _on_click(self, pos, button, action):
|
||||
if action != "start" or button != "left":
|
||||
if action != mcrfpy.InputState.PRESSED or button != mcrfpy.MouseButton.LEFT:
|
||||
return
|
||||
if self.manager:
|
||||
self.manager.handle_slot_click(self.slot_name)
|
||||
|
|
@ -274,14 +274,14 @@ class ItemManager:
|
|||
|
||||
def _on_grid_click(self, grid_name, pos, button, action):
|
||||
"""Handle click on a registered grid."""
|
||||
if action != "start":
|
||||
if action != mcrfpy.InputState.PRESSED:
|
||||
return
|
||||
|
||||
if button == "right":
|
||||
if button == mcrfpy.MouseButton.RIGHT:
|
||||
self.cancel_pickup()
|
||||
return
|
||||
|
||||
if button != "left":
|
||||
if button != mcrfpy.MouseButton.LEFT:
|
||||
return
|
||||
|
||||
grid, item_map, color_layer = self.grids[grid_name]
|
||||
|
|
|
|||
|
|
@ -194,7 +194,7 @@ class Modal:
|
|||
|
||||
def make_click(cb):
|
||||
def handler(pos, button, action):
|
||||
if button == "left" and action == "end" and cb:
|
||||
if button == mcrfpy.MouseButton.LEFT and action == mcrfpy.InputState.RELEASED and cb:
|
||||
cb()
|
||||
return handler
|
||||
|
||||
|
|
@ -208,7 +208,7 @@ class Modal:
|
|||
def _on_overlay_click(self, pos, button, action):
|
||||
"""Handle clicks on overlay (outside modal)."""
|
||||
# Check if click is outside modal
|
||||
if button == "left" and action == "end":
|
||||
if button == mcrfpy.MouseButton.LEFT and action == mcrfpy.InputState.RELEASED:
|
||||
mx, my = self.modal_frame.x, self.modal_frame.y
|
||||
mw, mh = self.modal_frame.w, self.modal_frame.h
|
||||
px, py = pos.x, pos.y
|
||||
|
|
|
|||
|
|
@ -138,7 +138,7 @@ class ScrollableList:
|
|||
# Set up click handler
|
||||
def make_click_handler(index):
|
||||
def handler(pos, button, action):
|
||||
if button == "left" and action == "end":
|
||||
if button == mcrfpy.MouseButton.LEFT and action == mcrfpy.InputState.RELEASED:
|
||||
self.select(index)
|
||||
return handler
|
||||
|
||||
|
|
|
|||
|
|
@ -245,20 +245,20 @@ class ButtonDemo:
|
|||
|
||||
def on_key(self, key, state):
|
||||
"""Handle keyboard input."""
|
||||
if state != "start":
|
||||
if state != mcrfpy.InputState.PRESSED:
|
||||
return
|
||||
|
||||
if key == "Escape":
|
||||
if key == mcrfpy.Key.ESCAPE:
|
||||
sys.exit(0)
|
||||
elif key == "Num1" and len(self.buttons) > 0:
|
||||
elif key == mcrfpy.Key.NUM_1 and len(self.buttons) > 0:
|
||||
self.buttons[0].callback()
|
||||
elif key == "Num2" and len(self.buttons) > 1:
|
||||
elif key == mcrfpy.Key.NUM_2 and len(self.buttons) > 1:
|
||||
self.buttons[1].callback()
|
||||
elif key == "Num3" and len(self.buttons) > 2:
|
||||
elif key == mcrfpy.Key.NUM_3 and len(self.buttons) > 2:
|
||||
self.buttons[2].callback()
|
||||
elif key == "Num4" and len(self.buttons) > 3:
|
||||
elif key == mcrfpy.Key.NUM_4 and len(self.buttons) > 3:
|
||||
self.buttons[3].callback()
|
||||
elif key == "D":
|
||||
elif key == mcrfpy.Key.D:
|
||||
# Toggle disabled button
|
||||
self.disabled_btn.enabled = not self.disabled_btn.enabled
|
||||
if self.disabled_btn.enabled:
|
||||
|
|
|
|||
|
|
@ -230,31 +230,31 @@ class ChoiceListDemo:
|
|||
|
||||
def on_key(self, key, state):
|
||||
"""Handle keyboard input."""
|
||||
if state != "start":
|
||||
if state != mcrfpy.InputState.PRESSED:
|
||||
return
|
||||
|
||||
if key == "Escape":
|
||||
if key == mcrfpy.Key.ESCAPE:
|
||||
sys.exit(0)
|
||||
|
||||
# Get active list
|
||||
active = self.lists[self.active_list_idx] if self.lists else None
|
||||
|
||||
if key == "Up" and active:
|
||||
if key == mcrfpy.Key.UP and active:
|
||||
active.navigate(-1)
|
||||
elif key == "Down" and active:
|
||||
elif key == mcrfpy.Key.DOWN and active:
|
||||
active.navigate(1)
|
||||
elif key == "Enter" and active:
|
||||
elif key == mcrfpy.Key.ENTER and active:
|
||||
active.confirm()
|
||||
elif key == "Tab":
|
||||
elif key == mcrfpy.Key.TAB:
|
||||
# Switch active list
|
||||
self.active_list_idx = (self.active_list_idx + 1) % len(self.lists)
|
||||
self._update_active_indicator()
|
||||
elif key == "A":
|
||||
elif key == mcrfpy.Key.A:
|
||||
# Add item to dynamic list
|
||||
self.add_counter += 1
|
||||
self.dynamic_list.add_choice(f"New Item {self.add_counter}")
|
||||
self.dynamic_info.text = f"Items: {len(self.dynamic_list.choices)}"
|
||||
elif key == "R":
|
||||
elif key == mcrfpy.Key.R:
|
||||
# Remove selected from dynamic list
|
||||
if len(self.dynamic_list.choices) > 1:
|
||||
self.dynamic_list.remove_choice(self.dynamic_list.selected_index)
|
||||
|
|
|
|||
|
|
@ -187,7 +187,7 @@ class ClickPickupDemo:
|
|||
|
||||
def _on_grid_click(self, pos, button, action):
|
||||
"""Handle grid click."""
|
||||
if action != "start":
|
||||
if action != mcrfpy.InputState.PRESSED:
|
||||
return
|
||||
|
||||
cell = self._get_grid_cell(pos)
|
||||
|
|
@ -196,13 +196,13 @@ class ClickPickupDemo:
|
|||
|
||||
x, y = cell
|
||||
|
||||
if button == "right":
|
||||
if button == mcrfpy.MouseButton.RIGHT:
|
||||
# Cancel pickup
|
||||
if self.held_entity:
|
||||
self._cancel_pickup()
|
||||
return
|
||||
|
||||
if button != "left":
|
||||
if button != mcrfpy.MouseButton.LEFT:
|
||||
return
|
||||
|
||||
if self.held_entity is None:
|
||||
|
|
@ -334,10 +334,10 @@ class ClickPickupDemo:
|
|||
|
||||
def on_key(self, key, state):
|
||||
"""Handle keyboard input."""
|
||||
if state != "start":
|
||||
if state != mcrfpy.InputState.PRESSED:
|
||||
return
|
||||
|
||||
if key == "Escape":
|
||||
if key == mcrfpy.Key.ESCAPE:
|
||||
if self.held_entity:
|
||||
self._cancel_pickup()
|
||||
return
|
||||
|
|
|
|||
|
|
@ -234,9 +234,9 @@ class DragDropFrameDemo:
|
|||
|
||||
def on_key(self, key, state):
|
||||
"""Handle keyboard input."""
|
||||
if state != "start":
|
||||
if state != mcrfpy.InputState.PRESSED:
|
||||
return
|
||||
if key == "Escape":
|
||||
if key == mcrfpy.Key.ESCAPE:
|
||||
# Return to cookbook menu or exit
|
||||
try:
|
||||
from cookbook_main import main
|
||||
|
|
|
|||
|
|
@ -142,7 +142,7 @@ class GridDragDropDemo:
|
|||
|
||||
def _on_grid_click(self, pos, button, action):
|
||||
"""Handle grid click for drag start/end."""
|
||||
if button != "left":
|
||||
if button != mcrfpy.MouseButton.LEFT:
|
||||
return
|
||||
|
||||
# Convert screen pos to grid cell
|
||||
|
|
@ -154,7 +154,7 @@ class GridDragDropDemo:
|
|||
if not (0 <= grid_x < grid_w and 0 <= grid_y < grid_h):
|
||||
return
|
||||
|
||||
if action == "start":
|
||||
if action == mcrfpy.InputState.PRESSED:
|
||||
# Start drag if there's an entity here
|
||||
entity = self._get_entity_at(grid_x, grid_y)
|
||||
if entity:
|
||||
|
|
@ -166,7 +166,7 @@ class GridDragDropDemo:
|
|||
# Highlight start cell yellow
|
||||
self.color_layer.set((grid_x, grid_y), (255, 255, 100, 200))
|
||||
|
||||
elif action == "end":
|
||||
elif action == mcrfpy.InputState.RELEASED:
|
||||
if self.dragging_entity:
|
||||
# Drop the entity
|
||||
target_cell = (grid_x, grid_y)
|
||||
|
|
@ -224,9 +224,9 @@ class GridDragDropDemo:
|
|||
|
||||
def on_key(self, key, state):
|
||||
"""Handle keyboard input."""
|
||||
if state != "start":
|
||||
if state != mcrfpy.InputState.PRESSED:
|
||||
return
|
||||
if key == "Escape":
|
||||
if key == mcrfpy.Key.ESCAPE:
|
||||
# Cancel any drag in progress
|
||||
if self.dragging_entity and self.drag_start_cell:
|
||||
self.dragging_entity.grid_pos = self.drag_start_cell
|
||||
|
|
|
|||
|
|
@ -275,15 +275,15 @@ class StatBarDemo:
|
|||
|
||||
def on_key(self, key, state):
|
||||
"""Handle keyboard input."""
|
||||
if state != "start":
|
||||
if state != mcrfpy.InputState.PRESSED:
|
||||
return
|
||||
|
||||
if key == "Escape":
|
||||
if key == mcrfpy.Key.ESCAPE:
|
||||
sys.exit(0)
|
||||
|
||||
# Number keys to modify bars
|
||||
bar_keys = ['hp', 'mp', 'stamina', 'xp']
|
||||
key_map = {"Num1": 0, "Num2": 1, "Num3": 2, "Num4": 3}
|
||||
key_map = {mcrfpy.Key.NUM_1: 0, mcrfpy.Key.NUM_2: 1, mcrfpy.Key.NUM_3: 2, mcrfpy.Key.NUM_4: 3}
|
||||
|
||||
if key in key_map:
|
||||
idx = key_map[key]
|
||||
|
|
@ -293,11 +293,11 @@ class StatBarDemo:
|
|||
bar.set_value(bar.current - 10, animate=True)
|
||||
self.status.text = f"Status: Decreased {bar_keys[idx].upper()}"
|
||||
|
||||
elif key == "F":
|
||||
elif key == mcrfpy.Key.F:
|
||||
self.flash_bar.flash()
|
||||
self.status.text = "Status: Flash effect triggered!"
|
||||
|
||||
elif key == "R":
|
||||
elif key == mcrfpy.Key.R:
|
||||
# Reset all bars
|
||||
self.bars['hp'].set_value(75, 100, animate=True)
|
||||
self.bars['mp'].set_value(50, 80, animate=True)
|
||||
|
|
|
|||
|
|
@ -182,18 +182,18 @@ class TextBoxDemo:
|
|||
|
||||
def on_key(self, key, state):
|
||||
"""Handle keyboard input."""
|
||||
if state != "start":
|
||||
if state != mcrfpy.InputState.PRESSED:
|
||||
return
|
||||
|
||||
if key == "Escape":
|
||||
if key == mcrfpy.Key.ESCAPE:
|
||||
sys.exit(0)
|
||||
elif key == "Num1":
|
||||
elif key == mcrfpy.Key.NUM_1:
|
||||
# Start typewriter animation
|
||||
self.typewriter_box.on_complete = self.on_typewriter_complete
|
||||
self.typewriter_box.set_text(self.sample_text, animate=True)
|
||||
self.completion_label.text = "Status: Playing..."
|
||||
self.completion_label.fill_color = mcrfpy.Color(200, 200, 100)
|
||||
elif key == "Num2":
|
||||
elif key == mcrfpy.Key.NUM_2:
|
||||
# Change instant text
|
||||
texts = [
|
||||
"This text appeared instantly. Press 2 to change it to different content.",
|
||||
|
|
@ -203,17 +203,17 @@ class TextBoxDemo:
|
|||
]
|
||||
import random
|
||||
self.instant_box.set_text(random.choice(texts), animate=False)
|
||||
elif key == "Num3":
|
||||
elif key == mcrfpy.Key.NUM_3:
|
||||
# Skip animation
|
||||
self.typewriter_box.skip_animation()
|
||||
self.completion_label.text = "Status: Skipped"
|
||||
self.completion_label.fill_color = mcrfpy.Color(150, 150, 150)
|
||||
elif key == "Num4":
|
||||
elif key == mcrfpy.Key.NUM_4:
|
||||
# Clear text
|
||||
self.typewriter_box.clear()
|
||||
self.completion_label.text = "Status: Cleared"
|
||||
self.completion_label.fill_color = mcrfpy.Color(150, 150, 150)
|
||||
elif key == "D":
|
||||
elif key == mcrfpy.Key.D:
|
||||
# Cycle dialogue
|
||||
self.dialogue_index = (self.dialogue_index + 1) % len(self.dialogues)
|
||||
speaker, text = self.dialogues[self.dialogue_index]
|
||||
|
|
|
|||
|
|
@ -163,32 +163,32 @@ class ToastDemo:
|
|||
|
||||
def on_key(self, key, state):
|
||||
"""Handle keyboard input."""
|
||||
if state != "start":
|
||||
if state != mcrfpy.InputState.PRESSED:
|
||||
return
|
||||
|
||||
if key == "Escape":
|
||||
if key == mcrfpy.Key.ESCAPE:
|
||||
sys.exit(0)
|
||||
elif key == "Num1":
|
||||
elif key == mcrfpy.Key.NUM_1:
|
||||
self.toast_count += 1
|
||||
self.toasts.show(f"Default notification #{self.toast_count}")
|
||||
self.update_stats()
|
||||
elif key == "Num2":
|
||||
elif key == mcrfpy.Key.NUM_2:
|
||||
self.toast_count += 1
|
||||
self.toasts.show_success("Operation completed successfully!")
|
||||
self.update_stats()
|
||||
elif key == "Num3":
|
||||
elif key == mcrfpy.Key.NUM_3:
|
||||
self.toast_count += 1
|
||||
self.toasts.show_error("An error occurred!")
|
||||
self.update_stats()
|
||||
elif key == "Num4":
|
||||
elif key == mcrfpy.Key.NUM_4:
|
||||
self.toast_count += 1
|
||||
self.toasts.show_warning("Warning: Low health!")
|
||||
self.update_stats()
|
||||
elif key == "Num5":
|
||||
elif key == mcrfpy.Key.NUM_5:
|
||||
self.toast_count += 1
|
||||
self.toasts.show_info("New quest available")
|
||||
self.update_stats()
|
||||
elif key == "S":
|
||||
elif key == mcrfpy.Key.S:
|
||||
# Spam multiple toasts
|
||||
messages = [
|
||||
"Game saved!",
|
||||
|
|
@ -201,7 +201,7 @@ class ToastDemo:
|
|||
self.toast_count += 1
|
||||
self.toasts.show(msg)
|
||||
self.update_stats()
|
||||
elif key == "C":
|
||||
elif key == mcrfpy.Key.C:
|
||||
self.toasts.dismiss_all()
|
||||
self.update_stats()
|
||||
|
||||
|
|
|
|||
|
|
@ -146,21 +146,24 @@ class DemoRunner:
|
|||
self.create_menu()
|
||||
|
||||
def handle_key(key, state):
|
||||
if state != "start":
|
||||
if state != mcrfpy.InputState.PRESSED:
|
||||
return
|
||||
|
||||
# Number keys 1-9 for direct screen access
|
||||
if key in [f"Num{n}" for n in "123456789"]:
|
||||
idx = int(key[-1]) - 1
|
||||
_num_key_map = {mcrfpy.Key.NUM_1: 0, mcrfpy.Key.NUM_2: 1, mcrfpy.Key.NUM_3: 2,
|
||||
mcrfpy.Key.NUM_4: 3, mcrfpy.Key.NUM_5: 4, mcrfpy.Key.NUM_6: 5,
|
||||
mcrfpy.Key.NUM_7: 6, mcrfpy.Key.NUM_8: 7, mcrfpy.Key.NUM_9: 8}
|
||||
if key in _num_key_map:
|
||||
idx = _num_key_map[key]
|
||||
if idx < len(self.screens):
|
||||
mcrfpy.setScene(self.screens[idx].scene_name)
|
||||
|
||||
# ESC returns to menu
|
||||
elif key == "Escape":
|
||||
elif key == mcrfpy.Key.ESCAPE:
|
||||
menu.activate()
|
||||
|
||||
# Q quits
|
||||
elif key == "Q":
|
||||
elif key == mcrfpy.Key.Q:
|
||||
sys.exit(0)
|
||||
|
||||
# Register keyboard handler on menu scene
|
||||
|
|
|
|||
|
|
@ -162,18 +162,18 @@ def on_keypress(key, state):
|
|||
"""Handle keyboard input"""
|
||||
global patrol_paused
|
||||
|
||||
if state != "start":
|
||||
if state != mcrfpy.InputState.PRESSED:
|
||||
return
|
||||
|
||||
if key == "R":
|
||||
if key == mcrfpy.Key.R:
|
||||
reset_vision()
|
||||
elif key == "Space":
|
||||
elif key == mcrfpy.Key.SPACE:
|
||||
patrol_paused = not patrol_paused
|
||||
if patrol_paused:
|
||||
update_status("Status: PAUSED")
|
||||
else:
|
||||
update_status("Status: Patrolling")
|
||||
elif key == "Q":
|
||||
elif key == mcrfpy.Key.Q:
|
||||
mcrfpy.current_scene = None
|
||||
|
||||
def reset_vision():
|
||||
|
|
|
|||
|
|
@ -31,14 +31,14 @@ class ModifierTracker:
|
|||
self.ctrl = False
|
||||
self.alt = False
|
||||
|
||||
def update(self, key: str, action: str):
|
||||
def update(self, key, action):
|
||||
"""Call this from your key handler to update modifier state."""
|
||||
if key in ("LShift", "RShift"):
|
||||
self.shift = (action == "start")
|
||||
elif key in ("LControl", "RControl"):
|
||||
self.ctrl = (action == "start")
|
||||
elif key in ("LAlt", "RAlt"):
|
||||
self.alt = (action == "start")
|
||||
if key in (mcrfpy.Key.LEFT_SHIFT, mcrfpy.Key.RIGHT_SHIFT):
|
||||
self.shift = (action == mcrfpy.InputState.PRESSED)
|
||||
elif key in (mcrfpy.Key.LEFT_CONTROL, mcrfpy.Key.RIGHT_CONTROL):
|
||||
self.ctrl = (action == mcrfpy.InputState.PRESSED)
|
||||
elif key in (mcrfpy.Key.LEFT_ALT, mcrfpy.Key.RIGHT_ALT):
|
||||
self.alt = (action == mcrfpy.InputState.PRESSED)
|
||||
|
||||
|
||||
# =============================================================================
|
||||
|
|
@ -163,16 +163,16 @@ class FocusManager:
|
|||
self.modifiers.update(key, action)
|
||||
|
||||
# Only process on key press, not release (key repeat sends multiple "start")
|
||||
if action != "start":
|
||||
if action != mcrfpy.InputState.PRESSED:
|
||||
return False
|
||||
|
||||
# Global: Escape closes modals
|
||||
if key == "Escape":
|
||||
if key == mcrfpy.Key.ESCAPE:
|
||||
if self.pop_modal():
|
||||
return True
|
||||
|
||||
# Global: Tab cycles focus
|
||||
if key == "Tab":
|
||||
if key == mcrfpy.Key.TAB:
|
||||
direction = -1 if self.modifiers.shift else 1
|
||||
self.cycle(direction)
|
||||
return True
|
||||
|
|
@ -251,7 +251,7 @@ class FocusableGrid:
|
|||
|
||||
def _on_click(self, x, y, button, action):
|
||||
"""Handle click to focus this grid."""
|
||||
if self._focus_manager and action == "start":
|
||||
if self._focus_manager and action == mcrfpy.InputState.PRESSED:
|
||||
self._focus_manager.focus(self._focus_index)
|
||||
|
||||
def _update_player_display(self):
|
||||
|
|
@ -272,13 +272,13 @@ class FocusableGrid:
|
|||
self.outline_frame.outline_color = FocusManager.UNFOCUS_COLOR
|
||||
self.outline_frame.outline = FocusManager.UNFOCUS_OUTLINE
|
||||
|
||||
def handle_key(self, key: str, action: str) -> bool:
|
||||
def handle_key(self, key, action) -> bool:
|
||||
"""Handle WASD movement."""
|
||||
moves = {
|
||||
"W": (0, -1), "Up": (0, -1),
|
||||
"A": (-1, 0), "Left": (-1, 0),
|
||||
"S": (0, 1), "Down": (0, 1),
|
||||
"D": (1, 0), "Right": (1, 0),
|
||||
mcrfpy.Key.W: (0, -1), mcrfpy.Key.UP: (0, -1),
|
||||
mcrfpy.Key.A: (-1, 0), mcrfpy.Key.LEFT: (-1, 0),
|
||||
mcrfpy.Key.S: (0, 1), mcrfpy.Key.DOWN: (0, 1),
|
||||
mcrfpy.Key.D: (1, 0), mcrfpy.Key.RIGHT: (1, 0),
|
||||
}
|
||||
|
||||
if key in moves:
|
||||
|
|
@ -373,7 +373,7 @@ class TextInputWidget:
|
|||
|
||||
def _on_click(self, x, y, button, action):
|
||||
"""Handle click to focus."""
|
||||
if self._focus_manager and action == "start":
|
||||
if self._focus_manager and action == mcrfpy.InputState.PRESSED:
|
||||
self._focus_manager.focus(self._focus_index)
|
||||
|
||||
def _update_display(self):
|
||||
|
|
@ -404,7 +404,7 @@ class TextInputWidget:
|
|||
self.cursor.visible = False
|
||||
self._update_display()
|
||||
|
||||
def handle_key(self, key: str, action: str) -> bool:
|
||||
def handle_key(self, key, action) -> bool:
|
||||
"""Handle text input and editing keys."""
|
||||
if not self.focused:
|
||||
return False
|
||||
|
|
@ -412,27 +412,27 @@ class TextInputWidget:
|
|||
old_text = self.text
|
||||
handled = True
|
||||
|
||||
if key == "BackSpace":
|
||||
if key == mcrfpy.Key.BACKSPACE:
|
||||
if self.cursor_pos > 0:
|
||||
self.text = self.text[:self.cursor_pos-1] + self.text[self.cursor_pos:]
|
||||
self.cursor_pos -= 1
|
||||
elif key == "Delete":
|
||||
elif key == mcrfpy.Key.DELETE:
|
||||
if self.cursor_pos < len(self.text):
|
||||
self.text = self.text[:self.cursor_pos] + self.text[self.cursor_pos+1:]
|
||||
elif key == "Left":
|
||||
elif key == mcrfpy.Key.LEFT:
|
||||
self.cursor_pos = max(0, self.cursor_pos - 1)
|
||||
elif key == "Right":
|
||||
elif key == mcrfpy.Key.RIGHT:
|
||||
self.cursor_pos = min(len(self.text), self.cursor_pos + 1)
|
||||
elif key == "Home":
|
||||
elif key == mcrfpy.Key.HOME:
|
||||
self.cursor_pos = 0
|
||||
elif key == "End":
|
||||
elif key == mcrfpy.Key.END:
|
||||
self.cursor_pos = len(self.text)
|
||||
elif key in ("Return", "Tab"):
|
||||
elif key in (mcrfpy.Key.ENTER, mcrfpy.Key.TAB):
|
||||
# Don't consume - let focus manager handle
|
||||
handled = False
|
||||
elif len(key) == 1 and key.isprintable():
|
||||
# Insert character
|
||||
self.text = self.text[:self.cursor_pos] + key + self.text[self.cursor_pos:]
|
||||
elif len(key.name) == 1 and key.name.isprintable():
|
||||
# Insert character (key.name is "A"-"Z" for letter keys)
|
||||
self.text = self.text[:self.cursor_pos] + key.name.lower() + self.text[self.cursor_pos:]
|
||||
self.cursor_pos += 1
|
||||
else:
|
||||
handled = False
|
||||
|
|
@ -509,7 +509,7 @@ class MenuIcon:
|
|||
if not self._focus_manager:
|
||||
return
|
||||
|
||||
if action == "start":
|
||||
if action == mcrfpy.InputState.PRESSED:
|
||||
# If already focused, activate; otherwise just focus
|
||||
if self._focus_manager.focus_index == self._focus_index:
|
||||
self._activate()
|
||||
|
|
@ -535,9 +535,9 @@ class MenuIcon:
|
|||
self.frame.fill_color = mcrfpy.Color(60, 60, 80)
|
||||
self.tooltip_caption.visible = False
|
||||
|
||||
def handle_key(self, key: str, action: str) -> bool:
|
||||
def handle_key(self, key, action) -> bool:
|
||||
"""Handle activation keys."""
|
||||
if key in ("Space", "Return"):
|
||||
if key in (mcrfpy.Key.SPACE, mcrfpy.Key.ENTER):
|
||||
self._activate()
|
||||
return True
|
||||
return False
|
||||
|
|
|
|||
|
|
@ -13,7 +13,7 @@ scene = mcrfpy.Scene("test_modern")
|
|||
scene.children.append(mcrfpy.Frame(pos=(0, 0), size=(800, 600)))
|
||||
|
||||
def my_handler(key, action):
|
||||
if action == "start":
|
||||
if action == mcrfpy.InputState.PRESSED:
|
||||
print(f" Key handler received: {key}")
|
||||
|
||||
scene.on_key = my_handler
|
||||
|
|
|
|||
|
|
@ -46,15 +46,15 @@ grid.entities.append(treasure)
|
|||
|
||||
# Movement handler using modern API
|
||||
def handle_keys(key, state):
|
||||
if state == "start":
|
||||
if state == mcrfpy.InputState.PRESSED:
|
||||
x, y = player.pos[0], player.pos[1]
|
||||
if key == "W":
|
||||
if key == mcrfpy.Key.W:
|
||||
player.pos = (x, y - 1)
|
||||
elif key == "S":
|
||||
elif key == mcrfpy.Key.S:
|
||||
player.pos = (x, y + 1)
|
||||
elif key == "A":
|
||||
elif key == mcrfpy.Key.A:
|
||||
player.pos = (x - 1, y)
|
||||
elif key == "D":
|
||||
elif key == mcrfpy.Key.D:
|
||||
player.pos = (x + 1, y)
|
||||
|
||||
scene.on_key = handle_keys
|
||||
|
|
|
|||
|
|
@ -35,7 +35,7 @@ scene.children.append(grid)
|
|||
|
||||
# Add keyboard controls using modern API
|
||||
def move_around(key, state):
|
||||
if state == "start":
|
||||
if state == mcrfpy.InputState.PRESSED:
|
||||
print(f"You pressed {key}")
|
||||
|
||||
scene.on_key = move_around
|
||||
|
|
|
|||
|
|
@ -169,12 +169,15 @@ class GeometryDemoRunner:
|
|||
self.create_menu()
|
||||
|
||||
def handle_key(key, state):
|
||||
if state != "start":
|
||||
if state != mcrfpy.InputState.PRESSED:
|
||||
return
|
||||
|
||||
# Number keys 1-9 for direct screen access
|
||||
if key in [f"Num{n}" for n in "123456789"]:
|
||||
idx = int(key[-1]) - 1
|
||||
_num_key_map = {mcrfpy.Key.NUM_1: 0, mcrfpy.Key.NUM_2: 1, mcrfpy.Key.NUM_3: 2,
|
||||
mcrfpy.Key.NUM_4: 3, mcrfpy.Key.NUM_5: 4, mcrfpy.Key.NUM_6: 5,
|
||||
mcrfpy.Key.NUM_7: 6, mcrfpy.Key.NUM_8: 7, mcrfpy.Key.NUM_9: 8}
|
||||
if key in _num_key_map:
|
||||
idx = _num_key_map[key]
|
||||
if idx < len(self.screens):
|
||||
# Clean up ALL screen's timers first
|
||||
for screen in self.screens:
|
||||
|
|
@ -185,13 +188,13 @@ class GeometryDemoRunner:
|
|||
self.screens[idx].restart_timers()
|
||||
|
||||
# ESC returns to menu
|
||||
elif key == "Escape":
|
||||
elif key == mcrfpy.Key.ESCAPE:
|
||||
for screen in self.screens:
|
||||
screen.cleanup()
|
||||
geo_menu.activate()
|
||||
|
||||
# Q quits
|
||||
elif key == "Q":
|
||||
elif key == mcrfpy.Key.Q:
|
||||
sys.exit(0)
|
||||
|
||||
# Register keyboard handler on all scenes
|
||||
|
|
|
|||
|
|
@ -41,14 +41,14 @@ class Draggable(mcrfpy.Frame):
|
|||
self.tick.stop()
|
||||
|
||||
def minmax(self, pos, btn, event):
|
||||
if event != "start": return
|
||||
if event != mcrfpy.InputState.PRESSED: return
|
||||
self.minimized = not self.minimized
|
||||
self.minimize_btn.children[0].text = "+" if self.minimized else "-"
|
||||
self.clock.visible = not self.minimized
|
||||
self.h = 40 if self.minimized else 150
|
||||
|
||||
def toggle_move(self, *args):
|
||||
if not self.dragging and args[-1] == "start":
|
||||
if not self.dragging and args[-1] == mcrfpy.InputState.PRESSED:
|
||||
self.dragging = True
|
||||
self.drag_start_pos = args[0]
|
||||
self.on_move = self.update_pos
|
||||
|
|
@ -66,7 +66,7 @@ class Draggable(mcrfpy.Frame):
|
|||
self.clock.text = f"{str(self.time//60).zfill(2)}:{str(self.time%60).zfill(2)}"
|
||||
|
||||
def spawn(*args):
|
||||
if args[-1] != "start": return
|
||||
if args[-1] != mcrfpy.InputState.PRESSED: return
|
||||
scene.children.append(Draggable((50, 100)))
|
||||
|
||||
add_btn = mcrfpy.Frame((5, 5), (32, 32), fill_color = (64, 12, 12), children=[mcrfpy.Caption((8, 0), text="+", font=mcrfpy.default_font, font_size=24)])
|
||||
|
|
|
|||
|
|
@ -160,21 +160,21 @@ def show_both():
|
|||
def handle_keypress(key_str, state):
|
||||
"""Handle keyboard input"""
|
||||
global mode
|
||||
if state == "end": return
|
||||
if state == mcrfpy.InputState.RELEASED: return
|
||||
print(key_str)
|
||||
if key_str == "Esc" or key_str == "Q":
|
||||
if key_str == mcrfpy.Key.ESCAPE or key_str == mcrfpy.Key.Q:
|
||||
print("\nExiting...")
|
||||
sys.exit(0)
|
||||
elif key_str == "A" or key_str == "1":
|
||||
elif key_str == mcrfpy.Key.A or key_str == mcrfpy.Key.NUM_1:
|
||||
mode = "ASTAR"
|
||||
show_astar()
|
||||
elif key_str == "D" or key_str == "2":
|
||||
elif key_str == mcrfpy.Key.D or key_str == mcrfpy.Key.NUM_2:
|
||||
mode = "DIJKSTRA"
|
||||
show_dijkstra()
|
||||
elif key_str == "B" or key_str == "3":
|
||||
elif key_str == mcrfpy.Key.B or key_str == mcrfpy.Key.NUM_3:
|
||||
mode = "BOTH"
|
||||
show_both()
|
||||
elif key_str == "Space":
|
||||
elif key_str == mcrfpy.Key.SPACE:
|
||||
# Refresh current mode
|
||||
if mode == "ASTAR":
|
||||
show_astar()
|
||||
|
|
@ -203,7 +203,7 @@ ui.append(grid)
|
|||
|
||||
# Scale and position
|
||||
grid.size = (600, 400) # 30*20, 20*20
|
||||
grid.position = (100, 100)
|
||||
grid.pos = (100, 100)
|
||||
|
||||
# Add title
|
||||
title = mcrfpy.Caption(pos=(250, 20), text="A* vs Dijkstra Pathfinding")
|
||||
|
|
|
|||
|
|
@ -152,21 +152,24 @@ def show_combination(index):
|
|||
def handle_keypress(key_str, state):
|
||||
"""Handle keyboard input"""
|
||||
global current_combo_index
|
||||
if state == "end": return
|
||||
if state == mcrfpy.InputState.RELEASED: return
|
||||
|
||||
if key_str == "Esc" or key_str == "Q":
|
||||
if key_str == mcrfpy.Key.ESCAPE or key_str == mcrfpy.Key.Q:
|
||||
print("\nExiting...")
|
||||
sys.exit(0)
|
||||
elif key_str == "Space" or key_str == "N":
|
||||
elif key_str == mcrfpy.Key.SPACE or key_str == mcrfpy.Key.N:
|
||||
show_combination(current_combo_index + 1)
|
||||
elif key_str == "P":
|
||||
elif key_str == mcrfpy.Key.P:
|
||||
show_combination(current_combo_index - 1)
|
||||
elif key_str == "R":
|
||||
elif key_str == mcrfpy.Key.R:
|
||||
show_combination(current_combo_index)
|
||||
elif key_str in "123456":
|
||||
combo_num = int(key_str) - 1 # 0-based index
|
||||
if combo_num < len(all_combinations):
|
||||
show_combination(combo_num)
|
||||
else:
|
||||
num_keys = {mcrfpy.Key.NUM_1: 0, mcrfpy.Key.NUM_2: 1, mcrfpy.Key.NUM_3: 2,
|
||||
mcrfpy.Key.NUM_4: 3, mcrfpy.Key.NUM_5: 4, mcrfpy.Key.NUM_6: 5}
|
||||
if key_str in num_keys:
|
||||
combo_num = num_keys[key_str]
|
||||
if combo_num < len(all_combinations):
|
||||
show_combination(combo_num)
|
||||
|
||||
# Create the demo
|
||||
print("Dijkstra All Paths Demo")
|
||||
|
|
@ -183,7 +186,7 @@ ui.append(grid)
|
|||
|
||||
# Scale and position
|
||||
grid.size = (560, 400)
|
||||
grid.position = (120, 100)
|
||||
grid.pos = (120, 100)
|
||||
|
||||
# Add title
|
||||
title = mcrfpy.Caption(pos=(200, 20), text="Dijkstra - All Paths (Valid & Invalid)")
|
||||
|
|
|
|||
|
|
@ -169,15 +169,15 @@ def show_path(index):
|
|||
def handle_keypress(key_str, state):
|
||||
"""Handle keyboard input"""
|
||||
global current_path_index
|
||||
if state == "end": return
|
||||
if key_str == "Esc":
|
||||
if state == mcrfpy.InputState.RELEASED: return
|
||||
if key_str == mcrfpy.Key.ESCAPE:
|
||||
print("\nExiting...")
|
||||
sys.exit(0)
|
||||
elif key_str == "N" or key_str == "Space":
|
||||
elif key_str == mcrfpy.Key.N or key_str == mcrfpy.Key.SPACE:
|
||||
show_path(current_path_index + 1)
|
||||
elif key_str == "P":
|
||||
elif key_str == mcrfpy.Key.P:
|
||||
show_path(current_path_index - 1)
|
||||
elif key_str == "R":
|
||||
elif key_str == mcrfpy.Key.R:
|
||||
show_path(current_path_index)
|
||||
|
||||
# Create the demo
|
||||
|
|
@ -194,7 +194,7 @@ ui.append(grid)
|
|||
|
||||
# Scale and position
|
||||
grid.size = (560, 400)
|
||||
grid.position = (120, 100)
|
||||
grid.pos = (120, 100)
|
||||
|
||||
# Add title
|
||||
title = mcrfpy.Caption(pos=(200, 20), text="Dijkstra Pathfinding - Cycle Paths")
|
||||
|
|
|
|||
|
|
@ -79,7 +79,7 @@ perspective_names = ["Omniscient", "Player", "Enemy"]
|
|||
# UI Setup
|
||||
ui = visibility_demo.children
|
||||
ui.append(grid)
|
||||
grid.position = (50, 100)
|
||||
grid.pos = (50, 100)
|
||||
grid.size = (900, 600) # 30*30, 20*30
|
||||
|
||||
# Title
|
||||
|
|
@ -138,40 +138,39 @@ def cycle_perspective():
|
|||
# Key handlers
|
||||
def handle_keys(key, state):
|
||||
"""Handle keyboard input"""
|
||||
if state == "end": return
|
||||
key = key.lower()
|
||||
if state == mcrfpy.InputState.RELEASED: return
|
||||
# Player movement (WASD)
|
||||
if key == "w":
|
||||
if key == mcrfpy.Key.W:
|
||||
move_entity(player, 0, -1)
|
||||
elif key == "s":
|
||||
elif key == mcrfpy.Key.S:
|
||||
move_entity(player, 0, 1)
|
||||
elif key == "a":
|
||||
elif key == mcrfpy.Key.A:
|
||||
move_entity(player, -1, 0)
|
||||
elif key == "d":
|
||||
elif key == mcrfpy.Key.D:
|
||||
move_entity(player, 1, 0)
|
||||
|
||||
# Enemy movement (Arrows)
|
||||
elif key == "up":
|
||||
elif key == mcrfpy.Key.UP:
|
||||
move_entity(enemy, 0, -1)
|
||||
elif key == "down":
|
||||
elif key == mcrfpy.Key.DOWN:
|
||||
move_entity(enemy, 0, 1)
|
||||
elif key == "left":
|
||||
elif key == mcrfpy.Key.LEFT:
|
||||
move_entity(enemy, -1, 0)
|
||||
elif key == "right":
|
||||
elif key == mcrfpy.Key.RIGHT:
|
||||
move_entity(enemy, 1, 0)
|
||||
|
||||
# Tab to cycle perspective
|
||||
elif key == "tab":
|
||||
elif key == mcrfpy.Key.TAB:
|
||||
cycle_perspective()
|
||||
|
||||
# Space to update visibility
|
||||
elif key == "space":
|
||||
elif key == mcrfpy.Key.SPACE:
|
||||
player.update_visibility()
|
||||
enemy.update_visibility()
|
||||
print("Updated visibility for both entities")
|
||||
|
||||
# R to reset
|
||||
elif key == "r":
|
||||
elif key == mcrfpy.Key.R:
|
||||
player.x, player.y = 5, 10
|
||||
enemy.x, enemy.y = 25, 10
|
||||
player.update_visibility()
|
||||
|
|
@ -180,7 +179,7 @@ def handle_keys(key, state):
|
|||
print("Reset positions")
|
||||
|
||||
# Q to quit
|
||||
elif key == "q":
|
||||
elif key == mcrfpy.Key.Q:
|
||||
print("Exiting...")
|
||||
sys.exit(0)
|
||||
|
||||
|
|
|
|||
|
|
@ -456,18 +456,17 @@ class ProcgenDemoBase(ABC):
|
|||
elif key == mcrfpy.Key.ESCAPE:
|
||||
self._return_to_menu()
|
||||
else:
|
||||
# Number keys for layer toggles - convert to string for parsing
|
||||
key_str = str(key) if not isinstance(key, str) else key
|
||||
if key_str.startswith("Key.NUM") or (len(key_str) == 1 and key_str.isdigit()):
|
||||
try:
|
||||
num = int(key_str[-1])
|
||||
if 1 <= num <= len(self.layer_defs):
|
||||
layer_def = self.layer_defs[num - 1]
|
||||
toggle = self.widgets.get(f"layer_{layer_def.name}")
|
||||
if toggle:
|
||||
toggle.toggle()
|
||||
except (ValueError, IndexError):
|
||||
pass
|
||||
# Number keys for layer toggles
|
||||
_num_key_map = {mcrfpy.Key.NUM_1: 1, mcrfpy.Key.NUM_2: 2, mcrfpy.Key.NUM_3: 3,
|
||||
mcrfpy.Key.NUM_4: 4, mcrfpy.Key.NUM_5: 5, mcrfpy.Key.NUM_6: 6,
|
||||
mcrfpy.Key.NUM_7: 7, mcrfpy.Key.NUM_8: 8, mcrfpy.Key.NUM_9: 9}
|
||||
if key in _num_key_map:
|
||||
num = _num_key_map[key]
|
||||
if 1 <= num <= len(self.layer_defs):
|
||||
layer_def = self.layer_defs[num - 1]
|
||||
toggle = self.widgets.get(f"layer_{layer_def.name}")
|
||||
if toggle:
|
||||
toggle.toggle()
|
||||
|
||||
def _return_to_menu(self):
|
||||
"""Return to demo menu."""
|
||||
|
|
|
|||
|
|
@ -160,17 +160,14 @@ class DemoLauncher:
|
|||
if action != mcrfpy.InputState.PRESSED:
|
||||
return
|
||||
|
||||
# Convert key to string for easier comparison
|
||||
key_str = str(key) if not isinstance(key, str) else key
|
||||
|
||||
# Number keys to launch demos directly
|
||||
if key_str.startswith("Key.NUM") or (len(key_str) == 1 and key_str.isdigit()):
|
||||
try:
|
||||
num = int(key_str[-1])
|
||||
if 1 <= num <= len(self.DEMOS):
|
||||
self._launch_demo(num - 1)
|
||||
except (ValueError, IndexError):
|
||||
pass
|
||||
_num_key_map = {mcrfpy.Key.NUM_1: 1, mcrfpy.Key.NUM_2: 2, mcrfpy.Key.NUM_3: 3,
|
||||
mcrfpy.Key.NUM_4: 4, mcrfpy.Key.NUM_5: 5, mcrfpy.Key.NUM_6: 6,
|
||||
mcrfpy.Key.NUM_7: 7, mcrfpy.Key.NUM_8: 8, mcrfpy.Key.NUM_9: 9}
|
||||
if key in _num_key_map:
|
||||
num = _num_key_map[key]
|
||||
if 1 <= num <= len(self.DEMOS):
|
||||
self._launch_demo(num - 1)
|
||||
elif key == mcrfpy.Key.ESCAPE:
|
||||
sys.exit(0)
|
||||
|
||||
|
|
|
|||
|
|
@ -27,7 +27,7 @@ def test_minimal():
|
|||
|
||||
print("Attempting to call on_click...")
|
||||
try:
|
||||
obj.on_click((50, 50), "left", "start")
|
||||
obj.on_click((50, 50), mcrfpy.MouseButton.LEFT, mcrfpy.InputState.PRESSED)
|
||||
print("Call succeeded!")
|
||||
except Exception as e:
|
||||
print(f"Exception: {type(e).__name__}: {e}")
|
||||
|
|
@ -51,7 +51,7 @@ def test_without_callback_clear():
|
|||
obj = MyFrame(pos=(100, 100), size=(100, 100))
|
||||
|
||||
print("Calling...")
|
||||
obj.on_click((50, 50), "left", "start")
|
||||
obj.on_click((50, 50), mcrfpy.MouseButton.LEFT, mcrfpy.InputState.PRESSED)
|
||||
|
||||
print("Deleting without clearing callback...")
|
||||
del obj
|
||||
|
|
@ -69,7 +69,7 @@ def test_added_to_scene():
|
|||
scene.children.append(obj)
|
||||
|
||||
print("Calling via scene.children[0]...")
|
||||
scene.children[0].on_click((50, 50), "left", "start")
|
||||
scene.children[0].on_click((50, 50), mcrfpy.MouseButton.LEFT, mcrfpy.InputState.PRESSED)
|
||||
|
||||
print("About to exit...")
|
||||
sys.exit(0)
|
||||
|
|
|
|||
|
|
@ -120,7 +120,7 @@ ui.append(cached_shader)
|
|||
|
||||
# Keyboard handler
|
||||
def on_key(key, state):
|
||||
if state == "start" and key in ("Q", "Escape"):
|
||||
if state == mcrfpy.InputState.PRESSED and key in (mcrfpy.Key.Q, mcrfpy.Key.ESCAPE):
|
||||
print("PASS: Shader POC test complete - exiting")
|
||||
sys.exit(0)
|
||||
|
||||
|
|
|
|||
|
|
@ -55,15 +55,15 @@ test_count = 0
|
|||
|
||||
def on_key(key, state):
|
||||
global test_count
|
||||
if state != "start":
|
||||
if state != mcrfpy.InputState.PRESSED:
|
||||
return
|
||||
|
||||
if key == "Num1" or key == "1":
|
||||
if key == mcrfpy.Key.NUM_1:
|
||||
test_frame.shader_enabled = True
|
||||
status.text = "Status: Shader ENABLED"
|
||||
update_display()
|
||||
test_count += 1
|
||||
elif key == "Num2" or key == "2":
|
||||
elif key == mcrfpy.Key.NUM_2:
|
||||
test_frame.shader_enabled = False
|
||||
status.text = "Status: Shader DISABLED"
|
||||
update_display()
|
||||
|
|
@ -76,7 +76,7 @@ def on_key(key, state):
|
|||
else:
|
||||
status.text = "Status: Shader DISABLED - Position OK!"
|
||||
status.fill_color = (100, 255, 100, 255)
|
||||
elif key in ("Q", "Escape"):
|
||||
elif key in (mcrfpy.Key.Q, mcrfpy.Key.ESCAPE):
|
||||
if test_frame.x == 200 and test_frame.y == 200:
|
||||
print(f"PASS: Position remained correct after {test_count} toggles")
|
||||
else:
|
||||
|
|
|
|||
|
|
@ -100,7 +100,7 @@ enemy.sprite_index = 69 # E
|
|||
# UI setup
|
||||
ui = chain_test.children
|
||||
ui.append(grid)
|
||||
grid.position = (100, 100)
|
||||
grid.pos = (100, 100)
|
||||
grid.size = (600, 450)
|
||||
|
||||
title = mcrfpy.Caption(pos=(300, 20), text="Animation Chaining Test")
|
||||
|
|
@ -179,23 +179,21 @@ def update_camera(timer, runtime):
|
|||
def handle_input(key, state):
|
||||
global camera_follow
|
||||
|
||||
if state != "start":
|
||||
if state != mcrfpy.InputState.PRESSED:
|
||||
return
|
||||
|
||||
key = key.lower()
|
||||
|
||||
if key == "q":
|
||||
if key == mcrfpy.Key.Q:
|
||||
sys.exit(0)
|
||||
elif key == "num1":
|
||||
elif key == mcrfpy.Key.NUM_1:
|
||||
animate_player()
|
||||
elif key == "num2":
|
||||
elif key == mcrfpy.Key.NUM_2:
|
||||
animate_enemy()
|
||||
elif key == "num3":
|
||||
elif key == mcrfpy.Key.NUM_3:
|
||||
animate_both()
|
||||
elif key == "c":
|
||||
elif key == mcrfpy.Key.C:
|
||||
camera_follow = not camera_follow
|
||||
info.text = f"Camera follow: {'ON' if camera_follow else 'OFF'}"
|
||||
elif key == "r":
|
||||
elif key == mcrfpy.Key.R:
|
||||
# Reset positions
|
||||
player.x, player.y = 2, 2
|
||||
enemy.x, enemy.y = 17, 12
|
||||
|
|
|
|||
|
|
@ -17,12 +17,12 @@ def test_click_callback_signature(pos, button, action):
|
|||
results.append(("on_click pos is Vector", False))
|
||||
print(f"FAIL: on_click receives {type(pos).__name__} instead of Vector: {pos}")
|
||||
|
||||
# Verify button and action types
|
||||
if isinstance(button, str) and isinstance(action, str):
|
||||
results.append(("on_click button/action are strings", True))
|
||||
# Verify button and action types (enums since #306)
|
||||
if isinstance(button, mcrfpy.MouseButton) and isinstance(action, mcrfpy.InputState):
|
||||
results.append(("on_click button/action are enums", True))
|
||||
print(f"PASS: button={button!r}, action={action!r}")
|
||||
else:
|
||||
results.append(("on_click button/action are strings", False))
|
||||
results.append(("on_click button/action are enums", False))
|
||||
print(f"FAIL: button={type(button).__name__}, action={type(action).__name__}")
|
||||
|
||||
# #230 - Hover callbacks now receive only (pos), not (pos, button, action)
|
||||
|
|
@ -112,7 +112,7 @@ print("\n--- Simulating callback calls ---")
|
|||
|
||||
# Test that the callbacks are set up correctly
|
||||
# on_click still takes (pos, button, action)
|
||||
test_click_callback_signature(mcrfpy.Vector(150, 150), "left", "start")
|
||||
test_click_callback_signature(mcrfpy.Vector(150, 150), mcrfpy.MouseButton.LEFT, mcrfpy.InputState.PRESSED)
|
||||
# #230 - Hover callbacks now take only (pos)
|
||||
test_on_enter_callback_signature(mcrfpy.Vector(100, 100))
|
||||
test_on_exit_callback_signature(mcrfpy.Vector(300, 300))
|
||||
|
|
|
|||
|
|
@ -44,7 +44,7 @@ entity.sprite_index = 64 # @
|
|||
# UI setup
|
||||
ui = test_anim.children
|
||||
ui.append(grid)
|
||||
grid.position = (100, 100)
|
||||
grid.pos = (100, 100)
|
||||
grid.size = (450, 450) # 15 * 30 pixels per cell
|
||||
|
||||
# Title
|
||||
|
|
@ -160,23 +160,21 @@ def test_immediate_position():
|
|||
|
||||
# Input handler
|
||||
def handle_input(key, state):
|
||||
if state != "start":
|
||||
if state != mcrfpy.InputState.PRESSED:
|
||||
return
|
||||
|
||||
key = key.lower()
|
||||
|
||||
if key == "q":
|
||||
if key == mcrfpy.Key.Q:
|
||||
print("Exiting test...")
|
||||
sys.exit(0)
|
||||
elif key == "space":
|
||||
elif key == mcrfpy.Key.SPACE:
|
||||
if not animating:
|
||||
start_animation()
|
||||
else:
|
||||
print("Animation already in progress!")
|
||||
elif key == "t":
|
||||
elif key == mcrfpy.Key.T:
|
||||
# Test immediate position change
|
||||
test_immediate_position()
|
||||
elif key == "r":
|
||||
elif key == mcrfpy.Key.R:
|
||||
# Reset position
|
||||
entity.x = 5
|
||||
entity.y = 5
|
||||
|
|
|
|||
|
|
@ -1,8 +1,9 @@
|
|||
#!/usr/bin/env python3
|
||||
"""Test Key, MouseButton, and InputState enum functionality.
|
||||
|
||||
Tests the new input-related enums that provide type-safe alternatives to
|
||||
string-based key codes, mouse buttons, and event states.
|
||||
Tests the input-related enums that provide type-safe key codes,
|
||||
mouse buttons, and event states. Legacy string comparison was
|
||||
removed in #306 -- these enums now use standard IntEnum comparison.
|
||||
"""
|
||||
|
||||
import mcrfpy
|
||||
|
|
@ -10,7 +11,7 @@ import sys
|
|||
|
||||
|
||||
def test_key_enum():
|
||||
"""Test Key enum members and backwards compatibility."""
|
||||
"""Test Key enum members and int values."""
|
||||
print("Testing Key enum...")
|
||||
|
||||
# Test that enum exists and has expected members
|
||||
|
|
@ -23,24 +24,19 @@ def test_key_enum():
|
|||
assert int(mcrfpy.Key.A) == 0, "Key.A should be 0"
|
||||
assert int(mcrfpy.Key.ESCAPE) == 36, "Key.ESCAPE should be 36"
|
||||
|
||||
# Test backwards compatibility with legacy strings
|
||||
assert mcrfpy.Key.A == "A", "Key.A should equal 'A'"
|
||||
assert mcrfpy.Key.ESCAPE == "Escape", "Key.ESCAPE should equal 'Escape'"
|
||||
assert mcrfpy.Key.LEFT_SHIFT == "LShift", "Key.LEFT_SHIFT should equal 'LShift'"
|
||||
assert mcrfpy.Key.RIGHT_CONTROL == "RControl", "Key.RIGHT_CONTROL should equal 'RControl'"
|
||||
assert mcrfpy.Key.NUM_1 == "Num1", "Key.NUM_1 should equal 'Num1'"
|
||||
assert mcrfpy.Key.NUMPAD_5 == "Numpad5", "Key.NUMPAD_5 should equal 'Numpad5'"
|
||||
assert mcrfpy.Key.F12 == "F12", "Key.F12 should equal 'F12'"
|
||||
assert mcrfpy.Key.SPACE == "Space", "Key.SPACE should equal 'Space'"
|
||||
# Test enum self-comparison
|
||||
assert mcrfpy.Key.ESCAPE == mcrfpy.Key.ESCAPE, "Key.ESCAPE should equal itself"
|
||||
assert mcrfpy.Key.A != mcrfpy.Key.ESCAPE, "Key.A should not equal Key.ESCAPE"
|
||||
|
||||
# Test that enum name also matches
|
||||
assert mcrfpy.Key.ESCAPE == "ESCAPE", "Key.ESCAPE should also equal 'ESCAPE'"
|
||||
# Verify legacy string comparison is removed (#306)
|
||||
assert not (mcrfpy.Key.ESCAPE == "Escape"), "Legacy string comparison should be removed"
|
||||
assert not (mcrfpy.Key.A == "A"), "Legacy string comparison should be removed"
|
||||
|
||||
print(" All Key tests passed")
|
||||
|
||||
|
||||
def test_mouse_button_enum():
|
||||
"""Test MouseButton enum members and backwards compatibility."""
|
||||
"""Test MouseButton enum members."""
|
||||
print("Testing MouseButton enum...")
|
||||
|
||||
# Test that enum exists and has expected members
|
||||
|
|
@ -54,21 +50,19 @@ def test_mouse_button_enum():
|
|||
assert int(mcrfpy.MouseButton.RIGHT) == 1, "MouseButton.RIGHT should be 1"
|
||||
assert int(mcrfpy.MouseButton.MIDDLE) == 2, "MouseButton.MIDDLE should be 2"
|
||||
|
||||
# Test backwards compatibility with legacy strings
|
||||
assert mcrfpy.MouseButton.LEFT == "left", "MouseButton.LEFT should equal 'left'"
|
||||
assert mcrfpy.MouseButton.RIGHT == "right", "MouseButton.RIGHT should equal 'right'"
|
||||
assert mcrfpy.MouseButton.MIDDLE == "middle", "MouseButton.MIDDLE should equal 'middle'"
|
||||
assert mcrfpy.MouseButton.X1 == "x1", "MouseButton.X1 should equal 'x1'"
|
||||
assert mcrfpy.MouseButton.X2 == "x2", "MouseButton.X2 should equal 'x2'"
|
||||
# Test enum self-comparison
|
||||
assert mcrfpy.MouseButton.LEFT == mcrfpy.MouseButton.LEFT
|
||||
assert mcrfpy.MouseButton.LEFT != mcrfpy.MouseButton.RIGHT
|
||||
|
||||
# Test that enum name also matches
|
||||
assert mcrfpy.MouseButton.LEFT == "LEFT", "MouseButton.LEFT should also equal 'LEFT'"
|
||||
# Verify legacy string comparison is removed (#306)
|
||||
assert not (mcrfpy.MouseButton.LEFT == "left"), "Legacy string comparison should be removed"
|
||||
assert not (mcrfpy.MouseButton.RIGHT == "right"), "Legacy string comparison should be removed"
|
||||
|
||||
print(" All MouseButton tests passed")
|
||||
|
||||
|
||||
def test_input_state_enum():
|
||||
"""Test InputState enum members and backwards compatibility."""
|
||||
"""Test InputState enum members."""
|
||||
print("Testing InputState enum...")
|
||||
|
||||
# Test that enum exists and has expected members
|
||||
|
|
@ -80,13 +74,13 @@ def test_input_state_enum():
|
|||
assert int(mcrfpy.InputState.PRESSED) == 0, "InputState.PRESSED should be 0"
|
||||
assert int(mcrfpy.InputState.RELEASED) == 1, "InputState.RELEASED should be 1"
|
||||
|
||||
# Test backwards compatibility with legacy strings
|
||||
assert mcrfpy.InputState.PRESSED == "start", "InputState.PRESSED should equal 'start'"
|
||||
assert mcrfpy.InputState.RELEASED == "end", "InputState.RELEASED should equal 'end'"
|
||||
# Test enum self-comparison
|
||||
assert mcrfpy.InputState.PRESSED == mcrfpy.InputState.PRESSED
|
||||
assert mcrfpy.InputState.PRESSED != mcrfpy.InputState.RELEASED
|
||||
|
||||
# Test that enum name also matches
|
||||
assert mcrfpy.InputState.PRESSED == "PRESSED", "InputState.PRESSED should also equal 'PRESSED'"
|
||||
assert mcrfpy.InputState.RELEASED == "RELEASED", "InputState.RELEASED should also equal 'RELEASED'"
|
||||
# Verify legacy string comparison is removed (#306)
|
||||
assert not (mcrfpy.InputState.PRESSED == "start"), "Legacy string comparison should be removed"
|
||||
assert not (mcrfpy.InputState.RELEASED == "end"), "Legacy string comparison should be removed"
|
||||
|
||||
print(" All InputState tests passed")
|
||||
|
||||
|
|
|
|||
|
|
@ -70,81 +70,81 @@ def handle_key(key, action):
|
|||
"""Handle keyboard input for scene transitions."""
|
||||
global current_transition, transition_duration
|
||||
|
||||
if action != "start":
|
||||
if action != mcrfpy.InputState.PRESSED:
|
||||
return
|
||||
|
||||
current_scene = (mcrfpy.current_scene.name if mcrfpy.current_scene else None)
|
||||
|
||||
# Number keys set transition type
|
||||
keyselections = {
|
||||
"Num1": mcrfpy.Transition.FADE,
|
||||
"Num2": mcrfpy.Transition.SLIDE_LEFT,
|
||||
"Num3": mcrfpy.Transition.SLIDE_RIGHT,
|
||||
"Num4": mcrfpy.Transition.SLIDE_UP,
|
||||
"Num5": mcrfpy.Transition.SLIDE_DOWN,
|
||||
"Num6": mcrfpy.Transition.NONE
|
||||
mcrfpy.Key.NUM_1: mcrfpy.Transition.FADE,
|
||||
mcrfpy.Key.NUM_2: mcrfpy.Transition.SLIDE_LEFT,
|
||||
mcrfpy.Key.NUM_3: mcrfpy.Transition.SLIDE_RIGHT,
|
||||
mcrfpy.Key.NUM_4: mcrfpy.Transition.SLIDE_UP,
|
||||
mcrfpy.Key.NUM_5: mcrfpy.Transition.SLIDE_DOWN,
|
||||
mcrfpy.Key.NUM_6: mcrfpy.Transition.NONE
|
||||
}
|
||||
if key in keyselections:
|
||||
current_transition = keyselections[key]
|
||||
print(f"Transition set to: {current_transition}")
|
||||
#if key == "Num1":
|
||||
#if key == mcrfpy.Key.NUM_1:
|
||||
# current_transition = "fade"
|
||||
# print("Transition set to: fade")
|
||||
#elif key == "Num2":
|
||||
#elif key == mcrfpy.Key.NUM_2:
|
||||
# current_transition = "slide_left"
|
||||
# print("Transition set to: slide_left")
|
||||
#elif key == "Num3":
|
||||
#elif key == mcrfpy.Key.NUM_3:
|
||||
# current_transition = "slide_right"
|
||||
# print("Transition set to: slide_right")
|
||||
#elif key == "Num4":
|
||||
#elif key == mcrfpy.Key.NUM_4:
|
||||
# current_transition = "slide_up"
|
||||
# print("Transition set to: slide_up")
|
||||
#elif key == "Num5":
|
||||
#elif key == mcrfpy.Key.NUM_5:
|
||||
# current_transition = "slide_down"
|
||||
# print("Transition set to: slide_down")
|
||||
#elif key == "Num6":
|
||||
#elif key == mcrfpy.Key.NUM_6:
|
||||
# current_transition = None # Instant
|
||||
# print("Transition set to: instant")
|
||||
|
||||
# Letter keys change scene
|
||||
keytransitions = {
|
||||
"R": red_scene,
|
||||
"B": blue_scene,
|
||||
"G": green_scene,
|
||||
"M": menu_scene
|
||||
mcrfpy.Key.R: red_scene,
|
||||
mcrfpy.Key.B: blue_scene,
|
||||
mcrfpy.Key.G: green_scene,
|
||||
mcrfpy.Key.M: menu_scene
|
||||
}
|
||||
if key in keytransitions:
|
||||
if mcrfpy.current_scene != keytransitions[key]:
|
||||
keytransitions[key].activate(current_transition, transition_duration)
|
||||
#elif key == "R":
|
||||
#elif key == mcrfpy.Key.R:
|
||||
# if current_scene != "red_scene":
|
||||
# print(f"Transitioning to red_scene with {current_transition}")
|
||||
# if current_transition:
|
||||
# mcrfpy.setScene("red_scene", current_transition, transition_duration)
|
||||
# else:
|
||||
# red_scene.activate()
|
||||
#elif key == "B":
|
||||
#elif key == mcrfpy.Key.B:
|
||||
# if current_scene != "blue_scene":
|
||||
# print(f"Transitioning to blue_scene with {current_transition}")
|
||||
# if current_transition:
|
||||
# mcrfpy.setScene("blue_scene", current_transition, transition_duration)
|
||||
# else:
|
||||
# blue_scene.activate()
|
||||
#elif key == "G":
|
||||
#elif key == mcrfpy.Key.G:
|
||||
# if current_scene != "green_scene":
|
||||
# print(f"Transitioning to green_scene with {current_transition}")
|
||||
# if current_transition:
|
||||
# mcrfpy.setScene("green_scene", current_transition, transition_duration)
|
||||
# else:
|
||||
# green_scene.activate()
|
||||
#elif key == "M":
|
||||
#elif key == mcrfpy.Key.M:
|
||||
# if current_scene != "menu_scene":
|
||||
# print(f"Transitioning to menu_scene with {current_transition}")
|
||||
# if current_transition:
|
||||
# mcrfpy.setScene("menu_scene", current_transition, transition_duration)
|
||||
# else:
|
||||
# menu_scene.activate()
|
||||
elif key == "Escape":
|
||||
elif key == mcrfpy.Key.ESCAPE:
|
||||
print("Exiting...")
|
||||
sys.exit(0)
|
||||
|
||||
|
|
|
|||
|
|
@ -78,9 +78,9 @@ def create_demo():
|
|||
# Keyboard handler
|
||||
def handle_keys(scene_name, key):
|
||||
if not focus_mgr.handle_key(key):
|
||||
if key == "Tab":
|
||||
if key == mcrfpy.Key.TAB:
|
||||
focus_mgr.focus_next()
|
||||
elif key == "Escape":
|
||||
elif key == mcrfpy.Key.ESCAPE:
|
||||
print("\nFinal values:")
|
||||
for i, inp in enumerate(inputs):
|
||||
print(f" Field {i+1}: '{inp.get_text()}'")
|
||||
|
|
|
|||
|
|
@ -45,11 +45,13 @@ def test_key_enum_members():
|
|||
|
||||
check("IE: Key enum members", test_key_enum_members)
|
||||
|
||||
def test_inputstate_legacy():
|
||||
assert mcrfpy.InputState.PRESSED == "start"
|
||||
assert mcrfpy.InputState.RELEASED == "end"
|
||||
def test_inputstate_values():
|
||||
assert int(mcrfpy.InputState.PRESSED) == 0
|
||||
assert int(mcrfpy.InputState.RELEASED) == 1
|
||||
# Legacy string comparison removed (#306)
|
||||
assert mcrfpy.InputState.PRESSED != "start"
|
||||
|
||||
check("IE: InputState legacy string compat", test_inputstate_legacy)
|
||||
check("IE: InputState enum values", test_inputstate_values)
|
||||
|
||||
def test_click_handler():
|
||||
frame = mcrfpy.Frame(pos=(100, 100), size=(200, 50))
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue