181 lines
6.4 KiB
Swift
181 lines
6.4 KiB
Swift
//
|
|
// ClassLike.swift
|
|
// Adwaita
|
|
//
|
|
// Created by david-swift on 14.02.24.
|
|
//
|
|
|
|
/// Classes and interfaces share a lot of their properties.
|
|
protocol ClassLike {
|
|
|
|
/// The type name.
|
|
var name: String { get }
|
|
/// The C symbol prefix.
|
|
var cSymbolPrefix: String { get }
|
|
/// The C type.
|
|
var cType: String? { get }
|
|
/// The signals.
|
|
var signals: [Signal] { get }
|
|
/// The properties.
|
|
var properties: [Property] { get }
|
|
|
|
}
|
|
|
|
extension ClassLike {
|
|
|
|
/// Get the properties of the class and its parent classes.
|
|
/// - Parameters:
|
|
/// - namespace: The namespace.
|
|
/// - configurations: The configurations for the classes in the namespace.
|
|
/// - Returns: The properties.
|
|
func properties(namespace: Namespace, configurations: [WidgetConfiguration]) -> [Property] {
|
|
var properties = properties.filter { !($0.deprecated ?? false) }
|
|
for type in parentTypes(namespace: namespace) {
|
|
properties += type
|
|
.properties(namespace: namespace, configurations: configurations)
|
|
.map { property in
|
|
var property = property
|
|
if property.prefix == nil {
|
|
property.prefix = type.prefix()
|
|
property.cast = configurations.first { $0.class == type.name }?.cast ?? false
|
|
}
|
|
return property
|
|
}
|
|
}
|
|
return properties.reduce(into: [String: Property]()) { result, property in
|
|
result[property.name] = property
|
|
}
|
|
.values
|
|
.sorted { $0.name < $1.name }
|
|
}
|
|
|
|
/// Get the code for the properties of the static widgets.
|
|
/// - Parameters:
|
|
/// - namespace: The namespace.
|
|
/// - configs: The configurations.
|
|
/// - Returns: The code.
|
|
func staticWidgetProperties(namespace: Namespace, configs: [WidgetConfiguration]) -> String {
|
|
var content = ""
|
|
for type in parentTypes(namespace: namespace) {
|
|
content += type.staticWidgetProperties(namespace: namespace, configs: configs)
|
|
}
|
|
guard let config = configs.first(where: { $0.class == name }) else {
|
|
return content
|
|
}
|
|
for staticWidget in config.staticWidgets {
|
|
content += """
|
|
|
|
/// The body for the widget "\(staticWidget.name)".
|
|
var \(staticWidget.name): () -> Body = { [] }
|
|
"""
|
|
}
|
|
return content
|
|
}
|
|
|
|
/// Get the assignments for the static widgets of the class and its parent classes.
|
|
/// - Parameters:
|
|
/// - namespace: The namespace.
|
|
/// - configs: The configurations.
|
|
/// - Returns: The code.
|
|
func staticWidgets(namespace: Namespace, configs: [WidgetConfiguration]) -> String {
|
|
var content = ""
|
|
for type in parentTypes(namespace: namespace) {
|
|
content += type.staticWidgets(namespace: namespace, configs: configs)
|
|
}
|
|
guard let config = configs.first(where: { $0.class == name }) else {
|
|
return content
|
|
}
|
|
let widgetPointer = config.cast ? "storage.opaquePointer?.cast()" : "storage.opaquePointer"
|
|
for widget in config.staticWidgets {
|
|
content += """
|
|
|
|
var \(widget.name)Storage: [ViewStorage] = []
|
|
for view in \(widget.name)() {
|
|
\(widget.name)Storage.append(view.storage(data: data, type: type))
|
|
\(widget.add)(\(widgetPointer), \(widget.name)Storage.last?.opaquePointer?.cast())
|
|
}
|
|
storage.content["\(widget.name)"] = \(widget.name)Storage
|
|
"""
|
|
}
|
|
return content
|
|
}
|
|
|
|
/// Generate the modifiers for static widgets.
|
|
/// - Parameters:
|
|
/// - config: The widget configuration.
|
|
/// - configs: The available widget configurations.
|
|
/// - namespace: The namespace.
|
|
/// - Returns: The code.
|
|
func generateWidgetModifiers(
|
|
config: WidgetConfiguration,
|
|
configs: [WidgetConfiguration],
|
|
namespace: Namespace
|
|
) -> String {
|
|
var content = ""
|
|
for widget in config.staticWidgets {
|
|
content += """
|
|
|
|
/// Set the body for "\(widget.name)".
|
|
/// - Parameter body: The body.
|
|
/// - Returns: The widget.
|
|
public func \(widget.name)(@ViewBuilder _ body: @escaping () -> Body) -> Self {
|
|
var newSelf = self
|
|
newSelf.\(widget.name) = body
|
|
return newSelf
|
|
}
|
|
"""
|
|
}
|
|
for type in parentTypes(namespace: namespace) {
|
|
if let config = configs.first(where: { $0.class == type.name }) {
|
|
content += type.generateWidgetModifiers(config: config, configs: configs, namespace: namespace)
|
|
}
|
|
}
|
|
return content
|
|
}
|
|
|
|
/// Get the signals of the class and its parent classes.
|
|
/// - Parameter namespace: The namespace.
|
|
/// - Returns: The signals.
|
|
func signals(namespace: Namespace) -> [Signal] {
|
|
var signals: [Signal] = signals
|
|
for type in parentTypes(namespace: namespace) {
|
|
signals += type.signals(namespace: namespace)
|
|
}
|
|
return signals.reduce(into: [String: Signal]()) { result, property in
|
|
result[property.name] = property
|
|
}
|
|
.values
|
|
.sorted { $0.name < $1.name }
|
|
}
|
|
|
|
/// Get the parent class and interfaces.
|
|
/// - Parameter namespace: The namespace in the namespace.
|
|
/// - Returns: The types.
|
|
func parentTypes(namespace: Namespace) -> [ClassLike] {
|
|
var types: [ClassLike] = []
|
|
guard let `class` = self as? Class else {
|
|
return types
|
|
}
|
|
if let parent = namespace.classes.first(where: { $0.name == `class`.parent }), parent.name != "Widget" {
|
|
types.append(parent)
|
|
}
|
|
for conformance in `class`.conformances {
|
|
if let type = namespace.interfaces.first(where: { $0.name == conformance.name }) {
|
|
types.append(type)
|
|
}
|
|
}
|
|
return types
|
|
}
|
|
|
|
/// Get the widget's prefix (e.g. "adw_preferences_row").
|
|
/// - Returns: The prefix.
|
|
func prefix() -> String {
|
|
if cType?.hasPrefix("Adw") ?? false {
|
|
return "adw_\(cSymbolPrefix)"
|
|
} else {
|
|
return "gtk_\(cSymbolPrefix)"
|
|
}
|
|
}
|
|
|
|
}
|