diff --git a/Sources/Adwaita/View/Fixed+.swift b/Sources/Adwaita/View/Fixed+.swift new file mode 100644 index 0000000..b5fd22d --- /dev/null +++ b/Sources/Adwaita/View/Fixed+.swift @@ -0,0 +1,53 @@ +// +// Fixed+.swift +// Adwaita +// +// Created by david-swift on 21.07.24. +// + +import CAdw + +extension Fixed { + + /// Place an element in the coordinate system. + /// - Parameters: + /// - xCoordinate: The x coordinate. + /// - yCoordinate: The y coordinate. + /// - id: A unique identifier. + /// - view: The element. + /// - Returns: The coordinate system with the element. + public func element( + x xCoordinate: Double, + y yCoordinate: Double, + id: String, + @ViewBuilder view: @escaping () -> Body + ) -> Self { + var newSelf = self + newSelf.appearFunctions.append { storage, modifiers in + let view = view().storage(modifiers: modifiers) + gtk_fixed_put( + storage.pointer?.cast(), + view.pointer?.cast(), + xCoordinate, + yCoordinate + ) + storage.content[id] = [view] + } + newSelf.updateFunctions.append { storage, modifiers, updateProperties in + guard let content = storage.content[id]?.first else { + return + } + view().updateStorage(content, modifiers: modifiers, updateProperties: updateProperties) + if updateProperties { + gtk_fixed_move( + storage.pointer?.cast(), + content.pointer?.cast(), + xCoordinate, + yCoordinate + ) + } + } + return newSelf + } + +} diff --git a/Sources/Adwaita/View/Generated/Fixed.swift b/Sources/Adwaita/View/Generated/Fixed.swift new file mode 100644 index 0000000..68d47c3 --- /dev/null +++ b/Sources/Adwaita/View/Generated/Fixed.swift @@ -0,0 +1,107 @@ +// +// Fixed.swift +// Adwaita +// +// Created by auto-generation on 21.07.24. +// + +import CAdw +import LevenshteinTransformations + +/// `GtkFixed` places its child widgets at fixed positions and with fixed sizes. +/// +/// `GtkFixed` performs no automatic layout management. +/// +/// For most applications, you should not use this container! It keeps +/// you from having to learn about the other GTK containers, but it +/// results in broken applications. With `GtkFixed`, the following +/// things will result in truncated text, overlapping widgets, and +/// other display bugs: +/// +/// - Themes, which may change widget sizes. +/// +/// - Fonts other than the one you used to write the app will of course +/// change the size of widgets containing text; keep in mind that +/// users may use a larger font because of difficulty reading the +/// default, or they may be using a different OS that provides different fonts. +/// +/// - Translation of text into other languages changes its size. Also, +/// display of non-English text will use a different font in many +/// cases. +/// +/// In addition, `GtkFixed` does not pay attention to text direction and +/// thus may produce unwanted results if your app is run under right-to-left +/// languages such as Hebrew or Arabic. That is: normally GTK will order +/// containers appropriately for the text direction, e.g. to put labels to +/// the right of the thing they label when using an RTL language, but it can’t +/// do that with `GtkFixed`. So if you need to reorder widgets depending on +/// the text direction, you would need to manually detect it and adjust child +/// positions accordingly. +/// +/// Finally, fixed positioning makes it kind of annoying to add/remove +/// UI elements, since you have to reposition all the other elements. This +/// is a long-term maintenance problem for your application. +/// +/// If you know none of these things are an issue for your application, +/// and prefer the simplicity of `GtkFixed`, by all means use the +/// widget. But you should be aware of the tradeoffs. +public struct Fixed: Widget { + + /// Additional update functions for type extensions. + var updateFunctions: [(ViewStorage, [(View) -> View], Bool) -> Void] = [] + /// Additional appear functions for type extensions. + var appearFunctions: [(ViewStorage, [(View) -> View]) -> Void] = [] + + /// The accessible role of the given `GtkAccessible` implementation. + /// + /// The accessible role cannot be changed once set. + var accessibleRole: String? + /// The application. + var app: GTUIApp? + /// The window. + var window: GTUIApplicationWindow? + + /// Initialize `Fixed`. + public init() { + } + + /// Get the widget's view storage. + /// - Parameter modifiers: The view modifiers. + /// - Returns: The view storage. + public func container(modifiers: [(View) -> View]) -> ViewStorage { + let storage = ViewStorage(gtk_fixed_new()?.opaque()) + for function in appearFunctions { + function(storage, modifiers) + } + update(storage, modifiers: modifiers, updateProperties: true) + + return storage + } + + /// Update the widget's view storage. + /// - Parameters: + /// - storage: The view storage. + /// - modifiers: The view modifiers. + /// - updateProperties: Whether to update the view's properties. + public func update(_ storage: ViewStorage, modifiers: [(View) -> View], updateProperties: Bool) { + storage.modify { widget in + + + + } + for function in updateFunctions { + function(storage, modifiers, updateProperties) + } + } + + /// The accessible role of the given `GtkAccessible` implementation. + /// + /// The accessible role cannot be changed once set. + public func accessibleRole(_ accessibleRole: String?) -> Self { + var newSelf = self + newSelf.accessibleRole = accessibleRole + + return newSelf + } + +} diff --git a/Sources/Generation/GenerationConfiguration.swift b/Sources/Generation/GenerationConfiguration.swift index e5a1af5..567470b 100644 --- a/Sources/Generation/GenerationConfiguration.swift +++ b/Sources/Generation/GenerationConfiguration.swift @@ -271,7 +271,8 @@ struct GenerationConfiguration { class: "Separator", initializer: "gtk_separator_new(GTK_ORIENTATION_VERTICAL)", excludeProperties: ["orientation"] - ) + ), + .init(class: "Fixed") ] /// The unshortening map. diff --git a/Tests/FixedDemo.swift b/Tests/FixedDemo.swift new file mode 100644 index 0000000..ebdbc09 --- /dev/null +++ b/Tests/FixedDemo.swift @@ -0,0 +1,28 @@ +// +// FixedDemo.swift +// Adwaita +// +// Created by david-swift on 21.07.24. +// + +// swiftlint:disable missing_docs + +import Adwaita +import Foundation + +struct FixedDemo: View { + + @State private var button = (x: 0.0, y: 0.0) + + var view: Body { + Fixed() + .element(x: button.x, y: button.y, id: "button") { + Button("Move") { + button = (x: Double.random(in: 0...100), y: Double.random(in: 0...100)) + } + } + } + +} + +// swiftlint:enable missing_docs diff --git a/Tests/Page.swift b/Tests/Page.swift index f05b99a..4582549 100644 --- a/Tests/Page.swift +++ b/Tests/Page.swift @@ -31,6 +31,7 @@ enum Page: String, Identifiable, CaseIterable, Codable, CustomStringConvertible case navigationView case picture case idle + case fixed var id: Self { self @@ -102,6 +103,8 @@ enum Page: String, Identifiable, CaseIterable, Codable, CustomStringConvertible return "Display an image" case .idle: return "Update UI from an asynchronous context" + case .fixed: + return "Place widgets in a coordinate system" } } @@ -147,6 +150,8 @@ enum Page: String, Identifiable, CaseIterable, Codable, CustomStringConvertible PictureDemo(url: pictureURL, app: app, window: window) case .idle: IdleDemo() + case .fixed: + FixedDemo() } } // swiftlint:enable cyclomatic_complexity