gtk4/subclass/
text_view.rs

1// Take a look at the license at the top of the repository in the LICENSE file.
2
3// rustdoc-stripper-ignore-next
4//! Traits intended for subclassing [`TextView`].
5
6use glib::translate::*;
7
8use crate::{
9    ffi, prelude::*, subclass::prelude::*, DeleteType, MovementStep, Scrollable, Snapshot,
10    TextExtendSelection, TextIter, TextView, TextViewLayer,
11};
12
13pub trait TextViewImpl: WidgetImpl + ObjectSubclass<Type: IsA<TextView> + IsA<Scrollable>> {
14    /// The class handler for the `GtkTextView::backspace`
15    ///   keybinding signal.
16    fn backspace(&self) {
17        self.parent_backspace()
18    }
19
20    /// The class handler for the `GtkTextView::copy-clipboard`
21    ///   keybinding signal.
22    fn copy_clipboard(&self) {
23        self.parent_copy_clipboard()
24    }
25
26    /// The class handler for the `GtkTextView::cut-clipboard`
27    ///   keybinding signal
28    fn cut_clipboard(&self) {
29        self.parent_cut_clipboard()
30    }
31
32    /// The class handler for the `GtkTextView::delete-from-cursor`
33    ///   keybinding signal.
34    fn delete_from_cursor(&self, type_: DeleteType, count: i32) {
35        self.parent_delete_from_cursor(type_, count)
36    }
37
38    /// The class handler for the `GtkTextView::extend-selection` signal.
39    fn extend_selection(
40        &self,
41        granularity: TextExtendSelection,
42        location: &TextIter,
43        start: &mut TextIter,
44        end: &mut TextIter,
45    ) -> glib::ControlFlow {
46        self.parent_extend_selection(granularity, location, start, end)
47    }
48
49    /// The class handler for the `GtkTextView::insert-at-cursor`
50    ///   keybinding signal.
51    fn insert_at_cursor(&self, text: &str) {
52        self.parent_insert_at_cursor(text)
53    }
54
55    /// The class handler for the `GtkTextView::insert-emoji` signal.
56    fn insert_emoji(&self) {
57        self.parent_insert_emoji()
58    }
59
60    /// The class handler for the `GtkTextView::move-cursor`
61    ///   keybinding signal.
62    fn move_cursor(&self, step: MovementStep, count: i32, extend_selection: bool) {
63        self.parent_move_cursor(step, count, extend_selection)
64    }
65
66    /// The class handler for the `GtkTextView::paste-clipboard`
67    ///   keybinding signal.
68    fn paste_clipboard(&self) {
69        self.parent_paste_clipboard()
70    }
71
72    /// The class handler for the `GtkTextView::set-anchor`
73    ///   keybinding signal.
74    fn set_anchor(&self) {
75        self.parent_set_anchor()
76    }
77
78    /// The snapshot_layer vfunc is called before and after the text
79    ///   view is drawing its own text. Applications can override this vfunc
80    ///   in a subclass to draw customized content underneath or above the
81    ///   text. In the [`TextViewLayer::BelowText`][crate::TextViewLayer::BelowText] and [`TextViewLayer::AboveText`][crate::TextViewLayer::AboveText]
82    ///   layers the drawing is done in the buffer coordinate space.
83    fn snapshot_layer(&self, layer: TextViewLayer, snapshot: Snapshot) {
84        self.parent_snapshot_layer(layer, snapshot)
85    }
86
87    /// The class handler for the `GtkTextView::toggle-overwrite`
88    ///   keybinding signal.
89    fn toggle_overwrite(&self) {
90        self.parent_toggle_overwrite()
91    }
92}
93
94pub trait TextViewImplExt: TextViewImpl {
95    fn parent_backspace(&self) {
96        unsafe {
97            let data = Self::type_data();
98            let parent_class = data.as_ref().parent_class() as *mut ffi::GtkTextViewClass;
99            if let Some(f) = (*parent_class).backspace {
100                f(self.obj().unsafe_cast_ref::<TextView>().to_glib_none().0)
101            }
102        }
103    }
104
105    fn parent_copy_clipboard(&self) {
106        unsafe {
107            let data = Self::type_data();
108            let parent_class = data.as_ref().parent_class() as *mut ffi::GtkTextViewClass;
109            if let Some(f) = (*parent_class).copy_clipboard {
110                f(self.obj().unsafe_cast_ref::<TextView>().to_glib_none().0)
111            }
112        }
113    }
114
115    fn parent_cut_clipboard(&self) {
116        unsafe {
117            let data = Self::type_data();
118            let parent_class = data.as_ref().parent_class() as *mut ffi::GtkTextViewClass;
119            if let Some(f) = (*parent_class).cut_clipboard {
120                f(self.obj().unsafe_cast_ref::<TextView>().to_glib_none().0)
121            }
122        }
123    }
124
125    fn parent_delete_from_cursor(&self, type_: DeleteType, count: i32) {
126        unsafe {
127            let data = Self::type_data();
128            let parent_class = data.as_ref().parent_class() as *mut ffi::GtkTextViewClass;
129            if let Some(f) = (*parent_class).delete_from_cursor {
130                f(
131                    self.obj().unsafe_cast_ref::<TextView>().to_glib_none().0,
132                    type_.into_glib(),
133                    count,
134                )
135            }
136        }
137    }
138
139    fn parent_extend_selection(
140        &self,
141        granularity: TextExtendSelection,
142        location: &TextIter,
143        start: &mut TextIter,
144        end: &mut TextIter,
145    ) -> glib::ControlFlow {
146        unsafe {
147            let data = Self::type_data();
148            let parent_class = data.as_ref().parent_class() as *mut ffi::GtkTextViewClass;
149            if let Some(f) = (*parent_class).extend_selection {
150                glib::ControlFlow::from_glib(f(
151                    self.obj().unsafe_cast_ref::<TextView>().to_glib_none().0,
152                    granularity.into_glib(),
153                    location.to_glib_none().0,
154                    start.to_glib_none_mut().0,
155                    end.to_glib_none_mut().0,
156                ))
157            } else {
158                glib::ControlFlow::Break
159            }
160        }
161    }
162
163    fn parent_insert_at_cursor(&self, text: &str) {
164        unsafe {
165            let data = Self::type_data();
166            let parent_class = data.as_ref().parent_class() as *mut ffi::GtkTextViewClass;
167            if let Some(f) = (*parent_class).insert_at_cursor {
168                f(
169                    self.obj().unsafe_cast_ref::<TextView>().to_glib_none().0,
170                    text.to_glib_none().0,
171                )
172            }
173        }
174    }
175
176    fn parent_insert_emoji(&self) {
177        unsafe {
178            let data = Self::type_data();
179            let parent_class = data.as_ref().parent_class() as *mut ffi::GtkTextViewClass;
180            if let Some(f) = (*parent_class).insert_emoji {
181                f(self.obj().unsafe_cast_ref::<TextView>().to_glib_none().0)
182            }
183        }
184    }
185
186    fn parent_move_cursor(&self, step: MovementStep, count: i32, extend_selection: bool) {
187        unsafe {
188            let data = Self::type_data();
189            let parent_class = data.as_ref().parent_class() as *mut ffi::GtkTextViewClass;
190            if let Some(f) = (*parent_class).move_cursor {
191                f(
192                    self.obj().unsafe_cast_ref::<TextView>().to_glib_none().0,
193                    step.into_glib(),
194                    count,
195                    extend_selection.into_glib(),
196                )
197            }
198        }
199    }
200
201    fn parent_paste_clipboard(&self) {
202        unsafe {
203            let data = Self::type_data();
204            let parent_class = data.as_ref().parent_class() as *mut ffi::GtkTextViewClass;
205            if let Some(f) = (*parent_class).paste_clipboard {
206                f(self.obj().unsafe_cast_ref::<TextView>().to_glib_none().0)
207            }
208        }
209    }
210
211    fn parent_set_anchor(&self) {
212        unsafe {
213            let data = Self::type_data();
214            let parent_class = data.as_ref().parent_class() as *mut ffi::GtkTextViewClass;
215            if let Some(f) = (*parent_class).set_anchor {
216                f(self.obj().unsafe_cast_ref::<TextView>().to_glib_none().0)
217            }
218        }
219    }
220
221    fn parent_snapshot_layer(&self, layer: TextViewLayer, snapshot: Snapshot) {
222        unsafe {
223            let data = Self::type_data();
224            let parent_class = data.as_ref().parent_class() as *mut ffi::GtkTextViewClass;
225            if let Some(f) = (*parent_class).snapshot_layer {
226                f(
227                    self.obj().unsafe_cast_ref::<TextView>().to_glib_none().0,
228                    layer.into_glib(),
229                    snapshot.to_glib_none().0,
230                )
231            }
232        }
233    }
234
235    fn parent_toggle_overwrite(&self) {
236        unsafe {
237            let data = Self::type_data();
238            let parent_class = data.as_ref().parent_class() as *mut ffi::GtkTextViewClass;
239            if let Some(f) = (*parent_class).toggle_overwrite {
240                f(self.obj().unsafe_cast_ref::<TextView>().to_glib_none().0)
241            }
242        }
243    }
244}
245
246impl<T: TextViewImpl> TextViewImplExt for T {}
247
248unsafe impl<T: TextViewImpl> IsSubclassable<T> for TextView {
249    fn class_init(class: &mut glib::Class<Self>) {
250        Self::parent_class_init::<T>(class);
251
252        let klass = class.as_mut();
253        klass.backspace = Some(text_view_backspace::<T>);
254        klass.copy_clipboard = Some(text_view_copy_clipboard::<T>);
255        klass.cut_clipboard = Some(text_view_cut_clipboard::<T>);
256        klass.delete_from_cursor = Some(text_view_delete_from_cursor::<T>);
257        klass.extend_selection = Some(text_view_extend_selection::<T>);
258        klass.insert_at_cursor = Some(text_view_insert_at_cursor::<T>);
259        klass.insert_emoji = Some(text_view_insert_emoji::<T>);
260        klass.move_cursor = Some(text_view_move_cursor::<T>);
261        klass.paste_clipboard = Some(text_view_paste_clipboard::<T>);
262        klass.set_anchor = Some(text_view_set_anchor::<T>);
263        klass.snapshot_layer = Some(text_view_snapshot_layer::<T>);
264        klass.toggle_overwrite = Some(text_view_toggle_overwrite::<T>);
265    }
266}
267
268unsafe extern "C" fn text_view_backspace<T: TextViewImpl>(ptr: *mut ffi::GtkTextView) {
269    let instance = &*(ptr as *mut T::Instance);
270    let imp = instance.imp();
271
272    imp.backspace()
273}
274
275unsafe extern "C" fn text_view_copy_clipboard<T: TextViewImpl>(ptr: *mut ffi::GtkTextView) {
276    let instance = &*(ptr as *mut T::Instance);
277    let imp = instance.imp();
278
279    imp.copy_clipboard()
280}
281
282unsafe extern "C" fn text_view_cut_clipboard<T: TextViewImpl>(ptr: *mut ffi::GtkTextView) {
283    let instance = &*(ptr as *mut T::Instance);
284    let imp = instance.imp();
285
286    imp.cut_clipboard()
287}
288
289unsafe extern "C" fn text_view_delete_from_cursor<T: TextViewImpl>(
290    ptr: *mut ffi::GtkTextView,
291    type_: ffi::GtkDeleteType,
292    count: i32,
293) {
294    let instance = &*(ptr as *mut T::Instance);
295    let imp = instance.imp();
296
297    imp.delete_from_cursor(from_glib(type_), count)
298}
299
300unsafe extern "C" fn text_view_extend_selection<T: TextViewImpl>(
301    ptr: *mut ffi::GtkTextView,
302    granularity: ffi::GtkTextExtendSelection,
303    location: *const ffi::GtkTextIter,
304    start: *mut ffi::GtkTextIter,
305    end: *mut ffi::GtkTextIter,
306) -> glib::ffi::gboolean {
307    let instance = &*(ptr as *mut T::Instance);
308    let imp = instance.imp();
309
310    let mut start_copy = from_glib_none(start);
311    let mut end_copy = from_glib_none(end);
312
313    let result = imp.extend_selection(
314        from_glib(granularity),
315        &from_glib_borrow(location),
316        &mut start_copy,
317        &mut end_copy,
318    );
319    *start = *start_copy.to_glib_none().0;
320    *end = *end_copy.to_glib_none().0;
321
322    result.into_glib()
323}
324
325unsafe extern "C" fn text_view_insert_at_cursor<T: TextViewImpl>(
326    ptr: *mut ffi::GtkTextView,
327    text_ptr: *const libc::c_char,
328) {
329    let instance = &*(ptr as *mut T::Instance);
330    let imp = instance.imp();
331    let text: Borrowed<glib::GString> = from_glib_borrow(text_ptr);
332
333    imp.insert_at_cursor(text.as_str())
334}
335
336unsafe extern "C" fn text_view_insert_emoji<T: TextViewImpl>(ptr: *mut ffi::GtkTextView) {
337    let instance = &*(ptr as *mut T::Instance);
338    let imp = instance.imp();
339
340    imp.insert_emoji()
341}
342
343unsafe extern "C" fn text_view_move_cursor<T: TextViewImpl>(
344    ptr: *mut ffi::GtkTextView,
345    step: ffi::GtkMovementStep,
346    count: i32,
347    extend_selection: glib::ffi::gboolean,
348) {
349    let instance = &*(ptr as *mut T::Instance);
350    let imp = instance.imp();
351
352    imp.move_cursor(from_glib(step), count, from_glib(extend_selection))
353}
354
355unsafe extern "C" fn text_view_paste_clipboard<T: TextViewImpl>(ptr: *mut ffi::GtkTextView) {
356    let instance = &*(ptr as *mut T::Instance);
357    let imp = instance.imp();
358
359    imp.paste_clipboard()
360}
361
362unsafe extern "C" fn text_view_set_anchor<T: TextViewImpl>(ptr: *mut ffi::GtkTextView) {
363    let instance = &*(ptr as *mut T::Instance);
364    let imp = instance.imp();
365
366    imp.set_anchor()
367}
368
369unsafe extern "C" fn text_view_snapshot_layer<T: TextViewImpl>(
370    ptr: *mut ffi::GtkTextView,
371    layer: ffi::GtkTextViewLayer,
372    snapshot: *mut ffi::GtkSnapshot,
373) {
374    let instance = &*(ptr as *mut T::Instance);
375    let imp = instance.imp();
376
377    imp.snapshot_layer(from_glib(layer), from_glib_none(snapshot))
378}
379
380unsafe extern "C" fn text_view_toggle_overwrite<T: TextViewImpl>(ptr: *mut ffi::GtkTextView) {
381    let instance = &*(ptr as *mut T::Instance);
382    let imp = instance.imp();
383
384    imp.toggle_overwrite()
385}