@@ -20,7 +20,8 @@ pub struct CommitRequest {
2020/// Shared queue of fields asking to be committed. Field event listeners push
2121/// here; the panel drains it each tick.
2222pub type ChangeQueue = Rc < RefCell < Vec < CommitRequest > > > ;
23- /// Shared queue of pointer interactions (mousedown/mouseup) for drag support.
23+ /// Shared queue of field activation, numeric-gesture starts, and presentation
24+ /// updates.
2425pub type InteractionQueue = Rc < RefCell < Vec < InteractionEvent > > > ;
2526
2627pub ( crate ) fn new_change_queue ( ) -> ChangeQueue {
@@ -32,28 +33,14 @@ pub(crate) fn new_interaction_queue() -> InteractionQueue {
3233
3334#[ derive( Debug , Clone ) ]
3435pub enum InteractionEvent {
35- PointerDown {
36- field : String ,
37- /// Engine mouse coordinates, when the RmlUi event provided them.
38- /// Generic pointer users do not need an anchor; numeric drags do.
39- anchor : Option < ( i32 , i32 ) > ,
40- } ,
41- PointerUp {
42- field : String ,
43- } ,
44- /// RmlUi's drag, which captures the pointer: `DragEnd` arrives wherever the
45- /// button comes up, including outside the panel.
46- DragStart {
36+ /// A non-numeric field was activated. Ordinary controls intentionally use
37+ /// RmlUi's normal click event; only numeric drag completion bypasses hit
38+ /// testing.
39+ Click {
4740 field : String ,
4841 } ,
49- DragEnd {
50- field : String ,
51- } ,
52- /// Exact horizontal movement from one RmlUi drag event. RmlUi emits this
53- /// before the pointer is put back at its drag anchor.
54- DragMove {
42+ PointerDown {
5543 field : String ,
56- dx : f32 ,
5744 } ,
5845 /// A numeric field asks the panel-owned presentation surface to follow its
5946 /// drag. The field describes values; the surface owns all RmlUi geometry.
@@ -182,70 +169,44 @@ pub(crate) fn on_enter(
182169 Ok ( ( ) )
183170}
184171
185- /// Listen for the events a field drag is made of.
186- ///
187- /// The drag is bracketed by RmlUi's own `dragstart`/`dragend`, not by the
188- /// engine's mouse callbacks. The engine hands mouse input to its RmlUi contexts
189- /// *before* its event clients, and RmlUi consumes a press over the panel -- so
190- /// the plugin's `mouse_press` is never called for a click on a field, never
191- /// becomes the engine's mouse owner, and never receives `mouse_release`. A drag
192- /// released outside the panel could not be ended at all.
193- ///
194- /// RmlUi captures the pointer for a drag, so `dragend` arrives wherever the
195- /// button comes up, on or off the element. That is the signal to use. (The
196- /// element must opt in with `drag: drag` in RCSS.)
172+ /// Register the ordinary activation of a non-numeric field.
197173///
198- /// `mousedown`/`mouseup` still bracket a *click*, which is what opens the inline
199- /// editor when the pointer never moved far enough to become a drag.
174+ /// The generic field helper only needs a completed click. Numeric fields use
175+ /// [`on_numeric_pointer`], where the engine owns relative pointer capture and
176+ /// the panel decides whether the gesture became a drag.
200177pub ( crate ) fn on_pointer (
201178 interface : & NativeInterfaceRef ,
202179 element : u64 ,
203180 name : String ,
204181 interactions : & InteractionQueue ,
205182) -> Result < ( ) , Error > {
206- for ( event, make) in [
207- (
208- "mousedown" ,
209- ( |field| InteractionEvent :: PointerDown {
210- field,
211- anchor : None ,
212- } ) as fn ( String ) -> InteractionEvent ,
213- ) ,
214- ( "mouseup" , |field| InteractionEvent :: PointerUp { field } ) ,
215- ( "dragstart" , |field| InteractionEvent :: DragStart { field } ) ,
216- ( "dragend" , |field| InteractionEvent :: DragEnd { field } ) ,
217- ] {
218- let queue = interactions. clone ( ) ;
219- let field = name. clone ( ) ;
220- interface
221- . rml_ui ( )
222- . element_add_event_listener ( element, event, false , move || {
223- queue. borrow_mut ( ) . push ( make ( field. clone ( ) ) ) ;
224- } ) ?;
225- }
183+ let queue = interactions. clone ( ) ;
184+ interface
185+ . rml_ui ( )
186+ . element_add_event_listener ( element, "click" , false , move || {
187+ queue. borrow_mut ( ) . push ( InteractionEvent :: Click {
188+ field : name. clone ( ) ,
189+ } ) ;
190+ } ) ?;
226191 Ok ( ( ) )
227192}
228193
229- /// Register numeric drag events with RmlUi's per-motion coordinates .
194+ /// Register the boundaries of an application-owned numeric gesture .
230195///
231- /// RmlUi captures a numeric field's drag before SBC receives normal mouse
232- /// callbacks. Polling the engine cursor later made a small physical move look
233- /// large when the original click landed away from the field's logical value.
234- /// Instead, this mirrors Chili: consume the current RmlUi `drag` movement and
235- /// immediately put the pointer back where the press began.
196+ /// RmlUi only tells us where the press happened. The engine then captures raw
197+ /// relative motion and re-pins the physical cursor; [`PanelInput`] consumes its
198+ /// typed lifecycle and deltas on update. RmlUi does not participate in ending
199+ /// this gesture, so neither release nor cancellation depends on hit testing.
236200pub ( crate ) fn on_numeric_pointer (
237201 interface : & NativeInterfaceRef ,
238202 context : u64 ,
239203 element : u64 ,
240204 name : String ,
241205 interactions : & InteractionQueue ,
242206) -> Result < ( ) , Error > {
243- let anchor = Rc :: new ( RefCell :: new ( None :: < ( i32 , i32 ) > ) ) ;
244-
245207 {
246208 let queue = interactions. clone ( ) ;
247209 let field = name. clone ( ) ;
248- let anchor = anchor. clone ( ) ;
249210 let iface = * interface;
250211 interface
251212 . rml_ui ( )
@@ -256,91 +217,11 @@ pub(crate) fn on_numeric_pointer(
256217 let Some ( ( x, y) ) = current_rml_mouse_position ( & iface) else {
257218 return ;
258219 } ;
259- let Some ( anchor_position) = engine_mouse_position ( & iface, x, y) else {
260- return ;
261- } ;
262- * anchor. borrow_mut ( ) = Some ( anchor_position) ;
263220 let _ = iface
264221 . rml_ui ( )
265222 . context_set_pointer_capture ( context, x, y, true ) ;
266223 queue. borrow_mut ( ) . push ( InteractionEvent :: PointerDown {
267224 field : field. clone ( ) ,
268- anchor : Some ( anchor_position) ,
269- } ) ;
270- } ) ?;
271- }
272- {
273- let queue = interactions. clone ( ) ;
274- let field = name. clone ( ) ;
275- let iface = * interface;
276- interface
277- . rml_ui ( )
278- . element_add_event_listener ( element, "mouseup" , false , move || {
279- if current_rml_mouse_button ( & iface) != Some ( 0 ) {
280- return ;
281- }
282- let _ = iface
283- . rml_ui ( )
284- . context_set_pointer_capture ( context, 0 , 0 , false ) ;
285- queue. borrow_mut ( ) . push ( InteractionEvent :: PointerUp {
286- field : field. clone ( ) ,
287- } ) ;
288- } ) ?;
289- }
290- {
291- let queue = interactions. clone ( ) ;
292- let field = name. clone ( ) ;
293- interface
294- . rml_ui ( )
295- . element_add_event_listener ( element, "dragstart" , false , move || {
296- // RmlUi dispatches `dragstart` immediately before the first
297- // `drag`. Do not warp here: it changes the context position
298- // before that first `drag` can read its movement. The next
299- // listener consumes and pins this same physical motion.
300- queue. borrow_mut ( ) . push ( InteractionEvent :: DragStart {
301- field : field. clone ( ) ,
302- } ) ;
303- } ) ?;
304- }
305- {
306- let queue = interactions. clone ( ) ;
307- let field = name. clone ( ) ;
308- let anchor = anchor. clone ( ) ;
309- let iface = * interface;
310- interface
311- . rml_ui ( )
312- . element_add_event_listener ( element, "drag" , false , move || {
313- let Some ( ( mouse_x, _) ) = current_rml_mouse_position ( & iface) else {
314- return ;
315- } ;
316- let Some ( ( anchor_x, anchor_y) ) = * anchor. borrow ( ) else {
317- return ;
318- } ;
319- let dx = ( mouse_x - anchor_x) as f32 ;
320- if dx != 0.0 {
321- queue. borrow_mut ( ) . push ( InteractionEvent :: DragMove {
322- field : field. clone ( ) ,
323- dx,
324- } ) ;
325- // The backend's synthetic anchor move fires `drag` once
326- // more with zero movement. It has already restored both
327- // pointer positions, so avoid a redundant OS cursor warp.
328- let _ = iface. unsynced_ctrl ( ) . warp_mouse ( anchor_x, anchor_y) ;
329- }
330- } ) ?;
331- }
332- {
333- let queue = interactions. clone ( ) ;
334- let field = name;
335- let iface = * interface;
336- interface
337- . rml_ui ( )
338- . element_add_event_listener ( element, "dragend" , false , move || {
339- let _ = iface
340- . rml_ui ( )
341- . context_set_pointer_capture ( context, 0 , 0 , false ) ;
342- queue. borrow_mut ( ) . push ( InteractionEvent :: DragEnd {
343- field : field. clone ( ) ,
344225 } ) ;
345226 } ) ?;
346227 }
@@ -446,9 +327,6 @@ pub trait Field {
446327 fn end_edit ( & mut self , _interface : & NativeInterfaceRef ) { }
447328}
448329
449- /// RmlUi event positions use top-origin screen coordinates; engine mouse and
450- /// `warp_mouse` use the bottom-origin coordinates exposed by Spring's native
451- /// input API.
452330fn current_rml_mouse_position ( interface : & NativeInterfaceRef ) -> Option < ( i32 , i32 ) > {
453331 let rml = interface. rml_ui ( ) ;
454332 let ( event, ..) = rml. event_get_current ( ) . ok ( ) ?;
@@ -467,10 +345,3 @@ fn current_rml_mouse_button(interface: &NativeInterfaceRef) -> Option<i32> {
467345 let ( button, found) = rml. event_get_parameter_int ( event, "button" ) . ok ( ) ?;
468346 found. then_some ( button)
469347}
470-
471- /// Convert an RmlUi top-origin event position for Spring's bottom-origin mouse
472- /// API. The relative Rml capture itself retains top-origin coordinates.
473- fn engine_mouse_position ( interface : & NativeInterfaceRef , x : i32 , y : i32 ) -> Option < ( i32 , i32 ) > {
474- let geometry = interface. display ( ) . get_view_geometry ( ) . ok ( ) ?;
475- Some ( ( x, geometry. viewSizeY - y - 1 ) )
476- }
0 commit comments