1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
pub mod macros {
#[doc(hidden)]
#[macro_export]
macro_rules! __grade_find_builder_internal {
(AboutDialog) => {gtk::AboutDialogBuilder};
(AccelLabel) => {gtk::AccelLabelBuilder};
(ActionBar) => {gtk::ActionBarBuilder};
(AppChooserButton) => {gtk::AppChooserButtonBuilder};
(AppChooserDialog) => {gtk::AppChooserDialogBuilder};
(AppChooserWidget) => {gtk::AppChooserWidgetBuilder};
(Application) => {gtk::ApplicationBuilder};
(ApplicationWindow) => {gtk::ApplicationWindowBuilder};
(AspectFrame) => {gtk::AspectFrameBuilder};
(Assistant) => {gtk::AssistantBuilder};
(Box) => {gtk::BoxBuilder};
(Button) => {gtk::ButtonBuilder};
(ButtonBox) => {gtk::ButtonBoxBuilder};
(Calendear) => {gtk::CalendearBuilder};
(CellAreaBox) => {gtk::CellAreaBoxBuilder};
(CellRendererAccel) => {gtk::CellRendererAccelBuilder};
(CellRendererCombo) => {gtk::CellRendererComboBuilder};
(CellRendererPixbuf) => {gtk::CellRendererPixbufBuilder};
(CellRendererProgress) => {gtk::CellRendererProgressBuilder};
(CellRendererSpin) => {gtk::CellRendererSpinBuilder};
(CellRendererSpinner) => {gtk::CellRendererSpinnerBuilder};
(CellRendererText) => {gtk::CellRendererTextBuilder};
(CellRendererToggle) => {gtk::CellRendererToggleBuilder};
(CellView) => {gtk::CellViewBuilder};
(CheckButton) => {gtk::CheckButtonBuilder};
(CheckMenuItem) => {gtk::CheckMenuItemBuilder};
(ColorButton) => {gtk::ColorButtonBuilder};
(ColorChooserDialog) => {gtk::ColorChooserDialogBuilder};
(ColorChooserWidget) => {gtk::ColorChooserWidgetBuilder};
(ComboBox) => {gtk::ComboBoxBuilder};
(ComboBoxText) => {gtk::ComboBoxTextBuilder};
(Dialog) => {gtk::DialogBuilder};
(DrawingArea) => {gtk::DrawingAreaBuilder};
(Entry) => {gtk::EntryBuilder};
(EntryCompletion) => {gtk::EntryCompletionBuilder};
(EventBox) => {gtk::EventBoxBuilder};
(Expander) => {gtk::ExpanderBuilder};
(FileChooserButton) => {gtk::FileChooserButtonBuilder};
(FileChooserDialog) => {gtk::FileChooserDialogBuilder};
(FileChooserNative) => {gtk::FileChooserNativeBuilder};
(FileChooserWidget) => {gtk::FileChooserWidgetBuilder};
(FlowBox) => {gtk::FlowBoxBuilder};
(FlowBoxChild) => {gtk::FlowBoxChildBuilder};
(FontButtonBuilder) => {gtk::FontButtonBuilderBuilder};
(FontChooserDialog) => {gtk::FontChooserDialogBuilder};
(FontChooserWidget) => {gtk::FontChooserWidgetBuilder};
(Frame) => {gtk::FrameBuilder};
(GLArea) => {gtk::GLAreaBuilder};
(GestureDrag) => {gtk::GestureDragBuilder};
(GestureLongPress) => {gtk::GestureLongPressBuilder};
(GestureMultiPress) => {gtk::GestureMultiPressBuilder};
(GesturePan) => {gtk::GesturePanBuilder};
(GestureRotate) => {gtk::GestureRotateBuilder};
(GestureSwipe) => {gtk::GestureSwipeBuilder};
(GestureZoom) => {gtk::GestureZoomBuilder};
(Grid) => {gtk::GridBuilder};
(HeaderBar) => {gtk::HeaderBarBuilder};
(IMContextSimple) => {gtk::IMContextSimpleBuilder};
(IMMulticontext) => {gtk::IMMulticontextBuilder};
(Image) => {gtk::ImageBuilder};
(InfoBar) => {gtk::InfoBarBuilder};
(Invisible) => {gtk::InvisibleBuilder};
(Label) => {gtk::LabelBuilder};
(Layout) => {gtk::LayoutBuilder};
(LevelBar) => {gtk::LevelBarBuilder};
(LinkButton) => {gtk::LinkButtonBuilder};
(ListBox) => {gtk::ListBoxBuilder};
(ListBoxRow) => {gtk::ListBoxRowBuilder};
(LockButton) => {gtk::LockButtonBuilder};
(MenuBar) => {gtk::MenuBarBuilder};
(MenuButton) => {gtk::MenuButtonBuilder};
(MenuItem) => {gtk::MenuItemBuilder};
(MenuToolButton) => {gtk::MenuToolButtonBuilder};
(MessageDialog) => {gtk::MessageDialogBuilder};
(ModelButton) => {gtk::ModelButtonBuilder};
(MountOperation) => {gtk::MountOperationBuilder};
(Notenook) => {gtk::NotenookBuilder};
(OffscreenWindow) => {gtk::OffscreenWindowBuilder};
(Overlay) => {gtk::OverlayBuilder};
(PadController) => {gtk::PadControllerBuilder};
(Paned) => {gtk::PanedBuilder};
(PlacesSidebar) => {gtk::PlacesSidebarBuilder};
(Plug) => {gtk::PlugBuilder};
(Popover) => {gtk::PopoverBuilder};
(PopoverMenu) => {gtk::PopoverMenuBuilder};
(PrintOperation) => {gtk::PrintOperationBuilder};
(ProgressBar) => {gtk::ProgressBarBuilder};
(RadioButton) => {gtk::RadioButtonBuilder};
(RadioMenuItem) => {gtk::RadioMenuItemBuilder};
(RadioToolButton) => {gtk::RadioToolButtonBuilder};
(RecentChooserDialog) => {gtk::RecentChooserDialogBuilder};
(RecentChooserMenu) => {gtk::RecentChooserMenuBuilder};
(RecentChooserWidget) => {gtk::RecentChooserWidgetBuilder};
(RecentManager) => {gtk::RecentManagerBuilder};
(Revealer) => {gtk::RevealerBuilder};
(Scale) => {gtk::ScaleBuilder};
(ScaleButton) => {gtk::ScaleButtonBuilder};
(Scrollbar) => {gtk::ScrollbarBuilder};
(ScrolledWindow) => {gtk::ScrolledWindowBuilder};
(SearchBar) => {gtk::SearchBarBuilder};
(SearchEntry) => {gtk::SearchEntryBuilder};
(Separator) => {gtk::SeparatorBuilder};
(SeparatorMenuItem) => {gtk::SeparatorMenuItemBuilder};
(SeparatorToolItem) => {gtk::SeparatorToolItemBuilder};
(SizeGroup) => {gtk::SizeGroupBuilder};
(Socket) => {gtk::SocketBuilder};
(SpinButton) => {gtk::SpinButtonBuilder};
(Spinner) => {gtk::SpinnerBuilder};
(Stack) => {gtk::StackBuilder};
(StackSidebar) => {gtk::BuilderStackSidebar};
(StackSwitcher) => {gtk::StackSwitcherBuilder};
(Statusbar) => {gtk::StatusbarBuilder};
(StyleContext) => {gtk::StyleContextBuilder};
(Switch) => {gtk::SwitchBuilder};
(TextBuffer) => {gtk::TextBufferBuilder};
(TextTag) => {gtk::TextTagBuilder};
(TextView) => {gtk::TextViewBuilder};
(ToggleButton) => {gtk::ToggleButtonBuilder};
(ToggleToolButton) => {Tgtk::oggleToolButtonBuilder};
(ToolButton) => {gtk::ToolButtonBuilder};
(ToolItem) => {gtk::ToolItemBuilder};
(ToolItemGroup) => {gtk::ToolItemGroupBuilder};
(ToolPalette) => {gtk::ToolPaletteBuilder};
(Toolbar) => {gtk::ToolbarBuilder};
(TreeView) => {gtk::TreeViewBuilder};
(TreeViewColumn) => {gtk::TreeViewColumnBuilder};
(Viewport) => {gtk::ViewportBuilder};
(VolumeButton) => {gtk::VolumeButtonBuilder};
(Window) => {gtk::WindowBuilder};
}
#[doc(hidden)]
#[macro_export]
macro_rules! __grade_find_builder {
($n:ident:$p:ident) => {$crate::__grade_find_builder_internal!($p)};
($p:ident) => {$crate::__grade_find_builder_internal!($p)};
}
#[doc(hidden)]
#[macro_export]
macro_rules! __grade_link_to_name {
($n:ident:$p:ident, $parent:ident) => {let $n = & $parent;};
($p:ident, $parent:ident) => {};
}
#[macro_export]
macro_rules! __build_func {
($parent:ident, [$pack_func:ident $(,$pack_arg:expr)*], $child:ident$(:$child_alias:ident)? {$($child_body:tt)*}) => {
$parent.$pack_func(
& $crate::build! {$child$(:$child_alias)? {$($child_body)*}}.upcast::<gtk::Widget>(),
$($pack_arg),*
);
};
($parent:ident, $child:ident$(:$child_alias:ident)? {$($child_body:tt)*}) => {
$parent.add(
& build! { $child$(:$child_alias)? { $($child_body)* } }.upcast::<gtk::Widget>()
);
};
}
#[doc(hidden)]
#[macro_export]
macro_rules! __grade_connect_signal {
($grade_widget:ident, notify($field:ident), $callback:expr) => { let _ = $grade_widget.connect_notify(Some("$field"), $callback); };
($grade_widget:ident, $signal:path, $callback:expr) => { let _ =$grade_widget.connect("$signal", true, $callback);};
}
#[macro_export]
macro_rules! build {
{
$parent:ident$(:$parent_alias:ident)? {
$( $field:ident:$val:expr, )*
$( => $signal:path: $callback:expr, )*
$( -- $([$pack_func:ident $(,$pack_arg:expr)*])? $child:ident$(:$child_alias:ident)? {$($child_body:tt)*})*
$( .. $meth:ident($($meth_body:expr),*) )*
}
} => {
{
#[allow(unused_mut)] let mut builder = <$crate::__grade_find_builder!($parent$(:$parent_alias)?)>::new();
$(builder = builder.$field($val); )*
let grade_widget = builder.build();
$crate::__grade_link_to_name!($parent$(:$parent_alias)?, grade_widget);
$( $crate::__build_func!(grade_widget, $([$pack_func $(,$pack_arg)*],)? $child$(:$child_alias)? {$($child_body)*}); )*
$( grade_widget.$meth($($meth_body),*); )*
$( $crate::__grade_connect_signal!(grade_widget, $signal, $callback);)*
grade_widget
}
};
}
}
#[cfg(test)]
mod tests {
use gtk::*;
use pango::EllipsizeMode;
use crate::build;
macro_rules! assert_gtype {
($x:expr, $typ:ty) => (assert!($x.clone().dynamic_cast::<$typ>().is_ok()););
}
#[test]
fn inline_application() {
let app = Application::new(Some("com.github.grade.test.inline_application"), Default::default()).unwrap();
let grade_window = build! {
ApplicationWindow {
application: &app,
show_menubar: false,
default_height: 300,
default_width: 400,
=> show_menubar_notify: |_win| {None},
-- Viewport {
-- Grid {
hexpand: true,
vexpand: true,
-- [attach, 1, 3, 1, 1 ] _left_button:Button {
vexpand: true,
label: "Left",
name: "label_left",
}
-- [attach, 3, 3, 1, 1 ] _right_button:Button {
label: "Right",
name: "label_right",
}
-- [attach, 2, 3, 1, 1 ] Label {
label: "This is a Label, amazing!",
ellipsize: EllipsizeMode::End,
}
..attach(
& build! {
TextView {
buffer: & build! {
TextBuffer {
text: "This is a textview, look at it and despair!",
}
},
}
}.upcast::<Widget>(), 1+0, 1, 2+1, 1+1
)
}
}
..set_titlebar( Some( &build! {
HeaderBar {
title: "A grade test app",
-- [pack_start] Button {
label: "Start",
}
-- [pack_end] _end_button:Button {
label: "End",
}
}
}.upcast::<Widget>()))
}
};
assert_gtype!(&grade_window, ApplicationWindow);
let hbar = (&grade_window.get_titlebar().unwrap()).clone();
let grid = &grade_window.get_child().unwrap().downcast::<Viewport>().unwrap().get_child().unwrap().downcast::<Grid>().unwrap().clone();
let left_button = &grid.get_child_at(1,3).unwrap().downcast::<Button>().unwrap().clone();
let mid_label = &grid.get_child_at(2,3).unwrap().downcast::<Label>().unwrap().clone();
let right_button = &grid.get_child_at(3,3).unwrap().downcast::<Button>().unwrap().clone();
let tv = &grid.get_child_at(1,1).unwrap().downcast::<TextView>().unwrap().clone();
let (start_iter, end_iter) = &tv.get_buffer().unwrap().get_bounds();
assert_eq!(hbar.clone().downcast::<HeaderBar>().unwrap().get_children().len(), 2);
assert_eq!(hbar.clone().downcast::<HeaderBar>().unwrap().get_children()[0].clone().downcast::<Button>().unwrap().get_label().unwrap(), "Start");
assert_eq!(hbar.clone().downcast::<HeaderBar>().unwrap().get_children()[1].clone().downcast::<Button>().unwrap().get_label().unwrap(), "End");
assert_eq!(grid.get_children().len(), 4);
println!("{:?}", &grid);
assert_eq!(left_button.get_label().unwrap(),"Left");
assert_eq!(WidgetExt::get_name(left_button).unwrap(),"label_left");
assert_eq!(right_button.get_label().unwrap(),"Right");
assert_eq!(WidgetExt::get_name(right_button).unwrap(),"label_right");
assert_eq!(mid_label.get_label().unwrap(), "This is a Label, amazing!");
assert_eq!(mid_label.get_ellipsize(), EllipsizeMode::End);
assert_eq!(grid.get_cell_height(&left_button.clone()), 1);
assert_eq!(grid.get_cell_height(&right_button.clone()), 1);
assert_eq!(grid.get_cell_height(&mid_label.clone()), 1);
assert_eq!(grid.get_cell_height(&tv.clone()), 2);
assert_eq!(grid.get_cell_width(&left_button.clone()), 1);
assert_eq!(grid.get_cell_width(&right_button.clone()), 1);
assert_eq!(grid.get_cell_width(&mid_label.clone()), 1);
assert_eq!(grid.get_cell_width(&tv.clone()), 3);
assert_eq!(tv.get_buffer().unwrap().get_text(start_iter, end_iter, true).unwrap(), "This is a textview, look at it and despair!");
}
}