GTK: `background` modifier, support widget updates in `WidgetView` (#344)
Re-created #340. * Added background modifier support for color backgrounds * Fix indentation * Allow WidgetView to be initialized with an update closure in order to fix updates to children of WidgetViews * Fix indentation Co-authored-by: Morten Bek Ditlevsen <morten@ka-ching.dk>
This commit is contained in:
parent
6ef59293f5
commit
c9877dcbd7
|
@ -43,3 +43,14 @@ extension _FlexFrameLayout: WidgetModifier {
|
|||
gtk_widget_set_size_request(widget, Int32(idealWidth ?? -1), Int32(idealHeight ?? -1))
|
||||
}
|
||||
}
|
||||
|
||||
extension _BackgroundModifier: WidgetModifier where Background == Color {
|
||||
public func modify(widget: UnsafeMutablePointer<GtkWidget>) {
|
||||
let resolved = _ColorProxy(self.background).resolve(in: environment)
|
||||
var color = GdkRGBA(red: resolved.red,
|
||||
green: resolved.green,
|
||||
blue: resolved.blue,
|
||||
alpha: resolved.opacity)
|
||||
gtk_widget_override_background_color(widget, GtkStateFlags(rawValue: 0), &color)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -24,38 +24,44 @@ protocol WidgetModifier {
|
|||
|
||||
extension ModifiedContent: ViewDeferredToRenderer where Content: View {
|
||||
public var deferredBody: AnyView {
|
||||
if let widgetModifier = modifier as? WidgetModifier {
|
||||
if let anyView = content as? ViewDeferredToRenderer,
|
||||
let anyWidget = mapAnyView(
|
||||
anyView.deferredBody,
|
||||
transform: { (widget: AnyWidget) in widget }
|
||||
)
|
||||
{
|
||||
return AnyView(WidgetView {
|
||||
let contentWidget = anyWidget.new($0)
|
||||
widgetModifier.modify(widget: contentWidget)
|
||||
return contentWidget
|
||||
} content: {
|
||||
if let parentView = anyWidget as? ParentView {
|
||||
ForEach(Array(parentView.children.enumerated()), id: \.offset) { _, view in
|
||||
view
|
||||
}
|
||||
}
|
||||
})
|
||||
} else if let anyWidget = content as? AnyWidget {
|
||||
return AnyView(WidgetView {
|
||||
let contentWidget = anyWidget.new($0)
|
||||
widgetModifier.modify(widget: contentWidget)
|
||||
return contentWidget
|
||||
} content: {
|
||||
if let parentView = anyWidget as? ParentView {
|
||||
ForEach(Array(parentView.children.enumerated()), id: \.offset) { _, view in
|
||||
view
|
||||
}
|
||||
}
|
||||
})
|
||||
guard let widgetModifier = modifier as? WidgetModifier else {
|
||||
return AnyView(content)
|
||||
}
|
||||
let anyWidget: AnyWidget
|
||||
if let anyView = content as? ViewDeferredToRenderer,
|
||||
let _anyWidget = mapAnyView(
|
||||
anyView.deferredBody,
|
||||
transform: { (widget: AnyWidget) in widget }
|
||||
)
|
||||
{
|
||||
anyWidget = _anyWidget
|
||||
} else if let _anyWidget = content as? AnyWidget {
|
||||
anyWidget = _anyWidget
|
||||
} else {
|
||||
return AnyView(content)
|
||||
}
|
||||
return AnyView(WidgetView {
|
||||
let contentWidget = anyWidget.new($0)
|
||||
widgetModifier.modify(widget: contentWidget)
|
||||
return contentWidget
|
||||
}
|
||||
update: { widget in
|
||||
anyWidget.update(widget: widget)
|
||||
|
||||
// Is it correct to apply the modifier again after updating?
|
||||
// I assume so since the modifier parameters may have changed.
|
||||
if case .widget(let w) = widget.storage {
|
||||
widgetModifier.modify(widget: w)
|
||||
}
|
||||
}
|
||||
return AnyView(content)
|
||||
content: {
|
||||
if let parentView = anyWidget as? ParentView, parentView.children.count > 1 {
|
||||
ForEach(Array(parentView.children.enumerated()), id: \.offset) { _, view in
|
||||
view
|
||||
}
|
||||
} else if let parentView = anyWidget as? ParentView, parentView.children.count == 1 {
|
||||
parentView.children[0]
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
|
|
@ -27,16 +27,19 @@ extension AnyWidget {
|
|||
|
||||
struct WidgetView<Content: View>: View, AnyWidget, ParentView {
|
||||
let build: (UnsafeMutablePointer<GtkApplication>) -> UnsafeMutablePointer<GtkWidget>
|
||||
let update: (Widget) -> Void
|
||||
let content: Content
|
||||
let expand: Bool
|
||||
|
||||
init(build: @escaping (UnsafeMutablePointer<GtkApplication>) -> UnsafeMutablePointer<GtkWidget>,
|
||||
update: @escaping (Widget) -> Void = { _ in },
|
||||
expand: Bool = false,
|
||||
@ViewBuilder content: () -> Content)
|
||||
{
|
||||
self.build = build
|
||||
self.expand = expand
|
||||
self.content = content()
|
||||
self.update = update
|
||||
}
|
||||
|
||||
func new(_ application: UnsafeMutablePointer<GtkApplication>) -> UnsafeMutablePointer<GtkWidget> {
|
||||
|
@ -44,9 +47,8 @@ struct WidgetView<Content: View>: View, AnyWidget, ParentView {
|
|||
}
|
||||
|
||||
func update(widget: Widget) {
|
||||
// Rebuild from scratch
|
||||
if case let .widget(w) = widget.storage {
|
||||
widget.destroy()
|
||||
if case .widget = widget.storage {
|
||||
update(widget)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -22,7 +22,7 @@ struct Counter: View {
|
|||
@State private var count: Int = 0
|
||||
var body: some View {
|
||||
VStack {
|
||||
Text("\(count)")
|
||||
Text("\(count)").background(Color(red: 0.5, green: 1, blue: 0.5))
|
||||
HStack {
|
||||
Button("Decrement") { count -= 1 }
|
||||
Button("Increment") { count += 1 }
|
||||
|
|
Loading…
Reference in New Issue