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.attrs 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.encodeToString 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.specifications.Canvas3DOptions 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(options: Canvas3DOptions, vision: Vision?): ReactElement { return child(CanvasControls) { attrs { this.options = options this.vision = vision } } } internal external interface CanvasControlsProps : RProps { public var options: Canvas3DOptions public var vision: Vision? } internal val CanvasControls: FunctionalComponent = functionalComponent("CanvasControls") { props -> flexColumn { flexRow { css { border(1.px, BorderStyle.solid, Color.blue) padding(4.px) } props.vision?.let { vision -> button { +"Export" attrs { onClickFunction = { val json = vision.encodeToString() saveData(it, "object.json", "text/json") { json } } } } } } propertyEditor( ownProperties = props.options, allProperties = props.options.withDefault(Canvas3DOptions.descriptor.defaultMeta), descriptor = Canvas3DOptions.descriptor, expanded = false ) } } public external interface ThreeControlsProps : RProps { public var canvasOptions: Canvas3DOptions public var vision: Vision? public var selected: Name? public var onSelect: (Name) -> Unit } @JsExport public val ThreeControls: FunctionalComponent = functionalComponent { props -> ringSmartTabs(if (props.selected != null) "Properties" else "Tree") { ringTab("Canvas") { ringIsland("Canvas configuration") { canvasControls(props.canvasOptions, props.vision) } } ringTab("Tree") { flexColumn { css { border(1.px, BorderStyle.solid, Color.lightGray) padding(10.px) flexGrow = 1.0 flexWrap = FlexWrap.wrap } h2 { +"Object tree" } styledDiv { css { overflowY = Overflow.auto flexGrow = 1.0 } props.vision?.let { objectTree(it, props.selected, props.onSelect) } } } } if (props.selected != null) { ringTab("Properties") { props.selected.let { selected -> val selectedObject: Vision? = when { selected == null -> null selected.isEmpty() -> props.vision else -> (props.vision as? VisionGroup)?.get(selected) } if (selectedObject != null) { ringPropertyEditor(selectedObject, key = selected) } } } } props.children() } } public fun RBuilder.ringThreeControls( canvasOptions: Canvas3DOptions, vision: Vision?, selected: Name?, onSelect: (Name) -> Unit = {}, builder: RBuilder.() -> Unit = {}, ): ReactElement = child(ThreeControls) { attrs { this.canvasOptions = canvasOptions this.vision = vision this.selected = selected this.onSelect = onSelect } builder() }