package space.kscience.visionforge.ring import kotlinx.css.* import kotlinx.css.properties.border import kotlinx.html.js.onClickFunction import org.w3c.dom.events.Event import org.w3c.files.Blob import org.w3c.files.BlobPropertyBag import react.* import react.dom.button import react.dom.h2 import ringui.island.ringIsland import ringui.tabs.ringSmartTabs import ringui.tabs.ringTab import space.kscience.dataforge.meta.withDefault import space.kscience.dataforge.names.Name import space.kscience.dataforge.names.isEmpty import space.kscience.visionforge.Vision import space.kscience.visionforge.VisionGroup import space.kscience.visionforge.react.flexColumn import space.kscience.visionforge.react.flexRow import space.kscience.visionforge.react.objectTree import space.kscience.visionforge.react.propertyEditor import space.kscience.visionforge.solid.SolidGroup import space.kscience.visionforge.solid.specifications.Canvas3DOptions import space.kscience.visionforge.solid.three.ThreeCanvas import styled.css import styled.styledDiv internal fun saveData(event: Event, fileName: String, mimeType: String = "text/plain", dataBuilder: () -> String) { event.stopPropagation(); event.preventDefault(); val fileSaver = kotlinext.js.require("file-saver") val blob = Blob(arrayOf(dataBuilder()), BlobPropertyBag("$mimeType;charset=utf-8")) fileSaver.saveAs(blob, fileName) } internal fun RBuilder.canvasControls(canvas: ThreeCanvas): ReactElement { return child(CanvasControls) { attrs { this.canvas = canvas } } } internal external interface CanvasControlsProps : RProps { public var canvas: ThreeCanvas } internal val CanvasControls: FunctionalComponent = functionalComponent("CanvasControls") { props -> val visionManager = useMemo( { props.canvas.three.solids.visionManager }, arrayOf(props.canvas) ) flexColumn { flexRow { css { border(1.px, BorderStyle.solid, Color.blue) padding(4.px) } button { +"Export" attrs { onClickFunction = { val json = (props.canvas.content as? SolidGroup)?.let { group -> visionManager.encodeToString(group) } if (json != null) { saveData(it, "object.json", "text/json") { json } } } } } } propertyEditor( ownProperties = props.canvas.options, allProperties = props.canvas.options.withDefault(Canvas3DOptions.descriptor.defaultMeta), descriptor = Canvas3DOptions.descriptor, expanded = false ) } } public external interface ThreeControlsProps : RProps { public var canvas: ThreeCanvas public var selected: Name? public var onSelect: (Name) -> Unit } @JsExport public val ThreeControls: FunctionalComponent = functionalComponent { props -> val vision = props.canvas.content ringSmartTabs(if (props.selected != null) "Properties" else null) { ringTab("Canvas") { ringIsland("Canvas configuration") { canvasControls(props.canvas) } } ringTab("Tree") { styledDiv { css { border(1.px, BorderStyle.solid, Color.lightGray) padding(10.px) } h2 { +"Object tree" } styledDiv { css { flex(1.0, 1.0, FlexBasis.inherit) } props.canvas.content?.let { objectTree(it, props.selected, props.onSelect) } } } } ringTab("Properties") { props.selected.let { selected -> val selectedObject: Vision? = when { selected == null -> null selected.isEmpty() -> vision else -> (vision as? VisionGroup)?.get(selected) } if (selectedObject != null) { ringPropertyEditor(selectedObject, key = selected) } } } props.children() } } public fun RBuilder.ringThreeControls( canvas: ThreeCanvas, selected: Name?, onSelect: (Name) -> Unit = {}, builder: RBuilder.() -> Unit = {}, ): ReactElement = child(ThreeControls) { attrs { this.canvas = canvas this.selected = selected this.onSelect = onSelect } builder() }