swiftbricks/Sources/SwiftBricks/Renderer/ControlRenderer.swift

182 lines
5.9 KiB
Swift
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import SwiftUI
/// JSON schemaSwiftUI
/// SwiftBricksBrickswidget
public struct ControlRenderer: View {
let schema: ControlSchema
@ObservedObject var engine: BricksEngine
public init(schema: ControlSchema, engine: BricksEngine) {
self.schema = schema
self.engine = engine
}
public var body: some View {
let pctHeight = parsePercentHeight(schema.options.height)
renderWidget(schema)
.frame(
maxWidth: resolveWidth(schema.options),
maxHeight: pctHeight != nil ? .infinity : resolveHeight(schema.options),
alignment: resolveAlignment(schema.options)
)
.layoutPriority(pctHeight ?? 0)
}
// MARK: - Widget
@ViewBuilder
func renderWidget(_ schema: ControlSchema) -> some View {
let type = schema.widgettype
// widget
if let factory = engine.getWidgetFactory(type: type) {
factory(schema, engine)
} else {
renderKnownWidget(schema, type: type)
}
}
@ViewBuilder
func renderKnownWidget(_ schema: ControlSchema, type: String) -> some View {
switch type {
//
case "Text":
TextControl(schema: schema, engine: engine)
case "Title1":
TitleControl(schema: schema, engine: engine, level: 1)
case "Title2":
TitleControl(schema: schema, engine: engine, level: 2)
case "Title3":
TitleControl(schema: schema, engine: engine, level: 3)
case "Title4":
TitleControl(schema: schema, engine: engine, level: 4)
case "Title5":
TitleControl(schema: schema, engine: engine, level: 5)
case "Title6":
TitleControl(schema: schema, engine: engine, level: 6)
case "Label":
LabelControl(schema: schema, engine: engine)
//
case "Input", "UiStr":
InputControl(schema: schema, engine: engine)
case "Textarea", "UiText":
TextareaControl(schema: schema, engine: engine)
case "UiNumber":
NumberControl(schema: schema, engine: engine)
case "UiDate":
DateControl(schema: schema, engine: engine)
case "Select", "UiCode":
SelectControl(schema: schema, engine: engine)
//
case "Button":
ButtonControl(schema: schema, engine: engine)
//
case "VBox", "Card":
VBoxControl(schema: schema, engine: engine)
case "HBox":
HBoxControl(schema: schema, engine: engine)
case "VScrollPanel", "HScrollPanel":
ScrollPanelControl(schema: schema, engine: engine)
case "Filler":
Spacer().frame(maxWidth: .infinity, maxHeight: .infinity)
case "DynamicColumn":
DynamicColumnControl(schema: schema, engine: engine)
//
case "Tabular", "DataViewer":
TabularControl(schema: schema, engine: engine)
case "Form":
FormControl(schema: schema, engine: engine)
case "InlineForm":
InlineFormControl(schema: schema, engine: engine)
//
case "TabView":
TabViewControl(schema: schema, engine: engine)
case "Menu":
MenuControl(schema: schema, engine: engine)
//
case "PopupWindow":
PopupWindowControl(schema: schema, engine: engine)
// HTML
case "Html":
HtmlControl(schema: schema, engine: engine)
// Image
case "Image":
ImageControl(schema: schema, engine: engine)
// VideoPlayer
case "VideoPlayer":
VideoPlayerControl(schema: schema, engine: engine)
// urlwidget
case "urlwidget":
UrlWidgetControl(schema: schema, engine: engine)
default:
// widgettype
VStack {
Text("⚠️ Unknown: \(type)")
.font(.caption)
.foregroundColor(.secondary)
}
}
}
// MARK: -
private func resolveWidth(_ opts: ControlOptions) -> CGFloat? {
if let w = opts.width {
if w == "100%" { return nil } // 使framemaxWidth
if let px = parsePixels(w) { return px }
}
return nil
}
private func resolveHeight(_ opts: ControlOptions) -> CGFloat? {
if let h = opts.height {
if h == "100%" { return nil }
if let px = parsePixels(h) { return px }
}
return nil
}
private func resolveAlignment(_ opts: ControlOptions) -> Alignment {
switch opts.alignItems {
case "center": return .center
case "flex-end", "end": return .trailing
case "flex-start", "start": return .leading
default: return .topLeading
}
}
private func parsePercentHeight(_ h: String?) -> Double? {
guard let h = h, h.hasSuffix("%"), let val = Double(h.dropLast()) else { return nil }
return val > 0 ? val : nil
}
private func parsePixels(_ str: String) -> CGFloat? {
let cleaned = str.replacingOccurrences(of: "px", with: "")
return CGFloat(Double(cleaned) ?? 0)
}
}
// MARK: -
struct SubWidgetsView: View {
let subwidgets: [ControlSchema]
@ObservedObject var engine: BricksEngine
var body: some View {
ForEach(Array(subwidgets.enumerated()), id: \.offset) { _, sub in
ControlRenderer(schema: sub, engine: engine)
}
}
}