Skip to content
This repository has been archived by the owner on Oct 17, 2024. It is now read-only.

Commit

Permalink
Migrate to Meta backend
Browse files Browse the repository at this point in the history
  • Loading branch information
david-swift committed Aug 13, 2024
1 parent 574aca2 commit 9f83b23
Show file tree
Hide file tree
Showing 157 changed files with 3,515 additions and 4,675 deletions.
4 changes: 1 addition & 3 deletions .swiftlint.yml
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,6 @@ opt_in_rules:
- convenience_type
- discouraged_none_name
- discouraged_object_literal
- discouraged_optional_boolean
- discouraged_optional_collection
- empty_collection_literal
- empty_count
- empty_string
Expand Down Expand Up @@ -51,7 +49,6 @@ opt_in_rules:
- multiline_parameters_brackets
- no_extension_access_modifier
- no_grouping_extension
- no_magic_numbers
- number_separator
- operator_usage_whitespace
- optional_enum_case_matching
Expand Down Expand Up @@ -164,3 +161,4 @@ type_contents_order:
excluded:
- Sources/Adwaita/View/Generated/
- Sources/Adwaita/Adwaita.docc/
- .build/
8 changes: 0 additions & 8 deletions Contributors.md

This file was deleted.

13 changes: 6 additions & 7 deletions Package.swift
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// swift-tools-version: 5.8
// swift-tools-version: 5.9
//
// Package.swift
// Adwaita
Expand All @@ -11,9 +11,7 @@ import PackageDescription
/// The Adwaita package.
let package = Package(
name: "Adwaita",
platforms: [
.macOS(.v10_15)
],
platforms: [.macOS(.v10_15), .iOS(.v13), .tvOS(.v13), .watchOS(.v6), .macCatalyst(.v13)],
products: [
.library(
name: "Adwaita",
Expand All @@ -25,6 +23,7 @@ let package = Package(
)
],
dependencies: [
.package(url: "https://github.com/AparokshaUI/Meta", branch: "main"),
.package(
url: "https://github.com/david-swift/LevenshteinTransformations",
from: "0.1.1"
Expand All @@ -40,7 +39,8 @@ let package = Package(
name: "Adwaita",
dependencies: [
"CAdw",
.product(name: "LevenshteinTransformations", package: "LevenshteinTransformations")
.product(name: "LevenshteinTransformations", package: "LevenshteinTransformations"),
.product(name: "Meta", package: "Meta")
]
),
.executableTarget(
Expand All @@ -51,8 +51,7 @@ let package = Package(
),
.executableTarget(
name: "Demo",
dependencies: ["Adwaita"],
path: "Tests"
dependencies: ["Adwaita"]
)
]
)
69 changes: 48 additions & 21 deletions Sources/Adwaita/Menu/MenuButton.swift
Original file line number Diff line number Diff line change
Expand Up @@ -8,16 +8,14 @@
import CAdw

/// A button widget for menus.
public struct MenuButton: MenuItem {
public struct MenuButton: MenuWidget {

/// The button's label.
var label: String
/// The button's action handler.
var handler: () -> Void
/// The keyboard shortcut.
var shortcut = ""
/// Whether the keyboard shortcut is currently available.
var active = true
/// Whether to prefer adding the action to the application window.
var preferApplicationWindow: Bool

Expand All @@ -35,33 +33,62 @@ public struct MenuButton: MenuItem {
self.handler = handler
}

/// Add the button to a menu.
/// The view storage.
/// - Parameters:
/// - menu: The menu.
/// - app: The application containing the menu.
/// - window: The application window containing the menu.
public func addMenuItem(menu: OpaquePointer?, app: GTUIApp, window: GTUIApplicationWindow?) {
if let window, preferApplicationWindow {
window.addKeyboardShortcut(active ? shortcut : "", id: filteredLabel, handler: handler)
g_menu_append(menu, label, "win." + filteredLabel)
/// - modifiers: Modify the views before updating.
/// - type: The type of the views.
/// - Returns: The view storage.
public func container<Data>(
modifiers: [(any AnyView) -> any AnyView],
type: Data.Type
) -> ViewStorage where Data: ViewRenderData {
let storage = ViewStorage(nil)
let getItem: (AdwaitaApp, AdwaitaWindow?) -> OpaquePointer? = { app, window in
var label = filteredLabel
storage.fields["app"] = app
if let window, preferApplicationWindow {
app.addKeyboardShortcut(shortcut, id: filteredLabel, window: window, handler: handler)
label = "win." + label
storage.fields["window"] = window
} else {
app.addKeyboardShortcut(shortcut, id: filteredLabel, handler: handler)
label = "app." + label
}
return g_menu_item_new(self.label, label)
}
storage.pointer = getItem
return storage
}

/// Update the stored content.
/// - Parameters:
/// - storage: The storage to update.
/// - modifiers: Modify the views before updating.
/// - updateProperties: Whether to update the properties.
/// - type: The type of the views.
public func update<Data>(
_ storage: ViewStorage,
modifiers: [(AnyView) -> AnyView],
updateProperties: Bool,
type: Data.Type
) where Data: ViewRenderData {
guard let app = storage.fields["app"] as? AdwaitaApp else {
return
}
if let window = storage.fields["window"] as? AdwaitaWindow, preferApplicationWindow {
app.addKeyboardShortcut(shortcut, id: filteredLabel, window: window, handler: handler)
} else {
app.addKeyboardShortcut(active ? shortcut : "", id: filteredLabel, handler: handler)
g_menu_append(menu, label, "app." + filteredLabel)
app.addKeyboardShortcut(shortcut, id: filteredLabel, handler: handler)
}
}

/// Create a keyboard shortcut for an application from a button.
///
/// Note that the keyboard shortcut is available after the view has been visible for the first time.
/// - Parameters:
/// - shortcut: The keyboard shortcut.
/// - active: Whether the keyboard shortcut is currently available.
/// - Parameter shortcut: The keyboard shortcut.
/// - Returns: The button.
public func keyboardShortcut(_ shortcut: String, active: Bool = true) -> Self {
var newSelf = self
newSelf.shortcut = shortcut
newSelf.active = active
return newSelf
public func keyboardShortcut(_ shortcut: String) -> Self {
modify { $0.shortcut = shortcut }
}

}
85 changes: 85 additions & 0 deletions Sources/Adwaita/Menu/MenuCollection.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
//
// MenuCollection.swift
// Adwaita
//
// Created by david-swift on 02.08.2024.
//

import CAdw
import Foundation

/// A collection of menus.
public struct MenuCollection: MenuWidget, Wrapper {

/// The content of the collection.
var content: Body

/// Initialize a menu.
/// - Parameter content: The content of the collection.
public init(@ViewBuilder content: @escaping () -> Body) {
self.content = content()
}

/// The view storage.
/// - Parameters:
/// - modifiers: Modify the views before updating.
/// - type: The type of the views.
/// - Returns: The view storage.
public func container<Data>(
modifiers: [(any AnyView) -> any AnyView],
type: Data.Type
) -> ViewStorage where Data: ViewRenderData {
let storages = content.storages(modifiers: modifiers, type: type)
return .init(nil, content: [.mainContent: storages])
}

/// Update the stored content.
/// - Parameters:
/// - storage: The storage to update.
/// - modifiers: Modify the views before updating.
/// - updateProperties: Whether to update the properties.
/// - type: The type of the views.
public func update<Data>(
_ storage: ViewStorage,
modifiers: [(AnyView) -> AnyView],
updateProperties: Bool,
type: Data.Type
) where Data: ViewRenderData {
guard let storages = storage.content[.mainContent] else {
return
}
content.update(storages, modifiers: modifiers, updateProperties: updateProperties, type: type)
}

/// Render the collection as a menu.
/// - Parameters:
/// - app: The app object.
/// - window: The window object.
/// - Returns: The view storage with the GMenu as the pointer.
public func getMenu(app: AdwaitaApp, window: AdwaitaWindow?) -> ViewStorage {
let menu = g_menu_new()
let storage = container(modifiers: [], type: MenuContext.self)
initializeMenu(menu: menu, storage: storage, app: app, window: window)
storage.pointer = menu
return storage
}

/// Initialize a menu.
/// - Parameters:
/// - menu: The pointer to the GMenu.
/// - storage: The storage for the menu's content.
/// - app: The app object.
/// - window: The window object.
func initializeMenu(menu: OpaquePointer?, storage: ViewStorage, app: AdwaitaApp, window: AdwaitaWindow?) {
if storage.pointer == nil {
for element in storage.content[.mainContent] ?? [] {
initializeMenu(menu: menu, storage: element, app: app, window: window)
}
} else if let item = (storage.pointer as? (AdwaitaApp, AdwaitaWindow?) -> OpaquePointer?) {
let item = item(app, window)
g_menu_append_item(menu, item)
storage.pointer = item
}
}

}
21 changes: 21 additions & 0 deletions Sources/Adwaita/Menu/MenuContext.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
//
// MenuContext.swift
// Adwaita
//
// Created by david-swift on 01.08.24.
//

/// The menu items view context.
public enum MenuContext: ViewRenderData {

/// The type of the widgets.
public typealias WidgetType = MenuWidget
/// The wrapper type.
public typealias WrapperType = MenuCollection
/// The either view type.
public typealias EitherViewType = MenuEitherView

}

/// The type of the widgets.
public protocol MenuWidget: Meta.Widget { }
23 changes: 23 additions & 0 deletions Sources/Adwaita/Menu/MenuEitherView.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
//
// MenuEitherView.swift
// Adwaita
//
// Created by david-swift on 06.08.2024.
//

/// Show one of two views depending on a condition.
public struct MenuEitherView: Meta.EitherView, SimpleView {

/// The view.
public var view: Body

/// Initialize an either view.
/// - Parameters:
/// - condition: The condition.
/// - view1: The first view.
/// - view2: The second view.
public init(_ condition: Bool, view1: () -> Body, else view2: () -> Body) {
self.view = condition ? view1() : view2()
}

}
53 changes: 39 additions & 14 deletions Sources/Adwaita/Menu/MenuSection.swift
Original file line number Diff line number Diff line change
@@ -1,35 +1,60 @@
//
// Submenu.swift
// MenuButton.swift
// Adwaita
//
// Created by david-swift on 22.10.23.
//

import CAdw

/// A section for menus.
public struct MenuSection: MenuItem {
/// A button widget for menus.
public struct MenuSection: MenuWidget {

/// The content of the section.
var sectionContent: MenuContent
var sectionContent: Body

/// Initialize a section for menus.
/// - Parameter content: The content of the section.
public init(@MenuBuilder content: () -> MenuContent) {
public init(@ViewBuilder content: () -> Body) {
self.sectionContent = content()
}

/// Add the section to a menu.
/// The view storage.
/// - Parameters:
/// - menu: The menu.
/// - app: The application containing the menu.
/// - window: The application window containing the menu.
public func addMenuItem(menu: OpaquePointer?, app: GTUIApp, window: GTUIApplicationWindow?) {
let section = g_menu_new()
g_menu_append_section(menu, nil, section?.cast())
for element in sectionContent {
element.addMenuItems(menu: section, app: app, window: window)
/// - modifiers: Modify the views before updating.
/// - type: The type of the views.
/// - Returns: The view storage.
public func container<Data>(
modifiers: [(any AnyView) -> any AnyView],
type: Data.Type
) -> ViewStorage where Data: ViewRenderData {
let storage = ViewStorage(nil)
let getItem: (AdwaitaApp, AdwaitaWindow?) -> OpaquePointer? = { app, window in
let childStorage = MenuCollection { sectionContent }.getMenu(app: app, window: window)
storage.content[.mainContent] = [childStorage]
return g_menu_item_new_section(nil, childStorage.opaquePointer?.cast())
}
storage.pointer = getItem
return storage
}

/// Update the stored content.
/// - Parameters:
/// - storage: The storage to update.
/// - modifiers: Modify the views before updating.
/// - updateProperties: Whether to update the properties.
/// - type: The type of the views.
public func update<Data>(
_ storage: ViewStorage,
modifiers: [(AnyView) -> AnyView],
updateProperties: Bool,
type: Data.Type
) where Data: ViewRenderData {
guard let content = storage.content[.mainContent]?.first else {
return
}
MenuCollection { sectionContent }
.updateStorage(content, modifiers: [], updateProperties: updateProperties, type: MenuContext.self)
}

}
Loading

0 comments on commit 9f83b23

Please sign in to comment.