Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
40 changes: 40 additions & 0 deletions python/taichi/ui/constants.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,46 @@
MMB = "MMB"
RMB = "RMB"

# Function keys
F1 = "F1"
F2 = "F2"
F3 = "F3"
F4 = "F4"
F5 = "F5"
F6 = "F6"
F7 = "F7"
F8 = "F8"
F9 = "F9"
F10 = "F10"
F11 = "F11"
F12 = "F12"

# Navigation keys
INSERT = "Insert"
DELETE = "Delete"
HOME = "Home"
END = "End"
PAGEUP = "PageUp"
PAGEDOWN = "PageDown"

# Numpad keys
NUMPAD0 = "Numpad0"
NUMPAD1 = "Numpad1"
NUMPAD2 = "Numpad2"
NUMPAD3 = "Numpad3"
NUMPAD4 = "Numpad4"
NUMPAD5 = "Numpad5"
NUMPAD6 = "Numpad6"
NUMPAD7 = "Numpad7"
NUMPAD8 = "Numpad8"
NUMPAD9 = "Numpad9"
NUMPAD_DECIMAL = "NumpadDecimal"
NUMPAD_DIVIDE = "NumpadDivide"
NUMPAD_MULTIPLY = "NumpadMultiply"
NUMPAD_SUBTRACT = "NumpadSubtract"
NUMPAD_ADD = "NumpadAdd"
NUMPAD_ENTER = "NumpadEnter"

# Event types
PRESS = "Press"
RELEASE = "Release"
16 changes: 16 additions & 0 deletions python/taichi/ui/window.py
Original file line number Diff line number Diff line change
Expand Up @@ -138,6 +138,22 @@ def get_cursor_pos(self):
"""Get current cursor position, in the range `[0, 1] x [0, 1]`."""
return self.window.get_cursor_pos()

def get_scroll_delta(self):
"""Get the accumulated scroll wheel delta since last call.

Returns:
tuple: (dx, dy) scroll delta values. Resets to (0, 0) after being read.

Example::

>>> while window.running:
... dx, dy = window.get_scroll_delta()
... if dy != 0:
... zoom += dy * 0.1
... window.show()
"""
return self.window.get_scroll_delta()

def show(self):
"""Display this window."""
return self.window.show()
Expand Down
8 changes: 8 additions & 0 deletions taichi/python/export_ggui.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -648,6 +648,13 @@ struct PyWindow {
return py::make_tuple(x, y);
}

py::tuple py_get_scroll_delta() {
auto delta = window->get_scroll_delta();
double dx = std::get<0>(delta);
double dy = std::get<1>(delta);
return py::make_tuple(dx, dy);
}

void destroy() {
if (window) {
window.reset();
Expand All @@ -671,6 +678,7 @@ void export_ggui(py::module &m) {
.def("get_image_buffer_as_numpy", &PyWindow::get_image_buffer)
.def("is_pressed", &PyWindow::is_pressed)
.def("get_cursor_pos", &PyWindow::py_get_cursor_pos)
.def("get_scroll_delta", &PyWindow::py_get_scroll_delta)
.def("is_running", &PyWindow::is_running)
.def("set_is_running", &PyWindow::set_is_running)
.def("get_event", &PyWindow::get_event)
Expand Down
28 changes: 28 additions & 0 deletions taichi/ui/common/input_handler.h
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,30 @@ class InputHandler {
user_mouse_button_callbacks_.push_back(f);
}

void scroll_callback(GLFWwindow *window, double xoffset, double yoffset) {
scroll_dx_ += xoffset;
scroll_dy_ += yoffset;
for (auto f : user_scroll_callbacks_) {
f(xoffset, yoffset);
}
}

void add_scroll_callback(std::function<void(double, double)> f) {
user_scroll_callbacks_.push_back(f);
}

double scroll_dx() const {
return scroll_dx_;
}
double scroll_dy() const {
return scroll_dy_;
}

void reset_scroll() {
scroll_dx_ = 0;
scroll_dy_ = 0;
}

InputHandler() : keys_(1024, false) {
}

Expand All @@ -102,6 +126,10 @@ class InputHandler {
std::vector<std::function<void(int, int)>> user_key_callbacks_;
std::vector<std::function<void(double, double)>> user_mouse_pos_callbacks_;
std::vector<std::function<void(int, int)>> user_mouse_button_callbacks_;
std::vector<std::function<void(double, double)>> user_scroll_callbacks_;

double scroll_dx_ = 0;
double scroll_dy_ = 0;
};

} // namespace taichi::ui
17 changes: 17 additions & 0 deletions taichi/ui/common/window_base.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ void WindowBase::set_callbacks() {
glfwSetKeyCallback(glfw_window_, key_callback);
glfwSetCursorPosCallback(glfw_window_, mouse_pos_callback);
glfwSetMouseButtonCallback(glfw_window_, mouse_button_callback);
glfwSetScrollCallback(glfw_window_, scroll_callback);

input_handler_.add_key_callback([&](int key, int action) {
// Catch exception from button_id_to_name().
Expand Down Expand Up @@ -110,6 +111,14 @@ std::pair<float, float> WindowBase::get_cursor_pos() {
return std::make_pair(x, y);
}

std::pair<double, double> WindowBase::get_scroll_delta() {
CHECK_WINDOW_SHOWING;
double dx = input_handler_.scroll_dx();
double dy = input_handler_.scroll_dy();
input_handler_.reset_scroll();
return std::make_pair(dx, dy);
}

std::vector<Event> WindowBase::get_events(EventType tag) {
CHECK_WINDOW_SHOWING;
glfwPollEvents();
Expand Down Expand Up @@ -198,4 +207,12 @@ void WindowBase::mouse_button_callback(GLFWwindow *glfw_window,
modifier);
}

void WindowBase::scroll_callback(GLFWwindow *glfw_window,
double xoffset,
double yoffset) {
auto window =
reinterpret_cast<WindowBase *>(glfwGetWindowUserPointer(glfw_window));
window->input_handler_.scroll_callback(glfw_window, xoffset, yoffset);
}

} // namespace taichi::ui
6 changes: 6 additions & 0 deletions taichi/ui/common/window_base.h
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,8 @@ class WindowBase {

std::pair<float, float> get_cursor_pos();

std::pair<double, double> get_scroll_delta();

std::vector<Event> get_events(EventType tag);

bool get_event(EventType tag);
Expand Down Expand Up @@ -87,6 +89,10 @@ class WindowBase {
int button,
int action,
int modifier);

static void scroll_callback(GLFWwindow *glfw_window,
double xoffset,
double yoffset);
};

} // namespace taichi::ui
93 changes: 90 additions & 3 deletions taichi/ui/utils/utils.h
Original file line number Diff line number Diff line change
Expand Up @@ -112,6 +112,46 @@ struct Keys {
DEFINE_KEY(LMB);
DEFINE_KEY(MMB);
DEFINE_KEY(RMB);

// Function keys
DEFINE_KEY(F1);
DEFINE_KEY(F2);
DEFINE_KEY(F3);
DEFINE_KEY(F4);
DEFINE_KEY(F5);
DEFINE_KEY(F6);
DEFINE_KEY(F7);
DEFINE_KEY(F8);
DEFINE_KEY(F9);
DEFINE_KEY(F10);
DEFINE_KEY(F11);
DEFINE_KEY(F12);

// Navigation
DEFINE_KEY(Insert);
DEFINE_KEY(Delete);
DEFINE_KEY(Home);
DEFINE_KEY(End);
DEFINE_KEY(PageUp);
DEFINE_KEY(PageDown);

// Numpad
DEFINE_KEY(Numpad0);
DEFINE_KEY(Numpad1);
DEFINE_KEY(Numpad2);
DEFINE_KEY(Numpad3);
DEFINE_KEY(Numpad4);
DEFINE_KEY(Numpad5);
DEFINE_KEY(Numpad6);
DEFINE_KEY(Numpad7);
DEFINE_KEY(Numpad8);
DEFINE_KEY(Numpad9);
DEFINE_KEY(NumpadDecimal);
DEFINE_KEY(NumpadDivide);
DEFINE_KEY(NumpadMultiply);
DEFINE_KEY(NumpadSubtract);
DEFINE_KEY(NumpadAdd);
DEFINE_KEY(NumpadEnter);
#undef DEFINE_KEY
};

Expand All @@ -132,7 +172,45 @@ inline std::unordered_map<std::string, int> get_keys_map() {
{Keys::CapsLock, GLFW_KEY_CAPS_LOCK},
{Keys::LMB, GLFW_MOUSE_BUTTON_LEFT},
{Keys::MMB, GLFW_MOUSE_BUTTON_MIDDLE},
{Keys::RMB, GLFW_MOUSE_BUTTON_RIGHT}};
{Keys::RMB, GLFW_MOUSE_BUTTON_RIGHT},
// Function keys
{Keys::F1, GLFW_KEY_F1},
{Keys::F2, GLFW_KEY_F2},
{Keys::F3, GLFW_KEY_F3},
{Keys::F4, GLFW_KEY_F4},
{Keys::F5, GLFW_KEY_F5},
{Keys::F6, GLFW_KEY_F6},
{Keys::F7, GLFW_KEY_F7},
{Keys::F8, GLFW_KEY_F8},
{Keys::F9, GLFW_KEY_F9},
{Keys::F10, GLFW_KEY_F10},
{Keys::F11, GLFW_KEY_F11},
{Keys::F12, GLFW_KEY_F12},
// Navigation
{Keys::Insert, GLFW_KEY_INSERT},
{Keys::Delete, GLFW_KEY_DELETE},
{Keys::Home, GLFW_KEY_HOME},
{Keys::End, GLFW_KEY_END},
{Keys::PageUp, GLFW_KEY_PAGE_UP},
{Keys::PageDown, GLFW_KEY_PAGE_DOWN},
// Numpad
{Keys::Numpad0, GLFW_KEY_KP_0},
{Keys::Numpad1, GLFW_KEY_KP_1},
{Keys::Numpad2, GLFW_KEY_KP_2},
{Keys::Numpad3, GLFW_KEY_KP_3},
{Keys::Numpad4, GLFW_KEY_KP_4},
{Keys::Numpad5, GLFW_KEY_KP_5},
{Keys::Numpad6, GLFW_KEY_KP_6},
{Keys::Numpad7, GLFW_KEY_KP_7},
{Keys::Numpad8, GLFW_KEY_KP_8},
{Keys::Numpad9, GLFW_KEY_KP_9},
{Keys::NumpadDecimal, GLFW_KEY_KP_DECIMAL},
{Keys::NumpadDivide, GLFW_KEY_KP_DIVIDE},
{Keys::NumpadMultiply, GLFW_KEY_KP_MULTIPLY},
{Keys::NumpadSubtract, GLFW_KEY_KP_SUBTRACT},
{Keys::NumpadAdd, GLFW_KEY_KP_ADD},
{Keys::NumpadEnter, GLFW_KEY_KP_ENTER},
};
return keys;
}

Expand All @@ -155,6 +233,9 @@ inline int buttom_name_to_id(const std::string &name) {
c = c - ('a' - 'A');
return (int)c;
}
if (c >= '0' && c <= '9') {
return (int)c; // GLFW_KEY_0-9 are ASCII codes 48-57
}
}

auto keys = get_keys_map();
Expand All @@ -173,13 +254,19 @@ inline std::string button_id_to_name(int id) {
name += c;
return name;
}
if (id >= '0' && id <= '9') {
std::string name;
name += (char)id;
return name;
}
auto keys = get_inv_keys_map();

if (keys.find(id) != keys.end()) {
return keys.at(id);
} else {
throw std::runtime_error(std::string("unrecognized id: ") +
std::to_string(id));
// Fallback: return "Key_<id>" instead of throwing for unknown keys.
// This ensures unmapped keys still generate events that users can match on.
return std::string("Key_") + std::to_string(id);
}
}
#endif
Expand Down
Loading