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