///|
priv enum IWidget {
IWindow(win~ : @gtk.Window, child~ : Ref[IWidget])
IBox(
gtk_box~ : @gtk.Box,
children~ : Ref[Array[IWidget]],
css_classes~ : Ref[Array[String]]
)
IButton(
button~ : @gtk.Button,
on_clicked~ : Ref[() -> Unit],
css_classes~ : Ref[Array[String]]
)
ILabel(label~ : @gtk.Label, css_classes~ : Ref[Array[String]])
IEntry(
entry~ : @gtk.Entry,
last_text~ : Ref[String],
on_changed~ : Ref[(String) -> Unit],
on_activate~ : Ref[(() -> Unit)?],
updating~ : Ref[Bool]
)
IAdwApplicationWindow(win~ : @adw.ApplicationWindow, content~ : Ref[IWidget])
IAdwToolbarView(
view~ : @adw.ToolbarView,
top_bar~ : Ref[IWidget?],
bottom_bar~ : Ref[IWidget?],
content~ : Ref[IWidget]
)
IAdwHeaderBar(
header_bar~ : @adw.HeaderBar,
title_widget~ : Ref[IWidget?],
start~ : Ref[Array[IWidget]],
end~ : Ref[Array[IWidget]]
)
IScrolledWindow(sw~ : @gtk.ScrolledWindow, child~ : Ref[IWidget])
IListBox(
list_box~ : @gtk.ListBox,
children~ : Ref[Map[String, IWidget]],
css_classes~ : Ref[Array[String]]
)
ICheckButton(
check_button~ : @gtk.CheckButton,
on_toggled~ : Ref[(Bool) -> Unit],
last_active~ : Ref[Bool]
)
IAdwClamp(clamp~ : @adw.Clamp, child~ : Ref[IWidget])
IAdwActionRow(
action_row~ : @adw.ActionRow,
prefix~ : Ref[Array[IWidget]],
suffix~ : Ref[Array[IWidget]]
)
ISeparator(sep~ : @gtk.Separator)
IAdwNavigationSplitView(
split_view~ : @adw.NavigationSplitView,
sidebar_page~ : @adw.NavigationPage,
content_page~ : @adw.NavigationPage,
sidebar~ : Ref[IWidget],
content~ : Ref[IWidget]
)
}
///|
fn IWidget::gtk_widget(self : IWidget) -> @gtk.Widget {
match self {
IWindow(win~, ..) => win.as_widget()
IBox(gtk_box~, ..) => gtk_box.as_widget()
IButton(button~, ..) => button.as_widget()
ILabel(label~, ..) => label.as_widget()
IEntry(entry~, ..) => entry.as_widget()
IAdwApplicationWindow(win~, ..) => win.as_gtk_widget()
IAdwToolbarView(view~, ..) => view.as_gtk_widget()
IAdwHeaderBar(header_bar~, ..) => header_bar.as_gtk_widget()
IScrolledWindow(sw~, ..) => sw.as_widget()
IListBox(list_box~, ..) => list_box.as_widget()
ICheckButton(check_button~, ..) => check_button.as_widget()
IAdwClamp(clamp~, ..) => clamp.as_gtk_widget()
IAdwActionRow(action_row~, ..) => action_row.as_gtk_widget()
ISeparator(sep~) => sep.as_widget()
IAdwNavigationSplitView(split_view~, ..) => split_view.as_gtk_widget()
}
}
///|
fn IWidget::destroy(self : IWidget) -> Unit {
match self {
IWindow(win~, child~) => {
child.val.destroy()
win.destroy()
}
IBox(children~, ..) =>
for c in children.val {
c.destroy()
}
IButton(_) | ILabel(..) | IEntry(..) | ICheckButton(_) | ISeparator(_) => ()
IAdwApplicationWindow(win~, content~) => {
content.val.destroy()
win.destroy()
}
IAdwToolbarView(top_bar~, bottom_bar~, content~, ..) => {
if top_bar.val is Some(w) {
w.destroy()
}
if bottom_bar.val is Some(w) {
w.destroy()
}
content.val.destroy()
}
IAdwHeaderBar(title_widget~, start~, end~, ..) => {
if title_widget.val is Some(w) {
w.destroy()
}
for w in start.val {
w.destroy()
}
for w in end.val {
w.destroy()
}
}
IScrolledWindow(child~, ..) => child.val.destroy()
IListBox(children~, ..) =>
for _, c in children.val {
c.destroy()
}
IAdwClamp(child~, ..) => child.val.destroy()
IAdwActionRow(prefix~, suffix~, ..) => {
for w in prefix.val {
w.destroy()
}
for w in suffix.val {
w.destroy()
}
}
IAdwNavigationSplitView(sidebar~, content~, ..) => {
sidebar.val.destroy()
content.val.destroy()
}
}
}
///|
fn[Message] VWidget::create(
self : VWidget[Message],
app : @gtk.Application,
dispatch : (Message) -> Unit,
) -> IWidget {
match self {
Window(title~, default_width~, default_height~, child~) =>
create_window(app, dispatch, title, default_width, default_height, child)
Box(
orientation~,
spacing~,
margin_top~,
margin_bottom~,
margin_start~,
margin_end~,
halign~,
css_classes~,
children~
) =>
create_box(
app, dispatch, orientation, spacing, margin_top, margin_bottom, margin_start,
margin_end, halign, css_classes, children,
)
Button(label~, icon_name~, css_classes~, on_clicked~) =>
create_button(dispatch, label, icon_name, css_classes, on_clicked)
Label(
text~,
markup~,
wrap~,
selectable~,
xalign~,
max_width_chars~,
css_classes~
) =>
create_label(
text, markup, wrap, selectable, xalign, max_width_chars, css_classes,
)
Entry(text~, placeholder~, hexpand~, on_changed~, on_activate~) =>
create_entry(
dispatch, text, placeholder, hexpand, on_changed, on_activate,
)
AdwApplicationWindow(title~, default_width~, default_height~, content~) =>
create_adw_application_window(
app, dispatch, title, default_width, default_height, content,
)
AdwToolbarView(top_bar~, bottom_bar~, content~) =>
create_adw_toolbar_view(app, dispatch, top_bar, bottom_bar, content)
AdwHeaderBar(title_widget~, start~, end~) =>
create_adw_header_bar(app, dispatch, title_widget, start, end)
ScrolledWindow(hscrollbar_policy~, vscrollbar_policy~, vexpand~, child~) =>
create_scrolled_window(
app, dispatch, hscrollbar_policy, vscrollbar_policy, vexpand, child,
)
ListBox(css_classes~, children~) =>
create_list_box(app, dispatch, css_classes, children)
CheckButton(active~, on_toggled~) =>
create_check_button(dispatch, active, on_toggled)
AdwClamp(maximum_size~, child~) =>
create_adw_clamp(app, dispatch, maximum_size, child)
AdwActionRow(title~, subtitle~, prefix~, suffix~) =>
create_adw_action_row(app, dispatch, title, subtitle, prefix, suffix)
Separator(orientation~) => create_separator(orientation)
AdwNavigationSplitView(
sidebar~,
sidebar_title~,
content~,
content_title~,
min_sidebar_width~,
max_sidebar_width~,
sidebar_width_fraction~
) =>
create_adw_navigation_split_view(
app, dispatch, sidebar, sidebar_title, content, content_title, min_sidebar_width,
max_sidebar_width, sidebar_width_fraction,
)
}
}
///|
fn[Message] create_window(
app : @gtk.Application,
dispatch : (Message) -> Unit,
title : String,
default_width : Int,
default_height : Int,
child : VWidget[Message],
) -> IWidget {
let win = @gtk.Window::new()
win.set_application(Some(app))
win.set_title(Some(title))
win.set_default_size(default_width, default_height)
win.connect_destroy(_ => app.quit()) |> ignore()
let child_iwidget = child.create(app, dispatch)
win.set_child(Some(child_iwidget.gtk_widget()))
win.present()
IWindow(win~, child=Ref(child_iwidget))
}
///|
fn[Message] create_box(
app : @gtk.Application,
dispatch : (Message) -> Unit,
orientation : Orientation,
spacing : Int,
margin_top : Int,
margin_bottom : Int,
margin_start : Int,
margin_end : Int,
halign : Align?,
css_classes : Array[String],
children : Array[VWidget[Message]],
) -> IWidget {
let b = @gtk.Box::new(orientation.to_gtk(), spacing)
b.set_margin_top(margin_top)
b.set_margin_bottom(margin_bottom)
b.set_margin_start(margin_start)
b.set_margin_end(margin_end)
if halign is Some(a) {
b.as_widget().set_halign(a.to_gtk())
}
for cls in css_classes {
b.as_widget().add_css_class(cls)
}
let child_widgets = children.map(fn(c) {
let ci = c.create(app, dispatch)
b.append(ci.gtk_widget())
ci
})
IBox(gtk_box=b, children=Ref(child_widgets), css_classes=Ref(css_classes))
}
///|
fn[Message] create_button(
dispatch : (Message) -> Unit,
label : String,
icon_name : String,
css_classes : Array[String],
on_clicked : Message,
) -> IWidget {
let button = if icon_name != "" {
@gtk.Button::new_from_icon_name(icon_name)
} else {
@gtk.Button::new_with_label(label)
}
for cls in css_classes {
button.as_widget().add_css_class(cls)
}
let on_clicked_ref : Ref[() -> Unit] = Ref(fn() { dispatch(on_clicked) })
button.connect_clicked(_ => (on_clicked_ref.val)()) |> ignore()
IButton(button~, on_clicked=on_clicked_ref, css_classes=Ref(css_classes))
}
///|
fn create_label(
text : String,
markup : Bool,
wrap : Bool,
selectable : Bool,
xalign : Double,
max_width_chars : Int,
css_classes : Array[String],
) -> IWidget {
let label = @gtk.Label::new(None)
if markup {
label.set_markup(text)
} else {
label.set_text(text)
}
label.set_wrap(wrap)
label.set_selectable(selectable)
label.set_xalign(Float::from_double(xalign))
if max_width_chars >= 0 {
label.set_max_width_chars(max_width_chars)
}
for cls in css_classes {
label.as_widget().add_css_class(cls)
}
ILabel(label~, css_classes=Ref(css_classes))
}
///|
fn[Message] create_entry(
dispatch : (Message) -> Unit,
text : String,
placeholder : String,
hexpand : Bool,
on_changed : (String) -> Message,
on_activate : Message?,
) -> IWidget {
let entry = @gtk.Entry::new()
entry.as_editable().set_text(text)
entry.set_placeholder_text(Some(placeholder))
if hexpand {
entry.as_widget().set_hexpand(true)
}
let handler : Ref[(String) -> Unit] = Ref(fn(t) { dispatch(on_changed(t)) })
let activate_handler : Ref[(() -> Unit)?] = Ref(
on_activate.map(fn(msg) { fn() { dispatch(msg) } }),
)
let last_text : Ref[String] = Ref(text)
let updating : Ref[Bool] = Ref(false)
let buf = entry.get_buffer()
let _ = buf.connect_inserted_text(fn(buf, _, _, _) {
if updating.val {
return
}
let t = buf.get_text()
last_text.val = t
(handler.val)(t)
})
let _ = buf.connect_deleted_text(fn(buf, _, _) {
if updating.val {
return
}
let t = buf.get_text()
last_text.val = t
(handler.val)(t)
})
let _ = entry.connect_activate(fn(_) {
match activate_handler.val {
Some(f) => f()
None => ()
}
})
IEntry(
entry~,
last_text~,
on_changed=handler,
on_activate=activate_handler,
updating~,
)
}
///|
fn[Message] create_adw_application_window(
app : @gtk.Application,
dispatch : (Message) -> Unit,
title : String,
default_width : Int,
default_height : Int,
content : VWidget[Message],
) -> IWidget {
let win = @adw.ApplicationWindow::new(app)
win.set_title(Some(title))
win.set_default_size(default_width, default_height)
win.connect_destroy(_ => app.quit()) |> ignore()
let content_iw = content.create(app, dispatch)
win.set_content(Some(content_iw.gtk_widget()))
win.present()
IAdwApplicationWindow(win~, content=Ref(content_iw))
}
///|
fn[Message] create_adw_toolbar_view(
app : @gtk.Application,
dispatch : (Message) -> Unit,
top_bar : VWidget[Message]?,
bottom_bar : VWidget[Message]?,
content : VWidget[Message],
) -> IWidget {
let view = @adw.ToolbarView::new()
let top_iw = match top_bar {
Some(v) => {
let i = v.create(app, dispatch)
view.add_top_bar(i.gtk_widget())
Some(i)
}
None => None
}
let bottom_iw = match bottom_bar {
Some(v) => {
let i = v.create(app, dispatch)
view.add_bottom_bar(i.gtk_widget())
Some(i)
}
None => None
}
let content_iw = content.create(app, dispatch)
view.set_content(Some(content_iw.gtk_widget()))
IAdwToolbarView(
view~,
top_bar=Ref(top_iw),
bottom_bar=Ref(bottom_iw),
content=Ref(content_iw),
)
}
///|
fn[Message] create_adw_header_bar(
app : @gtk.Application,
dispatch : (Message) -> Unit,
title_widget : VWidget[Message]?,
start : Array[VWidget[Message]],
end : Array[VWidget[Message]],
) -> IWidget {
let header_bar = @adw.HeaderBar::new()
let title_iw = match title_widget {
Some(v) => {
let i = v.create(app, dispatch)
header_bar.set_title_widget(Some(i.gtk_widget()))
Some(i)
}
None => None
}
let start_iw = start.map(fn(v) {
let i = v.create(app, dispatch)
header_bar.pack_start(i.gtk_widget())
i
})
let end_iw = end.map(fn(v) {
let i = v.create(app, dispatch)
header_bar.pack_end(i.gtk_widget())
i
})
IAdwHeaderBar(
header_bar~,
title_widget=Ref(title_iw),
start=Ref(start_iw),
end=Ref(end_iw),
)
}
///|
fn[Message] create_scrolled_window(
app : @gtk.Application,
dispatch : (Message) -> Unit,
hscrollbar_policy : @gtk.PolicyType,
vscrollbar_policy : @gtk.PolicyType,
vexpand : Bool,
child : VWidget[Message],
) -> IWidget {
let sw = @gtk.ScrolledWindow::new()
sw.set_policy(hscrollbar_policy, vscrollbar_policy)
if vexpand {
sw.as_widget().set_vexpand(true)
}
let child_iw = child.create(app, dispatch)
sw.set_child(Some(child_iw.gtk_widget()))
IScrolledWindow(sw~, child=Ref(child_iw))
}
///|
fn[Message] create_list_box(
app : @gtk.Application,
dispatch : (Message) -> Unit,
css_classes : Array[String],
children : Map[String, VWidget[Message]],
) -> IWidget {
let lb = @gtk.ListBox::new()
lb.set_selection_mode(@gtk.SelectionMode::None)
for cls in css_classes {
lb.as_widget().add_css_class(cls)
}
let child_widgets : Map[String, IWidget] = Map([])
for key, c in children {
let ci = c.create(app, dispatch)
lb.append(ci.gtk_widget())
child_widgets[key] = ci
}
IListBox(
list_box=lb,
children=Ref(child_widgets),
css_classes=Ref(css_classes),
)
}
///|
fn[Message] create_check_button(
dispatch : (Message) -> Unit,
active : Bool,
on_toggled : (Bool) -> Message,
) -> IWidget {
let cb = @gtk.CheckButton::new()
cb.set_active(active)
let handler : Ref[(Bool) -> Unit] = Ref(fn(a) { dispatch(on_toggled(a)) })
let last_active : Ref[Bool] = Ref(active)
cb.connect_toggled(fn(cb) {
let a = cb.get_active()
last_active.val = a
(handler.val)(a)
})
|> ignore()
ICheckButton(check_button=cb, on_toggled=handler, last_active~)
}
///|
fn[Message] create_adw_clamp(
app : @gtk.Application,
dispatch : (Message) -> Unit,
maximum_size : Int,
child : VWidget[Message],
) -> IWidget {
let clamp = @adw.Clamp::new()
clamp.set_maximum_size(maximum_size)
let child_iw = child.create(app, dispatch)
clamp.set_child(Some(child_iw.gtk_widget()))
IAdwClamp(clamp~, child=Ref(child_iw))
}
///|
fn[Message] create_adw_action_row(
app : @gtk.Application,
dispatch : (Message) -> Unit,
title : String,
subtitle : String,
prefix : Array[VWidget[Message]],
suffix : Array[VWidget[Message]],
) -> IWidget {
let row = @adw.ActionRow::new()
row.as_preferences_row().set_title(title)
row.set_subtitle(subtitle)
let prefix_iw = prefix.map(fn(v) {
let i = v.create(app, dispatch)
row.add_prefix(i.gtk_widget())
i
})
let suffix_iw = suffix.map(fn(v) {
let i = v.create(app, dispatch)
row.add_suffix(i.gtk_widget())
i
})
IAdwActionRow(action_row=row, prefix=Ref(prefix_iw), suffix=Ref(suffix_iw))
}
///|
fn create_separator(orientation : Orientation) -> IWidget {
ISeparator(sep=@gtk.Separator::new(orientation.to_gtk()))
}
///|
fn[Message] create_adw_navigation_split_view(
app : @gtk.Application,
dispatch : (Message) -> Unit,
sidebar : VWidget[Message],
sidebar_title : String,
content : VWidget[Message],
content_title : String,
min_sidebar_width : Double,
max_sidebar_width : Double,
sidebar_width_fraction : Double,
) -> IWidget {
let sidebar_iw = sidebar.create(app, dispatch)
let sidebar_page = @adw.NavigationPage::new(
sidebar_iw.gtk_widget(),
sidebar_title,
)
let content_iw = content.create(app, dispatch)
let content_page = @adw.NavigationPage::new(
content_iw.gtk_widget(),
content_title,
)
let split_view = @adw.NavigationSplitView::new()
split_view.set_min_sidebar_width(min_sidebar_width)
split_view.set_max_sidebar_width(max_sidebar_width)
split_view.set_sidebar_width_fraction(sidebar_width_fraction)
split_view.set_sidebar(sidebar_page)
split_view.set_content(content_page)
IAdwNavigationSplitView(
split_view~,
sidebar_page~,
content_page~,
sidebar=Ref(sidebar_iw),
content=Ref(content_iw),
)
}
///|
fn[Message] reconcile_optional_child(
app : @gtk.Application,
dispatch : (Message) -> Unit,
old_child : IWidget?,
new_child : VWidget[Message]?,
remove~ : (IWidget) -> Unit,
add~ : (IWidget) -> Unit,
) -> IWidget? {
match (old_child, new_child) {
(Some(old), Some(new)) =>
match old.reconcile(new, app, dispatch) {
Some(updated) => Some(updated)
None => {
remove(old)
old.destroy()
let w = new.create(app, dispatch)
add(w)
Some(w)
}
}
(Some(old), None) => {
remove(old)
old.destroy()
None
}
(None, Some(new)) => {
let w = new.create(app, dispatch)
add(w)
Some(w)
}
(None, None) => None
}
}
///|
fn[Message] IWidget::reconcile(
self : IWidget,
widget : VWidget[Message],
app : @gtk.Application,
dispatch : (Message) -> Unit,
) -> IWidget? {
match (self, widget) {
(
IWindow(win~, child~) as iw,
Window(title~, default_width~, default_height~, child=new_child),
) => {
win.set_title(Some(title))
win.set_default_size(default_width, default_height)
let new_child_iw = reconcile_widget(app, dispatch, child.val, new_child)
win.set_child(Some(new_child_iw.gtk_widget()))
child.val = new_child_iw
Some(iw)
}
(
IBox(gtk_box~, children~, css_classes~) as ib,
Box(
orientation=_,
spacing=_,
margin_top~,
margin_bottom~,
margin_start~,
margin_end~,
halign~,
css_classes=new_css_classes,
children=new_children
),
) => {
gtk_box.set_margin_top(margin_top)
gtk_box.set_margin_bottom(margin_bottom)
gtk_box.set_margin_start(margin_start)
gtk_box.set_margin_end(margin_end)
match halign {
Some(a) => gtk_box.as_widget().set_halign(a.to_gtk())
None => gtk_box.as_widget().set_halign(@gtk.Align::Fill)
}
for cls in css_classes.val {
gtk_box.as_widget().remove_css_class(cls)
}
for cls in new_css_classes {
gtk_box.as_widget().add_css_class(cls)
}
css_classes.val = new_css_classes
children.val = reconcile_array(
app,
dispatch,
children.val,
new_children,
remove=fn(w) { gtk_box.remove(w.gtk_widget()) },
append=fn(w) { gtk_box.append(w.gtk_widget()) },
)
Some(ib)
}
(
IButton(button~, on_clicked~, css_classes~) as ib,
Button(
label~,
icon_name~,
css_classes=new_css_classes,
on_clicked=new_on_clicked
),
) => {
if icon_name != "" {
button.set_icon_name(icon_name)
} else {
button.set_label(label)
}
for cls in css_classes.val {
button.as_widget().remove_css_class(cls)
}
for cls in new_css_classes {
button.as_widget().add_css_class(cls)
}
css_classes.val = new_css_classes
on_clicked.val = fn() { dispatch(new_on_clicked) }
Some(ib)
}
(
ILabel(label~, css_classes~) as il,
Label(
text~,
markup~,
wrap~,
selectable~,
xalign~,
max_width_chars~,
css_classes=new_css_classes
),
) => {
if markup {
label.set_markup(text)
} else {
label.set_text(text)
}
label.set_wrap(wrap)
label.set_selectable(selectable)
label.set_xalign(Float::from_double(xalign))
if max_width_chars >= 0 {
label.set_max_width_chars(max_width_chars)
}
for cls in css_classes.val {
label.as_widget().remove_css_class(cls)
}
for cls in new_css_classes {
label.as_widget().add_css_class(cls)
}
css_classes.val = new_css_classes
Some(il)
}
(
IEntry(entry~, last_text~, on_changed~, on_activate~, updating~) as ie,
Entry(
text~,
placeholder~,
hexpand=_,
on_changed=new_on_changed,
on_activate=new_on_activate
),
) => {
if last_text.val != text {
updating.val = true
entry.get_buffer().set_text(text, -1)
updating.val = false
last_text.val = text
}
entry.set_placeholder_text(Some(placeholder))
on_changed.val = fn(t) { dispatch(new_on_changed(t)) }
on_activate.val = new_on_activate.map(fn(msg) { fn() { dispatch(msg) } })
Some(ie)
}
(
IAdwApplicationWindow(win~, content~) as iw,
AdwApplicationWindow(
title~,
default_width~,
default_height~,
content=new_content
),
) => {
win.set_title(Some(title))
win.set_default_size(default_width, default_height)
let new_content_iw = reconcile_widget(
app,
dispatch,
content.val,
new_content,
)
win.set_content(Some(new_content_iw.gtk_widget()))
content.val = new_content_iw
Some(iw)
}
(
IAdwToolbarView(view~, top_bar~, bottom_bar~, content~) as iv,
AdwToolbarView(
top_bar=new_top,
bottom_bar=new_bottom,
content=new_content
),
) => {
top_bar.val = reconcile_optional_child(
app,
dispatch,
top_bar.val,
new_top,
remove=fn(w) { view.remove(w.gtk_widget()) },
add=fn(w) { view.add_top_bar(w.gtk_widget()) },
)
bottom_bar.val = reconcile_optional_child(
app,
dispatch,
bottom_bar.val,
new_bottom,
remove=fn(w) { view.remove(w.gtk_widget()) },
add=fn(w) { view.add_bottom_bar(w.gtk_widget()) },
)
let new_content_iw = reconcile_widget(
app,
dispatch,
content.val,
new_content,
)
view.set_content(Some(new_content_iw.gtk_widget()))
content.val = new_content_iw
Some(iv)
}
(
IAdwHeaderBar(header_bar~, title_widget~, start~, end~) as ih,
AdwHeaderBar(title_widget=new_title, start=new_start, end=new_end),
) => {
title_widget.val = reconcile_optional_child(
app,
dispatch,
title_widget.val,
new_title,
remove=fn(_) { header_bar.set_title_widget(None) },
add=fn(w) { header_bar.set_title_widget(Some(w.gtk_widget())) },
)
start.val = reconcile_array(
app,
dispatch,
start.val,
new_start,
remove=fn(w) { header_bar.remove(w.gtk_widget()) },
append=fn(w) { header_bar.pack_start(w.gtk_widget()) },
)
end.val = reconcile_array(
app,
dispatch,
end.val,
new_end,
remove=fn(w) { header_bar.remove(w.gtk_widget()) },
append=fn(w) { header_bar.pack_end(w.gtk_widget()) },
)
Some(ih)
}
(
IScrolledWindow(sw~, child~) as isw,
ScrolledWindow(
hscrollbar_policy~,
vscrollbar_policy~,
vexpand=_,
child=new_child
),
) => {
sw.set_policy(hscrollbar_policy, vscrollbar_policy)
let new_child_iw = reconcile_widget(app, dispatch, child.val, new_child)
sw.set_child(Some(new_child_iw.gtk_widget()))
child.val = new_child_iw
Some(isw)
}
(
IListBox(list_box~, children~, css_classes~) as ilb,
ListBox(css_classes=new_css_classes, children=new_children),
) => {
for cls in css_classes.val {
list_box.as_widget().remove_css_class(cls)
}
for cls in new_css_classes {
list_box.as_widget().add_css_class(cls)
}
css_classes.val = new_css_classes
children.val = reconcile_map(
app,
dispatch,
children.val,
new_children,
remove=fn(w) { list_box.remove(w.gtk_widget()) },
append=fn(w) { list_box.append(w.gtk_widget()) },
)
Some(ilb)
}
(
ICheckButton(check_button~, on_toggled~, last_active~) as icb,
CheckButton(active~, on_toggled=new_on_toggled),
) => {
if last_active.val != active {
check_button.set_active(active)
last_active.val = active
}
on_toggled.val = fn(a) { dispatch(new_on_toggled(a)) }
Some(icb)
}
(IAdwClamp(clamp~, child~) as ic, AdwClamp(maximum_size~, child=new_child)) => {
clamp.set_maximum_size(maximum_size)
let new_child_iw = reconcile_widget(app, dispatch, child.val, new_child)
clamp.set_child(Some(new_child_iw.gtk_widget()))
child.val = new_child_iw
Some(ic)
}
(
IAdwActionRow(action_row~, prefix~, suffix~) as iar,
AdwActionRow(title~, subtitle~, prefix=new_prefix, suffix=new_suffix),
) => {
action_row.as_preferences_row().set_title(title)
action_row.set_subtitle(subtitle)
prefix.val = reconcile_array(
app,
dispatch,
prefix.val,
new_prefix,
remove=fn(w) { action_row.remove(w.gtk_widget()) },
append=fn(w) { action_row.add_prefix(w.gtk_widget()) },
)
suffix.val = reconcile_array(
app,
dispatch,
suffix.val,
new_suffix,
remove=fn(w) { action_row.remove(w.gtk_widget()) },
append=fn(w) { action_row.add_suffix(w.gtk_widget()) },
)
Some(iar)
}
(ISeparator(_) as is_, Separator(orientation=_)) => Some(is_)
(
IAdwNavigationSplitView(
split_view~,
sidebar_page~,
content_page~,
sidebar~,
content~
) as inv,
AdwNavigationSplitView(
sidebar=new_sidebar,
sidebar_title~,
content=new_content,
content_title~,
min_sidebar_width~,
max_sidebar_width~,
sidebar_width_fraction~
),
) => {
split_view.set_min_sidebar_width(min_sidebar_width)
split_view.set_max_sidebar_width(max_sidebar_width)
split_view.set_sidebar_width_fraction(sidebar_width_fraction)
sidebar_page.set_title(sidebar_title)
content_page.set_title(content_title)
let new_sidebar_iw = reconcile_widget(
app,
dispatch,
sidebar.val,
new_sidebar,
)
sidebar_page.set_child(new_sidebar_iw.gtk_widget())
sidebar.val = new_sidebar_iw
let new_content_iw = reconcile_widget(
app,
dispatch,
content.val,
new_content,
)
content_page.set_child(new_content_iw.gtk_widget())
content.val = new_content_iw
Some(inv)
}
_ => None
}
}