v0.2.0-dev-22 #47
@ -16,6 +16,15 @@ kotlin {
|
||||
jvm {
|
||||
withJava()
|
||||
}
|
||||
js{
|
||||
useCommonJs()
|
||||
browser {
|
||||
commonWebpackConfig {
|
||||
sourceMaps = false
|
||||
cssSupport.enabled = false
|
||||
}
|
||||
}
|
||||
}
|
||||
sourceSets {
|
||||
commonMain {
|
||||
dependencies {
|
||||
@ -31,6 +40,7 @@ kotlin {
|
||||
jsMain {
|
||||
dependencies {
|
||||
implementation(project(":ui:bootstrap"))
|
||||
implementation(project(":ui:ring"))
|
||||
implementation(project(":visionforge-threejs"))
|
||||
implementation(npm("react-file-drop", "3.0.6"))
|
||||
}
|
||||
|
@ -14,10 +14,10 @@ import space.kscience.gdml.decodeFromString
|
||||
import space.kscience.visionforge.Vision
|
||||
import space.kscience.visionforge.bootstrap.gridRow
|
||||
import space.kscience.visionforge.bootstrap.nameCrumbs
|
||||
import space.kscience.visionforge.bootstrap.threeControls
|
||||
import space.kscience.visionforge.gdml.toVision
|
||||
import space.kscience.visionforge.react.ThreeCanvasComponent
|
||||
import space.kscience.visionforge.react.flexColumn
|
||||
import space.kscience.visionforge.ring.ringThreeControls
|
||||
import space.kscience.visionforge.solid.Solid
|
||||
import space.kscience.visionforge.solid.Solids
|
||||
import space.kscience.visionforge.solid.specifications.Canvas3DOptions
|
||||
@ -31,14 +31,6 @@ external interface GDMLAppProps : RProps {
|
||||
var selected: Name?
|
||||
}
|
||||
|
||||
//private val canvasConfig = Canvas3DOptions {
|
||||
// camera = Camera {
|
||||
// distance = 2100.0
|
||||
// latitude = PI / 6
|
||||
// azimuth = PI + PI / 6
|
||||
// }
|
||||
//}
|
||||
|
||||
@JsExport
|
||||
val GDMLApp = functionalComponent<GDMLAppProps>("GDMLApp") { props ->
|
||||
var selected by useState { props.selected }
|
||||
@ -120,7 +112,7 @@ val GDMLApp = functionalComponent<GDMLAppProps>("GDMLApp") { props ->
|
||||
}
|
||||
}
|
||||
canvas?.let {
|
||||
threeControls(it, selected, onSelect)
|
||||
ringThreeControls(it, selected, onSelect)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
3
demo/gdml/webpack.config.d/01.ring.js
vendored
Normal file
3
demo/gdml/webpack.config.d/01.ring.js
vendored
Normal file
@ -0,0 +1,3 @@
|
||||
const ringConfig = require('@jetbrains/ring-ui/webpack.config').config;
|
||||
|
||||
config.module.rules.push(...ringConfig.module.rules)
|
7
demo/gdml/webpack.config.d/02.boostrap.js
vendored
Normal file
7
demo/gdml/webpack.config.d/02.boostrap.js
vendored
Normal file
@ -0,0 +1,7 @@
|
||||
config.module.rules.push({
|
||||
test: /\.css$/,
|
||||
include: [
|
||||
require.resolve('bootstrap/dist/css/bootstrap.min.css')
|
||||
],
|
||||
use: ['style-loader', 'css-loader']
|
||||
});
|
@ -49,7 +49,6 @@ public external interface PropertyEditorProps : RProps {
|
||||
*/
|
||||
public var descriptor: NodeDescriptor?
|
||||
|
||||
|
||||
/**
|
||||
* A coroutine scope for updates
|
||||
*/
|
||||
|
@ -7,6 +7,11 @@ val dataforgeVersion: String by rootProject.extra
|
||||
kotlin{
|
||||
js{
|
||||
useCommonJs()
|
||||
browser {
|
||||
commonWebpackConfig {
|
||||
cssSupport.enabled = false
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -15,4 +20,8 @@ dependencies{
|
||||
|
||||
implementation(npm("@jetbrains/icons", "3.14.1"))
|
||||
implementation(npm("@jetbrains/ring-ui", "4.0.7"))
|
||||
implementation(npm("core-js","3.12.1"))
|
||||
compileOnly(npm("url-loader","4.1.1"))
|
||||
compileOnly(npm("postcss-loader","5.2.0"))
|
||||
compileOnly(npm("source-map-loader","2.0.1"))
|
||||
}
|
@ -20,11 +20,11 @@ public external interface AlertProps : WithClassName {
|
||||
public typealias AlertType = String
|
||||
|
||||
public object AlertTypes {
|
||||
public var ERROR = "error"
|
||||
public var MESSAGE = "message"
|
||||
public var SUCCESS = "success"
|
||||
public var WARNING = "warning"
|
||||
public var LOADING = "loading"
|
||||
public var ERROR: String = "error"
|
||||
public var MESSAGE: String = "message"
|
||||
public var SUCCESS: String = "success"
|
||||
public var WARNING: String = "warning"
|
||||
public var LOADING: String = "loading"
|
||||
}
|
||||
|
||||
public fun RBuilder.ringAlert(handler: RHandler<AlertProps>) {
|
||||
|
@ -9,15 +9,15 @@ import react.dom.WithClassName
|
||||
public external interface LinkProps : WithClassName {
|
||||
public var innerClassName: String
|
||||
public var active: Boolean
|
||||
var inherit: Boolean
|
||||
var pseudo: Boolean
|
||||
var hover: Boolean
|
||||
var href: String
|
||||
var onPlainLeftClick: (MouseEvent) -> Unit
|
||||
var onClick: (MouseEvent) -> Unit
|
||||
public var inherit: Boolean
|
||||
public var pseudo: Boolean
|
||||
public var hover: Boolean
|
||||
public var href: String
|
||||
public var onPlainLeftClick: (MouseEvent) -> Unit
|
||||
public var onClick: (MouseEvent) -> Unit
|
||||
}
|
||||
|
||||
fun RBuilder.ringLink(handler: RHandler<LinkProps>) {
|
||||
public fun RBuilder.ringLink(handler: RHandler<LinkProps>) {
|
||||
RingUI.Link {
|
||||
handler()
|
||||
}
|
||||
|
@ -25,6 +25,16 @@ public fun RBuilder.ringIsland(handler: RHandler<IslandProps>) {
|
||||
}
|
||||
}
|
||||
|
||||
public fun RBuilder.ringIsland(header: String, handler: RHandler<IslandContentProps>) {
|
||||
ringIsland {
|
||||
ringIslandHeader {
|
||||
+header
|
||||
}
|
||||
ringIslandContent(handler)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public fun RBuilder.ringAdaptiveIsland(handler: RHandler<IslandProps>) {
|
||||
IslandModule.AdaptiveIsland {
|
||||
handler()
|
||||
|
21
ui/ring/src/main/kotlin/ringui/tabs/SmartTabs.kt
Normal file
21
ui/ring/src/main/kotlin/ringui/tabs/SmartTabs.kt
Normal file
@ -0,0 +1,21 @@
|
||||
package ringui.tabs
|
||||
|
||||
import react.RBuilder
|
||||
import react.RHandler
|
||||
import react.dom.WithClassName
|
||||
|
||||
public external interface SmartTabsProps: WithClassName {
|
||||
public var initSelected: String
|
||||
}
|
||||
|
||||
|
||||
public fun RBuilder.ringSmartTabs(active: String? = null, handler: RHandler<SmartTabsProps>){
|
||||
TabsModule.SmartTabs{
|
||||
active?.let{
|
||||
attrs {
|
||||
initSelected = active
|
||||
}
|
||||
}
|
||||
handler()
|
||||
}
|
||||
}
|
50
ui/ring/src/main/kotlin/ringui/tabs/Tabs.kt
Normal file
50
ui/ring/src/main/kotlin/ringui/tabs/Tabs.kt
Normal file
@ -0,0 +1,50 @@
|
||||
package ringui.tabs
|
||||
|
||||
import react.RBuilder
|
||||
import react.RClass
|
||||
import react.RHandler
|
||||
import react.dom.WithClassName
|
||||
|
||||
@JsModule("@jetbrains/ring-ui/components/tabs/tabs")
|
||||
internal external object TabsModule {
|
||||
val Tabs: RClass<TabsProps>
|
||||
val Tab: RClass<TabProps>
|
||||
val SmartTabs: RClass<SmartTabsProps>
|
||||
//val CustomItem: RClass<CustomItemProps>
|
||||
}
|
||||
|
||||
//https://github.com/JetBrains/ring-ui/blob/master/components/tabs/tabs.js
|
||||
public external interface TabsProps : WithClassName {
|
||||
public var theme: String
|
||||
public var selected: String
|
||||
public var onSelect: (String) -> Unit
|
||||
public var href: String
|
||||
public var autoCollapse: Boolean
|
||||
}
|
||||
|
||||
public external interface CustomItemProps : WithClassName
|
||||
|
||||
public external interface TabProps : WithClassName {
|
||||
public var title: dynamic // PropTypes.oneOfType([PropTypes.node, PropTypes.func]).isRequired,
|
||||
public var id: String
|
||||
}
|
||||
|
||||
public fun RBuilder.ringTabs(active: String? = null, handler: RHandler<TabsProps>) {
|
||||
TabsModule.Tabs {
|
||||
active?.let{
|
||||
attrs {
|
||||
selected = active
|
||||
}
|
||||
}
|
||||
handler()
|
||||
}
|
||||
}
|
||||
|
||||
public fun RBuilder.ringTab(title: dynamic, handler: RHandler<TabProps>) {
|
||||
TabsModule.Tab {
|
||||
attrs {
|
||||
this.title = title
|
||||
}
|
||||
handler()
|
||||
}
|
||||
}
|
@ -0,0 +1,75 @@
|
||||
package space.kscience.visionforge.ring
|
||||
|
||||
import org.w3c.dom.Element
|
||||
import react.RBuilder
|
||||
import react.dom.render
|
||||
import ringui.island.ringIsland
|
||||
import ringui.island.ringIslandContent
|
||||
import ringui.island.ringIslandHeader
|
||||
import ringui.tabs.ringSmartTabs
|
||||
import ringui.tabs.ringTab
|
||||
import space.kscience.dataforge.meta.descriptors.NodeDescriptor
|
||||
import space.kscience.visionforge.*
|
||||
import space.kscience.visionforge.react.metaViewer
|
||||
import space.kscience.visionforge.react.propertyEditor
|
||||
import space.kscience.visionforge.solid.SolidReference
|
||||
|
||||
public fun RBuilder.ringPropertyEditor(
|
||||
vision: Vision,
|
||||
descriptor: NodeDescriptor? = vision.descriptor,
|
||||
key: Any? = null,
|
||||
) {
|
||||
|
||||
ringIsland {
|
||||
ringIslandHeader {
|
||||
attrs {
|
||||
border = true
|
||||
}
|
||||
+"Properties"
|
||||
}
|
||||
ringIslandContent {
|
||||
propertyEditor(
|
||||
ownProperties = vision.ownProperties,
|
||||
allProperties = vision.allProperties(),
|
||||
updateFlow = vision.propertyChanges,
|
||||
descriptor = descriptor,
|
||||
key = key
|
||||
)
|
||||
}
|
||||
}
|
||||
val styles = if (vision is SolidReference) {
|
||||
(vision.styles + vision.prototype.styles).distinct()
|
||||
} else {
|
||||
vision.styles
|
||||
}
|
||||
if (styles.isNotEmpty()) {
|
||||
ringIsland {
|
||||
ringIslandHeader {
|
||||
attrs {
|
||||
border = true
|
||||
}
|
||||
+"Styles"
|
||||
}
|
||||
ringIslandContent {
|
||||
ringSmartTabs {
|
||||
|
||||
}
|
||||
styles.forEach { styleName ->
|
||||
val style = vision.getStyle(styleName)
|
||||
if (style != null) {
|
||||
ringTab(styleName) {
|
||||
metaViewer(style)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public fun Element.ringPropertyEditor(
|
||||
item: Vision,
|
||||
descriptor: NodeDescriptor? = item.descriptor,
|
||||
): Unit = render(this) {
|
||||
ringPropertyEditor(item, descriptor = descriptor)
|
||||
}
|
@ -0,0 +1,150 @@
|
||||
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.descriptors.defaultMeta
|
||||
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<CanvasControlsProps> = 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<ThreeControlsProps> = 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()
|
||||
}
|
9
ui/ring/webpack.config.d/01.ring.js
vendored
9
ui/ring/webpack.config.d/01.ring.js
vendored
@ -1,6 +1,3 @@
|
||||
// wrap is useful, because declaring variables in module can be already declared
|
||||
// module creates own lexical environment
|
||||
(function (config) {
|
||||
const ringConfig = require('@jetbrains/ring-ui/webpack.config').config;
|
||||
config.module.rules.push(...ringConfig.module.rules);
|
||||
})(config);
|
||||
const ringConfig = require('@jetbrains/ring-ui/webpack.config').config;
|
||||
|
||||
config.module.rules.push(...ringConfig.module.rules)
|
@ -1,8 +1,7 @@
|
||||
package space.kscience.visionforge.solid
|
||||
|
||||
import javafx.application.Platform
|
||||
import javafx.beans.binding.Binding
|
||||
import javafx.beans.binding.ObjectBinding
|
||||
import javafx.beans.binding.*
|
||||
import space.kscience.dataforge.meta.*
|
||||
import space.kscience.dataforge.names.Name
|
||||
import space.kscience.dataforge.names.startsWith
|
||||
@ -46,18 +45,18 @@ public class VisualObjectFXBinding(public val fx: FX3DPlugin, public val obj: Vi
|
||||
}
|
||||
|
||||
public fun ObjectBinding<MetaItem?>.value(): Binding<Value?> = objectBinding { it.value }
|
||||
fun ObjectBinding<MetaItem?>.string() = stringBinding { it.string }
|
||||
fun ObjectBinding<MetaItem?>.number() = objectBinding { it.number }
|
||||
fun ObjectBinding<MetaItem?>.double() = objectBinding { it.double }
|
||||
fun ObjectBinding<MetaItem?>.float() = objectBinding { it.float }
|
||||
fun ObjectBinding<MetaItem?>.int() = objectBinding { it.int }
|
||||
fun ObjectBinding<MetaItem?>.long() = objectBinding { it.long }
|
||||
fun ObjectBinding<MetaItem?>.node() = objectBinding { it.node }
|
||||
public fun ObjectBinding<MetaItem?>.string(): StringBinding = stringBinding { it.string }
|
||||
public fun ObjectBinding<MetaItem?>.number(): Binding<Number?> = objectBinding { it.number }
|
||||
public fun ObjectBinding<MetaItem?>.double(): Binding<Double?> = objectBinding { it.double }
|
||||
public fun ObjectBinding<MetaItem?>.float(): Binding<Float?> = objectBinding { it.float }
|
||||
public fun ObjectBinding<MetaItem?>.int(): Binding<Int?> = objectBinding { it.int }
|
||||
public fun ObjectBinding<MetaItem?>.long(): Binding<Long?> = objectBinding { it.long }
|
||||
public fun ObjectBinding<MetaItem?>.node(): Binding<Meta?> = objectBinding { it.node }
|
||||
|
||||
fun ObjectBinding<MetaItem?>.string(default: String) = stringBinding { it.string ?: default }
|
||||
fun ObjectBinding<MetaItem?>.double(default: Double) = doubleBinding { it.double ?: default }
|
||||
fun ObjectBinding<MetaItem?>.float(default: Float) = floatBinding { it.float ?: default }
|
||||
fun ObjectBinding<MetaItem?>.int(default: Int) = integerBinding { it.int ?: default }
|
||||
fun ObjectBinding<MetaItem?>.long(default: Long) = longBinding { it.long ?: default }
|
||||
public fun ObjectBinding<MetaItem?>.string(default: String): StringBinding = stringBinding { it.string ?: default }
|
||||
public fun ObjectBinding<MetaItem?>.double(default: Double): DoubleBinding = doubleBinding { it.double ?: default }
|
||||
public fun ObjectBinding<MetaItem?>.float(default: Float): FloatBinding = floatBinding { it.float ?: default }
|
||||
public fun ObjectBinding<MetaItem?>.int(default: Int): IntegerBinding = integerBinding { it.int ?: default }
|
||||
public fun ObjectBinding<MetaItem?>.long(default: Long): LongBinding = longBinding { it.long ?: default }
|
||||
|
||||
fun <T> ObjectBinding<MetaItem?>.transform(transform: (MetaItem) -> T) = objectBinding { it?.let(transform) }
|
||||
public fun <T> ObjectBinding<MetaItem?>.transform(transform: (MetaItem) -> T): Binding<T?> = objectBinding { it?.let(transform) }
|
||||
|
Loading…
Reference in New Issue
Block a user