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))
|
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 {
|
extension ModifiedContent: ViewDeferredToRenderer where Content: View {
|
||||||
public var deferredBody: AnyView {
|
public var deferredBody: AnyView {
|
||||||
if let widgetModifier = modifier as? WidgetModifier {
|
guard let widgetModifier = modifier as? WidgetModifier else {
|
||||||
if let anyView = content as? ViewDeferredToRenderer,
|
return AnyView(content)
|
||||||
let anyWidget = mapAnyView(
|
}
|
||||||
anyView.deferredBody,
|
let anyWidget: AnyWidget
|
||||||
transform: { (widget: AnyWidget) in widget }
|
if let anyView = content as? ViewDeferredToRenderer,
|
||||||
)
|
let _anyWidget = mapAnyView(
|
||||||
{
|
anyView.deferredBody,
|
||||||
return AnyView(WidgetView {
|
transform: { (widget: AnyWidget) in widget }
|
||||||
let contentWidget = anyWidget.new($0)
|
)
|
||||||
widgetModifier.modify(widget: contentWidget)
|
{
|
||||||
return contentWidget
|
anyWidget = _anyWidget
|
||||||
} content: {
|
} else if let _anyWidget = content as? AnyWidget {
|
||||||
if let parentView = anyWidget as? ParentView {
|
anyWidget = _anyWidget
|
||||||
ForEach(Array(parentView.children.enumerated()), id: \.offset) { _, view in
|
} else {
|
||||||
view
|
return AnyView(content)
|
||||||
}
|
}
|
||||||
}
|
return AnyView(WidgetView {
|
||||||
})
|
let contentWidget = anyWidget.new($0)
|
||||||
} else if let anyWidget = content as? AnyWidget {
|
widgetModifier.modify(widget: contentWidget)
|
||||||
return AnyView(WidgetView {
|
return contentWidget
|
||||||
let contentWidget = anyWidget.new($0)
|
}
|
||||||
widgetModifier.modify(widget: contentWidget)
|
update: { widget in
|
||||||
return contentWidget
|
anyWidget.update(widget: widget)
|
||||||
} content: {
|
|
||||||
if let parentView = anyWidget as? ParentView {
|
// Is it correct to apply the modifier again after updating?
|
||||||
ForEach(Array(parentView.children.enumerated()), id: \.offset) { _, view in
|
// I assume so since the modifier parameters may have changed.
|
||||||
view
|
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 {
|
struct WidgetView<Content: View>: View, AnyWidget, ParentView {
|
||||||
let build: (UnsafeMutablePointer<GtkApplication>) -> UnsafeMutablePointer<GtkWidget>
|
let build: (UnsafeMutablePointer<GtkApplication>) -> UnsafeMutablePointer<GtkWidget>
|
||||||
|
let update: (Widget) -> Void
|
||||||
let content: Content
|
let content: Content
|
||||||
let expand: Bool
|
let expand: Bool
|
||||||
|
|
||||||
init(build: @escaping (UnsafeMutablePointer<GtkApplication>) -> UnsafeMutablePointer<GtkWidget>,
|
init(build: @escaping (UnsafeMutablePointer<GtkApplication>) -> UnsafeMutablePointer<GtkWidget>,
|
||||||
|
update: @escaping (Widget) -> Void = { _ in },
|
||||||
expand: Bool = false,
|
expand: Bool = false,
|
||||||
@ViewBuilder content: () -> Content)
|
@ViewBuilder content: () -> Content)
|
||||||
{
|
{
|
||||||
self.build = build
|
self.build = build
|
||||||
self.expand = expand
|
self.expand = expand
|
||||||
self.content = content()
|
self.content = content()
|
||||||
|
self.update = update
|
||||||
}
|
}
|
||||||
|
|
||||||
func new(_ application: UnsafeMutablePointer<GtkApplication>) -> UnsafeMutablePointer<GtkWidget> {
|
func new(_ application: UnsafeMutablePointer<GtkApplication>) -> UnsafeMutablePointer<GtkWidget> {
|
||||||
|
@ -44,9 +47,8 @@ struct WidgetView<Content: View>: View, AnyWidget, ParentView {
|
||||||
}
|
}
|
||||||
|
|
||||||
func update(widget: Widget) {
|
func update(widget: Widget) {
|
||||||
// Rebuild from scratch
|
if case .widget = widget.storage {
|
||||||
if case let .widget(w) = widget.storage {
|
update(widget)
|
||||||
widget.destroy()
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -22,7 +22,7 @@ struct Counter: View {
|
||||||
@State private var count: Int = 0
|
@State private var count: Int = 0
|
||||||
var body: some View {
|
var body: some View {
|
||||||
VStack {
|
VStack {
|
||||||
Text("\(count)")
|
Text("\(count)").background(Color(red: 0.5, green: 1, blue: 0.5))
|
||||||
HStack {
|
HStack {
|
||||||
Button("Decrement") { count -= 1 }
|
Button("Decrement") { count -= 1 }
|
||||||
Button("Increment") { count += 1 }
|
Button("Increment") { count += 1 }
|
||||||
|
|
Loading…
Reference in New Issue