Skip to main content

gtk/
tree_sortable.rs

1// Take a look at the license at the top of the repository in the LICENSE file.
2
3use crate::SortType;
4use glib::object::IsA;
5use glib::translate::*;
6use std::cmp::Ordering;
7use std::fmt;
8use std::mem;
9
10use crate::{TreeIter, TreeModel, TreeSortable};
11use ffi::{GtkTreeIter, GtkTreeModel};
12use glib::ffi::gpointer;
13
14#[derive(Clone, Copy, Debug, Eq, PartialEq, Ord, PartialOrd, Hash)]
15pub enum SortColumn {
16    #[doc(alias = "GTK_TREE_SORTABLE_DEFAULT_SORT_COLUMN_ID")]
17    Default,
18    Index(u32),
19}
20
21#[doc(hidden)]
22impl IntoGlib for SortColumn {
23    type GlibType = i32;
24
25    #[inline]
26    fn into_glib(self) -> i32 {
27        match self {
28            Self::Default => ffi::GTK_TREE_SORTABLE_DEFAULT_SORT_COLUMN_ID,
29            Self::Index(x) => {
30                assert!(x <= i32::max_value() as u32, "column index is too big");
31                x as i32
32            }
33        }
34    }
35}
36
37#[doc(hidden)]
38impl FromGlib<i32> for SortColumn {
39    #[inline]
40    unsafe fn from_glib(val: i32) -> Self {
41        skip_assert_initialized!();
42        match val {
43            ffi::GTK_TREE_SORTABLE_DEFAULT_SORT_COLUMN_ID => Self::Default,
44            x => {
45                assert!(x >= 0, "invalid column index");
46                Self::Index(x as u32)
47            }
48        }
49    }
50}
51
52impl fmt::Display for SortColumn {
53    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
54        write!(
55            f,
56            "SortColumn::{}",
57            match *self {
58                Self::Default => "Default",
59                Self::Index(_) => "Index",
60            }
61        )
62    }
63}
64
65mod sealed {
66    pub trait Sealed {}
67    impl<T: glib::IsA<crate::TreeSortable>> Sealed for T {}
68}
69
70pub trait TreeSortableExtManual: IsA<TreeSortable> + sealed::Sealed + 'static {
71    /// Sets the default comparison function used when sorting to be `sort_func`.
72    /// If the current sort column id of `self` is
73    /// `GTK_TREE_SORTABLE_DEFAULT_SORT_COLUMN_ID`, then the model will sort using
74    /// this function.
75    ///
76    /// If `sort_func` is [`None`], then there will be no default comparison function.
77    /// This means that once the model has been sorted, it can’t go back to the
78    /// default state. In this case, when the current sort column id of `self`
79    /// is `GTK_TREE_SORTABLE_DEFAULT_SORT_COLUMN_ID`, the model will be unsorted.
80    /// ## `sort_func`
81    /// The comparison function
82    #[doc(alias = "gtk_tree_sortable_set_default_sort_func")]
83    fn set_default_sort_func<F>(&self, sort_func: F)
84    where
85        F: Fn(&TreeModel, &TreeIter, &TreeIter) -> Ordering + 'static,
86    {
87        unsafe extern "C" fn trampoline<F: Fn(&TreeModel, &TreeIter, &TreeIter) -> Ordering>(
88            this: *mut GtkTreeModel,
89            iter: *mut GtkTreeIter,
90            iter2: *mut GtkTreeIter,
91            f: gpointer,
92        ) -> i32 {
93            let f: &F = &*(f as *const F);
94            f(
95                &TreeModel::from_glib_borrow(this),
96                &from_glib_borrow(iter),
97                &from_glib_borrow(iter2),
98            )
99            .into_glib()
100        }
101        unsafe extern "C" fn destroy_closure<
102            F: Fn(&TreeModel, &TreeIter, &TreeIter) -> Ordering,
103        >(
104            ptr: gpointer,
105        ) {
106            let _ = Box::<F>::from_raw(ptr as *mut _);
107        }
108        unsafe {
109            ffi::gtk_tree_sortable_set_default_sort_func(
110                self.as_ref().to_glib_none().0,
111                Some(trampoline::<F>),
112                into_raw(sort_func),
113                Some(destroy_closure::<F>),
114            )
115        }
116    }
117    /// Sets the comparison function used when sorting to be `sort_func`. If the
118    /// current sort column id of `self` is the same as `sort_column_id`, then
119    /// the model will sort using this function.
120    /// ## `sort_column_id`
121    /// the sort column id to set the function for
122    /// ## `sort_func`
123    /// The comparison function
124    #[doc(alias = "gtk_tree_sortable_set_sort_func")]
125    fn set_sort_func<F>(&self, sort_column_id: SortColumn, sort_func: F)
126    where
127        F: Fn(&TreeModel, &TreeIter, &TreeIter) -> Ordering + 'static,
128    {
129        unsafe extern "C" fn trampoline<F: Fn(&TreeModel, &TreeIter, &TreeIter) -> Ordering>(
130            this: *mut GtkTreeModel,
131            iter: *mut GtkTreeIter,
132            iter2: *mut GtkTreeIter,
133            f: gpointer,
134        ) -> i32 {
135            let f: &F = &*(f as *const F);
136            f(
137                &TreeModel::from_glib_borrow(this),
138                &from_glib_borrow(iter),
139                &from_glib_borrow(iter2),
140            )
141            .into_glib()
142        }
143        unsafe extern "C" fn destroy_closure<
144            F: Fn(&TreeModel, &TreeIter, &TreeIter) -> Ordering,
145        >(
146            ptr: gpointer,
147        ) {
148            let _ = Box::<F>::from_raw(ptr as *mut _);
149        }
150        unsafe {
151            ffi::gtk_tree_sortable_set_sort_func(
152                self.as_ref().to_glib_none().0,
153                sort_column_id.into_glib(),
154                Some(trampoline::<F>),
155                into_raw(sort_func),
156                Some(destroy_closure::<F>),
157            )
158        }
159    }
160    /// Fills in `sort_column_id` and `order` with the current sort column and the
161    /// order. It returns [`true`] unless the `sort_column_id` is
162    /// `GTK_TREE_SORTABLE_DEFAULT_SORT_COLUMN_ID` or
163    /// `GTK_TREE_SORTABLE_UNSORTED_SORT_COLUMN_ID`.
164    ///
165    /// # Returns
166    ///
167    /// [`true`] if the sort column is not one of the special sort
168    ///  column ids.
169    ///
170    /// ## `sort_column_id`
171    /// The sort column id to be filled in
172    ///
173    /// ## `order`
174    /// The [`SortType`][crate::SortType] to be filled in
175    #[doc(alias = "get_sort_column_id")]
176    #[doc(alias = "gtk_tree_sortable_get_sort_column_id")]
177    fn sort_column_id(&self) -> Option<(SortColumn, SortType)> {
178        unsafe {
179            let mut sort_column_id = mem::MaybeUninit::uninit();
180            let mut order = mem::MaybeUninit::uninit();
181            ffi::gtk_tree_sortable_get_sort_column_id(
182                self.as_ref().to_glib_none().0,
183                sort_column_id.as_mut_ptr(),
184                order.as_mut_ptr(),
185            );
186            let sort_column_id = sort_column_id.assume_init();
187            if sort_column_id != ffi::GTK_TREE_SORTABLE_UNSORTED_SORT_COLUMN_ID {
188                Some((from_glib(sort_column_id), from_glib(order.assume_init())))
189            } else {
190                None
191            }
192        }
193    }
194    /// Sets the current sort column to be `sort_column_id`. The `self` will
195    /// resort itself to reflect this change, after emitting a
196    /// [`sort-column-changed`][struct@crate::TreeSortable#sort-column-changed] signal. `sort_column_id` may either be
197    /// a regular column id, or one of the following special values:
198    ///
199    /// - `GTK_TREE_SORTABLE_DEFAULT_SORT_COLUMN_ID`: the default sort function
200    ///  will be used, if it is set
201    ///
202    /// - `GTK_TREE_SORTABLE_UNSORTED_SORT_COLUMN_ID`: no sorting will occur
203    /// ## `sort_column_id`
204    /// the sort column id to set
205    /// ## `order`
206    /// The sort order of the column
207    #[doc(alias = "gtk_tree_sortable_set_sort_column_id")]
208    fn set_sort_column_id(&self, sort_column_id: SortColumn, order: SortType) {
209        unsafe {
210            ffi::gtk_tree_sortable_set_sort_column_id(
211                self.as_ref().to_glib_none().0,
212                sort_column_id.into_glib(),
213                order.into_glib(),
214            );
215        }
216    }
217    fn set_unsorted(&self) {
218        unsafe {
219            ffi::gtk_tree_sortable_set_sort_column_id(
220                self.as_ref().to_glib_none().0,
221                ffi::GTK_TREE_SORTABLE_UNSORTED_SORT_COLUMN_ID,
222                SortType::Ascending.into_glib(),
223            );
224        }
225    }
226}
227
228fn into_raw<F, T>(func: F) -> gpointer
229where
230    F: Fn(&T, &TreeIter, &TreeIter) -> Ordering + 'static,
231{
232    skip_assert_initialized!();
233    let func: Box<F> = Box::new(func);
234    Box::into_raw(func) as gpointer
235}
236
237impl<O: IsA<TreeSortable>> TreeSortableExtManual for O {}