Add support for AdwBreakpointBin
This commit is contained in:
parent
016425e329
commit
963a02b1e1
@ -267,4 +267,36 @@ extension AnyView {
|
||||
.action(button: button, handler: handler)
|
||||
}
|
||||
|
||||
/// Add a breakpoint.
|
||||
/// - Parameters:
|
||||
/// - maxWidth: The maximum width.
|
||||
/// - matches: Whether the content view matches the breakpoint.
|
||||
public func breakpoint(maxWidth: Int, matches: Binding<Bool>) -> AnyView {
|
||||
BreakpointBin(condition: .maxWidth(maxWidth), matches: matches) { self }
|
||||
}
|
||||
|
||||
/// Add a breakpoint.
|
||||
/// - Parameters:
|
||||
/// - minWidth: The minimum width.
|
||||
/// - matches: Whether the content view matches the breakpoint.
|
||||
public func breakpoint(minWidth: Int, matches: Binding<Bool>) -> AnyView {
|
||||
BreakpointBin(condition: .minWidth(minWidth), matches: matches) { self }
|
||||
}
|
||||
|
||||
/// Add a breakpoint.
|
||||
/// - Parameters:
|
||||
/// - maxHeight: The maximum height.
|
||||
/// - matches: Whether the content view matches the breakpoint.
|
||||
public func breakpoint(maxHeight: Int, matches: Binding<Bool>) -> AnyView {
|
||||
BreakpointBin(condition: .maxHeight(maxHeight), matches: matches) { self }
|
||||
}
|
||||
|
||||
/// Add a breakpoint.
|
||||
/// - Parameters:
|
||||
/// - minHeight: The minimum height.
|
||||
/// - matches: Whether the content view matches the breakpoint.
|
||||
public func breakpoint(minHeight: Int, matches: Binding<Bool>) -> AnyView {
|
||||
BreakpointBin(condition: .minHeight(minHeight), matches: matches) { self }
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -52,3 +52,11 @@ gtui_alertdialog_choose (uint64_t dialog, uint64_t data, uint64_t parent)
|
||||
adw_alert_dialog_choose (dialog, parent, NULL, gtui_alertdialog_cb, data);
|
||||
}
|
||||
|
||||
static GValue
|
||||
gtui_initialize_boolean (gboolean boolean)
|
||||
{
|
||||
GValue val = G_VALUE_INIT;
|
||||
g_value_init(&val, G_TYPE_BOOLEAN);
|
||||
g_value_set_boolean(&val, boolean);
|
||||
return val;
|
||||
}
|
||||
|
@ -5,6 +5,8 @@
|
||||
// Created by david-swift on 15.01.24.
|
||||
//
|
||||
|
||||
import CAdw
|
||||
|
||||
extension Bool {
|
||||
|
||||
/// Get the gboolean for C.
|
||||
@ -12,4 +14,11 @@ extension Bool {
|
||||
self ? 1 : 0
|
||||
}
|
||||
|
||||
/// The gboolean as a GValue.
|
||||
public var gValue: UnsafePointer<GValue> {
|
||||
let pointer = UnsafeMutablePointer<GValue>.allocate(capacity: 1)
|
||||
pointer.initialize(to: gtui_initialize_boolean(cBool))
|
||||
return .init(pointer)
|
||||
}
|
||||
|
||||
}
|
||||
|
115
Sources/Core/View/BreakpointBin.swift
Normal file
115
Sources/Core/View/BreakpointBin.swift
Normal file
@ -0,0 +1,115 @@
|
||||
//
|
||||
// BreakpointBin.swift
|
||||
// Adwaita
|
||||
//
|
||||
// Created by david-swift on 21.10.24.
|
||||
//
|
||||
|
||||
import CAdw
|
||||
import Meta
|
||||
|
||||
/// Bind a dimension's to observe whether the child view matches a condition.
|
||||
public struct BreakpointBin: AdwaitaWidget {
|
||||
|
||||
/// The child view.
|
||||
@ViewProperty(
|
||||
set: { bin, view in
|
||||
var width: Int32 = 0
|
||||
var height: Int32 = 0
|
||||
gtk_widget_measure(view.cast(), GTK_ORIENTATION_VERTICAL, -1, &height, nil, nil, nil)
|
||||
gtk_widget_measure(view.cast(), GTK_ORIENTATION_HORIZONTAL, -1, &width, nil, nil, nil)
|
||||
gtk_widget_set_size_request(bin.cast(), width, height)
|
||||
adw_breakpoint_bin_set_child(bin.cast(), view.cast())
|
||||
},
|
||||
pointer: OpaquePointer.self,
|
||||
subview: OpaquePointer.self,
|
||||
context: AdwaitaMainView.self
|
||||
)
|
||||
var content
|
||||
|
||||
/// The condition.
|
||||
@Property(
|
||||
set: { bin, condition, storage in
|
||||
let condition = adw_breakpoint_condition_parse(condition.condition)
|
||||
if let breakpoint = storage.fields["breakpoint"] as? OpaquePointer {
|
||||
g_object_unref(adw_breakpoint_get_condition(breakpoint)?.cast())
|
||||
adw_breakpoint_set_condition(breakpoint, condition)
|
||||
} else {
|
||||
let breakpoint = adw_breakpoint_new(condition)
|
||||
adw_breakpoint_bin_add_breakpoint(bin.cast(), breakpoint)
|
||||
storage.fields["breakpoint"] = breakpoint
|
||||
if let bin = storage.content["_content"]?.first?.content["append"]?.first {
|
||||
adw_breakpoint_add_setter(
|
||||
breakpoint,
|
||||
bin.opaquePointer?.cast(),
|
||||
"visible",
|
||||
false.gValue
|
||||
)
|
||||
}
|
||||
}
|
||||
},
|
||||
pointer: OpaquePointer.self
|
||||
)
|
||||
var condition: BreakpointCondition = .maxWidth(0)
|
||||
|
||||
/// Whether the child view does not match the condition.
|
||||
@BindingProperty(
|
||||
observe: { bin, matches, storage in
|
||||
storage.notify(name: "current-breakpoint") {
|
||||
matches.wrappedValue = adw_breakpoint_bin_get_current_breakpoint(bin.cast()) != nil
|
||||
}
|
||||
},
|
||||
set: { _, _, _ in },
|
||||
pointer: OpaquePointer.self
|
||||
)
|
||||
var matches: Binding<Bool> = .constant(false)
|
||||
|
||||
/// Initialize a breakpoint bin.
|
||||
/// - Parameters:
|
||||
/// - condition: The condition.
|
||||
/// - matches: Whether the content matches the condition.
|
||||
/// - content: The content.
|
||||
public init(
|
||||
condition: BreakpointCondition,
|
||||
matches: Binding<Bool>,
|
||||
@ViewBuilder content: () -> Body
|
||||
) {
|
||||
self.condition = condition
|
||||
self.matches = matches
|
||||
self.content = content()
|
||||
}
|
||||
|
||||
/// Initialize the widget.
|
||||
public func initializeWidget() -> Any {
|
||||
adw_breakpoint_bin_new()?.opaque() as Any
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/// A breakpoint condition.
|
||||
public enum BreakpointCondition: Equatable {
|
||||
|
||||
/// Define a maximum width.
|
||||
case maxWidth(_ width: Int)
|
||||
/// Define a maximum height.
|
||||
case maxHeight(_ height: Int)
|
||||
/// Define a minimum width.
|
||||
case minWidth(_ width: Int)
|
||||
/// Define a minimum height.
|
||||
case minHeight(_ height: Int)
|
||||
|
||||
/// The condition to parse.
|
||||
var condition: String {
|
||||
switch self {
|
||||
case let .maxWidth(width):
|
||||
"max-width: \(width)sp"
|
||||
case let .maxHeight(height):
|
||||
"max-height: \(height)sp"
|
||||
case let .minWidth(width):
|
||||
"min-width: \(width)sp"
|
||||
case let .minHeight(height):
|
||||
"min-height: \(height)sp"
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -43,7 +43,6 @@ struct Demo: App {
|
||||
}
|
||||
.closeShortcut()
|
||||
.defaultSize(width: 600, height: 400)
|
||||
.resizable(false)
|
||||
.title("View Switcher Demo")
|
||||
Window(id: "form-demo", open: 0) { _ in
|
||||
FormDemo.WindowContent()
|
||||
|
@ -8,6 +8,7 @@
|
||||
// swiftlint:disable missing_docs
|
||||
|
||||
import Adwaita
|
||||
import CAdw
|
||||
|
||||
struct ViewSwitcherDemo: View {
|
||||
|
||||
@ -33,10 +34,6 @@ struct ViewSwitcherDemo: View {
|
||||
VStack {
|
||||
Text(selection.title)
|
||||
.padding()
|
||||
Button(bottom ? "Show Top Bar" : "Show Bottom Bar") {
|
||||
bottom.toggle()
|
||||
}
|
||||
.halign(.center)
|
||||
}
|
||||
.valign(.center)
|
||||
.topToolbar {
|
||||
@ -44,15 +41,16 @@ struct ViewSwitcherDemo: View {
|
||||
HeaderBar
|
||||
.empty()
|
||||
} else {
|
||||
toolbar
|
||||
toolbar(bottom: false)
|
||||
}
|
||||
}
|
||||
.bottomToolbar(visible: bottom) {
|
||||
toolbar
|
||||
toolbar(bottom: true)
|
||||
}
|
||||
.breakpoint(maxWidth: 600, matches: $bottom)
|
||||
}
|
||||
|
||||
var toolbar: AnyView {
|
||||
func toolbar(bottom: Bool) -> AnyView {
|
||||
HeaderBar(titleButtons: !bottom) { } end: { }
|
||||
.headerBarTitle {
|
||||
ViewSwitcher(selectedElement: $selection)
|
||||
|
Loading…
Reference in New Issue
Block a user