diff --git a/frontend/src/app/main/ui/workspace/viewport/actions.cljs b/frontend/src/app/main/ui/workspace/viewport/actions.cljs index e45482fb57..b4ebddbede 100644 --- a/frontend/src/app/main/ui/workspace/viewport/actions.cljs +++ b/frontend/src/app/main/ui/workspace/viewport/actions.cljs @@ -187,6 +187,8 @@ alt? (kbd/alt? event) meta? (kbd/meta? event) hovering? (some? @hover) + native-event (unchecked-get event "nativeEvent") + off-pt (dom/get-offset-position native-event) raw-pt (dom/get-client-position event) pt (uwvv/point->viewport raw-pt)] (st/emit! (mse/->MouseEvent :click ctrl? shift? alt? meta?)) @@ -208,9 +210,7 @@ (when (and (= :text (:type hover-shape)) (features/active-feature? @st/state "text-editor-wasm/v1") wasm.wasm/context-initialized?) - (let [raw-pt (dom/get-client-position event)] - ;; FIXME - (wasm.api/text-editor-set-cursor-from-point (.-x raw-pt) (.-y raw-pt)))))) + (wasm.api/text-editor-set-cursor-from-point (.-x off-pt) (.-y off-pt))))) (when (and @z? (not @space?) @@ -381,7 +381,9 @@ (let [last-position (mf/use-var nil)] (mf/use-fn (fn [event] - (let [raw-pt (dom/get-client-position event) + (let [native-event (unchecked-get event "nativeEvent") + off-pt (dom/get-offset-position native-event) + raw-pt (dom/get-client-position event) pt (uwvv/point->viewport raw-pt) ;; We calculate the delta because Safari's MouseEvent.movementX/Y drop @@ -390,6 +392,8 @@ (gpt/subtract raw-pt @last-position) (gpt/point 0 0))] + (wasm.api/text-editor-testing-coords (.-x off-pt) (.-y off-pt)) + (rx/push! move-stream pt) (reset! last-position raw-pt) (st/emit! (mse/->PointerEvent :delta delta diff --git a/frontend/src/app/render_wasm/api.cljs b/frontend/src/app/render_wasm/api.cljs index ba10f9ac64..75714bb1bf 100644 --- a/frontend/src/app/render_wasm/api.cljs +++ b/frontend/src/app/render_wasm/api.cljs @@ -83,6 +83,7 @@ ;; Re-export public text editor functions (def text-editor-start text-editor/text-editor-start) (def text-editor-stop text-editor/text-editor-stop) +(def text-editor-testing-coords text-editor/text-editor-testing-coords) (def text-editor-set-cursor-from-point text-editor/text-editor-set-cursor-from-point) (def text-editor-is-active? text-editor/text-editor-is-active?) (def text-editor-sync-content text-editor/text-editor-sync-content) @@ -1110,7 +1111,7 @@ (defn- set-objects-async "Asynchronously process shapes in chunks, yielding to the browser between chunks. Returns a promise that resolves when all shapes are processed. - + Renders a preview only periodically during loading to show progress, then does a full tile-based render at the end." [shapes render-callback] diff --git a/frontend/src/app/render_wasm/text_editor.cljs b/frontend/src/app/render_wasm/text_editor.cljs index 882f24f890..e050cb69f9 100644 --- a/frontend/src/app/render_wasm/text_editor.cljs +++ b/frontend/src/app/render_wasm/text_editor.cljs @@ -22,6 +22,11 @@ (aget buffer 2) (aget buffer 3))))) +(defn text-editor-testing-coords + [x y] + (when wasm/context-initialized? + (h/call wasm/internal-module "_text_editor_testing_coords" x y))) + (defn text-editor-set-cursor-from-point [x y] (when wasm/context-initialized? diff --git a/frontend/text-editor/src/editor/content/dom/Color.js b/frontend/text-editor/src/editor/content/dom/Color.js index ba798dd67a..69f4805495 100644 --- a/frontend/text-editor/src/editor/content/dom/Color.js +++ b/frontend/text-editor/src/editor/content/dom/Color.js @@ -76,3 +76,4 @@ export function getFills(fillStyle) { const [color, opacity] = getColor(fillStyle); return `[["^ ","~:fill-color","${color}","~:fill-opacity",${opacity}]]`; } + diff --git a/render-wasm/src/render/text_editor.rs b/render-wasm/src/render/text_editor.rs index 1a3839bccf..5def9e4596 100644 --- a/render-wasm/src/render/text_editor.rs +++ b/render-wasm/src/render/text_editor.rs @@ -41,7 +41,11 @@ fn render_cursor(canvas: &Canvas, editor_state: &TextEditorState, text_content: paint.set_color(editor_state.theme.cursor_color); paint.set_anti_alias(true); + let shape_matrix = shape.get_matrix(); + canvas.save(); + canvas.concat(&shape_matrix); canvas.draw_rect(rect, &paint); + canvas.restore(); } fn render_selection( @@ -95,8 +99,6 @@ fn calculate_cursor_rect( return None; } - let selrect = shape.selrect(); - let mut y_offset = vertical_align_offset(shape, &layout_paragraphs); for (idx, laid_out_para) in layout_paragraphs.iter().enumerate() { if idx == cursor.paragraph { @@ -153,8 +155,8 @@ fn calculate_cursor_rect( }; return Some(Rect::from_xywh( - selrect.x() + cursor_x, - selrect.y() + y_offset, + cursor_x, + y_offset, editor_state.theme.cursor_width, cursor_height, )); diff --git a/render-wasm/src/wasm/text_editor.rs b/render-wasm/src/wasm/text_editor.rs index b437ec7c63..79063896b1 100644 --- a/render-wasm/src/wasm/text_editor.rs +++ b/render-wasm/src/wasm/text_editor.rs @@ -1,5 +1,3 @@ -use std::io::Cursor; - use crate::math::{Matrix, Point, Rect}; use crate::mem; use crate::shapes::{Paragraph, Shape, TextContent, Type, VerticalAlign}; @@ -119,6 +117,37 @@ pub extern "C" fn text_editor_poll_event() -> u8 { // SELECTION MANAGEMENT // ============================================================================ +fn get_shape_relative_point(point: Point, view_matrix: Matrix, shape_matrix: Matrix) -> Option { + let Some(inv_view_matrix) = view_matrix.invert() else { + return None; + }; + let Some(inv_shape_matrix) = shape_matrix.invert() else { + return None; + }; + let transform_matrix: Matrix = Matrix::concat(&inv_shape_matrix, &inv_view_matrix); + let shape_relative_point = transform_matrix.map_point(point); + Some(shape_relative_point) +} + +#[no_mangle] +pub extern "C" fn text_editor_testing_coords(x: f32, y: f32) { + with_state_mut!(state, { + let view_matrix: Matrix = state.render_state.viewbox.get_matrix(); + let point = Point::new(x, y); + let Some(shape_id) = state.text_editor_state.active_shape_id else { + return; + }; + let Some(shape) = state.shapes.get(&shape_id) else { + return; + }; + let shape_matrix = shape.get_matrix(); + let Some(shape_rel_point) = get_shape_relative_point(point, view_matrix, shape_matrix) else { + return; + }; + // println!("testing_coords::shape_rel_point {:?}", shape_rel_point); + }); +} + #[no_mangle] pub extern "C" fn text_editor_set_cursor_from_point(x: f32, y: f32) { with_state_mut!(state, { @@ -126,44 +155,26 @@ pub extern "C" fn text_editor_set_cursor_from_point(x: f32, y: f32) { return; } + let view_matrix: Matrix = state.render_state.viewbox.get_matrix(); + let point = Point::new(x, y); let Some(shape_id) = state.text_editor_state.active_shape_id else { return; }; - - let (shape_matrix, view_matrix, selrect, vertical_align) = { - let Some(shape) = state.shapes.get(&shape_id) else { - return; - }; - ( - shape.get_concatenated_matrix(&state.shapes), - state.render_state.viewbox.get_matrix(), - shape.selrect(), - shape.vertical_align(), - ) + let Some(shape) = state.shapes.get(&shape_id) else { + return; }; - - let Some(inv_view_matrix) = view_matrix.invert() else { + let shape_matrix = shape.get_matrix(); + let Some(shape_rel_point) = get_shape_relative_point(point, view_matrix, shape_matrix) else { return; }; - let Some(inv_shape_matrix) = shape_matrix.invert() else { + let Type::Text(text_content) = &shape.shape_type else { return; }; - let mut matrix = Matrix::new_identity(); - matrix.post_concat(&inv_view_matrix); - matrix.post_concat(&inv_shape_matrix); - - let mapped_point = matrix.map_point(Point::new(x, y)); - - let Some(shape) = state.shapes.get_mut(&shape_id) else { - return; - }; - - let Type::Text(text_content) = &mut shape.shape_type else { - return; - }; + println!("cursor_from_point::shape_rel_point {:?}", shape_rel_point); + /* if text_content.layout.paragraphs.is_empty() && !text_content.paragraphs().is_empty() { let bounds = text_content.bounds; text_content.update_layout(bounds); @@ -171,7 +182,7 @@ pub extern "C" fn text_editor_set_cursor_from_point(x: f32, y: f32) { // Calculate vertical alignment offset (same as in render/text_editor.rs) let layout_paragraphs: Vec<_> = text_content.layout.paragraphs.iter().flatten().collect(); - let total_height: f32 = layout_paragraphs.iter().map(|p| p.height()).sum(); + let _total_height: f32 = layout_paragraphs.iter().map(|p| p.height()).sum(); let vertical_offset = match vertical_align { crate::shapes::VerticalAlign::Center => (selrect.height() - total_height) / 2.0, crate::shapes::VerticalAlign::Bottom => selrect.height() - total_height, @@ -184,8 +195,9 @@ pub extern "C" fn text_editor_set_cursor_from_point(x: f32, y: f32) { mapped_point.x - selrect.x(), mapped_point.y - selrect.y() - vertical_offset, ); - - if let Some(position) = text_content.get_caret_position_at(&adjusted_point) { + */ + if let Some(position) = text_content.get_caret_position_at(&shape_rel_point) { + println!("cursor_from_point::position {:?}", position); state.text_editor_state.set_caret_from_position(position); } }); @@ -218,13 +230,15 @@ pub extern "C" fn text_editor_extend_selection_to_point(x: f32, y: f32) { return; }; + /* let Some(inv_shape_matrix) = shape_matrix.invert() else { return; }; + */ let mut matrix = Matrix::new_identity(); matrix.post_concat(&inv_view_matrix); - matrix.post_concat(&inv_shape_matrix); + matrix.post_concat(&shape_matrix); let mapped_point = matrix.map_point(Point::new(x, y)); @@ -243,7 +257,8 @@ pub extern "C" fn text_editor_extend_selection_to_point(x: f32, y: f32) { // Calculate vertical alignment offset (same as in render/text_editor.rs) let layout_paragraphs: Vec<_> = text_content.layout.paragraphs.iter().flatten().collect(); - let total_height: f32 = layout_paragraphs.iter().map(|p| p.height()).sum(); + let _total_height: f32 = layout_paragraphs.iter().map(|p| p.height()).sum(); + /* let vertical_offset = match vertical_align { crate::shapes::VerticalAlign::Center => (selrect.height() - total_height) / 2.0, crate::shapes::VerticalAlign::Bottom => selrect.height() - total_height, @@ -255,8 +270,9 @@ pub extern "C" fn text_editor_extend_selection_to_point(x: f32, y: f32) { mapped_point.x - selrect.x(), mapped_point.y - selrect.y() - vertical_offset, ); + */ - if let Some(position) = text_content.get_caret_position_at(&adjusted_point) { + if let Some(position) = text_content.get_caret_position_at(&mapped_point) { state .text_editor_state .extend_selection_from_position(position);