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
205 changes: 205 additions & 0 deletions examples/touch_test.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,205 @@
<!DOCTYPE html>
<html>
<head>
<title>Touch Events Test</title>
<style>
body {
margin: 0;
padding: 20px;
font-family: Arial, sans-serif;
background: #f0f0f0;
}
.touch-area {
width: 400px;
height: 300px;
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
border-radius: 10px;
margin: 20px auto;
display: flex;
align-items: center;
justify-content: center;
color: white;
font-size: 24px;
font-weight: bold;
text-shadow: 0 2px 4px rgba(0,0,0,0.3);
box-shadow: 0 8px 16px rgba(0,0,0,0.1);
position: relative;
overflow: hidden;
}
.touch-info {
position: absolute;
top: 10px;
left: 10px;
background: rgba(0,0,0,0.7);
color: white;
padding: 10px;
border-radius: 5px;
font-size: 14px;
font-family: monospace;
white-space: pre-line;
}
.touch-point {
position: absolute;
width: 20px;
height: 20px;
background: rgba(255,255,255,0.8);
border: 2px solid white;
border-radius: 50%;
transform: translate(-50%, -50%);
pointer-events: none;
}
h1 {
text-align: center;
color: #333;
}
.log {
max-height: 200px;
overflow-y: auto;
background: #333;
color: #0f0;
font-family: monospace;
padding: 10px;
margin: 20px;
border-radius: 5px;
}
</style>
</head>
<body>
<h1>Touch Events Test</h1>
<div class="touch-area" id="touchArea">
Touch Here!
<div class="touch-info" id="touchInfo">
Touch Status: Ready
Touch Count: 0
</div>
</div>

<div class="log" id="eventLog">
Event log will appear here...
</div>

<script>
const touchArea = document.getElementById('touchArea');
const touchInfo = document.getElementById('touchInfo');
const eventLog = document.getElementById('eventLog');

let activeTouches = new Map();

function logEvent(message) {
const timestamp = new Date().toLocaleTimeString();
eventLog.textContent += `[${timestamp}] ${message}\n`;
eventLog.scrollTop = eventLog.scrollHeight;
}

function updateTouchInfo() {
const touchCount = activeTouches.size;
let infoText = `Touch Status: ${touchCount > 0 ? 'Active' : 'Ready'}\n`;
infoText += `Touch Count: ${touchCount}\n`;

if (touchCount > 0) {
infoText += `Active Touches:\n`;
activeTouches.forEach((touch, id) => {
infoText += ` ID ${id}: (${touch.x.toFixed(0)}, ${touch.y.toFixed(0)})\n`;
});
}

touchInfo.textContent = infoText;
}

function createTouchPoint(x, y, id) {
const point = document.createElement('div');
point.className = 'touch-point';
point.style.left = x + 'px';
point.style.top = y + 'px';
point.id = `touch-${id}`;
touchArea.appendChild(point);
}

function updateTouchPoint(x, y, id) {
const point = document.getElementById(`touch-${id}`);
if (point) {
point.style.left = x + 'px';
point.style.top = y + 'px';
}
}

function removeTouchPoint(id) {
const point = document.getElementById(`touch-${id}`);
if (point) {
point.remove();
}
}

touchArea.addEventListener('touchstart', function(e) {
e.preventDefault();

Array.from(e.changedTouches).forEach(touch => {
const rect = touchArea.getBoundingClientRect();
const x = touch.clientX - rect.left;
const y = touch.clientY - rect.top;

activeTouches.set(touch.identifier, { x, y });
createTouchPoint(x, y, touch.identifier);

logEvent(`TouchStart: ID ${touch.identifier} at (${x.toFixed(0)}, ${y.toFixed(0)})`);
});

updateTouchInfo();
});

touchArea.addEventListener('touchmove', function(e) {
e.preventDefault();

Array.from(e.changedTouches).forEach(touch => {
const rect = touchArea.getBoundingClientRect();
const x = touch.clientX - rect.left;
const y = touch.clientY - rect.top;

if (activeTouches.has(touch.identifier)) {
activeTouches.set(touch.identifier, { x, y });
updateTouchPoint(x, y, touch.identifier);

logEvent(`TouchMove: ID ${touch.identifier} at (${x.toFixed(0)}, ${y.toFixed(0)})`);
}
});

updateTouchInfo();
});

touchArea.addEventListener('touchend', function(e) {
e.preventDefault();

Array.from(e.changedTouches).forEach(touch => {
if (activeTouches.has(touch.identifier)) {
const touchData = activeTouches.get(touch.identifier);
activeTouches.delete(touch.identifier);
removeTouchPoint(touch.identifier);

logEvent(`TouchEnd: ID ${touch.identifier} at (${touchData.x.toFixed(0)}, ${touchData.y.toFixed(0)})`);
}
});

updateTouchInfo();
});

touchArea.addEventListener('touchcancel', function(e) {
e.preventDefault();

Array.from(e.changedTouches).forEach(touch => {
if (activeTouches.has(touch.identifier)) {
const touchData = activeTouches.get(touch.identifier);
activeTouches.delete(touch.identifier);
removeTouchPoint(touch.identifier);

logEvent(`TouchCancel: ID ${touch.identifier} at (${touchData.x.toFixed(0)}, ${touchData.y.toFixed(0)})`);
}
});

updateTouchInfo();
});

// Initial log message
logEvent('Touch event test loaded. Try touching the blue area!');
</script>
</body>
</html>
44 changes: 44 additions & 0 deletions packages/blitz-dom/src/events/driver.rs
Original file line number Diff line number Diff line change
Expand Up @@ -65,13 +65,37 @@ impl<'doc, Handler: EventHandler> EventDriver<'doc, Handler> {
UiEvent::MouseUp(_) => {
self.doc_mut().unactive_node();
}
UiEvent::TouchStart(event) => {
let dom_x = event.x + viewport_scroll.x as f32 / zoom;
let dom_y = event.y + viewport_scroll.y as f32 / zoom;
self.doc_mut().set_hover_to(dom_x, dom_y);
hover_node_id = self.doc().hover_node_id;
self.doc_mut().active_node();
self.doc_mut().set_mousedown_node_id(hover_node_id);
}
UiEvent::TouchEnd(_) => {
self.doc_mut().unactive_node();
}
UiEvent::TouchMove(event) => {
let dom_x = event.x + viewport_scroll.x as f32 / zoom;
let dom_y = event.y + viewport_scroll.y as f32 / zoom;
self.doc_mut().set_hover_to(dom_x, dom_y);
hover_node_id = self.doc().hover_node_id;
}
UiEvent::TouchCancel(_) => {
self.doc_mut().unactive_node();
}
_ => {}
};

let target = match event {
UiEvent::MouseMove(_) => hover_node_id,
UiEvent::MouseUp(_) => hover_node_id,
UiEvent::MouseDown(_) => hover_node_id,
UiEvent::TouchStart(_) => hover_node_id,
UiEvent::TouchEnd(_) => hover_node_id,
UiEvent::TouchMove(_) => hover_node_id,
UiEvent::TouchCancel(_) => hover_node_id,
UiEvent::KeyUp(_) => focussed_node_id,
UiEvent::KeyDown(_) => focussed_node_id,
UiEvent::Ime(_) => focussed_node_id,
Expand All @@ -93,6 +117,26 @@ impl<'doc, Handler: EventHandler> EventDriver<'doc, Handler> {
y: data.y + viewport_scroll.y as f32 / zoom,
..data
}),
UiEvent::TouchStart(mut data) => {
data.x += viewport_scroll.x as f32 / zoom;
data.y += viewport_scroll.y as f32 / zoom;
DomEventData::TouchStart(data)
}
UiEvent::TouchEnd(mut data) => {
data.x += viewport_scroll.x as f32 / zoom;
data.y += viewport_scroll.y as f32 / zoom;
DomEventData::TouchEnd(data)
}
UiEvent::TouchMove(mut data) => {
data.x += viewport_scroll.x as f32 / zoom;
data.y += viewport_scroll.y as f32 / zoom;
DomEventData::TouchMove(data)
}
UiEvent::TouchCancel(mut data) => {
data.x += viewport_scroll.x as f32 / zoom;
data.y += viewport_scroll.y as f32 / zoom;
DomEventData::TouchCancel(data)
}
UiEvent::KeyUp(data) => DomEventData::KeyUp(data),
UiEvent::KeyDown(data) => DomEventData::KeyDown(data),
UiEvent::Ime(data) => DomEventData::Ime(data),
Expand Down
16 changes: 16 additions & 0 deletions packages/blitz-dom/src/events/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ mod driver;
mod ime;
mod keyboard;
mod mouse;
mod touch;

use blitz_traits::events::{DomEvent, DomEventData};
pub use driver::{EventDriver, EventHandler, NoopEventHandler};
Expand Down Expand Up @@ -56,5 +57,20 @@ pub(crate) fn handle_dom_event<F: FnMut(DomEvent)>(
DomEventData::Input(_) => {
// Do nothing (no default action)
}
DomEventData::TouchStart(event) => {
touch::handle_touch_start(doc, target_node_id, event.x, event.y);
}
DomEventData::TouchEnd(event) => {
touch::handle_touch_end(doc, target_node_id, event, dispatch_event);
}
DomEventData::TouchMove(event) => {
let changed = touch::handle_touch_move(doc, target_node_id, event.x, event.y);
if changed {
doc.shell_provider.request_redraw();
}
}
DomEventData::TouchCancel(event) => {
touch::handle_touch_cancel(doc, target_node_id, event, dispatch_event);
}
}
}
67 changes: 67 additions & 0 deletions packages/blitz-dom/src/events/touch.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
use blitz_traits::events::{BlitzTouchEvent, DomEvent};
use crate::BaseDocument;
use keyboard_types::Modifiers;

/// Handle touch start events
pub(crate) fn handle_touch_start(
doc: &mut BaseDocument,
target_node_id: usize,
x: f32,
y: f32,
) {
println!("🟒 RUST: TouchStart at ({:.1}, {:.1}) on node {}", x, y, target_node_id);
// For now, just treat touch start similar to mouse down
// This can be expanded later with touch-specific functionality
crate::events::mouse::handle_mousedown(doc, target_node_id, x, y);
}

/// Handle touch end events
pub(crate) fn handle_touch_end<F: FnMut(DomEvent)>(
doc: &mut BaseDocument,
target_node_id: usize,
event: &BlitzTouchEvent,
dispatch_event: F,
) {
println!("πŸ”΄ RUST: TouchEnd at ({:.1}, {:.1}) on node {}", event.x, event.y, target_node_id);
// For now, just treat touch end similar to mouse up
// This can be expanded later with touch-specific functionality
let mouse_event = blitz_traits::events::BlitzMouseButtonEvent {
x: event.x,
y: event.y,
buttons: blitz_traits::events::MouseEventButtons::Primary,
mods: Modifiers::empty(),
button: blitz_traits::events::MouseEventButton::Main,
};
crate::events::mouse::handle_mouseup(doc, target_node_id, &mouse_event, dispatch_event);
}

/// Handle touch move events
pub(crate) fn handle_touch_move(
doc: &mut BaseDocument,
target_node_id: usize,
x: f32,
y: f32,
) -> bool {
println!("🟠 RUST: TouchMove to ({:.1}, {:.1}) on node {}", x, y, target_node_id);
// For now, just treat touch move similar to mouse move
// This can be expanded later with touch-specific functionality
crate::events::mouse::handle_mousemove(
doc,
target_node_id,
x,
y,
blitz_traits::events::MouseEventButtons::Primary,
)
}

/// Handle touch cancel events
pub(crate) fn handle_touch_cancel<F: FnMut(DomEvent)>(
doc: &mut BaseDocument,
target_node_id: usize,
event: &BlitzTouchEvent,
dispatch_event: F,
) {
println!("❌ RUST: TouchCancel at ({:.1}, {:.1}) on node {}", event.x, event.y, target_node_id);
// For now, just treat touch cancel similar to touch end
handle_touch_end(doc, target_node_id, event, dispatch_event);
}
Loading
Loading