Skip to main content

gtk4/
text.rs

1// Take a look at the license at the top of the repository in the LICENSE file.
2
3use std::mem::transmute;
4
5use glib::{
6    GString,
7    signal::{SignalHandlerId, connect_raw},
8    translate::*,
9};
10
11use crate::{DeleteType, MovementStep, Text, Widget, ffi, prelude::*};
12
13impl Text {
14    /// Emitted when the user hits the <kbd>Enter</kbd> key.
15    ///
16    /// The default bindings for this signal are all forms
17    /// of the <kbd>Enter</kbd> key.
18    pub fn connect_activate<F: Fn(&Text) + 'static>(&self, f: F) -> SignalHandlerId {
19        unsafe extern "C" fn activate_trampoline<F: Fn(&Text) + 'static>(
20            this: *mut ffi::GtkText,
21            f: glib::ffi::gpointer,
22        ) {
23            unsafe {
24                let f: &F = &*(f as *const F);
25                f(&from_glib_borrow(this))
26            }
27        }
28        unsafe {
29            let f: Box<F> = Box::new(f);
30            connect_raw(
31                self.as_ptr() as *mut _,
32                c"activate".as_ptr() as *const _,
33                Some(transmute::<*const (), unsafe extern "C" fn()>(
34                    activate_trampoline::<F> as *const (),
35                )),
36                Box::into_raw(f),
37            )
38        }
39    }
40
41    /// Emitted when the user asks for it.
42    ///
43    /// This is a [keybinding signal](class.SignalAction.html).
44    ///
45    /// The default bindings for this signal are
46    /// <kbd>Backspace</kbd> and <kbd>Shift</kbd>+<kbd>Backspace</kbd>.
47    pub fn connect_backspace<F: Fn(&Text) + 'static>(&self, f: F) -> SignalHandlerId {
48        unsafe extern "C" fn backspace_trampoline<F: Fn(&Text) + 'static>(
49            this: *mut ffi::GtkText,
50            f: glib::ffi::gpointer,
51        ) {
52            unsafe {
53                let f: &F = &*(f as *const F);
54                f(&from_glib_borrow(this))
55            }
56        }
57        unsafe {
58            let f: Box<F> = Box::new(f);
59            connect_raw(
60                self.as_ptr() as *mut _,
61                c"backspace".as_ptr() as *const _,
62                Some(transmute::<*const (), unsafe extern "C" fn()>(
63                    backspace_trampoline::<F> as *const (),
64                )),
65                Box::into_raw(f),
66            )
67        }
68    }
69
70    /// Emitted to copy the selection to the clipboard.
71    ///
72    /// This is a [keybinding signal](class.SignalAction.html).
73    ///
74    /// The default bindings for this signal are
75    /// <kbd>Ctrl</kbd>+<kbd>c</kbd> and
76    /// <kbd>Ctrl</kbd>+<kbd>Insert</kbd>.
77    pub fn connect_copy_clipboard<F: Fn(&Text) + 'static>(&self, f: F) -> SignalHandlerId {
78        unsafe extern "C" fn copy_clipboard_trampoline<F: Fn(&Text) + 'static>(
79            this: *mut ffi::GtkText,
80            f: glib::ffi::gpointer,
81        ) {
82            unsafe {
83                let f: &F = &*(f as *const F);
84                f(&from_glib_borrow(this))
85            }
86        }
87        unsafe {
88            let f: Box<F> = Box::new(f);
89            connect_raw(
90                self.as_ptr() as *mut _,
91                c"copy-clipboard".as_ptr() as *const _,
92                Some(transmute::<*const (), unsafe extern "C" fn()>(
93                    copy_clipboard_trampoline::<F> as *const (),
94                )),
95                Box::into_raw(f),
96            )
97        }
98    }
99
100    /// Emitted to cut the selection to the clipboard.
101    ///
102    /// This is a [keybinding signal](class.SignalAction.html).
103    ///
104    /// The default bindings for this signal are
105    /// <kbd>Ctrl</kbd>+<kbd>x</kbd> and
106    /// <kbd>Shift</kbd>+<kbd>Delete</kbd>.
107    pub fn connect_cut_clipboard<F: Fn(&Text) + 'static>(&self, f: F) -> SignalHandlerId {
108        unsafe extern "C" fn cut_clipboard_trampoline<F: Fn(&Text) + 'static>(
109            this: *mut ffi::GtkText,
110            f: glib::ffi::gpointer,
111        ) {
112            unsafe {
113                let f: &F = &*(f as *const F);
114                f(&from_glib_borrow(this))
115            }
116        }
117        unsafe {
118            let f: Box<F> = Box::new(f);
119            connect_raw(
120                self.as_ptr() as *mut _,
121                c"cut-clipboard".as_ptr() as *const _,
122                Some(transmute::<*const (), unsafe extern "C" fn()>(
123                    cut_clipboard_trampoline::<F> as *const (),
124                )),
125                Box::into_raw(f),
126            )
127        }
128    }
129
130    /// Emitted when the user initiates a text deletion.
131    ///
132    /// This is a [keybinding signal](class.SignalAction.html).
133    ///
134    /// If the @type_ is [enum@Gtk.DeleteType.chars], GTK deletes the
135    /// selection if there is one, otherwise it deletes the requested
136    /// number of characters.
137    ///
138    /// The default bindings for this signal are <kbd>Delete</kbd>
139    /// for deleting a character and <kbd>Ctrl</kbd>+<kbd>Delete</kbd>
140    /// for deleting a word.
141    /// ## `type_`
142    /// the granularity of the deletion
143    /// ## `count`
144    /// the number of @type_ units to delete
145    pub fn connect_delete_from_cursor<F: Fn(&Text, DeleteType, i32) + 'static>(
146        &self,
147        f: F,
148    ) -> SignalHandlerId {
149        unsafe extern "C" fn delete_from_cursor_trampoline<
150            F: Fn(&Text, DeleteType, i32) + 'static,
151        >(
152            this: *mut ffi::GtkText,
153            type_: ffi::GtkDeleteType,
154            count: libc::c_int,
155            f: glib::ffi::gpointer,
156        ) {
157            unsafe {
158                let f: &F = &*(f as *const F);
159                f(&from_glib_borrow(this), from_glib(type_), count)
160            }
161        }
162        unsafe {
163            let f: Box<F> = Box::new(f);
164            connect_raw(
165                self.as_ptr() as *mut _,
166                c"delete-from-cursor".as_ptr() as *const _,
167                Some(transmute::<*const (), unsafe extern "C" fn()>(
168                    delete_from_cursor_trampoline::<F> as *const (),
169                )),
170                Box::into_raw(f),
171            )
172        }
173    }
174
175    /// Emitted when the user initiates the insertion of a
176    /// fixed string at the cursor.
177    ///
178    /// This is a [keybinding signal](class.SignalAction.html).
179    ///
180    /// This signal has no default bindings.
181    /// ## `string`
182    /// the string to insert
183    pub fn connect_insert_at_cursor<F: Fn(&Text, &str) + 'static>(&self, f: F) -> SignalHandlerId {
184        unsafe extern "C" fn insert_at_cursor_trampoline<F: Fn(&Text, &str) + 'static>(
185            this: *mut ffi::GtkText,
186            string: *mut libc::c_char,
187            f: glib::ffi::gpointer,
188        ) {
189            unsafe {
190                let f: &F = &*(f as *const F);
191                f(&from_glib_borrow(this), &GString::from_glib_borrow(string))
192            }
193        }
194        unsafe {
195            let f: Box<F> = Box::new(f);
196            connect_raw(
197                self.as_ptr() as *mut _,
198                c"insert-at-cursor".as_ptr() as *const _,
199                Some(transmute::<*const (), unsafe extern "C" fn()>(
200                    insert_at_cursor_trampoline::<F> as *const (),
201                )),
202                Box::into_raw(f),
203            )
204        }
205    }
206
207    /// Emitted to present the Emoji chooser.
208    ///
209    /// This is a [keybinding signal](class.SignalAction.html).
210    ///
211    /// The default bindings for this signal are
212    /// <kbd>Ctrl</kbd>+<kbd>.</kbd> and
213    /// <kbd>Ctrl</kbd>+<kbd>;</kbd>
214    pub fn connect_insert_emoji<F: Fn(&Text) + 'static>(&self, f: F) -> SignalHandlerId {
215        unsafe extern "C" fn insert_emoji_trampoline<F: Fn(&Text) + 'static>(
216            this: *mut ffi::GtkText,
217            f: glib::ffi::gpointer,
218        ) {
219            unsafe {
220                let f: &F = &*(f as *const F);
221                f(&from_glib_borrow(this))
222            }
223        }
224        unsafe {
225            let f: Box<F> = Box::new(f);
226            connect_raw(
227                self.as_ptr() as *mut _,
228                c"insert-emoji".as_ptr() as *const _,
229                Some(transmute::<*const (), unsafe extern "C" fn()>(
230                    insert_emoji_trampoline::<F> as *const (),
231                )),
232                Box::into_raw(f),
233            )
234        }
235    }
236
237    /// Emitted when the user initiates a cursor movement.
238    ///
239    /// If the cursor is not visible in @self_, this signal causes
240    /// the viewport to be moved instead.
241    ///
242    /// This is a [keybinding signal](class.SignalAction.html).
243    ///
244    /// Applications should not connect to it, but may emit it with
245    /// `signal_emit_by_name()` if they need to control
246    /// the cursor programmatically.
247    ///
248    /// The default bindings for this signal come in two variants,
249    /// the variant with the <kbd>Shift</kbd> modifier extends the
250    /// selection, the variant without it does not.
251    /// There are too many key combinations to list them all here.
252    ///
253    /// - <kbd>←</kbd>, <kbd>→</kbd>, <kbd>↑</kbd>, <kbd>↓</kbd>
254    ///   move by individual characters/lines
255    /// - <kbd>Ctrl</kbd>+<kbd>←</kbd>, etc. move by words/paragraphs
256    /// - <kbd>Home</kbd> and <kbd>End</kbd> move to the ends of the buffer
257    /// ## `step`
258    /// the granularity of the move
259    /// ## `count`
260    /// the number of @step units to move
261    /// ## `extend`
262    /// true if the move should extend the selection
263    pub fn connect_move_cursor<F: Fn(&Text, MovementStep, i32, bool) + 'static>(
264        &self,
265        f: F,
266    ) -> SignalHandlerId {
267        unsafe extern "C" fn move_cursor_trampoline<
268            F: Fn(&Text, MovementStep, i32, bool) + 'static,
269        >(
270            this: *mut ffi::GtkText,
271            step: ffi::GtkMovementStep,
272            count: libc::c_int,
273            extend: glib::ffi::gboolean,
274            f: glib::ffi::gpointer,
275        ) {
276            unsafe {
277                let f: &F = &*(f as *const F);
278                f(
279                    &from_glib_borrow(this),
280                    from_glib(step),
281                    count,
282                    from_glib(extend),
283                )
284            }
285        }
286        unsafe {
287            let f: Box<F> = Box::new(f);
288            connect_raw(
289                self.as_ptr() as *mut _,
290                c"move-cursor".as_ptr() as *const _,
291                Some(transmute::<*const (), unsafe extern "C" fn()>(
292                    move_cursor_trampoline::<F> as *const (),
293                )),
294                Box::into_raw(f),
295            )
296        }
297    }
298
299    /// Emitted to paste the contents of the clipboard.
300    ///
301    /// This is a [keybinding signal](class.SignalAction.html).
302    ///
303    /// The default bindings for this signal are
304    /// <kbd>Ctrl</kbd>+<kbd>v</kbd> and <kbd>Shift</kbd>+<kbd>Insert</kbd>.
305    pub fn connect_paste_clipboard<F: Fn(&Text) + 'static>(&self, f: F) -> SignalHandlerId {
306        unsafe extern "C" fn paste_clipboard_trampoline<F: Fn(&Text) + 'static>(
307            this: *mut ffi::GtkText,
308            f: glib::ffi::gpointer,
309        ) {
310            unsafe {
311                let f: &F = &*(f as *const F);
312                f(&from_glib_borrow(this))
313            }
314        }
315        unsafe {
316            let f: Box<F> = Box::new(f);
317            connect_raw(
318                self.as_ptr() as *mut _,
319                c"paste-clipboard".as_ptr() as *const _,
320                Some(transmute::<*const (), unsafe extern "C" fn()>(
321                    paste_clipboard_trampoline::<F> as *const (),
322                )),
323                Box::into_raw(f),
324            )
325        }
326    }
327
328    pub fn connect_populate_popup<F: Fn(&Text, &Widget) + 'static>(&self, f: F) -> SignalHandlerId {
329        unsafe extern "C" fn populate_popup_trampoline<F: Fn(&Text, &Widget) + 'static>(
330            this: *mut ffi::GtkText,
331            widget: *mut ffi::GtkWidget,
332            f: glib::ffi::gpointer,
333        ) {
334            unsafe {
335                let f: &F = &*(f as *const F);
336                f(&from_glib_borrow(this), &from_glib_borrow(widget))
337            }
338        }
339        unsafe {
340            let f: Box<F> = Box::new(f);
341            connect_raw(
342                self.as_ptr() as *mut _,
343                c"populate-popup".as_ptr() as *const _,
344                Some(transmute::<*const (), unsafe extern "C" fn()>(
345                    populate_popup_trampoline::<F> as *const (),
346                )),
347                Box::into_raw(f),
348            )
349        }
350    }
351
352    /// Emitted when the preedit text changes.
353    ///
354    /// If an input method is used, the typed text will not immediately
355    /// be committed to the buffer. So if you are interested in the text,
356    /// connect to this signal.
357    /// ## `preedit`
358    /// the current preedit string
359    pub fn connect_preedit_changed<F: Fn(&Text, &str) + 'static>(&self, f: F) -> SignalHandlerId {
360        unsafe extern "C" fn preedit_changed_trampoline<F: Fn(&Text, &str) + 'static>(
361            this: *mut ffi::GtkText,
362            preedit: *mut libc::c_char,
363            f: glib::ffi::gpointer,
364        ) {
365            unsafe {
366                let f: &F = &*(f as *const F);
367                f(&from_glib_borrow(this), &GString::from_glib_borrow(preedit))
368            }
369        }
370        unsafe {
371            let f: Box<F> = Box::new(f);
372            connect_raw(
373                self.as_ptr() as *mut _,
374                c"preedit-changed".as_ptr() as *const _,
375                Some(transmute::<*const (), unsafe extern "C" fn()>(
376                    preedit_changed_trampoline::<F> as *const (),
377                )),
378                Box::into_raw(f),
379            )
380        }
381    }
382
383    /// Emitted to toggle the overwrite mode.
384    ///
385    /// This is a [keybinding signal](class.SignalAction.html).
386    ///
387    /// The default bindings for this signal is <kbd>Insert</kbd>.
388    pub fn connect_toggle_overwrite<F: Fn(&Text) + 'static>(&self, f: F) -> SignalHandlerId {
389        unsafe extern "C" fn toggle_overwrite_trampoline<F: Fn(&Text) + 'static>(
390            this: *mut ffi::GtkText,
391            f: glib::ffi::gpointer,
392        ) {
393            unsafe {
394                let f: &F = &*(f as *const F);
395                f(&from_glib_borrow(this))
396            }
397        }
398        unsafe {
399            let f: Box<F> = Box::new(f);
400            connect_raw(
401                self.as_ptr() as *mut _,
402                c"toggle-overwrite".as_ptr() as *const _,
403                Some(transmute::<*const (), unsafe extern "C" fn()>(
404                    toggle_overwrite_trampoline::<F> as *const (),
405                )),
406                Box::into_raw(f),
407            )
408        }
409    }
410
411    pub fn emit_activate(&self) {
412        self.emit_by_name::<()>("activate", &[]);
413    }
414
415    pub fn emit_backspace(&self) {
416        self.emit_by_name::<()>("backspace", &[]);
417    }
418
419    pub fn emit_copy_clipboard(&self) {
420        self.emit_by_name::<()>("copy-clipboard", &[]);
421    }
422
423    pub fn emit_cut_clipboard(&self) {
424        self.emit_by_name::<()>("cut-clipboard", &[]);
425    }
426
427    pub fn emit_delete_from_cursor(&self, type_: DeleteType, count: i32) {
428        self.emit_by_name::<()>("delete-from-cursor", &[&type_, &count]);
429    }
430
431    pub fn emit_insert_at_cursor(&self, string: impl IntoGStr) {
432        string.run_with_gstr(|string| {
433            self.emit_by_name::<()>("insert-at-cursor", &[&string]);
434        });
435    }
436
437    pub fn emit_insert_emoji(&self) {
438        self.emit_by_name::<()>("insert-emoji", &[]);
439    }
440
441    pub fn emit_move_cursor(&self, step: MovementStep, count: i32, extend: bool) {
442        self.emit_by_name::<()>("move-cursor", &[&step, &count, &extend]);
443    }
444
445    pub fn emit_paste_clipboard(&self) {
446        self.emit_by_name::<()>("paste-clipboard", &[]);
447    }
448
449    pub fn emit_preedit_changed(&self, preedit: impl IntoGStr) {
450        preedit.run_with_gstr(|preedit| {
451            self.emit_by_name::<()>("preedit-changed", &[&preedit]);
452        });
453    }
454
455    pub fn emit_toggle_overwrite(&self) {
456        self.emit_by_name::<()>("toggle-overwrite", &[]);
457    }
458}