C++ Pointer dispatch API

This commit is contained in:
Olivier Goffart 2023-07-25 09:03:50 +02:00 committed by Olivier Goffart
parent aebaa7d6c9
commit 3a2359f107
8 changed files with 175 additions and 124 deletions

View file

@ -256,6 +256,7 @@ endforeach()
set(generated_headers
${CMAKE_CURRENT_BINARY_DIR}/generated_include/slint_internal.h
${CMAKE_CURRENT_BINARY_DIR}/generated_include/slint_enums_internal.h
${CMAKE_CURRENT_BINARY_DIR}/generated_include/slint_enums.h
${CMAKE_CURRENT_BINARY_DIR}/generated_include/slint_string_internal.h
${CMAKE_CURRENT_BINARY_DIR}/generated_include/slint_brush_internal.h
${CMAKE_CURRENT_BINARY_DIR}/generated_include/slint_sharedvector_internal.h

View file

@ -9,26 +9,43 @@ use std::path::{Path, PathBuf};
// cSpell: ignore compat constexpr corelib deps sharedvector pathdata
fn enums(path: &Path) -> anyhow::Result<()> {
let mut enums =
std::fs::File::create(path).context("Error creating slint_internal_enums.h file")?;
writeln!(enums, "#pragma once")?;
writeln!(enums, "// This file is auto-generated from {}", file!())?;
writeln!(enums, "namespace slint::cbindgen_private {{")?;
let mut enums_priv = std::fs::File::create(path.join("slint_enums_internal.h"))
.context("Error creating slint_internal_enums.h file")?;
writeln!(enums_priv, "#pragma once")?;
writeln!(enums_priv, "// This file is auto-generated from {}", file!())?;
writeln!(enums_priv, "#include \"slint_enums.h\"")?;
writeln!(enums_priv, "namespace slint::cbindgen_private {{")?;
let mut enums_pub = std::fs::File::create(path.join("slint_enums.h"))
.context("Error creating slint_enums.h file")?;
writeln!(enums_pub, "#pragma once")?;
writeln!(enums_pub, "// This file is auto-generated from {}", file!())?;
writeln!(enums_pub, "namespace slint {{")?;
macro_rules! enum_file {
(PointerEventButton) => {{
writeln!(enums_priv, "using slint::PointerEventButton;")?;
&mut enums_pub
}};
($_:ident) => {
&mut enums_priv
};
}
macro_rules! print_enums {
($( $(#[doc = $enum_doc:literal])* $(#[non_exhaustive])? enum $Name:ident { $( $(#[doc = $value_doc:literal])* $Value:ident,)* })*) => {
$(
$(writeln!(enums, "///{}", $enum_doc)?;)*
writeln!(enums, "enum class {} {{", stringify!($Name))?;
let file = enum_file!($Name);
$(writeln!(file, "///{}", $enum_doc)?;)*
writeln!(file, "enum class {} {{", stringify!($Name))?;
$(
$(writeln!(enums, " ///{}", $value_doc)?;)*
writeln!(enums, " {},", stringify!($Value).trim_start_matches("r#"))?;
$(writeln!(file, " ///{}", $value_doc)?;)*
writeln!(file, " {},", stringify!($Value).trim_start_matches("r#"))?;
)*
writeln!(enums, "}};")?;
writeln!(file, "}};")?;
)*
}
}
i_slint_common::for_each_enums!(print_enums);
writeln!(enums, "}}")?;
writeln!(enums_pub, "}}")?;
writeln!(enums_priv, "}}")?;
Ok(())
}
@ -743,7 +760,7 @@ pub fn gen_all(
proc_macro2::fallback::force(); // avoid a abort if panic=abort is set
std::fs::create_dir_all(include_dir).context("Could not create the include directory")?;
let mut deps = Vec::new();
enums(&include_dir.join("slint_enums_internal.h"))?;
enums(include_dir)?;
gen_corelib(root_dir, include_dir, &mut deps, enabled_features)?;
gen_backend_qt(root_dir, include_dir, &mut deps)?;
gen_backend(root_dir, include_dir, &mut deps)?;

View file

@ -233,6 +233,13 @@ public:
cbindgen_private::slint_windowrc_dispatch_key_event(&inner, &event);
}
/// Send a pointer event to this window
void dispatch_pointer_event(const cbindgen_private::MouseEvent &event)
{
private_api::assert_main_thread();
cbindgen_private::slint_windowrc_dispatch_pointer_event(&inner, event);
}
/// Registers a font by the specified path. The path must refer to an existing
/// TrueType font.
/// \returns an empty optional on success, otherwise an error string
@ -523,6 +530,83 @@ public:
inner.dispatch_key_event(event);
}
/// Dispatches a pointer or mouse press event to the scene.
///
/// Use this function when you're implementing your own backend and want to forward user
/// pointer/mouse events.
///
/// \a pos represents the logical position of the pointer relative to the window.
/// \a button is the button that was pressed.
void dispatch_pointer_press_event(LogicalPosition pos, PointerEventButton button)
{
using slint::cbindgen_private::MouseEvent;
MouseEvent event { .tag = MouseEvent::Tag::Pressed,
.pressed = MouseEvent::Pressed_Body { .position = { pos.x, pos.y },
.button = button,
.click_count = 0 } };
inner.dispatch_pointer_event(event);
}
/// Dispatches a pointer or mouse release event to the scene.
///
/// Use this function when you're implementing your own backend and want to forward user
/// pointer/mouse events.
///
/// \a pos represents the logical position of the pointer relative to the window.
/// \a button is the button that was released.
void dispatch_pointer_release_event(LogicalPosition pos, PointerEventButton button)
{
using slint::cbindgen_private::MouseEvent;
MouseEvent event { .tag = MouseEvent::Tag::Released,
.released = MouseEvent::Released_Body { .position = { pos.x, pos.y },
.button = button,
.click_count = 0 } };
inner.dispatch_pointer_event(event);
}
/// Dispatches a pointer exit event to the scene.
///
/// Use this function when you're implementing your own backend and want to forward user
/// pointer/mouse events.
///
/// This event is triggered when the pointer exits the window.
void dispatch_pointer_exit_event()
{
using slint::cbindgen_private::MouseEvent;
MouseEvent event { .tag = MouseEvent::Tag::Exit, .moved = {} };
inner.dispatch_pointer_event(event);
}
/// Dispatches a pointer move event to the scene.
///
/// Use this function when you're implementing your own backend and want to forward user
/// pointer/mouse events.
///
/// \a pos represents the logical position of the pointer relative to the window.
void dispatch_pointer_move_event(LogicalPosition pos)
{
using slint::cbindgen_private::MouseEvent;
MouseEvent event { .tag = MouseEvent::Tag::Moved,
.moved = MouseEvent::Moved_Body { .position = { pos.x, pos.y } } };
inner.dispatch_pointer_event(event);
}
/// Dispatches a scroll (or wheel) event to the scene.
///
/// Use this function when you're implementing your own backend and want to forward user wheel
/// events.
///
/// \a parameter represents the logical position of the pointer relative to the window.
/// \a delta_x and \a delta_y represent the scroll delta values in the X and Y
/// directions in logical pixels.
void dispatch_pointer_scroll_event(LogicalPosition pos, float delta_x, float delta_y)
{
using slint::cbindgen_private::MouseEvent;
MouseEvent event { .tag = MouseEvent::Tag::Wheel,
.wheel = MouseEvent::Wheel_Body { .position = { pos.x, pos.y },
.delta_x = delta_x,
.delta_y = delta_y } };
inner.dispatch_pointer_event(event);
}
/// \private
private_api::WindowAdapterRc &window_handle() { return inner; }
/// \private

View file

@ -121,16 +121,6 @@ public:
return *reinterpret_cast<Window *>(&self);
}
/// Send a pointer event to this window
// Note: in rust, this is on the Window. FIXME: use a public event type
void dispatch_pointer_event(const cbindgen_private::MouseEvent &event)
{
private_api::assert_main_thread();
if (was_initialized) {
cbindgen_private::slint_windowrc_dispatch_pointer_event(&self, event);
}
}
/// Set the logical size of this window after a resize event
// Note: in rust, this is an event on the Window
void dispatch_resize_event(slint::LogicalSize s)

View file

@ -104,90 +104,42 @@ struct MyWindowAdapter : public slint_platform::WindowAdapter
SetWindowPos(hwnd, nullptr, x, y, width, height, 0);
}
std::optional<slint::cbindgen_private::MouseEvent> mouseEventForMessage(UINT uMsg,
LPARAM lParam)
{
float x = float(LOWORD(lParam));
float y = float(HIWORD(lParam));
auto makePressEvent = [=](UINT uMsg) {
slint::cbindgen_private::PointerEventButton button;
switch (uMsg) {
case WM_LBUTTONDOWN:
button = slint::cbindgen_private::PointerEventButton::Left;
break;
case WM_MBUTTONDOWN:
button = slint::cbindgen_private::PointerEventButton::Middle;
break;
case WM_RBUTTONDOWN:
button = slint::cbindgen_private::PointerEventButton::Right;
break;
default:
assert(!"not implemented");
}
return slint::cbindgen_private::MouseEvent {
.tag = slint::cbindgen_private::MouseEvent::Tag::Pressed,
.pressed =
slint::cbindgen_private::MouseEvent::Pressed_Body {
.position = { x, y },
.button = button,
}
};
};
auto makeReleaseEvent = [=](UINT uMsg) {
slint::cbindgen_private::PointerEventButton button;
switch (uMsg) {
case WM_LBUTTONUP:
button = slint::cbindgen_private::PointerEventButton::Left;
break;
case WM_MBUTTONUP:
button = slint::cbindgen_private::PointerEventButton::Middle;
break;
case WM_RBUTTONUP:
button = slint::cbindgen_private::PointerEventButton::Right;
break;
default:
assert(!"not implemented");
}
return slint::cbindgen_private::MouseEvent {
.tag = slint::cbindgen_private::MouseEvent::Tag::Released,
.released =
slint::cbindgen_private::MouseEvent::Released_Body {
.position = { x, y },
.button = button,
}
};
};
switch (uMsg) {
case WM_LBUTTONUP:
case WM_MBUTTONUP:
case WM_RBUTTONUP:
return makeReleaseEvent(uMsg);
case WM_LBUTTONDOWN:
case WM_MBUTTONDOWN:
case WM_RBUTTONDOWN:
return makePressEvent(uMsg);
case WM_MOUSEMOVE:
return slint::cbindgen_private::MouseEvent {
.tag = slint::cbindgen_private::MouseEvent::Tag::Moved,
.moved =
slint::cbindgen_private::MouseEvent::Moved_Body {
.position = { x, y },
}
};
default:
break;
}
return std::nullopt;
}
void mouse_event(UINT uMsg, LPARAM lParam)
{
if (auto event = mouseEventForMessage(uMsg, lParam)) {
dispatch_pointer_event(*event);
using slint::LogicalPosition;
using slint::PointerEventButton;
float x = float(LOWORD(lParam));
float y = float(HIWORD(lParam));
switch (uMsg) {
case WM_LBUTTONUP:
window().dispatch_pointer_release_event(LogicalPosition({ x, y }),
PointerEventButton::Left);
break;
case WM_MBUTTONUP:
window().dispatch_pointer_release_event(LogicalPosition({ x, y }),
PointerEventButton::Middle);
break;
case WM_RBUTTONUP:
window().dispatch_pointer_release_event(LogicalPosition({ x, y }),
PointerEventButton::Right);
break;
case WM_LBUTTONDOWN:
window().dispatch_pointer_press_event(LogicalPosition({ x, y }),
PointerEventButton::Left);
break;
case WM_MBUTTONDOWN:
window().dispatch_pointer_press_event(LogicalPosition({ x, y }),
PointerEventButton::Middle);
break;
case WM_RBUTTONDOWN:
window().dispatch_pointer_press_event(LogicalPosition({ x, y }),
PointerEventButton::Right);
break;
case WM_MOUSEMOVE:
window().dispatch_pointer_move_event(LogicalPosition({ x, y }));
break;
default:
break;
}
}

View file

@ -11,17 +11,17 @@
namespace slint_platform = slint::experimental::platform;
slint::cbindgen_private::PointerEventButton convert_button(Qt::MouseButtons b)
slint::PointerEventButton convert_button(Qt::MouseButtons b)
{
switch (b) {
case Qt::LeftButton:
return slint::cbindgen_private::PointerEventButton::Left;
return slint::PointerEventButton::Left;
case Qt::RightButton:
return slint::cbindgen_private::PointerEventButton::Right;
return slint::PointerEventButton::Right;
case Qt::MiddleButton:
return slint::cbindgen_private::PointerEventButton::Middle;
return slint::PointerEventButton::Middle;
default:
return slint::cbindgen_private::PointerEventButton::Other;
return slint::PointerEventButton::Other;
}
}
@ -134,29 +134,22 @@ public:
void mousePressEvent(QMouseEvent *event) override
{
slint_platform::update_timers_and_animations();
dispatch_pointer_event(slint::cbindgen_private::MouseEvent {
.tag = slint::cbindgen_private::MouseEvent::Tag::Pressed,
.pressed = slint::cbindgen_private::MouseEvent::Pressed_Body {
.position = { float(event->pos().x()), float(event->pos().y()) },
.button = convert_button(event->button()) } });
window().dispatch_pointer_press_event(
slint::LogicalPosition({ float(event->pos().x()), float(event->pos().y()) }),
convert_button(event->button()));
}
void mouseReleaseEvent(QMouseEvent *event) override
{
slint_platform::update_timers_and_animations();
dispatch_pointer_event(slint::cbindgen_private::MouseEvent {
.tag = slint::cbindgen_private::MouseEvent::Tag::Released,
.released = slint::cbindgen_private::MouseEvent::Released_Body {
.position = { float(event->pos().x()), float(event->pos().y()) },
.button = convert_button(event->button()) } });
window().dispatch_pointer_release_event(
slint::LogicalPosition({ float(event->pos().x()), float(event->pos().y()) }),
convert_button(event->button()));
}
void mouseMoveEvent(QMouseEvent *event) override
{
slint_platform::update_timers_and_animations();
dispatch_pointer_event(slint::cbindgen_private::MouseEvent {
.tag = slint::cbindgen_private::MouseEvent::Tag::Moved,
.moved = slint::cbindgen_private::MouseEvent::Moved_Body {
.position = { float(event->pos().x()), float(event->pos().y()) },
} });
window().dispatch_pointer_move_event(
slint::LogicalPosition({ float(event->pos().x()), float(event->pos().y()) }));
}
};