1mod container;
2mod iter_children;
3mod object_ext;
4mod remove;
5mod set_child;
6
7#[cfg(test)]
8mod tests;
9mod widget_ext;
10
11pub use container::RelmContainerExt;
12pub use iter_children::RelmIterChildrenExt;
13pub use object_ext::RelmObjectExt;
14pub use remove::{RelmRemoveAllExt, RelmRemoveExt};
15pub use set_child::RelmSetChildExt;
16pub use widget_ext::RelmWidgetExt;
17
18use gtk::prelude::{
19 ApplicationExt, ApplicationExtManual, Cast, IsA, ListBoxRowExt, StaticType, WidgetExt,
20};
21
22pub trait WidgetRef {
27 fn widget_ref(&self) -> >k::Widget;
31}
32
33impl<T: AsRef<gtk::Widget>> WidgetRef for T {
34 fn widget_ref(&self) -> >k::Widget {
35 self.as_ref()
36 }
37}
38
39pub trait WidgetTemplate:
44 Sized + std::fmt::Debug + AsRef<Self::Root> + std::ops::Deref<Target = Self::Root>
45{
46 type Root;
48
49 type Init;
51
52 fn init(init: Self::Init) -> Self;
54}
55
56pub trait ApplicationBuilderExt {
58 fn launch<F>(self, init: F)
60 where
61 F: Fn(gtk::Application, gtk::ApplicationWindow) + 'static;
62}
63
64impl ApplicationBuilderExt for gtk::builders::ApplicationBuilder {
65 fn launch<F>(self, init: F)
66 where
67 F: Fn(gtk::Application, gtk::ApplicationWindow) + 'static,
68 {
69 let app = self.build();
70
71 app.connect_activate(move |app| {
72 let window = gtk::ApplicationWindow::new(app);
73
74 init(app.clone(), window.clone());
75
76 window.set_visible(true);
77 });
78
79 app.run();
80 }
81}
82
83pub trait RelmListBoxExt {
85 fn index_of_child(&self, widget: &impl AsRef<gtk::Widget>) -> Option<i32>;
87
88 fn remove_row_of_child(&self, widget: &impl AsRef<gtk::Widget>);
90
91 fn row_of_child(&self, widget: &impl AsRef<gtk::Widget>) -> Option<gtk::ListBoxRow>;
93}
94
95impl RelmListBoxExt for gtk::ListBox {
96 fn index_of_child(&self, widget: &impl AsRef<gtk::Widget>) -> Option<i32> {
97 self.row_of_child(widget).map(|row| row.index())
98 }
99
100 fn remove_row_of_child(&self, widget: &impl AsRef<gtk::Widget>) {
101 if let Some(row) = self.row_of_child(widget) {
102 row.set_child(None::<>k::Widget>);
103 self.remove(&row);
104 }
105 }
106
107 fn row_of_child(&self, widget: &impl AsRef<gtk::Widget>) -> Option<gtk::ListBoxRow> {
108 if let Some(row) = widget.as_ref().ancestor(gtk::ListBoxRow::static_type()) {
109 if let Some(row) = row.downcast_ref::<gtk::ListBoxRow>() {
110 if let Some(parent_widget) = row.parent() {
111 if let Some(parent_box) = parent_widget.downcast_ref::<Self>() {
112 if parent_box == self {
113 return Some(row.clone());
114 }
115 }
116 }
117 }
118 }
119
120 None
121 }
122}
123
124pub trait ContainerChild {
133 type Child: IsA<gtk::Widget>;
135}
136
137macro_rules! container_child_impl {
138 ($($type:ty: $child:ty), +) => {
139 $(
140 impl ContainerChild for $type {
141 type Child = $child;
142 }
143 )+
144 };
145 ($($type:ty), +) => {
146 $(
147 #[allow(deprecated)]
148 impl ContainerChild for $type {
149 type Child = gtk::Widget;
150 }
151 )+
152 };
153}
154
155container_child_impl! {
156 gtk::Box,
157 gtk::Fixed,
158 gtk::Grid,
159 gtk::ActionBar,
160 gtk::Stack,
161 gtk::HeaderBar,
162 gtk::InfoBar,
163 gtk::Button,
164 gtk::ComboBox,
165 gtk::FlowBoxChild,
166 gtk::Frame,
167 gtk::Popover,
168 gtk::Window,
169 gtk::ApplicationWindow,
170 gtk::ListBoxRow,
171 gtk::ScrolledWindow,
172 gtk::Dialog,
173 gtk::LinkButton,
174 gtk::ToggleButton,
175 gtk::Overlay,
176 gtk::Revealer,
177 gtk::WindowHandle,
178 gtk::Expander,
179 gtk::AspectFrame
180}
181
182container_child_impl! {
183 gtk::ListBox: gtk::ListBoxRow,
184 gtk::FlowBox: gtk::FlowBoxChild
185}
186
187#[cfg(feature = "libadwaita")]
188#[cfg_attr(docsrs, doc(cfg(feature = "libadwaita")))]
189mod libadwaita {
190 use super::ContainerChild;
191
192 container_child_impl! {
193 adw::TabView,
194 adw::Window,
195 adw::Bin,
196 adw::ApplicationWindow,
197 adw::Clamp,
198 adw::ClampScrollable,
199 adw::SplitButton,
200 adw::StatusPage,
201 adw::PreferencesGroup,
202 adw::ToastOverlay,
203 adw::ExpanderRow,
204 adw::Carousel,
205 adw::Squeezer,
206 adw::Leaflet
207 }
208 container_child_impl! {
209 adw::PreferencesPage: adw::PreferencesGroup
210 }
211
212 #[cfg(all(feature = "libadwaita", feature = "gnome_45"))]
213 mod gnome_45 {
214 use super::ContainerChild;
215
216 container_child_impl! {
217 adw::NavigationView: adw::NavigationPage,
218 adw::NavigationSplitView: adw::NavigationPage
219 }
220 container_child_impl! {
221 adw::NavigationPage,
222 adw::BreakpointBin,
223 adw::OverlaySplitView,
224 adw::ToolbarView
225 }
226 }
227}