🎉 Feat apply styles to selection

This commit is contained in:
Aitor Moreno 2026-03-12 14:55:28 +01:00
parent 0f389fe3ad
commit 12382cfbb9
8 changed files with 133 additions and 89 deletions

View File

@ -788,14 +788,15 @@
(when (features/active-feature? state "render-wasm/v1") (when (features/active-feature? state "render-wasm/v1")
(rx/concat (rx/concat
;; Apply style to selected spans and sync content ;; Apply style to selected spans and sync content
(when (wasm.api/text-editor-is-active?) (let [has-selection? (wasm.api/text-editor-has-selection?)]
(let [span-attrs (select-keys attrs txt/text-node-attrs)] (when has-selection?
(when (not (empty? span-attrs)) (let [span-attrs (select-keys attrs txt/text-node-attrs)]
(let [result (wasm.api/apply-style-to-selection span-attrs)] (when (not (empty? span-attrs))
(when result (let [result (wasm.api/apply-style-to-selection span-attrs)]
(rx/of (v2-update-text-shape-content (when result
(:shape-id result) (:content result) (rx/of (v2-update-text-shape-content
:update-name? true))))))) (:shape-id result) (:content result)
:update-name? true))))))))
;; Resize (with delay for font-id changes) ;; Resize (with delay for font-id changes)
(cond->> (rx/of (dwwt/resize-wasm-text id)) (cond->> (rx/of (dwwt/resize-wasm-text id))
(contains? attrs :font-id) (contains? attrs :font-id)

View File

@ -120,7 +120,7 @@
on-copy on-copy
(mf/use-fn (mf/use-fn
(fn [^js event] (fn [^js event]
(when (text-editor/text-editor-is-active?) (when (text-editor/text-editor-has-focus?)
(dom/prevent-default event) (dom/prevent-default event)
(when (text-editor/text-editor-get-selection) (when (text-editor/text-editor-get-selection)
(let [text (text-editor/text-editor-export-selection)] (let [text (text-editor/text-editor-export-selection)]
@ -129,7 +129,7 @@
on-cut on-cut
(mf/use-fn (mf/use-fn
(fn [^js event] (fn [^js event]
(when (text-editor/text-editor-is-active?) (when (text-editor/text-editor-has-focus?)
(dom/prevent-default event) (dom/prevent-default event)
(when (text-editor/text-editor-get-selection) (when (text-editor/text-editor-get-selection)
(let [text (text-editor/text-editor-export-selection)] (let [text (text-editor/text-editor-export-selection)]
@ -144,7 +144,7 @@
on-key-down on-key-down
(mf/use-fn (mf/use-fn
(fn [^js event] (fn [^js event]
(when (and (text-editor/text-editor-is-active?) (when (and (text-editor/text-editor-has-focus?)
(not @composing?)) (not @composing?))
(let [key (.-key event) (let [key (.-key event)
ctrl? (or (.-ctrlKey event) (.-metaKey event)) ctrl? (or (.-ctrlKey event) (.-metaKey event))
@ -283,13 +283,13 @@
on-focus on-focus
(mf/use-fn (mf/use-fn
(fn [^js _event] (fn [^js _event]
(wasm.api/text-editor-start shape-id))) (wasm.api/text-editor-focus shape-id)))
on-blur on-blur
(mf/use-fn (mf/use-fn
(fn [^js _event] (fn [^js _event]
(sync-wasm-text-editor-content! {:finalize? true}) (sync-wasm-text-editor-content! {:finalize? true})
(wasm.api/text-editor-stop))) (wasm.api/text-editor-blur)))
style #js {:pointerEvents "all" style #js {:pointerEvents "all"
"--editor-container-width" (dm/str width "px") "--editor-container-width" (dm/str width "px")
@ -312,11 +312,15 @@
(fn [] (fn []
(let [timeout-id (atom nil) (let [timeout-id (atom nil)
schedule-blink (fn schedule-blink [] schedule-blink (fn schedule-blink []
(when (text-editor/text-editor-is-active?) (when (text-editor/text-editor-has-focus?)
(wasm.api/request-render "cursor-blink")) (wasm.api/request-render "cursor-blink"))
(reset! timeout-id (js/setTimeout schedule-blink caret-blink-interval-ms)))] (reset! timeout-id (js/setTimeout schedule-blink caret-blink-interval-ms)))]
(schedule-blink) (schedule-blink)
(fn [] (fn []
;; ESTO ES JUSTO LO QUE NO QUIERO, NO QUIERO QUE SE HAGA
;; DISPOSE CUANDO SE DESMONTA EL COMPONENTE.
#_(when (text-editor/text-editor-dispose)
(wasm.api/request-render "text-editor-dispose"))
(when @timeout-id (when @timeout-id
(js/clearTimeout @timeout-id)))))) (js/clearTimeout @timeout-id))))))

View File

@ -292,7 +292,7 @@
(when left-click? (when left-click?
(st/emit! (mse/->MouseEvent :up ctrl? shift? alt? meta?)) (st/emit! (mse/->MouseEvent :up ctrl? shift? alt? meta?))
(when (wasm.api/text-editor-is-active?) (when (wasm.api/text-editor-has-focus?)
(wasm.api/text-editor-pointer-up (.-x off-pt) (.-y off-pt)))) (wasm.api/text-editor-pointer-up (.-x off-pt) (.-y off-pt))))
(when middle-click? (when middle-click?

View File

@ -92,14 +92,15 @@
(def clear-canvas-pixels webgl/clear-canvas-pixels) (def clear-canvas-pixels webgl/clear-canvas-pixels)
;; Re-export public text editor functions ;; Re-export public text editor functions
(def text-editor-start text-editor/text-editor-start) (def text-editor-focus text-editor/text-editor-focus)
(def text-editor-stop text-editor/text-editor-stop) (def text-editor-blur text-editor/text-editor-blur)
(def text-editor-set-cursor-from-offset text-editor/text-editor-set-cursor-from-offset) (def text-editor-set-cursor-from-offset text-editor/text-editor-set-cursor-from-offset)
(def text-editor-set-cursor-from-point text-editor/text-editor-set-cursor-from-point) (def text-editor-set-cursor-from-point text-editor/text-editor-set-cursor-from-point)
(def text-editor-pointer-down text-editor/text-editor-pointer-down) (def text-editor-pointer-down text-editor/text-editor-pointer-down)
(def text-editor-pointer-move text-editor/text-editor-pointer-move) (def text-editor-pointer-move text-editor/text-editor-pointer-move)
(def text-editor-pointer-up text-editor/text-editor-pointer-up) (def text-editor-pointer-up text-editor/text-editor-pointer-up)
(def text-editor-is-active? text-editor/text-editor-is-active?) (def text-editor-has-focus? text-editor/text-editor-has-focus?)
(def text-editor-has-selection? text-editor/text-editor-has-selection?)
(def text-editor-select-all text-editor/text-editor-select-all) (def text-editor-select-all text-editor/text-editor-select-all)
(def text-editor-select-word-boundary text-editor/text-editor-select-word-boundary) (def text-editor-select-word-boundary text-editor/text-editor-select-word-boundary)
(def text-editor-sync-content text-editor/text-editor-sync-content) (def text-editor-sync-content text-editor/text-editor-sync-content)
@ -136,6 +137,13 @@
:fill "none"} :fill "none"}
[:& shape-wrapper {:shape shape}]])) [:& shape-wrapper {:shape shape}]]))
(defn is-text-editor-wasm-enabled
[state]
(let [runtime-features (get state :features-runtime)
enabled-features (get state :features)]
(or (contains? runtime-features "text-editor-wasm/v1")
(contains? enabled-features "text-editor-wasm/v1"))))
(defn get-static-markup (defn get-static-markup
[shape] [shape]
(-> (->
@ -155,17 +163,17 @@
;; Update text editor blink (so cursor toggles) using the same timestamp ;; Update text editor blink (so cursor toggles) using the same timestamp
(try (try
(when wasm/context-initialized? (when wasm/context-initialized?
(text-editor/text-editor-update-blink timestamp)
;; Render text editor overlay on top of main canvas (only if feature enabled) ;; Render text editor overlay on top of main canvas (only if feature enabled)
;; Determine if text-editor-wasm feature is active without requiring ;; Determine if text-editor-wasm feature is active without requiring
;; app.main.features to avoid circular dependency: check runtime and ;; app.main.features to avoid circular dependency: check runtime and
;; persisted feature sets in the store state. ;; persisted feature sets in the store state.
(when (text-editor-wasm?) (when (is-text-editor-wasm-enabled @st/state)
(text-editor/text-editor-render-overlay)) (text-editor/text-editor-update-blink timestamp)
;; Poll for editor events; if any event occurs, trigger a re-render (text-editor/text-editor-render-overlay)
(let [ev (text-editor/text-editor-poll-event)] ;; Poll for editor events; if any event occurs, trigger a re-render
(when (and ev (not= ev 0)) (let [ev (text-editor/text-editor-poll-event)]
(request-render "text-editor-event")))) (when (and ev (not= ev 0))
(request-render "text-editor-event")))))
(catch :default e (catch :default e
(js/console.error "text-editor overlay/update failed:" e))) (js/console.error "text-editor overlay/update failed:" e)))

View File

@ -12,16 +12,16 @@
[app.render-wasm.mem :as mem] [app.render-wasm.mem :as mem]
[app.render-wasm.wasm :as wasm])) [app.render-wasm.wasm :as wasm]))
(defn text-editor-start (defn text-editor-focus
[id] [id]
(when wasm/context-initialized? (when wasm/context-initialized?
(let [buffer (uuid/get-u32 id)] (let [buffer (uuid/get-u32 id)]
(when-not (h/call wasm/internal-module "_text_editor_start" (when-not (h/call wasm/internal-module "_text_editor_focus"
(aget buffer 0) (aget buffer 0)
(aget buffer 1) (aget buffer 1)
(aget buffer 2) (aget buffer 2)
(aget buffer 3)) (aget buffer 3))
(throw (js/Error. "TextEditor initialization failed")))))) (throw (js/Error. "TextEditor focus failed"))))))
(defn text-editor-set-cursor-from-offset (defn text-editor-set-cursor-from-offset
"Sets caret position from shape relative coordinates" "Sets caret position from shape relative coordinates"
@ -142,19 +142,29 @@
(when wasm/context-initialized? (when wasm/context-initialized?
(h/call wasm/internal-module "_text_editor_select_word_boundary" x y))) (h/call wasm/internal-module "_text_editor_select_word_boundary" x y)))
(defn text-editor-stop (defn text-editor-blur
[] []
(when wasm/context-initialized? (when wasm/context-initialized?
(when-not (h/call wasm/internal-module "_text_editor_stop") (when-not (h/call wasm/internal-module "_text_editor_blur")
(throw (js/Error. "TextEditor finalization failed"))))) (throw (js/Error. "TextEditor blur failed")))))
(defn text-editor-is-active? (defn text-editor-dispose
[]
(when wasm/context-initialized?
(h/call wasm/internal-module "_text_editor_dispose")))
(defn text-editor-has-focus?
([id] ([id]
(when wasm/context-initialized? (when wasm/context-initialized?
(not (zero? (h/call wasm/internal-module "_text_editor_is_active_with_id" id))))) (not (zero? (h/call wasm/internal-module "_text_editor_has_focus_with_id" id)))))
([] ([]
(when wasm/context-initialized? (when wasm/context-initialized?
(not (zero? (h/call wasm/internal-module "_text_editor_is_active")))))) (not (zero? (h/call wasm/internal-module "_text_editor_has_focus"))))))
(defn text-editor-has-selection?
([]
(when wasm/context-initialized?
(not (zero? (h/call wasm/internal-module "_text_editor_has_selection"))))))
(defn text-editor-export-content (defn text-editor-export-content
[] []
@ -198,18 +208,20 @@
(defn text-editor-get-selection (defn text-editor-get-selection
[] []
(when wasm/context-initialized? (when wasm/context-initialized?
(let [byte-offset (mem/alloc 16) (let [byte-offset (mem/alloc 16)
u32-offset (mem/->offset-32 byte-offset) u32-offset (mem/->offset-32 byte-offset)
heap (mem/get-heap-u32) heap (mem/get-heap-u32)
active? (h/call wasm/internal-module "_text_editor_get_selection" byte-offset)] has-selection? (h/call wasm/internal-module "_text_editor_get_selection" byte-offset)]
(try (if has-selection?
(when (= active? 1) (let [result {:anchor-para (aget heap u32-offset)
{:anchor-para (aget heap u32-offset) :anchor-offset (aget heap (+ u32-offset 1))
:anchor-offset (aget heap (+ u32-offset 1)) :focus-para (aget heap (+ u32-offset 2))
:focus-para (aget heap (+ u32-offset 2)) :focus-offset (aget heap (+ u32-offset 3))}]
:focus-offset (aget heap (+ u32-offset 3))}) (mem/free)
(finally result)
(mem/free)))))) (do
(mem/free)
nil)))))
;; This is used as a intermediate cache between Clojure global state and WASM state. ;; This is used as a intermediate cache between Clojure global state and WASM state.
(def ^:private shape-text-contents (atom {})) (def ^:private shape-text-contents (atom {}))
@ -260,7 +272,7 @@
shape-id and the fully merged content map ready for shape-id and the fully merged content map ready for
v2-update-text-shape-content." v2-update-text-shape-content."
[] []
(when (and wasm/context-initialized? (text-editor-is-active?)) (when (and wasm/context-initialized? (text-editor-has-focus?))
(let [shape-id (text-editor-get-active-shape-id) (let [shape-id (text-editor-get-active-shape-id)
new-texts (text-editor-export-content)] new-texts (text-editor-export-content)]
(when (and shape-id new-texts) (when (and shape-id new-texts)
@ -332,7 +344,7 @@
(defn apply-style-to-selection (defn apply-style-to-selection
[attrs use-shape-fn set-shape-text-content-fn] [attrs use-shape-fn set-shape-text-content-fn]
(when (and wasm/context-initialized? (text-editor-is-active?)) (when wasm/context-initialized?
(let [shape-id (text-editor-get-active-shape-id) (let [shape-id (text-editor-get-active-shape-id)
sel (text-editor-get-selection)] sel (text-editor-get-selection)]
(when (and shape-id sel) (when (and shape-id sel)

View File

@ -4,7 +4,7 @@ use skia_safe::textlayout::{RectHeightStyle, RectWidthStyle};
use skia_safe::{BlendMode, Canvas, Paint, Rect}; use skia_safe::{BlendMode, Canvas, Paint, Rect};
pub fn render_overlay(canvas: &Canvas, editor_state: &TextEditorState, shape: &Shape) { pub fn render_overlay(canvas: &Canvas, editor_state: &TextEditorState, shape: &Shape) {
if !editor_state.is_active { if !editor_state.has_focus {
return; return;
} }

View File

@ -165,7 +165,7 @@ pub struct TextEditorState {
pub theme: TextEditorTheme, pub theme: TextEditorTheme,
pub selection: TextSelection, pub selection: TextSelection,
pub composition: TextComposition, pub composition: TextComposition,
pub is_active: bool, pub has_focus: bool,
// This property indicates that we've started // This property indicates that we've started
// selecting something with the pointer. // selecting something with the pointer.
pub is_pointer_selection_active: bool, pub is_pointer_selection_active: bool,
@ -185,7 +185,7 @@ impl TextEditorState {
}, },
selection: TextSelection::new(), selection: TextSelection::new(),
composition: TextComposition::new(), composition: TextComposition::new(),
is_active: false, has_focus: false,
is_pointer_selection_active: false, is_pointer_selection_active: false,
active_shape_id: None, active_shape_id: None,
cursor_visible: true, cursor_visible: true,
@ -194,8 +194,8 @@ impl TextEditorState {
} }
} }
pub fn start(&mut self, shape_id: Uuid) { pub fn focus(&mut self, shape_id: Uuid) {
self.is_active = true; self.has_focus = true;
self.active_shape_id = Some(shape_id); self.active_shape_id = Some(shape_id);
self.cursor_visible = true; self.cursor_visible = true;
self.last_blink_time = 0.0; self.last_blink_time = 0.0;
@ -204,8 +204,18 @@ impl TextEditorState {
self.pending_events.clear(); self.pending_events.clear();
} }
pub fn stop(&mut self) { pub fn blur(&mut self) {
self.is_active = false; self.has_focus = false;
// self.active_shape_id = None;
self.cursor_visible = false;
self.last_blink_time = 0.0;
// self.selection.reset();
self.is_pointer_selection_active = false;
self.pending_events.clear();
}
pub fn dispose(&mut self) {
self.has_focus = false;
self.active_shape_id = None; self.active_shape_id = None;
self.cursor_visible = false; self.cursor_visible = false;
self.last_blink_time = 0.0; self.last_blink_time = 0.0;
@ -344,7 +354,7 @@ impl TextEditorState {
} }
pub fn update_blink(&mut self, timestamp_ms: f64) { pub fn update_blink(&mut self, timestamp_ms: f64) {
if !self.is_active { if !self.has_focus {
return; return;
} }

View File

@ -44,7 +44,7 @@ pub extern "C" fn text_editor_apply_theme(
} }
#[no_mangle] #[no_mangle]
pub extern "C" fn text_editor_start(a: u32, b: u32, c: u32, d: u32) -> bool { pub extern "C" fn text_editor_focus(a: u32, b: u32, c: u32, d: u32) -> bool {
with_state_mut!(state, { with_state_mut!(state, {
let shape_id = uuid_from_u32_quartet(a, b, c, d); let shape_id = uuid_from_u32_quartet(a, b, c, d);
@ -56,35 +56,48 @@ pub extern "C" fn text_editor_start(a: u32, b: u32, c: u32, d: u32) -> bool {
return false; return false;
} }
state.text_editor_state.start(shape_id); state.text_editor_state.focus(shape_id);
true true
}) })
} }
#[no_mangle] #[no_mangle]
pub extern "C" fn text_editor_stop() -> bool { pub extern "C" fn text_editor_blur() -> bool {
with_state_mut!(state, { with_state_mut!(state, {
if !state.text_editor_state.is_active { if !state.text_editor_state.has_focus {
return false; return false;
} }
state.text_editor_state.stop(); state.text_editor_state.blur();
true true
}) })
} }
#[no_mangle] #[no_mangle]
pub extern "C" fn text_editor_is_active() -> bool { pub extern "C" fn text_editor_dispose() -> bool {
with_state!(state, { state.text_editor_state.is_active }) with_state_mut!(state, {
state.text_editor_state.dispose();
true
})
} }
#[no_mangle] #[no_mangle]
pub extern "C" fn text_editor_is_active_with_id(a: u32, b: u32, c: u32, d: u32) -> bool { pub extern "C" fn text_editor_has_selection() -> bool {
with_state!(state, { state.text_editor_state.selection.is_selection() })
}
#[no_mangle]
pub extern "C" fn text_editor_has_focus() -> bool {
with_state!(state, { state.text_editor_state.has_focus })
}
#[no_mangle]
pub extern "C" fn text_editor_has_focus_with_id(a: u32, b: u32, c: u32, d: u32) -> bool {
with_state!(state, { with_state!(state, {
let shape_id = uuid_from_u32_quartet(a, b, c, d); let shape_id = uuid_from_u32_quartet(a, b, c, d);
let Some(active_shape_id) = state.text_editor_state.active_shape_id else { let Some(active_shape_id) = state.text_editor_state.active_shape_id else {
return false; return false;
}; };
state.text_editor_state.is_active && active_shape_id == shape_id state.text_editor_state.has_focus && active_shape_id == shape_id
}) })
} }
@ -106,7 +119,7 @@ pub extern "C" fn text_editor_get_active_shape_id(buffer_ptr: *mut u32) {
#[no_mangle] #[no_mangle]
pub extern "C" fn text_editor_select_all() -> bool { pub extern "C" fn text_editor_select_all() -> bool {
with_state_mut!(state, { with_state_mut!(state, {
if !state.text_editor_state.is_active { if !state.text_editor_state.has_focus {
return false; return false;
} }
@ -128,7 +141,7 @@ pub extern "C" fn text_editor_select_all() -> bool {
#[no_mangle] #[no_mangle]
pub extern "C" fn text_editor_select_word_boundary(x: f32, y: f32) { pub extern "C" fn text_editor_select_word_boundary(x: f32, y: f32) {
with_state_mut!(state, { with_state_mut!(state, {
if !state.text_editor_state.is_active { if !state.text_editor_state.has_focus {
return; return;
} }
@ -165,7 +178,7 @@ pub extern "C" fn text_editor_poll_event() -> u8 {
#[no_mangle] #[no_mangle]
pub extern "C" fn text_editor_pointer_down(x: f32, y: f32) { pub extern "C" fn text_editor_pointer_down(x: f32, y: f32) {
with_state_mut!(state, { with_state_mut!(state, {
if !state.text_editor_state.is_active { if !state.text_editor_state.has_focus {
return; return;
} }
let Some(shape_id) = state.text_editor_state.active_shape_id else { let Some(shape_id) = state.text_editor_state.active_shape_id else {
@ -188,7 +201,7 @@ pub extern "C" fn text_editor_pointer_down(x: f32, y: f32) {
#[no_mangle] #[no_mangle]
pub extern "C" fn text_editor_pointer_move(x: f32, y: f32) { pub extern "C" fn text_editor_pointer_move(x: f32, y: f32) {
with_state_mut!(state, { with_state_mut!(state, {
if !state.text_editor_state.is_active { if !state.text_editor_state.has_focus {
return; return;
} }
let point = Point::new(x, y); let point = Point::new(x, y);
@ -216,7 +229,7 @@ pub extern "C" fn text_editor_pointer_move(x: f32, y: f32) {
#[no_mangle] #[no_mangle]
pub extern "C" fn text_editor_pointer_up(x: f32, y: f32) { pub extern "C" fn text_editor_pointer_up(x: f32, y: f32) {
with_state_mut!(state, { with_state_mut!(state, {
if !state.text_editor_state.is_active { if !state.text_editor_state.has_focus {
return; return;
} }
let point = Point::new(x, y); let point = Point::new(x, y);
@ -244,7 +257,7 @@ pub extern "C" fn text_editor_pointer_up(x: f32, y: f32) {
#[no_mangle] #[no_mangle]
pub extern "C" fn text_editor_set_cursor_from_offset(x: f32, y: f32) { pub extern "C" fn text_editor_set_cursor_from_offset(x: f32, y: f32) {
with_state_mut!(state, { with_state_mut!(state, {
if !state.text_editor_state.is_active { if !state.text_editor_state.has_focus {
return; return;
} }
@ -267,7 +280,7 @@ pub extern "C" fn text_editor_set_cursor_from_offset(x: f32, y: f32) {
#[no_mangle] #[no_mangle]
pub extern "C" fn text_editor_set_cursor_from_point(x: f32, y: f32) { pub extern "C" fn text_editor_set_cursor_from_point(x: f32, y: f32) {
with_state_mut!(state, { with_state_mut!(state, {
if !state.text_editor_state.is_active { if !state.text_editor_state.has_focus {
return; return;
} }
@ -435,7 +448,7 @@ pub extern "C" fn text_editor_insert_text() -> Result<()> {
}; };
with_state_mut!(state, { with_state_mut!(state, {
if !state.text_editor_state.is_active { if !state.text_editor_state.has_focus {
return Ok(()); return Ok(());
} }
@ -488,7 +501,7 @@ pub extern "C" fn text_editor_insert_text() -> Result<()> {
#[no_mangle] #[no_mangle]
pub extern "C" fn text_editor_delete_backward(word_boundary: bool) { pub extern "C" fn text_editor_delete_backward(word_boundary: bool) {
with_state_mut!(state, { with_state_mut!(state, {
if !state.text_editor_state.is_active { if !state.text_editor_state.has_focus {
return; return;
} }
@ -541,7 +554,7 @@ pub extern "C" fn text_editor_delete_backward(word_boundary: bool) {
#[no_mangle] #[no_mangle]
pub extern "C" fn text_editor_delete_forward(word_boundary: bool) { pub extern "C" fn text_editor_delete_forward(word_boundary: bool) {
with_state_mut!(state, { with_state_mut!(state, {
if !state.text_editor_state.is_active { if !state.text_editor_state.has_focus {
return; return;
} }
@ -594,7 +607,7 @@ pub extern "C" fn text_editor_delete_forward(word_boundary: bool) {
#[no_mangle] #[no_mangle]
pub extern "C" fn text_editor_insert_paragraph() { pub extern "C" fn text_editor_insert_paragraph() {
with_state_mut!(state, { with_state_mut!(state, {
if !state.text_editor_state.is_active { if !state.text_editor_state.has_focus {
return; return;
} }
@ -652,7 +665,7 @@ pub extern "C" fn text_editor_move_cursor(
extend_selection: bool, extend_selection: bool,
) { ) {
with_state_mut!(state, { with_state_mut!(state, {
if !state.text_editor_state.is_active { if !state.text_editor_state.has_focus {
return; return;
} }
@ -735,7 +748,7 @@ pub extern "C" fn text_editor_move_cursor(
#[no_mangle] #[no_mangle]
pub extern "C" fn text_editor_get_cursor_rect() -> *mut u8 { pub extern "C" fn text_editor_get_cursor_rect() -> *mut u8 {
with_state_mut!(state, { with_state_mut!(state, {
if !state.text_editor_state.is_active || !state.text_editor_state.cursor_visible { if !state.text_editor_state.has_focus || !state.text_editor_state.cursor_visible {
return std::ptr::null_mut(); return std::ptr::null_mut();
} }
@ -769,7 +782,7 @@ pub extern "C" fn text_editor_get_cursor_rect() -> *mut u8 {
#[no_mangle] #[no_mangle]
pub extern "C" fn text_editor_get_selection_rects() -> *mut u8 { pub extern "C" fn text_editor_get_selection_rects() -> *mut u8 {
with_state_mut!(state, { with_state_mut!(state, {
if !state.text_editor_state.is_active { if !state.text_editor_state.has_focus {
return std::ptr::null_mut(); return std::ptr::null_mut();
} }
@ -818,10 +831,6 @@ pub extern "C" fn text_editor_update_blink(timestamp_ms: f64) {
#[no_mangle] #[no_mangle]
pub extern "C" fn text_editor_render_overlay() { pub extern "C" fn text_editor_render_overlay() {
with_state_mut!(state, { with_state_mut!(state, {
if !state.text_editor_state.is_active {
return;
}
let Some(shape_id) = state.text_editor_state.active_shape_id else { let Some(shape_id) = state.text_editor_state.active_shape_id else {
return; return;
}; };
@ -858,7 +867,7 @@ pub extern "C" fn text_editor_render_overlay() {
#[no_mangle] #[no_mangle]
pub extern "C" fn text_editor_export_content() -> *mut u8 { pub extern "C" fn text_editor_export_content() -> *mut u8 {
with_state!(state, { with_state!(state, {
if !state.text_editor_state.is_active { if !state.text_editor_state.has_focus {
return std::ptr::null_mut(); return std::ptr::null_mut();
} }
@ -901,7 +910,7 @@ pub extern "C" fn text_editor_export_content() -> *mut u8 {
pub extern "C" fn text_editor_export_selection() -> *mut u8 { pub extern "C" fn text_editor_export_selection() -> *mut u8 {
use std::ptr; use std::ptr;
with_state!(state, { with_state!(state, {
if !state.text_editor_state.is_active { if !state.text_editor_state.has_focus {
return ptr::null_mut(); return ptr::null_mut();
} }
let Some(shape_id) = state.text_editor_state.active_shape_id else { let Some(shape_id) = state.text_editor_state.active_shape_id else {
@ -976,10 +985,10 @@ pub extern "C" fn text_editor_export_selection() -> *mut u8 {
} }
#[no_mangle] #[no_mangle]
pub extern "C" fn text_editor_get_selection(buffer_ptr: *mut u32) -> u32 { pub extern "C" fn text_editor_get_selection(buffer_ptr: *mut u32) -> bool {
with_state!(state, { with_state!(state, {
if !state.text_editor_state.is_active { if !state.text_editor_state.selection.is_selection() {
return 0; return false;
} }
let sel = &state.text_editor_state.selection; let sel = &state.text_editor_state.selection;
unsafe { unsafe {
@ -988,7 +997,7 @@ pub extern "C" fn text_editor_get_selection(buffer_ptr: *mut u32) -> u32 {
*buffer_ptr.add(2) = sel.focus.paragraph as u32; *buffer_ptr.add(2) = sel.focus.paragraph as u32;
*buffer_ptr.add(3) = sel.focus.offset as u32; *buffer_ptr.add(3) = sel.focus.offset as u32;
} }
1 true
}) })
} }