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 && let Some(row) = row.downcast_ref::<gtk::ListBoxRow>()
110 && let Some(parent_widget) = row.parent()
111 && let Some(parent_box) = parent_widget.downcast_ref::<Self>()
112 && parent_box == self
113 {
114 return Some(row.clone());
115 }
116
117 None
118 }
119}
120
121pub trait ContainerChild {
130 type Child: IsA<gtk::Widget>;
132}
133
134macro_rules! container_child_impl {
135 ($($type:ty: $child:ty), +) => {
136 $(
137 impl ContainerChild for $type {
138 type Child = $child;
139 }
140 )+
141 };
142 ($($type:ty), +) => {
143 $(
144 #[allow(deprecated)]
145 impl ContainerChild for $type {
146 type Child = gtk::Widget;
147 }
148 )+
149 };
150}
151
152container_child_impl! {
153 gtk::Box,
154 gtk::Fixed,
155 gtk::Grid,
156 gtk::ActionBar,
157 gtk::Stack,
158 gtk::HeaderBar,
159 gtk::InfoBar,
160 gtk::Button,
161 gtk::ComboBox,
162 gtk::FlowBox,
163 gtk::FlowBoxChild,
164 gtk::Frame,
165 gtk::Popover,
166 gtk::Window,
167 gtk::ApplicationWindow,
168 gtk::ListBox,
169 gtk::ListBoxRow,
170 gtk::ScrolledWindow,
171 gtk::Dialog,
172 gtk::LinkButton,
173 gtk::ToggleButton,
174 gtk::Overlay,
175 gtk::Revealer,
176 gtk::WindowHandle,
177 gtk::Expander,
178 gtk::AspectFrame
179}
180
181#[cfg(feature = "libadwaita")]
182#[cfg_attr(docsrs, doc(cfg(feature = "libadwaita")))]
183mod libadwaita {
184 use super::ContainerChild;
185
186 container_child_impl! {
187 adw::TabView,
188 adw::Window,
189 adw::Bin,
190 adw::ApplicationWindow,
191 adw::Clamp,
192 adw::ClampScrollable,
193 adw::SplitButton,
194 adw::StatusPage,
195 adw::PreferencesGroup,
196 adw::ToastOverlay,
197 adw::ExpanderRow,
198 adw::Carousel,
199 adw::Squeezer,
200 adw::Leaflet
201 }
202 container_child_impl! {
203 adw::PreferencesPage: adw::PreferencesGroup
204 }
205
206 #[cfg(all(feature = "libadwaita", feature = "gnome_45"))]
207 mod gnome_45 {
208 use super::ContainerChild;
209
210 container_child_impl! {
211 adw::NavigationView: adw::NavigationPage,
212 adw::NavigationSplitView: adw::NavigationPage
213 }
214 container_child_impl! {
215 adw::NavigationPage,
216 adw::BreakpointBin,
217 adw::OverlaySplitView,
218 adw::ToolbarView
219 }
220 }
221}
222
223#[cfg(feature = "libpanel")]
224#[cfg_attr(docsrs, doc(cfg(feature = "libpanel")))]
225mod libpanel {
226 use super::ContainerChild;
227 container_child_impl! {
228 panel::Frame: panel::Widget
229 }
230 container_child_impl! {
231 panel::Paned,
232 panel::Widget
233 }
234}