From 0eab156b7c8732631d749be16f471dcb0e055256 Mon Sep 17 00:00:00 2001 From: Edwin Jakobs Date: Thu, 26 Mar 2020 11:50:19 +0100 Subject: [PATCH] Move Panel into orx-panel --- build.gradle | 1 - orx-gui/build.gradle | 2 +- .../org/openrndr/panel/ControlManager.kt | 592 ++++++++++++++++++ .../kotlin/org/openrndr/panel/FontManager.kt | 24 + .../ObservableCopyOnWriteArrayList.kt | 31 + .../panel/collections/ObservableHashSet.kt | 36 ++ .../org/openrndr/panel/elements/Body.kt | 5 + .../org/openrndr/panel/elements/Button.kt | 100 +++ .../org/openrndr/panel/elements/Canvas.kt | 44 ++ .../openrndr/panel/elements/Colorpicker.kt | 164 +++++ .../panel/elements/ColorpickerButton.kt | 121 ++++ .../kotlin/org/openrndr/panel/elements/Div.kt | 44 ++ .../openrndr/panel/elements/DropdownButton.kt | 281 +++++++++ .../org/openrndr/panel/elements/Element.kt | 289 +++++++++ .../openrndr/panel/elements/EnvelopeButton.kt | 139 ++++ .../openrndr/panel/elements/EnvelopeEditor.kt | 229 +++++++ .../openrndr/panel/elements/LayoutBuilder.kt | 95 +++ .../openrndr/panel/elements/SequenceEditor.kt | 150 +++++ .../org/openrndr/panel/elements/Slider.kt | 251 ++++++++ .../openrndr/panel/elements/TextElements.kt | 100 +++ .../org/openrndr/panel/elements/Textfield.kt | 156 +++++ .../org/openrndr/panel/elements/Toggle.kt | 118 ++++ .../org/openrndr/panel/elements/XYPad.kt | 250 ++++++++ .../org/openrndr/panel/layout/Layouter.kt | 261 ++++++++ .../org/openrndr/panel/style/DefaultStyles.kt | 200 ++++++ .../org/openrndr/panel/style/Matcher.kt | 54 ++ .../org/openrndr/panel/style/Selector.kt | 129 ++++ .../org/openrndr/panel/style/StyleSheet.kt | 221 +++++++ .../org/openrndr/panel/tools/Tooltip.kt | 53 ++ .../main/resources/fonts/Roboto-Medium.ttf | Bin 0 -> 162588 bytes .../main/resources/fonts/Roboto-Regular.ttf | Bin 0 -> 162876 bytes .../panel/test/SelectorBuilderTest.kt | 57 ++ .../org/openrndr/panel/test/StyleSheetTest.kt | 18 + settings.gradle | 1 + 34 files changed, 4214 insertions(+), 2 deletions(-) create mode 100644 orx-panel/src/main/kotlin/org/openrndr/panel/ControlManager.kt create mode 100644 orx-panel/src/main/kotlin/org/openrndr/panel/FontManager.kt create mode 100644 orx-panel/src/main/kotlin/org/openrndr/panel/collections/ObservableCopyOnWriteArrayList.kt create mode 100644 orx-panel/src/main/kotlin/org/openrndr/panel/collections/ObservableHashSet.kt create mode 100644 orx-panel/src/main/kotlin/org/openrndr/panel/elements/Body.kt create mode 100644 orx-panel/src/main/kotlin/org/openrndr/panel/elements/Button.kt create mode 100644 orx-panel/src/main/kotlin/org/openrndr/panel/elements/Canvas.kt create mode 100644 orx-panel/src/main/kotlin/org/openrndr/panel/elements/Colorpicker.kt create mode 100644 orx-panel/src/main/kotlin/org/openrndr/panel/elements/ColorpickerButton.kt create mode 100644 orx-panel/src/main/kotlin/org/openrndr/panel/elements/Div.kt create mode 100644 orx-panel/src/main/kotlin/org/openrndr/panel/elements/DropdownButton.kt create mode 100644 orx-panel/src/main/kotlin/org/openrndr/panel/elements/Element.kt create mode 100644 orx-panel/src/main/kotlin/org/openrndr/panel/elements/EnvelopeButton.kt create mode 100644 orx-panel/src/main/kotlin/org/openrndr/panel/elements/EnvelopeEditor.kt create mode 100644 orx-panel/src/main/kotlin/org/openrndr/panel/elements/LayoutBuilder.kt create mode 100644 orx-panel/src/main/kotlin/org/openrndr/panel/elements/SequenceEditor.kt create mode 100644 orx-panel/src/main/kotlin/org/openrndr/panel/elements/Slider.kt create mode 100644 orx-panel/src/main/kotlin/org/openrndr/panel/elements/TextElements.kt create mode 100644 orx-panel/src/main/kotlin/org/openrndr/panel/elements/Textfield.kt create mode 100644 orx-panel/src/main/kotlin/org/openrndr/panel/elements/Toggle.kt create mode 100644 orx-panel/src/main/kotlin/org/openrndr/panel/elements/XYPad.kt create mode 100644 orx-panel/src/main/kotlin/org/openrndr/panel/layout/Layouter.kt create mode 100644 orx-panel/src/main/kotlin/org/openrndr/panel/style/DefaultStyles.kt create mode 100644 orx-panel/src/main/kotlin/org/openrndr/panel/style/Matcher.kt create mode 100644 orx-panel/src/main/kotlin/org/openrndr/panel/style/Selector.kt create mode 100644 orx-panel/src/main/kotlin/org/openrndr/panel/style/StyleSheet.kt create mode 100644 orx-panel/src/main/kotlin/org/openrndr/panel/tools/Tooltip.kt create mode 100644 orx-panel/src/main/resources/fonts/Roboto-Medium.ttf create mode 100644 orx-panel/src/main/resources/fonts/Roboto-Regular.ttf create mode 100644 orx-panel/src/test/java/org/openrndr/panel/test/SelectorBuilderTest.kt create mode 100644 orx-panel/src/test/java/org/openrndr/panel/test/StyleSheetTest.kt diff --git a/build.gradle b/build.gradle index a2bbb91b..3d3c4d1b 100644 --- a/build.gradle +++ b/build.gradle @@ -16,7 +16,6 @@ apply plugin: 'org.jetbrains.dokka' project.ext { openrndrVersion = "0.3.40-rc.5" - panelVersion = "0.3.22-rc.3" kotlinVersion = "1.3.70" spekVersion = "2.0.10" libfreenectVersion = "0.5.7-1.5.2" diff --git a/orx-gui/build.gradle b/orx-gui/build.gradle index c6fddf2a..78e1c41b 100644 --- a/orx-gui/build.gradle +++ b/orx-gui/build.gradle @@ -1,6 +1,6 @@ dependencies { api project(":orx-parameters") - api "org.openrndr.panel:openrndr-panel:$panelVersion" + api project(":orx-panel") implementation "org.openrndr:openrndr-dialogs:$openrndrVersion" implementation "com.google.code.gson:gson:$gsonVersion" } \ No newline at end of file diff --git a/orx-panel/src/main/kotlin/org/openrndr/panel/ControlManager.kt b/orx-panel/src/main/kotlin/org/openrndr/panel/ControlManager.kt new file mode 100644 index 00000000..ba3aa934 --- /dev/null +++ b/orx-panel/src/main/kotlin/org/openrndr/panel/ControlManager.kt @@ -0,0 +1,592 @@ +package org.openrndr.panel + +import mu.KotlinLogging +import org.openrndr.* +import org.openrndr.color.ColorRGBa +import org.openrndr.draw.* +import org.openrndr.math.Matrix44 +import org.openrndr.math.Vector2 +import org.openrndr.panel.elements.* +import org.openrndr.panel.layout.Layouter +import org.openrndr.panel.style.* +import org.openrndr.shape.Rectangle +import org.openrndr.shape.intersects + +//class SurfaceCache(val width: Int, val height: Int, val contentScale:Double) { +// val cache = renderTarget(width, height, contentScale) { +// colorMap() +// depthBuffer() +// } +// +// private val atlas = mutableMapOf() +// +// private var root: PackNode = PackNode(IntRectangle(0, 0, width, height)) +// val packer = IntPacker() +// +// fun flush() { +// atlas.clear() +// root = PackNode(IntRectangle(0, 0, width, height)) +// } +// +// fun drawCached(drawer: Drawer, element: Element, f: () -> Unit): IntRectangle { +// val rectangle = atlas.getOrPut(element) { +// val r = packer.insert(root, IntRectangle(0, 0, Math.ceil(element.layout.screenWidth).toInt(), +// Math.ceil(element.layout.screenHeight).toInt()))?.area?:throw RuntimeException("bork") +// draw(drawer, r, f) +// r +// } +// if (element.draw.dirty) { +// draw(drawer, rectangle, f) +// } +// drawer.ortho() +// drawer.isolated { +// drawer.model = Matrix44.IDENTITY +// drawer.image(cache.colorMap(0), Rectangle(rectangle.corner.x * 1.0, rectangle.corner.y * 1.0, rectangle.width * 1.0, rectangle.height * 1.0), +// element.screenArea) +// } +// return rectangle +// } +// +// fun draw(drawer: Drawer, rectangle: IntRectangle, f: () -> Unit) { +// drawer.isolatedWithTarget(cache) { +// drawer.ortho(cache) +// drawer.drawStyle.blendMode = BlendMode.REPLACE +// drawer.drawStyle.fill = ColorRGBa.BLACK.opacify(0.0) +// drawer.drawStyle.stroke = null +// drawer.view = Matrix44.IDENTITY +// drawer.model = Matrix44.IDENTITY +// drawer.rectangle(Rectangle(rectangle.x * 1.0, rectangle.y * 1.0, rectangle.width * 1.0, rectangle.height * 1.0)) +// +// drawer.drawStyle.blendMode = BlendMode.OVER +// drawer.drawStyle.clip = Rectangle(rectangle.x * 1.0, rectangle.y * 1.0, rectangle.width * 1.0, rectangle.height * 1.0) +// drawer.view = Matrix44.IDENTITY +// drawer.model = org.openrndr.math.transforms.translate(rectangle.x * 1.0, rectangle.y * 1.0, 0.0) +// f() +// } +// } +//} + +private val logger = KotlinLogging.logger {} + +class ControlManager : Extension { + var body: Element? = null + val layouter = Layouter() + val fontManager = FontManager() + lateinit var window: Program.Window + private val renderTargetCache = HashMap() + + lateinit var program: Program + override var enabled: Boolean = true + + var contentScale = 1.0 + lateinit var renderTarget: RenderTarget + + init { + fontManager.register("default", resourceUrl("/fonts/Roboto-Regular.ttf")) + layouter.styleSheets.addAll(defaultStyles().flatMap { it.flatten() }) + } + + inner class DropInput { + var target: Element? = null + fun drop(event: DropEvent) { + target?.drop?.dropped?.trigger(event) + } + } + + val dropInput = DropInput() + + inner class KeyboardInput { + var target: Element? = null + set(value) { + if (value != field) { + field?.pseudoClasses?.remove(ElementPseudoClass("active")) + field?.keyboard?.focusLost?.trigger(FocusEvent()) + value?.keyboard?.focusGained?.trigger(FocusEvent()) + field = value + field?.pseudoClasses?.add(ElementPseudoClass("active")) + } + } + + fun press(event: KeyEvent) { + target?.let { + var current: Element? = it + while (current != null) { + if (!event.propagationCancelled) { + current.keyboard.pressed.trigger(event) + } + current = current.parent + } + checkForManualRedraw() + } + } + + fun release(event: KeyEvent) { + target?.keyboard?.released?.trigger(event) + if (target != null) { + checkForManualRedraw() + } + } + + fun repeat(event: KeyEvent) { + target?.keyboard?.repeated?.trigger(event) + if (target != null) { + checkForManualRedraw() + } + } + + fun character(event: Program.CharacterEvent) { + target?.keyboard?.character?.trigger(event) + if (target != null) { + checkForManualRedraw() + } + } + + fun requestFocus(element: Element) { + target = element + } + } + + val keyboardInput = KeyboardInput() + + inner class MouseInput { + var dragTarget: Element? = null + var clickTarget: Element? = null + var lastClick = System.currentTimeMillis() + + fun scroll(event: MouseEvent) { + fun traverse(element: Element) { + element.children.forEach(::traverse) + if (!event.propagationCancelled) { + if (event.position in element.screenArea && element.computedStyle.display != Display.NONE) { + element.mouse.scrolled.trigger(event) + if (event.propagationCancelled) { + keyboardInput.target = element + } + } + } + } + body?.let(::traverse) + checkForManualRedraw() + } + + fun click(event: MouseEvent) { + logger.debug { "click event: $event" } + dragTarget = null + val ct = System.currentTimeMillis() + logger.debug { "click target: $clickTarget" } + + clickTarget?.let { + if (it.handlesDoubleClick) { + if (ct - lastClick > 500) { + logger.debug { "normal click on $clickTarget" } + it.mouse.clicked.trigger(event) + } else { + if (clickTarget != null) { + logger.debug { "double-click on $clickTarget" } + it.mouse.doubleClicked.trigger(event) + } + } + lastClick = ct + } else { + logger.debug { "normal click on $clickTarget" } + it.mouse.clicked.trigger(event) + } + } + checkForManualRedraw() + } + + fun press(event: MouseEvent) { + logger.debug { "press event: $event" } + val candidates = mutableListOf>() + fun traverse(element: Element, depth: Int = 0) { + + if (element.computedStyle.overflow == Overflow.Scroll) { + if (event.position !in element.screenArea) { + return + } + } + + if (element.computedStyle.display != Display.NONE) { + element.children.forEach { traverse(it, depth + 1) } + } + + + if (!event.propagationCancelled && event.position in element.screenArea && element.computedStyle.display != Display.NONE) { + candidates.add(Pair(element, depth)) + } + } + + body?.let { traverse(it) } + //candidates.sortByDescending { it.second } + clickTarget = null + candidates.sortWith(compareBy({ -it.first.layout.zIndex }, { -it.second })) + for (c in candidates) { + if (!event.propagationCancelled) { + c.first.mouse.pressed.trigger(event) + if (event.propagationCancelled) { + logger.debug { "propagation cancelled by ${c.first}" } + dragTarget = c.first + clickTarget = c.first + keyboardInput.target = c.first + } + } + } + + if (clickTarget == null) { + dragTarget = null + keyboardInput.target = null + } + + checkForManualRedraw() + } + + fun drag(event: MouseEvent) { + logger.debug { "drag event $event" } + dragTarget?.mouse?.dragged?.trigger(event) + if (event.propagationCancelled) { + logger.debug { "propagation cancelled by $dragTarget setting clickTarget to null" } + clickTarget = null + } + checkForManualRedraw() + } + + val insideElements = mutableSetOf() + fun move(event: MouseEvent) { + val hover = ElementPseudoClass("hover") + val toRemove = insideElements.filter { (event.position !in it.screenArea) } + + toRemove.forEach { + it.mouse.exited.trigger(MouseEvent(event.position, Vector2.ZERO, Vector2.ZERO, MouseEventType.MOVED, MouseButton.NONE, event.modifiers, false)) + } + + insideElements.removeAll(toRemove) + + fun traverse(element: Element) { + if (event.position in element.screenArea) { + if (element !in insideElements) { + element.mouse.entered.trigger(event) + } + insideElements.add(element) + if (hover !in element.pseudoClasses) { + element.pseudoClasses.add(hover) + } + element.mouse.moved.trigger(event) + } else { + if (hover in element.pseudoClasses) { + element.pseudoClasses.remove(hover) + } + } + element.children.forEach(::traverse) + } + body?.let(::traverse) + checkForManualRedraw() + } + } + + fun checkForManualRedraw() { + if (window.presentationMode == PresentationMode.MANUAL) { + val redraw = body?.any { + it.draw.dirty + } ?: false + if (redraw) { + window.requestDraw() + } + } + } + + val mouseInput = MouseInput() + override fun setup(program: Program) { + this.program = program + + contentScale = program.window.scale.x + window = program.window + + //surfaceCache = SurfaceCache(4096, 4096, contentScale) + fontManager.contentScale = contentScale +// program.mouse.buttonUp.listen { mouseInput.release(it) } + program.mouse.buttonUp.listen { mouseInput.click(it) } + program.mouse.moved.listen { mouseInput.move(it) } + program.mouse.scrolled.listen { mouseInput.scroll(it) } + program.mouse.dragged.listen { mouseInput.drag(it) } + program.mouse.buttonDown.listen { mouseInput.press(it) } + + program.keyboard.keyDown.listen { keyboardInput.press(it) } + program.keyboard.keyUp.listen { keyboardInput.release(it) } + program.keyboard.keyRepeat.listen { keyboardInput.repeat(it) } + program.keyboard.character.listen { keyboardInput.character(it) } + + program.window.drop.listen { dropInput.drop(it) } + program.window.sized.listen { resize(program, it.size.x.toInt(), it.size.y.toInt()) } + + width = program.width + height = program.height + renderTarget = renderTarget(program.width, program.height, contentScale) { + colorBuffer() + } + + body?.draw?.dirty = true + } + + var width: Int = 0 + var height: Int = 0 + + private fun resize(program: Program, width: Int, height: Int) { + this.width = width + this.height = height + + body?.draw?.dirty = true + + if (renderTarget.colorBuffers.isNotEmpty()) { + renderTarget.colorBuffer(0).destroy() + renderTarget.depthBuffer?.destroy() + renderTarget.detachColorBuffers() + renderTarget.detachDepthBuffer() + renderTarget.destroy() + } else { + logger.error { "that is strange. no color buffers" } + } + + renderTarget = renderTarget(program.width, program.height, contentScale) { + colorBuffer() + depthBuffer() + } + + renderTarget.bind() + program.drawer.background(ColorRGBa.BLACK.opacify(0.0)) + renderTarget.unbind() + + renderTargetCache.forEach { (_, u) -> u.destroy() } + renderTargetCache.clear() + } + + private fun drawElement(element: Element, drawer: Drawer, zIndex: Int, zComp: Int) { + val newZComp = + element.computedStyle.zIndex.let { + when (it) { + is ZIndex.Value -> it.value + else -> zComp + } + } + + if (element.computedStyle.display != Display.NONE) { + if (element.computedStyle.overflow == Overflow.Visible) { + drawer.isolated { + drawer.translate(element.screenPosition) + if (newZComp == zIndex) { + element.draw(drawer) + } +// if (newZComp == zIndex) { +// surfaceCache.drawCached(drawer, element) { +// element.draw(drawer) +// } +// +// } + } + element.children.forEach { + drawElement(it, drawer, zIndex, newZComp) + } + } else { + val area = element.screenArea + val rt = renderTargetCache.computeIfAbsent(element) { + renderTarget(width, height, contentScale) { + colorBuffer() + depthBuffer() + } + } + + rt.bind() + drawer.background(ColorRGBa.BLACK.opacify(0.0)) + + drawer.pushProjection() + drawer.ortho(rt) + element.children.forEach { + drawElement(it, drawer, zIndex, newZComp) + } + rt.unbind() + drawer.popProjection() + + drawer.pushTransforms() + drawer.pushStyle() + drawer.translate(element.screenPosition) + + if (newZComp == zIndex) { + element.draw(drawer) + } + drawer.popStyle() + drawer.popTransforms() + + drawer.drawStyle.blendMode = BlendMode.OVER + //drawer.image(rt.colorMap(0)) + drawer.image(rt.colorBuffer(0), Rectangle(Vector2(area.x, area.y), area.width, area.height), + Rectangle(Vector2(area.x, area.y), area.width, area.height)) + } + } + element.draw.dirty = false + + } + + class ProfileData(var hits: Int = 0, var time: Long = 0) + + private val profiles = mutableMapOf() + private fun profile(name: String, f: () -> Unit) { + val start = System.currentTimeMillis() + f() + val end = System.currentTimeMillis() + val pd = profiles.getOrPut(name) { ProfileData(0, 0L) } + pd.hits++ + pd.time += (end - start) + + if (pd.hits == 100) { + //println("name: $name, avg: ${pd.time / pd.hits}ms, ${pd.hits}") + pd.hits = 0 + pd.time = 0 + } + } + + var drawCount = 0 + override fun afterDraw(drawer: Drawer, program: Program) { + if (program.width > 0 && program.height > 0) { + profile("after draw") { + + if (program.width != renderTarget.width || program.height != renderTarget.height) { + profile("resize target") { + body?.draw?.dirty = true + + renderTarget.colorBuffer(0).destroy() + renderTarget.destroy() + renderTarget = renderTarget(program.width, program.height, contentScale) { + colorBuffer() + } + + renderTarget.bind() + program.drawer.background(ColorRGBa.BLACK.opacify(0.0)) + renderTarget.unbind() + } + } + + val redraw = body?.any { + it.draw.dirty + } ?: false + + if (redraw) { + drawer.ortho() + drawer.view = Matrix44.IDENTITY + drawer.defaults() + + profile("redraw") { + renderTarget.bind() + body?.style = StyleSheet(CompoundSelector()) + body?.style?.width = program.width.px + body?.style?.height = program.height.px + + body?.let { + program.drawer.background(ColorRGBa.BLACK.opacify(0.0)) + layouter.computeStyles(it) + layouter.layout(it) + drawElement(it, program.drawer, 0, 0) + drawElement(it, program.drawer, 1, 0) + drawElement(it, program.drawer, 1000, 0) + } + renderTarget.unbind() + } + } + body?.visit { + draw.dirty = false + } + + profile("draw image") { + drawer.size(program.width, program.height) + drawer.ortho() + drawer.view = Matrix44.IDENTITY + drawer.defaults() + program.drawer.image(renderTarget.colorBuffer(0), 0.0, 0.0) + } + drawCount++ + } + } + } +} + +@Deprecated("use new style extend") +class ControlManagerBuilder(val controlManager: ControlManager) { + fun styleSheet(selector: CompoundSelector, init: StyleSheet.() -> Unit): StyleSheet { + val styleSheet = StyleSheet(selector).apply { init() } + controlManager.layouter.styleSheets.addAll(styleSheet.flatten()) + return styleSheet + } + + fun styleSheets(styleSheets: List) { + controlManager.layouter.styleSheets.addAll(styleSheets.flatMap { it.flatten() }) + } + + fun layout(init: Body.() -> Unit) { + val body = Body(controlManager) + body.init() + controlManager.body = body + } +} + + +fun ControlManager.styleSheet(selector: CompoundSelector, init: StyleSheet.() -> Unit): StyleSheet { + val styleSheet = StyleSheet(selector).apply { init() } + layouter.styleSheets.addAll(styleSheet.flatten()) + return styleSheet +} + +fun ControlManager.styleSheets(styleSheets: List) { + layouter.styleSheets.addAll(styleSheets.flatMap { it.flatten() }) +} + +fun ControlManager.layout(init: Body.() -> Unit) { + val body = Body(this) + body.init() + this.body = body +} + +@Deprecated("use Program.controlManager") +fun controlManager(builder: ControlManagerBuilder.() -> Unit): ControlManager { + val cm = ControlManager() + cm.fontManager.register("default", resourceUrl("/fonts/Roboto-Regular.ttf")) + cm.layouter.styleSheets.addAll(defaultStyles().flatMap { it.flatten() }) + val cmb = ControlManagerBuilder(cm) + cmb.builder() + return cm +} + +fun Program.controlManager(builder: ControlManagerBuilder.() -> Unit): ControlManager { + val cm = ControlManager() + cm.program = this + cm.fontManager.register("default", resourceUrl("/fonts/Roboto-Regular.ttf")) + cm.layouter.styleSheets.addAll(defaultStyles().flatMap { it.flatten() }) + val cmb = ControlManagerBuilder(cm) + cmb.builder() + return cm +} + +private fun Element.any(function: (Element) -> Boolean): Boolean { + if (function(this)) { + return true + } else { + children.forEach { + if (it.any(function)) { + return true + } + } + return false + } +} + +private fun Element.anyVisible(function: (Element) -> Boolean): Boolean { + if (computedStyle.display != Display.NONE && function(this)) { + return true + } + + if (computedStyle.display != Display.NONE) { + children.forEach { + if (it.anyVisible(function)) { + return true + } + } + } + return false +} \ No newline at end of file diff --git a/orx-panel/src/main/kotlin/org/openrndr/panel/FontManager.kt b/orx-panel/src/main/kotlin/org/openrndr/panel/FontManager.kt new file mode 100644 index 00000000..a04ec4ae --- /dev/null +++ b/orx-panel/src/main/kotlin/org/openrndr/panel/FontManager.kt @@ -0,0 +1,24 @@ +package org.openrndr.panel + +import org.openrndr.draw.FontImageMap +import org.openrndr.panel.style.LinearDimension +import org.openrndr.panel.style.StyleSheet +import org.openrndr.panel.style.fontFamily +import org.openrndr.panel.style.fontSize + +class FontManager { + val registry: MutableMap = mutableMapOf() + var contentScale: Double = 1.0 + + fun resolve(name: String): String? = registry[name] + + fun font(cs: StyleSheet): FontImageMap { + val fontUrl = resolve(cs.fontFamily) ?: "cp:fonts/Roboto-Medium.ttf" + val fontSize = (cs.fontSize as? LinearDimension.PX)?.value ?: 16.0 + return FontImageMap.fromUrl(fontUrl, fontSize, contentScale) + } + + fun register(name: String, url: String) { + registry[name] = url + } +} \ No newline at end of file diff --git a/orx-panel/src/main/kotlin/org/openrndr/panel/collections/ObservableCopyOnWriteArrayList.kt b/orx-panel/src/main/kotlin/org/openrndr/panel/collections/ObservableCopyOnWriteArrayList.kt new file mode 100644 index 00000000..017d2ac0 --- /dev/null +++ b/orx-panel/src/main/kotlin/org/openrndr/panel/collections/ObservableCopyOnWriteArrayList.kt @@ -0,0 +1,31 @@ +package org.openrndr.panel.collections + +import org.openrndr.events.Event +import java.util.concurrent.CopyOnWriteArrayList + +class ObservableCopyOnWriteArrayList : CopyOnWriteArrayList() { + + val changed = Event>() + override fun add(element: E): Boolean { + return if (super.add(element)) { + changed.trigger(this) + true + } else { + false + } + } + + override fun remove(element: E): Boolean { + return if (super.remove(element)) { + changed.trigger(this) + true + } else { + false + } + } + + override fun clear() { + super.clear() + changed.trigger(this) + } +} \ No newline at end of file diff --git a/orx-panel/src/main/kotlin/org/openrndr/panel/collections/ObservableHashSet.kt b/orx-panel/src/main/kotlin/org/openrndr/panel/collections/ObservableHashSet.kt new file mode 100644 index 00000000..bcb093c1 --- /dev/null +++ b/orx-panel/src/main/kotlin/org/openrndr/panel/collections/ObservableHashSet.kt @@ -0,0 +1,36 @@ +package org.openrndr.panel.collections + +import org.openrndr.events.Event +import java.util.* + +class ObservableHashSet : HashSet() { + + class ChangeEvent(val source: ObservableHashSet, val added: Set, val removed: Set) + + val changed = Event>() + + override fun add(element: E): Boolean { + return if (super.add(element)) { + changed.trigger(ChangeEvent(this, setOf(element), emptySet())) + true + } else { + false + } + } + + override fun remove(element: E): Boolean { + return if (super.remove(element)) { + changed.trigger(ChangeEvent(this, emptySet(), setOf(element))) + true + } else { + false + } + } + + override fun clear() { + val old = this.toSet() + super.clear() + changed.trigger(ChangeEvent(this, emptySet(), old)) + } + +} \ No newline at end of file diff --git a/orx-panel/src/main/kotlin/org/openrndr/panel/elements/Body.kt b/orx-panel/src/main/kotlin/org/openrndr/panel/elements/Body.kt new file mode 100644 index 00000000..6f53b6be --- /dev/null +++ b/orx-panel/src/main/kotlin/org/openrndr/panel/elements/Body.kt @@ -0,0 +1,5 @@ +package org.openrndr.panel.elements + +import org.openrndr.panel.ControlManager + +class Body(val controlManager: ControlManager) : Element(ElementType("Body")) \ No newline at end of file diff --git a/orx-panel/src/main/kotlin/org/openrndr/panel/elements/Button.kt b/orx-panel/src/main/kotlin/org/openrndr/panel/elements/Button.kt new file mode 100644 index 00000000..eea989fd --- /dev/null +++ b/orx-panel/src/main/kotlin/org/openrndr/panel/elements/Button.kt @@ -0,0 +1,100 @@ +package org.openrndr.panel.elements + +import org.openrndr.color.ColorRGBa +import org.openrndr.draw.Drawer +import org.openrndr.draw.FontImageMap +import org.openrndr.events.Event +import org.openrndr.panel.style.* +import org.openrndr.shape.Rectangle +import org.openrndr.text.Writer +import kotlin.math.round + + +class Button : Element(ElementType("button")) { + + var label: String = "OK" + + class ButtonEvent(val source: Button) + class Events(val clicked: Event = Event()) + + var data: Any? = null + + val events = Events() + + init { + mouse.pressed.listen { + it.cancelPropagation() + } + + mouse.clicked.listen { + if (disabled !in pseudoClasses) { + events.clicked.trigger(ButtonEvent(this)) + } + it.cancelPropagation() + } + + keyboard.pressed.listen { + if (it.key == 32) { + it.cancelPropagation() + if (disabled !in pseudoClasses) { + events.clicked.trigger(ButtonEvent(this)) + } + } + } + } + + override val widthHint: Double + get() { + computedStyle.let { style -> + val fontUrl = (root() as? Body)?.controlManager?.fontManager?.resolve(style.fontFamily) ?: "broken" + val fontSize = (style.fontSize as? LinearDimension.PX)?.value ?: 14.0 + val fontMap = FontImageMap.fromUrl(fontUrl, fontSize) + + val writer = Writer(null) + + writer.box = Rectangle(0.0, + 0.0, + Double.POSITIVE_INFINITY, + Double.POSITIVE_INFINITY) + + writer.drawStyle.fontMap = fontMap + writer.newLine() + writer.text(label, visible = false) + + return writer.cursor.x + } + } + + override fun draw(drawer: Drawer) { + + computedStyle.let { + + drawer.pushTransforms() + drawer.pushStyle() + drawer.fill = ((it.background as? Color.RGBa)?.color ?: ColorRGBa.PINK) + drawer.stroke = null + drawer.strokeWeight = 0.0 + + drawer.rectangle(0.0, 0.0, layout.screenWidth, layout.screenHeight) + + (root() as? Body)?.controlManager?.fontManager?.let { + val font = it.font(computedStyle) + val writer = Writer(drawer) + drawer.fontMap = (font) + val textWidth = writer.textWidth(label) + val textHeight = font.ascenderLength + + val offset = round((layout.screenWidth - textWidth) / 2.0) + val yOffset = round((layout.screenHeight / 2) + textHeight / 2.0 - 2.0) * 1.0 + + drawer.fill = ((computedStyle.color as? Color.RGBa)?.color ?: ColorRGBa.WHITE).opacify( + if (disabled in pseudoClasses) 0.25 else 1.0 + ) + drawer.text(label, 0.0 + offset, 0.0 + yOffset) + } + + drawer.popStyle() + drawer.popTransforms() + } + } +} \ No newline at end of file diff --git a/orx-panel/src/main/kotlin/org/openrndr/panel/elements/Canvas.kt b/orx-panel/src/main/kotlin/org/openrndr/panel/elements/Canvas.kt new file mode 100644 index 00000000..e758dbb0 --- /dev/null +++ b/orx-panel/src/main/kotlin/org/openrndr/panel/elements/Canvas.kt @@ -0,0 +1,44 @@ +package org.openrndr.panel.elements + +import org.openrndr.color.ColorRGBa +import org.openrndr.draw.* +import org.openrndr.math.Matrix44 + +class Canvas : Element(ElementType("canvas")) { + var userDraw: ((Drawer) -> Unit)? = null + private var renderTarget: RenderTarget? = null + + override fun draw(drawer: Drawer) { + val width = screenArea.width.toInt() + val height = screenArea.height.toInt() + + if (renderTarget != null) { + if (renderTarget?.width != width || renderTarget?.height != height) { + renderTarget?.colorBuffer(0)?.destroy() + renderTarget?.destroy() + renderTarget = null + } + } + + if (screenArea.width >= 1 && screenArea.height >= 1) { + if (renderTarget == null) { + renderTarget = renderTarget(screenArea.width.toInt(), screenArea.height.toInt(), drawer.context.contentScale) { + colorBuffer() + depthBuffer() + } + } + + renderTarget?.let { rt -> + drawer.isolatedWithTarget(rt) { + model = Matrix44.IDENTITY + view = Matrix44.IDENTITY + background(ColorRGBa.TRANSPARENT) + size(screenArea.width.toInt(), screenArea.height.toInt()) + ortho(rt) + userDraw?.invoke(this) + } + drawer.image(rt.colorBuffer(0), 0.0, 0.0) + } + } + } +} \ No newline at end of file diff --git a/orx-panel/src/main/kotlin/org/openrndr/panel/elements/Colorpicker.kt b/orx-panel/src/main/kotlin/org/openrndr/panel/elements/Colorpicker.kt new file mode 100644 index 00000000..461080af --- /dev/null +++ b/orx-panel/src/main/kotlin/org/openrndr/panel/elements/Colorpicker.kt @@ -0,0 +1,164 @@ +package org.openrndr.panel.elements + +import org.openrndr.KEY_BACKSPACE +import org.openrndr.KEY_ENTER +import org.openrndr.KEY_ESCAPE +import org.openrndr.MouseEvent +import org.openrndr.color.ColorHSVa +import org.openrndr.color.ColorRGBa +import org.openrndr.draw.ColorBuffer +import org.openrndr.draw.Drawer +import org.openrndr.draw.colorBuffer +import org.openrndr.events.Event +import org.openrndr.panel.style.Color +import org.openrndr.panel.style.color + +class Colorpicker : Element { + + internal var colorMap: ColorBuffer? = null + + var label: String = "Color" + + var saturation = 0.5 + var color: ColorRGBa + set(value) { + realColor = value + saturation = color.toHSVa().s + generateColorMap() + draw.dirty = true + } + get() { + return realColor + } + + private var realColor = ColorRGBa.WHITE + private var focussed = false + + class ColorChangedEvent(val source: Colorpicker, + val oldColor: ColorRGBa, + val newColor: ColorRGBa) + + class Events { + val colorChanged = Event() + } + + val events = Events() + + private var keyboardInput = "" + private fun pick(e: MouseEvent) { + val dx = e.position.x - layout.screenX + var dy = e.position.y - layout.screenY + + dy = 50.0 - dy + val oldColor = color + val hsv = ColorHSVa(360.0 / layout.screenWidth * dx, saturation, dy / 50.0) + realColor = hsv.toRGBa() + draw.dirty = true + events.colorChanged.trigger(ColorChangedEvent(this, oldColor, realColor)) + e.cancelPropagation() + } + constructor() : super(ElementType("colorpicker")) { + generateColorMap() + + mouse.exited.listen { + focussed = false + } + + mouse.scrolled.listen { + if (colorMap != null) { + //if (focussed) { + saturation = (saturation - it.rotation.y * 0.01).coerceIn(0.0, 1.0) + generateColorMap() + colorMap?.shadow?.upload() + it.cancelPropagation() + pick(it) + requestRedraw() + //} + } + } + + keyboard.focusLost.listen { + keyboardInput = "" + draw.dirty = true + } + + keyboard.character.listen { + keyboardInput += it.character + draw.dirty = true + it.cancelPropagation() + } + + keyboard.pressed.listen { + if (it.key == KEY_BACKSPACE) { + if (!keyboardInput.isEmpty()) { + keyboardInput = keyboardInput.substring(0, keyboardInput.length - 1) + draw.dirty = true + + } + it.cancelPropagation() + } + + if (it.key == KEY_ESCAPE) { + keyboardInput = "" + draw.dirty = true + it.cancelPropagation() + } + + + if (it.key == KEY_ENTER) { + val number = if (keyboardInput.length == 6) keyboardInput.toIntOrNull(16) else null + + number?.let { + val r = (number shr 16) and 0xff + val g = (number shr 8) and 0xff + val b = number and 0xff + val oldColor = color + color = ColorRGBa(r / 255.0, g / 255.0, b / 255.0) + events.colorChanged.trigger(ColorChangedEvent(this, oldColor, realColor)) + keyboardInput = "" + draw.dirty = true + + } + it.cancelPropagation() + } + } + + + mouse.pressed.listen { it.cancelPropagation(); focussed = true } + mouse.clicked.listen { it.cancelPropagation(); pick(it); focussed = true; } + mouse.dragged.listen { it.cancelPropagation(); pick(it); focussed = true; } + } + + private fun generateColorMap() { + colorMap?.shadow?.let { + for (y in 0..49) { + for (x in 0 until it.colorBuffer.width) { + val hsv = ColorHSVa(360.0 / it.colorBuffer.width * x, saturation, (49 - y) / 49.0) + it.write(x, y, hsv.toRGBa()) + } + } + it.upload() + } + } + + override fun draw(drawer: Drawer) { + if (colorMap == null) { + colorMap = colorBuffer(layout.screenWidth.toInt(), 50, 1.0) + generateColorMap() + } + + drawer.image(colorMap!!, 0.0, 0.0) + drawer.fill = (color) + drawer.stroke = null + drawer.shadeStyle = null + drawer.rectangle(0.0, 50.0, layout.screenWidth, 20.0) + + val f = (root() as? Body)?.controlManager?.fontManager?.font(computedStyle)!! + drawer.fontMap = f + drawer.fill = ((computedStyle.color as Color.RGBa).color) + + if (keyboardInput.isNotBlank()) { + drawer.text("input: $keyboardInput", 0.0, layout.screenHeight) + } + } +} \ No newline at end of file diff --git a/orx-panel/src/main/kotlin/org/openrndr/panel/elements/ColorpickerButton.kt b/orx-panel/src/main/kotlin/org/openrndr/panel/elements/ColorpickerButton.kt new file mode 100644 index 00000000..754fb3d8 --- /dev/null +++ b/orx-panel/src/main/kotlin/org/openrndr/panel/elements/ColorpickerButton.kt @@ -0,0 +1,121 @@ +package org.openrndr.panel.elements + +import org.openrndr.color.ColorRGBa +import org.openrndr.draw.Drawer +import org.openrndr.draw.LineCap +import org.openrndr.events.Event +import org.openrndr.panel.style.* +import org.openrndr.text.Writer + +class ColorpickerButton : Element(ElementType("colorpicker-button")) { + + var label: String = "OK" + var color: ColorRGBa = ColorRGBa(0.5, 0.5, 0.5) + set(value) { + if (value != field) { + field = value + events.valueChanged.trigger(ColorChangedEvent(this, value)) + } + } + + class ColorChangedEvent(val source: ColorpickerButton, val color: ColorRGBa) + + class Events { + val valueChanged = Event() + } + + val events = Events() + + init { + mouse.pressed.listen { + it.cancelPropagation() + } + mouse.clicked.listen { + append(SlideOut(0.0, screenArea.height, screenArea.width, 200.0, color, this)) + it.cancelPropagation() + } + } + + override fun append(element: Element) { + when (element) { + is Item, is SlideOut -> super.append(element) + else -> throw RuntimeException("only item and slideout") + } + super.append(element) + } + + fun items(): List = children.filter { it is Item }.map { it as Item } + + override fun draw(drawer: Drawer) { + + drawer.fill = ((computedStyle.background as? Color.RGBa)?.color ?: ColorRGBa.PINK) + drawer.stroke = null + drawer.strokeWeight = 0.0 + drawer.rectangle(0.0, 0.0, screenArea.width, screenArea.height) + + (root() as? Body)?.controlManager?.fontManager?.let { + val font = it.font(computedStyle) + + val writer = Writer(drawer) + drawer.fontMap = (font) + + val text = "$label" + + val textWidth = writer.textWidth(text) + val textHeight = font.ascenderLength + + val offset = Math.round((layout.screenWidth - textWidth) / 2.0) + val yOffset = Math.round((layout.screenHeight / 2) + textHeight / 2.0) - 2.0 + + drawer.fill = ((computedStyle.color as? Color.RGBa)?.color ?: ColorRGBa.WHITE) + drawer.fontMap = font + drawer.text(text, 0.0 + offset, 0.0 + yOffset) + drawer.stroke = (color) + drawer.pushStyle() + drawer.strokeWeight = (4.0) + drawer.lineCap = (LineCap.ROUND) + drawer.lineSegment(2.0, layout.screenHeight - 2.0, layout.screenWidth - 2.0, layout.screenHeight - 2.0) + drawer.popStyle() + } + } + + class SlideOut(val x: Double, val y: Double, val width: Double, val height: Double, color:ColorRGBa, parent: Element) : Element(ElementType("slide-out")) { + + init { + style = StyleSheet(CompoundSelector.DUMMY).apply { + position = Position.ABSOLUTE + left = LinearDimension.PX(x) + top = LinearDimension.PX(y) + width = LinearDimension.PX(this@SlideOut.width) + height = LinearDimension.Auto//LinearDimension.PX(this@SlideOut.height) + overflow = Overflow.Scroll + zIndex = ZIndex.Value(1000) + background = Color.RGBa(ColorRGBa(0.3, 0.3, 0.3)) + } + + val colorPicker = Colorpicker().apply { + this.color = color + label = (parent as ColorpickerButton).label + events.colorChanged.listen { + parent.color = it.newColor + parent.events.valueChanged.trigger(ColorChangedEvent(parent, parent.color)) + } + } + append(colorPicker) + + mouse.exited.listen { + dispose() + } + } + + override fun draw(drawer: Drawer) { + (root() as Body).controlManager.keyboardInput.requestFocus(children[0]) + drawer.fill = ((computedStyle.background as? Color.RGBa)?.color ?: ColorRGBa.PINK) + drawer.rectangle(0.0, 0.0, screenArea.width, screenArea.height) + } + + fun dispose() { + parent?.remove(this) + } + } +} \ No newline at end of file diff --git a/orx-panel/src/main/kotlin/org/openrndr/panel/elements/Div.kt b/orx-panel/src/main/kotlin/org/openrndr/panel/elements/Div.kt new file mode 100644 index 00000000..d545e54a --- /dev/null +++ b/orx-panel/src/main/kotlin/org/openrndr/panel/elements/Div.kt @@ -0,0 +1,44 @@ +package org.openrndr.panel.elements + +import org.openrndr.color.ColorRGBa +import org.openrndr.draw.Drawer +import org.openrndr.panel.style.Color +import org.openrndr.panel.style.Overflow +import org.openrndr.panel.style.background +import org.openrndr.panel.style.overflow +import kotlin.math.max + +open class Div : TextElement(ElementType("div")) { + init { + mouse.pressed.listen { + it.cancelPropagation() + } + mouse.scrolled.listen { + computedStyle.let { cs -> + if (cs.overflow != Overflow.Visible) { + scrollTop -= it.rotation.y * 10 + scrollTop = max(0.0, scrollTop) + draw.dirty = true + it.cancelPropagation() + } + } + } + } + + override fun draw(drawer: Drawer) { + computedStyle.let { style -> + style.background.let { + drawer.fill = ((it as? Color.RGBa)?.color ?: ColorRGBa.BLACK) + drawer.stroke = null + drawer.strokeWeight = 0.0 + //drawer.smooth(false) + drawer.rectangle(0.0, 0.0, layout.screenWidth, layout.screenHeight) + //drawer.smooth(true) + } + } + } + + override fun toString(): String { + return "Div(id=${id})" + } +} \ No newline at end of file diff --git a/orx-panel/src/main/kotlin/org/openrndr/panel/elements/DropdownButton.kt b/orx-panel/src/main/kotlin/org/openrndr/panel/elements/DropdownButton.kt new file mode 100644 index 00000000..766b879e --- /dev/null +++ b/orx-panel/src/main/kotlin/org/openrndr/panel/elements/DropdownButton.kt @@ -0,0 +1,281 @@ +package org.openrndr.panel.elements + +import org.openrndr.color.ColorRGBa +import org.openrndr.draw.Drawer +import org.openrndr.draw.FontImageMap +import org.openrndr.panel.style.* +import org.openrndr.shape.Rectangle +import org.openrndr.text.Writer +import kotlinx.coroutines.yield +import org.openrndr.KEY_ARROW_DOWN +import org.openrndr.KEY_ARROW_UP +import org.openrndr.KEY_ENTER +import org.openrndr.events.Event +import org.openrndr.launch +import kotlin.math.min +import kotlin.reflect.KMutableProperty0 + +class Item : Element(ElementType("item")) { + var label: String = "" + var data: Any? = null + + class PickedEvent(val source: Item) + + class Events { + val picked = Event() + } + + val events = Events() + + fun picked() { + events.picked.trigger(PickedEvent(this)) + } +} + +class DropdownButton : Element(ElementType("dropdown-button")) { + + var label: String = "OK" + var value: Item? = null + + class ValueChangedEvent(val source: DropdownButton, val value: Item) + + class Events { + val valueChanged = Event() + } + + val events = Events() + + init { + mouse.pressed.listen { + it.cancelPropagation() + } + + mouse.clicked.listen { + val itemCount = items().size + + if (children.none { it is SlideOut }) { + val height = min(240.0, itemCount * 24.0) + if (screenPosition.y < root().layout.screenHeight - height) { + val so = SlideOut(0.0, screenArea.height, screenArea.width, height, this, value) + append(so) + (root() as Body).controlManager.keyboardInput.requestFocus(so) + } else { + val so = SlideOut(0.0, screenArea.height - height, screenArea.width, height, this, value) + append(so) + (root() as Body).controlManager.keyboardInput.requestFocus(so) + } + } else { + (children.first { it is SlideOut } as SlideOut?)?.dispose() + } + } + } + + override val widthHint: Double? + get() { + computedStyle.let { style -> + val fontUrl = (root() as? Body)?.controlManager?.fontManager?.resolve(style.fontFamily) ?: "broken" + val fontSize = (style.fontSize as? LinearDimension.PX)?.value ?: 16.0 + val fontMap = FontImageMap.fromUrl(fontUrl, fontSize) + val writer = Writer(null) + + writer.box = Rectangle(0.0, + 0.0, + Double.POSITIVE_INFINITY, + Double.POSITIVE_INFINITY) + + val text = "$label ${(value?.label) ?: ""}" + writer.drawStyle.fontMap = fontMap + writer.newLine() + writer.text(text, visible = false) + + return writer.cursor.x + 10.0 + } + } + + + override fun append(element: Element) { + when (element) { + is Item, is SlideOut -> super.append(element) + else -> throw RuntimeException("only item and slideout") + } + super.append(element) + } + + fun items(): List = children.filterIsInstance().map { it } + + override fun draw(drawer: Drawer) { + + drawer.fill = ((computedStyle.background as? Color.RGBa)?.color ?: ColorRGBa.PINK) + drawer.stroke = null + drawer.rectangle(0.0, 0.0, screenArea.width, screenArea.height) + + (root() as? Body)?.controlManager?.fontManager?.let { + val font = it.font(computedStyle) + + val writer = Writer(drawer) + drawer.fontMap = (font) + + val text = (value?.label) ?: "" + + val textWidth = writer.textWidth(text) + val textHeight = font.ascenderLength + + val offset = Math.round((layout.screenWidth - textWidth)) + val yOffset = Math.round((layout.screenHeight / 2) + textHeight / 2.0) - 2.0 + + drawer.fill = ((computedStyle.color as? Color.RGBa)?.color ?: ColorRGBa.WHITE) + + drawer.text(label, 5.0, 0.0 + yOffset) + drawer.text(text, -5.0 + offset, 0.0 + yOffset) + } + } + + class SlideOut(val x: Double, val y: Double, val width: Double, val height: Double, parent: Element, active: Item?) : Element(ElementType("slide-out")) { + init { + + val itemButtons = mutableMapOf() + + var activeIndex = + if (active != null) { + (parent as DropdownButton).items().indexOf(active) + } else { + -1 + } + + keyboard.pressed.listen { + + if (it.key == KEY_ENTER) { + it.cancelPropagation() + dispose() + } + + if (it.key == KEY_ARROW_DOWN) { + activeIndex = (activeIndex + 1).coerceAtMost((parent as DropdownButton).items().size - 1) + it.cancelPropagation() + val newValue = parent.items()[activeIndex] + + parent.value?.let { + itemButtons[it]?.pseudoClasses?.remove(ElementPseudoClass("selected")) + } + parent.value?.let { + itemButtons[newValue]?.pseudoClasses?.add(ElementPseudoClass("selected")) + } + + parent.value = newValue + parent.events.valueChanged.trigger(ValueChangedEvent(parent, newValue)) + newValue.picked() + draw.dirty = true + + val ypos = 24.0 * activeIndex + if (ypos >= scrollTop + 10 * 24.0) { + scrollTop += 24.0 + } + + } + + if (it.key == KEY_ARROW_UP) { + activeIndex = (activeIndex - 1).coerceAtLeast(0) + + + val newValue = (parent as DropdownButton).items()[activeIndex] + + val ypos = 24.0 * activeIndex + if (ypos < scrollTop) { + scrollTop -= 24.0 + } + + parent.value?.let { + itemButtons[it]?.pseudoClasses?.remove(ElementPseudoClass("selected")) + } + parent.value?.let { + itemButtons[newValue]?.pseudoClasses?.add(ElementPseudoClass("selected")) + } + + parent.value = newValue + parent.events.valueChanged.trigger(ValueChangedEvent(parent, newValue)) + newValue.picked() + draw.dirty = true + } + } + + mouse.scrolled.listen { + scrollTop -= it.rotation.y + scrollTop = Math.max(0.0, scrollTop) + draw.dirty = true + it.cancelPropagation() + } + + mouse.exited.listen { + it.cancelPropagation() + dispose() + } + + style = StyleSheet(CompoundSelector.DUMMY).apply { + position = Position.ABSOLUTE + left = LinearDimension.PX(x) + top = LinearDimension.PX(y) + width = LinearDimension.PX(this@SlideOut.width) + height = LinearDimension.PX(this@SlideOut.height) + overflow = Overflow.Scroll + zIndex = ZIndex.Value(1000) + background = Color.Inherit + } + + (parent as DropdownButton).items().forEach { + append(Button().apply { + data = it + label = it.label + itemButtons[it] = this + events.clicked.listen { + parent.value = it.source.data as Item + parent.events.valueChanged.trigger(ValueChangedEvent(parent, it.source.data as Item)) + (data as Item).picked() + dispose() + } + }) + } + active?.let { + itemButtons[active]?.pseudoClasses?.add(ElementPseudoClass("selected")) + } + } + + override fun draw(drawer: Drawer) { + drawer.fill = ((computedStyle.background as? Color.RGBa)?.color ?: ColorRGBa.PINK) + drawer.stroke = null + drawer.strokeWeight = 0.0 + drawer.rectangle(0.0, 0.0, screenArea.width, screenArea.height) + drawer.strokeWeight = 1.0 + } + + fun dispose() { + parent?.remove(this) + } + } +} + +fun > DropdownButton.bind(property: KMutableProperty0, map: Map) { + val options = mutableMapOf() + map.forEach { (k, v) -> + options[k] = item { + label = v + events.picked.listen { + property.set(k) + } + } + } + var currentValue = property.get() + value = options[currentValue] + draw.dirty = true + + (root() as? Body)?.controlManager?.program?.launch { + while (true) { + val cval = property.get() + if (cval != currentValue) { + currentValue = cval + value = options[cval] + draw.dirty = true + } + yield() + } + } +} diff --git a/orx-panel/src/main/kotlin/org/openrndr/panel/elements/Element.kt b/orx-panel/src/main/kotlin/org/openrndr/panel/elements/Element.kt new file mode 100644 index 00000000..2fd85f3a --- /dev/null +++ b/orx-panel/src/main/kotlin/org/openrndr/panel/elements/Element.kt @@ -0,0 +1,289 @@ +package org.openrndr.panel.elements + +import org.openrndr.DropEvent +import org.openrndr.KeyEvent +import org.openrndr.MouseEvent +import org.openrndr.Program +import org.openrndr.draw.Drawer +import org.openrndr.events.Event +import org.openrndr.math.Vector2 +import org.openrndr.panel.collections.ObservableCopyOnWriteArrayList +import org.openrndr.panel.collections.ObservableHashSet +import org.openrndr.panel.style.CompoundSelector +import org.openrndr.panel.style.StyleSheet +import org.openrndr.shape.Rectangle + +import java.util.* + +data class ElementClass(val name: String) +data class ElementPseudoClass(val name: String) +data class ElementType(val name: String) + +val disabled = ElementPseudoClass("disabled") + +class FocusEvent + +open class Element(val type: ElementType) { + + var scrollTop = 0.0 + open val handlesDoubleClick = false + + open val widthHint: Double? + get() { + return null + } + + class MouseObservables { + val clicked = Event("element-mouse-clicked") + val doubleClicked = Event("element-mouse-double-clicked") + val entered = Event("element-mouse-entered") + val exited = Event("element-mouse-exited") + val dragged = Event("element-mouse-dragged") + val moved = Event("element-mouse-moved") + val scrolled = Event("element-mouse-scrolled") + val pressed = Event("element-mouse-pressed") + } + + class DropObserverables { + val dropped = Event("element-dropped") + } + + val drop = DropObserverables() + val mouse = MouseObservables() + + class KeyboardObservables { + val pressed = Event("element-keyboard-pressed") + val released = Event("element-keyboard-released") + val repeated = Event("element-keyboard-repeated") + val character = Event("element-keyboard-character") + val focusGained = Event("element-keyboard-focus-gained") + val focusLost = Event("element-keyboard-focus-lost") + } + + val keyboard = KeyboardObservables() + + class Layout { + var zIndex = 0 + var screenX = 0.0 + var screenY = 0.0 + var screenWidth = 0.0 + var screenHeight = 0.0 + var growWidth = 0.0 + var growHeight = 0.0 + override fun toString(): String { + return "Layout(screenX=$screenX, screenY=$screenY, screenWidth=$screenWidth, screenHeight=$screenHeight, growWidth=$growWidth, growHeight=$growHeight)" + } + } + + class Draw { + var dirty = true + } + + val draw = Draw() + val layout = Layout() + + class ClassEvent(val source: Element, val `class`: ElementClass) + class ClassObserverables { + val classAdded = Event("element-class-added") + val classRemoved = Event("element-class-removed") + } + + val classEvents = ClassObserverables() + + + var id: String? = null + val classes: ObservableHashSet = ObservableHashSet() + val pseudoClasses: ObservableHashSet = ObservableHashSet() + + var parent: Element? = null + val children: ObservableCopyOnWriteArrayList = ObservableCopyOnWriteArrayList() + get() = field + + var computedStyle: StyleSheet = StyleSheet(CompoundSelector.DUMMY) + var style: StyleSheet? = null + + init { + pseudoClasses.changed.listen { + draw.dirty = true + } + classes.changed.listen { + draw.dirty = true + it.added.forEach { + classEvents.classAdded.trigger(ClassEvent(this, it)) + } + it.removed.forEach { + classEvents.classRemoved.trigger(ClassEvent(this, it)) + } + + } + + children.changed.listen { + draw.dirty = true + } + } + + + fun root(): Element { + return parent?.root() ?: this + } + + open fun append(element: Element) { + if (element !in children) { + element.parent = this + children.add(element) + } + } + + fun remove(element: Element) { + if (element in children) { + element.parent = null + children.remove(element) + } + } + + open fun draw(drawer: Drawer) { + + } + + fun filter(f: (Element) -> Boolean): List { + val result = ArrayList() + val stack = Stack() + + stack.add(this) + while (!stack.isEmpty()) { + val node = stack.pop() + if (f(node)) { + result.add(node) + stack.addAll(node.children) + } + } + return result + } + + fun flatten(): List { + val result = ArrayList() + val stack = Stack() + + stack.add(this) + while (!stack.isEmpty()) { + val node = stack.pop() + + result.add(node) + stack.addAll(node.children) + } + return result + } + + fun previousSibling(): Element? { + parent?.let { p -> + p.childIndex(this)?.let { + if (it > 0) { + return p.children[it - 1] + } + } + } + return null + } + + fun childIndex(element: Element): Int? { + if (element in children) { + return children.indexOf(element) + } else { + return null + } + } + + fun ancestors(): List { + var c = this + val result = ArrayList() + + while (c.parent != null) { + c.parent?.let { + result.add(it) + c = it + } + } + return result + } + + fun previous(): Element? { + return parent?.let { p -> + val index = p.children.indexOf(this) + when (index) { + -1, 0 -> null + else -> p.children[index - 1] + } + } + } + + fun next(): Element? { + return parent?.let { p -> + when (val index = p.children.indexOf(this)) { + -1, p.children.size - 1 -> null + else -> p.children[index + 1] + } + } + + } + + fun move(steps: Int) { + parent?.let { p -> + if (steps != 0) { + val index = p.children.indexOf(this) + p.children.add(index + steps, this) + if (steps > 0) { + p.children.removeAt(index) + } else { + p.children.removeAt(index + 1) + } + } + } + } + + fun findFirst(element: Element, matches: (Element) -> Boolean): Element? { + if (matches.invoke(element)) { + return element + } else { + element.children.forEach { c -> + findFirst(c, matches)?.let { return it } + } + return null + } + } + + inline fun elementWithId(id: String): T? { + return findFirst(this) { e -> e.id == id && e is T } as T + } + + val screenPosition: Vector2 + get() = Vector2(layout.screenX, layout.screenY) + + val screenArea: Rectangle + get() = Rectangle(Vector2(layout.screenX, + layout.screenY), + layout.screenWidth, + layout.screenHeight) + + +} + +fun Element.requestRedraw() { + draw.dirty = true +} + +fun Element.disable() { + pseudoClasses.add(disabled) + requestRedraw() +} + +fun Element.enable() { + pseudoClasses.remove(disabled) + requestRedraw() +} + +fun Element.isDisabled(): Boolean = disabled in pseudoClasses + +fun Element.visit(function: Element.() -> Unit) { + this.function() + children.forEach { it.visit(function) } +} \ No newline at end of file diff --git a/orx-panel/src/main/kotlin/org/openrndr/panel/elements/EnvelopeButton.kt b/orx-panel/src/main/kotlin/org/openrndr/panel/elements/EnvelopeButton.kt new file mode 100644 index 00000000..3a6637b4 --- /dev/null +++ b/orx-panel/src/main/kotlin/org/openrndr/panel/elements/EnvelopeButton.kt @@ -0,0 +1,139 @@ +package org.openrndr.panel.elements + +import org.openrndr.color.ColorRGBa +import org.openrndr.draw.Drawer +import org.openrndr.math.Vector2 +import org.openrndr.panel.style.* +import org.openrndr.text.Cursor +import org.openrndr.text.Writer + +class EnvelopeButton : Element(ElementType("envelope-button")) { + + var label = "OK" + var envelope = Envelope() + set(value) { + field = value + envelopeSubscription?.let { + value.events.envelopeChanged.cancel(it) + } + envelopeSubscription = value.events.envelopeChanged.listen { + draw.dirty = true + } + } + + + var envelopeSubscription: ((Envelope.EnvelopeChangedEvent)->Unit)? = null + + init { + mouse.clicked.listen { + append(SlideOut(0.0, screenArea.height, screenArea.width, 200.0, this)) + } + envelopeSubscription = envelope.events.envelopeChanged.listen { + draw.dirty = true + } + } + + override fun append(element: Element) { + when (element) { + is Item, is SlideOut -> super.append(element) + else -> throw RuntimeException("only item and slideout") + } + super.append(element) + } + + fun items(): List = children.filter { it is Item }.map { it as Item } + + override fun draw(drawer: Drawer) { + drawer.fill = ((computedStyle.background as? Color.RGBa)?.color ?: ColorRGBa.PINK) + drawer.rectangle(0.0, 0.0, screenArea.width, screenArea.height) + + (root() as? Body)?.controlManager?.fontManager?.let { + var chartHeight = 0.0 + + (root() as? Body)?.controlManager?.fontManager?.let { + val font = it.font(computedStyle) + + val writer = Writer(drawer) + drawer.fontMap = (font) + drawer.fill = (ColorRGBa.BLACK) + writer.cursor = Cursor(0.0,layout.screenHeight - 4.0) + chartHeight = writer.cursor.y - font.height-4 + writer.text("$label") + } + + + val w = layout.screenWidth + val h = chartHeight + val m = envelope.points.map { + val v = (Vector2(w, h) * it) + Vector2(v.x, h - v.y) + } + + if (m.size > 1) { + drawer.stroke = (ColorRGBa.WHITE) + drawer.strokeWeight = (2.0) + drawer.lineStrip(m) + } + if (m.size == 1) { + drawer.stroke = (ColorRGBa.WHITE) + drawer.strokeWeight = (2.0) + drawer.lineSegment(0.0, m[0].y, layout.screenWidth, m[0].y) + } + + drawer.stroke = (ColorRGBa.BLACK.opacify(0.25)) + drawer.strokeWeight = (1.0) + drawer.lineSegment(envelope.offset * w, 0.0, envelope.offset * w, chartHeight) + + drawer.lineSegment(0.0, 0.0, 3.0, 0.0) + drawer.lineSegment(0.0, 0.0, 0.0, chartHeight) + drawer.lineSegment(0.0, chartHeight, 3.0, chartHeight) + + drawer.lineSegment(w, 0.0, w-3.0, 0.0) + drawer.lineSegment(w, 0.0, w, chartHeight) + drawer.lineSegment(w, chartHeight, w-3.0, chartHeight) + } + } + + + class SlideOut(val x: Double, val y: Double, val width: Double, val height: Double, parent: EnvelopeButton) : Element(ElementType("envelope-slide-out")) { + + init { + + mouse.clicked.listen { + it.cancelPropagation() + } + style = StyleSheet(CompoundSelector.DUMMY).apply { + position = Position.ABSOLUTE + left = LinearDimension.PX(x) + top = LinearDimension.PX(y) + width = LinearDimension.PX(this@SlideOut.width) + height = LinearDimension.Auto//LinearDimension.PX(this@SlideOut.height) + overflow = Overflow.Scroll + zIndex = ZIndex.Value(1) + background = Color.RGBa(ColorRGBa(0.3, 0.3, 0.3)) + } + + append(EnvelopeEditor().apply { + envelope = parent.envelope + }) + + append(Button().apply { + label = "done" + events.clicked.listen { + //parent.value = it.source.data as Item + //parent.events.valueChanged.onNext(ValueChangedEvent(parent, it.source.data as Item)) + dispose() + } + }) + } + + override fun draw(drawer: Drawer) { + drawer.fill = ((computedStyle.background as? Color.RGBa)?.color ?: ColorRGBa.PINK) + drawer.rectangle(0.0, 0.0, screenArea.width, screenArea.height) + } + + fun dispose() { + parent?.remove(this) + } + } +} \ No newline at end of file diff --git a/orx-panel/src/main/kotlin/org/openrndr/panel/elements/EnvelopeEditor.kt b/orx-panel/src/main/kotlin/org/openrndr/panel/elements/EnvelopeEditor.kt new file mode 100644 index 00000000..1994a701 --- /dev/null +++ b/orx-panel/src/main/kotlin/org/openrndr/panel/elements/EnvelopeEditor.kt @@ -0,0 +1,229 @@ +package org.openrndr.panel.elements + +import org.openrndr.MouseButton +import org.openrndr.color.ColorRGBa +import org.openrndr.draw.Drawer +import org.openrndr.math.Vector2 +import org.openrndr.KeyModifier +import org.openrndr.events.Event + +class Envelope(constant:Double = 0.5) { + + val points = mutableListOf(Vector2(0.5, constant)) + var activePoint: Vector2? = null + + var offset:Double = 0.0 + set(value) { field = value; events.envelopeChanged.trigger(EnvelopeChangedEvent(this))} + + class EnvelopeChangedEvent(val envelope: Envelope) + + class Events { + val envelopeChanged = Event("envelope-changed") + } + val events = Events() + + fun insertPoint(v: Vector2) { + for (i in 0 until points.size) { + if (points[i].x > v.x) { + points.add(i, v) + activePoint = v + events.envelopeChanged.trigger(EnvelopeChangedEvent(this)) + return + } + } + points.add(v) + activePoint = v + fixBounds() + events.envelopeChanged.trigger(EnvelopeChangedEvent(this)) + } + + fun findNearestPoint(v: Vector2) = points.minBy { (it - v).length } + + fun removePoint(v: Vector2) { + points.remove(v) + if (v === activePoint) { + activePoint = null + } + fixBounds() + events.envelopeChanged.trigger(EnvelopeChangedEvent(this)) + } + + private fun fixBounds() { + if (points.size >= 2) { + if (points[0].x != 0.0) { + points[0].copy(x=0.0).let { + if (activePoint === points[0]) { + activePoint = it + } + points[0] = it + } + } + if (points[points.size-1].x != 1.0) { + points[points.size-1].copy(x=1.0).let { + if (activePoint === points[points.size-1]) { + activePoint = it + } + points[points.size-1] = it + } + } + } + } + + fun updatePoint(old: Vector2, new: Vector2) { + val index = points.indexOf(old) + if (index != -1) { + points[index] = new + } + if (old === activePoint) { + activePoint = new + } + points.sortBy { it.x } + + fixBounds() + events.envelopeChanged.trigger(EnvelopeChangedEvent(this)) + } + + fun value(t: Double): Double { + + val st = t.coerceIn(0.0, 1.0) + + if (points.size == 1) { + return points[0].y + } + else if (points.size == 2) { + return points[0].y * (1.0-st) + points[1].y * st + } else { + if (st == 0.0) { + return points[0].y + } + if (st == 1.0) { + return points[points.size-1].y + } + + for (i in 0 until points.size-1) { + if (points[i].x <= st && points[i+1].x > st) { + val left = points[i] + var right = points[i+1] + + val dt = right.x - left.x + if (dt > 0.0) { + val f = (t - left.x) / dt + return left.y * (1.0-f) + right.y * f + } else { + return left.y + } + + } + } + return points[0].y + + } + + } + +} + +// -- + +class EnvelopeEditor : Element(ElementType("envelope-editor")) { + + var envelope = Envelope() + + init { + + fun query(position: Vector2): Vector2 { + val x = (position.x - layout.screenX) / layout.screenWidth + val y = 1.0 - ((position.y - layout.screenY) / layout.screenHeight) + + return Vector2(x, y) + } + + mouse.clicked.listen { + val query = query(it.position) + val nearest = envelope.findNearestPoint(query) + val distance = nearest?.let { (it - query).length } + + if (it.button == MouseButton.LEFT && !it.modifiers.contains(KeyModifier.CTRL)) { + when { + distance == null -> { + envelope.insertPoint(query) + draw.dirty = true + } + distance < 0.05 -> { + envelope.activePoint = nearest + } + else -> { + envelope.insertPoint(query) + draw.dirty = true + } + } + } else if (it.button == MouseButton.LEFT) { + if (distance != null && distance < 0.1) { + envelope.removePoint(nearest) + draw.dirty = true + } + } + it.cancelPropagation() + } + + mouse.pressed.listen { + val query = query(it.position) + val nearest = envelope.findNearestPoint(query) + val distance = nearest?.let { it - query }?.length + + if (distance == null) { + envelope.activePoint = null + draw.dirty = true + } else if (distance < 0.1) { + envelope.activePoint = nearest + } else { + envelope.activePoint = null + } + it.cancelPropagation() + } + + mouse.dragged.listen { + envelope.activePoint?.let { activePoint -> + val query = query(it.position) + if (!it.modifiers.contains(KeyModifier.SHIFT)) { + envelope.updatePoint(activePoint, query) + } else { + envelope.updatePoint(activePoint, Vector2(activePoint.x, query.y)) + } + draw.dirty = true + } + it.cancelPropagation() + } + } + + override fun draw(drawer: Drawer) { + val w = layout.screenWidth + val h = layout.screenHeight + + val m = envelope.points.map { + val v = (it * Vector2(w, h)) + Vector2(v.x, h - v.y) + } + + drawer.stroke = (ColorRGBa.BLACK.opacify(0.25)) + drawer.strokeWeight = (1.0) + drawer.lineSegment(layout.screenWidth/2.0, 0.0, layout.screenWidth/2.0,layout.screenHeight) + drawer.lineSegment(0.0,layout.screenHeight/2.0,layout.screenWidth, layout.screenHeight/2.0) + + if (m.size > 1) { + drawer.stroke = (ColorRGBa.WHITE) + drawer.strokeWeight = (2.0) + drawer.lineStrip(m) + drawer.fill = (ColorRGBa.WHITE) + drawer.stroke = null + drawer.circles(m, 4.0) + } else if (m.size == 1) { + drawer.stroke = (ColorRGBa.WHITE) + drawer.strokeWeight = (2.0) + drawer.lineSegment(0.0, m[0].y, layout.screenWidth, m[0].y) + drawer.fill = (ColorRGBa.WHITE) + drawer.stroke = null + drawer.circle(m[0], 4.0) + } + } +} diff --git a/orx-panel/src/main/kotlin/org/openrndr/panel/elements/LayoutBuilder.kt b/orx-panel/src/main/kotlin/org/openrndr/panel/elements/LayoutBuilder.kt new file mode 100644 index 00000000..4b2e9042 --- /dev/null +++ b/orx-panel/src/main/kotlin/org/openrndr/panel/elements/LayoutBuilder.kt @@ -0,0 +1,95 @@ +package org.openrndr.panel.elements + +import org.openrndr.draw.Drawer +import org.openrndr.panel.ControlManager + +fun Element.layout(init: Element.() -> Unit) { + init() +} + +fun layout(controlManager: ControlManager, init: Body.() -> Unit): Body { + val body = Body(controlManager) + body.init() + return body +} + +fun Element.initElement(classes: Array, element: T, init: T.() -> Unit): Element { + append(element) + element.classes.addAll(classes.map { ElementClass(it) }) + element.init() + return element +} + +fun Element.button(vararg classes: String, label: String = "button", init: Button.() -> Unit): Button { + val button = Button().apply { + this.classes.addAll(classes.map { ElementClass(it) }) + this.id = id + this.label = label + } + initElement(classes, button, init) + return button +} + +fun Button.clicked(listener: (Button.ButtonEvent) -> Unit) { + events.clicked.listen(listener) +} + +fun Element.slider(vararg classes: String, init: Slider.() -> Unit) = initElement(classes, Slider(), init) as Slider +fun Element.toggle(vararg classes: String, init: Toggle.() -> Unit) = initElement(classes, Toggle(), init) as Toggle + +fun Element.colorpicker(vararg classes: String, init: Colorpicker.() -> Unit) = initElement(classes, Colorpicker(), init) +fun Element.colorpickerButton(vararg classes: String, init: ColorpickerButton.() -> Unit) = initElement(classes, ColorpickerButton(), init) + +fun Element.xyPad(vararg classes: String, init: XYPad.() -> Unit) = initElement(classes, XYPad(), init) as XYPad + +fun Canvas.draw(f: (Drawer) -> Unit) { + this.userDraw = f +} + +fun Element.canvas(vararg classes: String, init: Canvas.() -> Unit) { + val canvas = Canvas() + classes.forEach { canvas.classes.add(ElementClass(it)) } + canvas.init() + append(canvas) +} + +fun Element.dropdownButton(vararg classes: String, id: String? = null, label: String = "button", init: DropdownButton.() -> Unit) = initElement(classes, DropdownButton().apply { + this.id = id + this.label = label +}, init) + +fun Element.envelopeButton(vararg classes: String, init: EnvelopeButton.() -> Unit) = initElement(classes, EnvelopeButton().apply {}, init) +fun Element.envelopeEditor(vararg classes: String, init: EnvelopeEditor.() -> Unit) = initElement(classes, EnvelopeEditor().apply {}, init) + +fun Element.sequenceEditor(vararg classes: String, init: SequenceEditor.() -> Unit) = initElement(classes, SequenceEditor().apply {}, init) + + +fun Element.textfield(vararg classes: String, init: Textfield.() -> Unit) = initElement(classes, Textfield(), init) + +fun DropdownButton.item(init: Item.() -> Unit): Item { + val item = Item().apply(init) + + + append(item) + return item +} + +fun Element.div(vararg classes: String, init: Div.() -> Unit): Div { + val div = Div() + initElement(classes, div, init) + return div +} + +inline fun Element.textElement(classes: Array, init: T.() -> String): T { + val te = T::class.java.newInstance() + te.classes.addAll(classes.map { ElementClass(it) }) + te.text(te.init()) + append(te) + return te +} + +fun Element.p(vararg classes: String, init: P.() -> String): P = textElement(classes, init) +fun Element.h1(vararg classes: String, init: H1.() -> String): H1 = textElement(classes, init) +fun Element.h2(vararg classes: String, init: H2.() -> String): H2 = textElement(classes, init) +fun Element.h3(vararg classes: String, init: H3.() -> String): H3 = textElement(classes, init) + diff --git a/orx-panel/src/main/kotlin/org/openrndr/panel/elements/SequenceEditor.kt b/orx-panel/src/main/kotlin/org/openrndr/panel/elements/SequenceEditor.kt new file mode 100644 index 00000000..db998aaf --- /dev/null +++ b/orx-panel/src/main/kotlin/org/openrndr/panel/elements/SequenceEditor.kt @@ -0,0 +1,150 @@ +package org.openrndr.panel.elements + +import kotlinx.coroutines.* +import org.openrndr.KeyModifier +import org.openrndr.color.ColorRGBa +import org.openrndr.draw.Drawer +import org.openrndr.draw.LineCap +import org.openrndr.events.Event +import org.openrndr.math.Vector2 +import org.openrndr.panel.tools.Tooltip +import kotlin.math.abs +import kotlin.math.round +import kotlin.math.roundToInt + +class SequenceEditor : Element(ElementType("sequence-editor")) { + + var value = mutableListOf(0.0) + var precision = 2 + var maximumSequenceLength = 16 + var minimumSequenceLength = 1 + + private var selectedIndex: Int? = null + private var tooltip: Tooltip? = null + + class ValueChangedEvent(val source: SequenceEditor, + val oldValue: List, + val newValue: List) + + class Events { + val valueChanged = Event("sequence-editor-value-changed") + } + + val events = Events() + + init { + fun query(position: Vector2): Vector2 { + val x = (position.x - layout.screenX) / layout.screenWidth + val y = 1.0 - ((position.y - layout.screenY) / (layout.screenHeight * 0.5)) + return Vector2(x, y) + } + + mouse.clicked.listen { + it.cancelPropagation() + requestRedraw() + } + mouse.pressed.listen { + if (value.isNotEmpty()) { + val dx = (layout.screenWidth / (value.size + 1)) + val index = (it.position.x - layout.screenX) / dx + + val d = index - round(index) + val dp = d * dx + val dpa = abs(dp) + + if (dpa < 10.0) { + selectedIndex = if (KeyModifier.CTRL !in it.modifiers) { + round(index).toInt() + } else { + if (value.size > minimumSequenceLength) { + val oldValue = value.map { it } + value.removeAt(round(index).toInt() - 1) + events.valueChanged.trigger(ValueChangedEvent(this, oldValue, value)) + } + null + } + } else { + if (KeyModifier.CTRL !in it.modifiers) { + if (value.size < maximumSequenceLength) { + val q = query(it.position) + val oldValue = value.map { it } + value.add(index.toInt(), q.y) + events.valueChanged.trigger(ValueChangedEvent(this, oldValue, value)) + } + } + } + } + it.cancelPropagation() + } + + var hoverJob: Job? = null + + mouse.exited.listen { + hoverJob?.cancel() + if (tooltip != null) { + tooltip = null + requestRedraw() + } + } + + mouse.moved.listen { + hoverJob?.let { job -> + job.cancel() + } + if (tooltip != null) { + tooltip = null + requestRedraw() + } + + if (value.isNotEmpty()) { + val dx = (layout.screenWidth / (value.size + 1)) + val index = (it.position.x - layout.screenX) / dx + val d = index - round(index) + val dp = d * dx + val dpa = abs(dp) + + if (dpa < 10.0) { + hoverJob = GlobalScope.launch { + val readIndex = index.roundToInt() - 1 + if (readIndex >= 0 && readIndex < value.size) { + val value = String.format("%.0${precision}f", value[readIndex]) + tooltip = Tooltip(this@SequenceEditor, it.position - Vector2(layout.screenX, layout.screenY), "index: ${index.roundToInt()}, $value") + requestRedraw() + } + } + } + } + } + mouse.dragged.listen { + val q = query(it.position) + selectedIndex?.let { index -> + val writeIndex = index - 1 + if (writeIndex >= 0 && writeIndex < value.size) { + val oldValue = value.map { it } + value[writeIndex] = q.y.coerceIn(-1.0, 1.0) + events.valueChanged.trigger(ValueChangedEvent(this, oldValue, value)) + } + requestRedraw() + } + } + } + + override fun draw(drawer: Drawer) { + drawer.stroke = (ColorRGBa.BLACK.opacify(0.25)) + drawer.strokeWeight = (1.0) + drawer.lineSegment(0.0, layout.screenHeight / 2.0, layout.screenWidth, layout.screenHeight / 2.0) + + drawer.strokeWeight = 1.0 + drawer.stroke = ColorRGBa.WHITE + for (i in value.indices) { + val dx = layout.screenWidth / (value.size + 1) + val height = -value[i] * layout.screenHeight / 2.0 + + val x = dx * (i + 1) + drawer.lineCap = LineCap.ROUND + drawer.lineSegment(x, layout.screenHeight / 2.0, x, layout.screenHeight / 2.0 + height) + drawer.circle(x, layout.screenHeight / 2.0 + height, 5.0) + } + tooltip?.draw(drawer) + } +} diff --git a/orx-panel/src/main/kotlin/org/openrndr/panel/elements/Slider.kt b/orx-panel/src/main/kotlin/org/openrndr/panel/elements/Slider.kt new file mode 100644 index 00000000..465bc9e7 --- /dev/null +++ b/orx-panel/src/main/kotlin/org/openrndr/panel/elements/Slider.kt @@ -0,0 +1,251 @@ +package org.openrndr.panel.elements + +import kotlinx.coroutines.yield +import mu.KotlinLogging +import org.openrndr.* +import org.openrndr.draw.Drawer +import org.openrndr.draw.LineCap +import org.openrndr.events.Event +import org.openrndr.math.Vector2 +import org.openrndr.panel.style.Color +import org.openrndr.panel.style.color +import org.openrndr.panel.style.effectiveColor +import org.openrndr.shape.Rectangle +import org.openrndr.text.Cursor +import org.openrndr.text.Writer +import java.text.NumberFormat +import java.text.ParseException +import kotlin.reflect.KMutableProperty0 + +private val logger = KotlinLogging.logger {} + +data class Range(val min: Double, val max: Double) { + val span: Double get() = max - min +} + +class Slider : Element(ElementType("slider")) { + var label = "" + var precision = 3 + var value: Double + set(v) { + val oldV = realValue + realValue = clean(v) + if (realValue != oldV) { + draw.dirty = true + events.valueChanged.trigger(ValueChangedEvent(this, false, oldV, realValue)) + } + } + get() = realValue + + private var interactiveValue: Double + set(v) { + val oldV = realValue + realValue = clean(v) + if (realValue != oldV) { + draw.dirty = true + events.valueChanged.trigger(ValueChangedEvent(this, true, oldV, realValue)) + } + } + get() = realValue + + + var range = Range(0.0, 10.0) + set(value) { + field = value + this.value = this.value + } + private var realValue = 0.0 + + fun clean(value: Double): Double { + val cleanV = value.coerceIn(range.min, range.max) + val quantized = String.format("%.0${precision}f", cleanV).replace(",", ".").toDouble() + return quantized + } + + class ValueChangedEvent(val source: Slider, + val interactive: Boolean, + val oldValue: Double, + val newValue: Double) + + class Events { + val valueChanged = Event("slider-value-changed") + } + + val events = Events() + + private val margin = 7.0 + private var keyboardInput = "" + + init { + mouse.pressed.listen { + val t = (it.position.x - layout.screenX - margin) / (layout.screenWidth - 2.0 * margin) + interactiveValue = t * range.span + range.min + it.cancelPropagation() + } + mouse.clicked.listen { + val t = (it.position.x - layout.screenX - margin) / (layout.screenWidth - 2.0 * margin) + interactiveValue = t * range.span + range.min + it.cancelPropagation() + } + mouse.dragged.listen { + val t = (it.position.x - layout.screenX - margin) / (layout.screenWidth - 2.0 * margin) + interactiveValue = t * range.span + range.min + it.cancelPropagation() + } + + mouse.scrolled.listen { + if (Math.abs(it.rotation.y) < 0.001) { + interactiveValue += range.span * 0.001 * it.rotation.x + it.cancelPropagation() + } + } + + keyboard.focusLost.listen { + keyboardInput = "" + draw.dirty = true + } + + keyboard.character.listen { + if (it.character in setOf('0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '.', ',', '-')) { + try { + val candidate = keyboardInput + it.character.toString() + if (candidate.length > 1) { + NumberFormat.getInstance().parse(candidate).toDouble() + } + keyboardInput = candidate + requestRedraw() + } catch (e: ParseException) { + } + } + it.cancelPropagation() + } + + + keyboard.repeated.listen { + val delta = Math.pow(10.0, -(precision - 0.0)) + if (it.key == KEY_ARROW_RIGHT) { + interactiveValue += delta + it.cancelPropagation() + } + + if (it.key == KEY_ARROW_LEFT) { + interactiveValue -= delta + it.cancelPropagation() + } + + } + keyboard.pressed.listen { + val delta = Math.pow(10.0, -(precision - 0.0)) + + if (it.key == KEY_ARROW_RIGHT) { + interactiveValue += delta + it.cancelPropagation() + } + + if (it.key == KEY_ARROW_LEFT) { + interactiveValue -= delta + it.cancelPropagation() + } + + if (it.key == KEY_BACKSPACE) { + if (!keyboardInput.isEmpty()) { + keyboardInput = keyboardInput.substring(0, keyboardInput.length - 1) + draw.dirty = true + } + it.cancelPropagation() + } + + if (it.key == KEY_ESCAPE) { + keyboardInput = "" + draw.dirty = true + it.cancelPropagation() + } + + if (it.key == KEY_ENTER) { + val number = NumberFormat.getInstance().parse(keyboardInput).toDouble() + if (number != null) { + interactiveValue = number.coerceIn(range.min, range.max) + } + keyboardInput = "" + draw.dirty = true + it.cancelPropagation() + } + + if (it.key == KEY_HOME) { + interactiveValue = range.min + keyboardInput = "" + it.cancelPropagation() + } + + if (it.key == KEY_END) { + interactiveValue = range.max + keyboardInput = "" + it.cancelPropagation() + } + } + } + + override fun draw(drawer: Drawer) { + val f = (root() as? Body)?.controlManager?.fontManager?.font(computedStyle)!! + drawer.translate(0.0, (layout.screenHeight - (10.0 + f.height)) / 2) + + drawer.fill = ((computedStyle.color as Color.RGBa).color) + drawer.stroke = ((computedStyle.color as Color.RGBa).color) + drawer.strokeWeight = (8.0) + drawer.lineCap = (LineCap.ROUND) + val x = ((value - range.min) / range.span) * (layout.screenWidth - 2 * margin) + + drawer.stroke = ((computedStyle.color as Color.RGBa).color.opacify(0.25)) + drawer.lineSegment(margin + 0.0, 2.0, margin + layout.screenWidth - 2 * margin, 2.0) + + drawer.stroke = ((computedStyle.color as Color.RGBa).color.opacify(1.0)) + drawer.lineSegment(margin, 2.0, margin + x, 2.0) + + drawer.stroke = null + drawer.circle(Vector2(margin + x, 2.0), 5.0) + + (root() as? Body)?.controlManager?.fontManager?.let { + val font = it.font(computedStyle) + val writer = Writer(drawer) + drawer.fontMap = (font) + drawer.fill = computedStyle.effectiveColor + writer.cursor = Cursor(0.0, 8.0) + writer.box = Rectangle(0.0, 8.0, Double.POSITIVE_INFINITY, Double.POSITIVE_INFINITY) + writer.newLine() + writer.text(label) + + if (keyboardInput.isEmpty()) { + val valueFormatted = String.format("%.0${precision}f", value) + val tw = writer.textWidth(valueFormatted) + writer.cursor.x = (layout.screenWidth - tw) + writer.text(valueFormatted) + } else { + val tw = writer.textWidth(keyboardInput) + writer.cursor.x = (layout.screenWidth - tw) + writer.text(keyboardInput) + } + } + } +} + +fun Slider.bind(property: KMutableProperty0) { + var currentValue: Double? = null + + events.valueChanged.listen { + currentValue = it.newValue + property.set(it.newValue) + } + if (root() as? Body == null) { + throw RuntimeException("no body") + } + (root() as? Body)?.controlManager?.program?.launch { + while (true) { + if (property.get() != currentValue) { + val lcur = property.get() + currentValue = lcur + value = lcur + } + yield() + } + } +} diff --git a/orx-panel/src/main/kotlin/org/openrndr/panel/elements/TextElements.kt b/orx-panel/src/main/kotlin/org/openrndr/panel/elements/TextElements.kt new file mode 100644 index 00000000..6138ca02 --- /dev/null +++ b/orx-panel/src/main/kotlin/org/openrndr/panel/elements/TextElements.kt @@ -0,0 +1,100 @@ +package org.openrndr.panel.elements + +import kotlinx.coroutines.yield +import org.openrndr.color.ColorRGBa +import org.openrndr.draw.Drawer +import org.openrndr.draw.FontImageMap +import org.openrndr.launch +import org.openrndr.math.Vector2 +import org.openrndr.panel.style.* +import org.openrndr.shape.Rectangle +import org.openrndr.text.Writer +import kotlin.reflect.KMutableProperty0 + +class TextNode(var text: String) : Element(ElementType("text")) { + + override fun draw(drawer: Drawer) { + computedStyle.let { style -> + style.color.let { + val fill = (it as? Color.RGBa)?.color ?: ColorRGBa.WHITE + drawer.fill = (fill) + } + val fontMap = (root() as Body).controlManager.fontManager.font(computedStyle) + val writer = Writer(drawer) + drawer.fontMap = (fontMap) + + writer.box= Rectangle(Vector2(layout.screenX * 0.0, layout.screenY * 0.0), layout.screenWidth, layout.screenHeight) + writer.newLine() + writer.text(text) + } + } + + fun sizeHint(): Rectangle { + computedStyle.let { style -> + val fontUrl = (root() as? Body)?.controlManager?.fontManager?.resolve(style.fontFamily)?:"broken" + val fontSize = (style.fontSize as? LinearDimension.PX)?.value?: 14.0 + val fontMap = FontImageMap.fromUrl(fontUrl, fontSize) + + val writer = Writer(null) + + writer.box = Rectangle(layout.screenX, + layout.screenY, + layout.screenWidth, + layout.screenHeight) + + writer.drawStyle.fontMap = fontMap + writer.newLine() + writer.text(text, visible = false) + + return Rectangle(layout.screenX, + layout.screenY, + layout.screenWidth, + (writer.cursor.y - layout.screenY) - fontMap.descenderLength*2) + } + + } + + override fun toString(): String { + return "TextNode(id='$id',text='$text')" + } +} + +class H1 : TextElement(ElementType("h1")) +class H2 : TextElement(ElementType("h2")) +class H3 : TextElement(ElementType("h3")) +class H4 : TextElement(ElementType("h4")) +class H5 : TextElement(ElementType("h5")) + +class P : TextElement(ElementType("p")) + +abstract class TextElement(et: ElementType) : Element(et) { + fun text(text: String) { + append(TextNode(text)) + } + fun replaceText(text : String) { + if (children.isEmpty()) { + text(text) + } else { + (children.first() as? TextNode)?.text = text + } + } +} + +fun TextElement.bind(property: KMutableProperty0) { + var currentValue: Double? = null + + + if (root() as? Body == null) { + throw RuntimeException("no body") + } + (root() as? Body)?.controlManager?.program?.launch { + var lastText = "" + while (true) { + if (property.get() != lastText) { + replaceText(property.get()) + lastText = property.get() + } + yield() + } + } +} diff --git a/orx-panel/src/main/kotlin/org/openrndr/panel/elements/Textfield.kt b/orx-panel/src/main/kotlin/org/openrndr/panel/elements/Textfield.kt new file mode 100644 index 00000000..29fd8d34 --- /dev/null +++ b/orx-panel/src/main/kotlin/org/openrndr/panel/elements/Textfield.kt @@ -0,0 +1,156 @@ +package org.openrndr.panel.elements + +import org.openrndr.KEY_BACKSPACE +import org.openrndr.color.ColorRGBa +import org.openrndr.draw.Drawer +import org.openrndr.draw.LineCap +import org.openrndr.panel.style.* +import kotlinx.coroutines.yield +import org.openrndr.KeyModifier +import org.openrndr.events.Event +import org.openrndr.launch +import org.openrndr.shape.Rectangle +import org.openrndr.text.Cursor +import org.openrndr.text.writer +import kotlin.reflect.KMutableProperty0 + +class Textfield : Element(ElementType("textfield")) { + + var value: String = "" + var label: String = "label" + + class ValueChangedEvent(val source: Textfield, val oldValue: String, val newValue: String) + class Events { + val valueChanged = Event("textfield-value-changed") + } + + val events = Events() + + init { + keyboard.repeated.listen { + if (it.key == KEY_BACKSPACE) { + if (value.isNotEmpty()) { + val oldValue = value + value = value.substring(0, value.length - 1) + events.valueChanged.trigger(ValueChangedEvent(this, oldValue, value)) + requestRedraw() + } + + } + it.cancelPropagation() + } + + keyboard.pressed.listen { + if (KeyModifier.CTRL in it.modifiers || KeyModifier.SUPER in it.modifiers) { + if (it.name == "v") { + val oldValue = value + (root() as Body).controlManager.program.clipboard.contents?.let { + value += it + + } + events.valueChanged.trigger(ValueChangedEvent(this, oldValue, value)) + it.cancelPropagation() + } + } + if (it.key == KEY_BACKSPACE) { + if (value.isNotEmpty()) { + val oldValue = value + value = value.substring(0, value.length - 1) + events.valueChanged.trigger(ValueChangedEvent(this, oldValue, value)) + } + } + requestRedraw() + it.cancelPropagation() + } + + keyboard.character.listen { + val oldValue = value + value += it.character + events.valueChanged.trigger(ValueChangedEvent(this, oldValue, value)) + it.cancelPropagation() + } + + mouse.pressed.listen { + it.cancelPropagation() + } + mouse.clicked.listen { + it.cancelPropagation() + } + } + + override fun draw(drawer: Drawer) { + drawer.fill = computedStyle.effectiveBackground + drawer.stroke = null + drawer.rectangle(0.0, 0.0, layout.screenWidth, layout.screenHeight) + + (root() as? Body)?.controlManager?.fontManager?.let { + val font = it.font(computedStyle) + + drawer.fontMap = (font) + val textHeight = font.ascenderLength + + val offset = 5.0 + val yOffset = Math.round((layout.screenHeight / 2) + textHeight / 2.0 - 2.0) * 1.0 + + drawer.fill = ((computedStyle.color as? Color.RGBa)?.color ?: ColorRGBa.WHITE) + drawer.text("$label", 0.0 + offset, 0.0 + yOffset - textHeight * 1.5) + + drawer.fill = (((computedStyle.color as? Color.RGBa)?.color ?: ColorRGBa.WHITE).opacify(0.05)) + drawer.rectangle(0.0 + offset, 0.0 + yOffset - (textHeight + 2), layout.screenWidth - 10.0, textHeight + 8.0) + + drawer.drawStyle.clip = Rectangle(screenPosition.x + offset, screenPosition.y + yOffset - (textHeight + 2), layout.screenWidth - 10.0, textHeight + 8.0) + + drawer.fill = ((computedStyle.color as? Color.RGBa)?.color ?: ColorRGBa.WHITE) + + var cursorX = 0.0 + writer(drawer) { + val emWidth = textWidth("m") * 2 + cursor = Cursor(offset, yOffset) + text(value, visible = false) + val width = cursor.x - offset + val scroll = + if (width > screenArea.width - emWidth) { + screenArea.width - emWidth - width + } else { + 0.0 + } + cursor = Cursor(offset + scroll, yOffset) + text(value) + cursorX = cursor.x + } + + if (ElementPseudoClass("active") in pseudoClasses) { + drawer.stroke = ColorRGBa.WHITE + drawer.lineSegment(cursorX + 1.0, yOffset, cursorX + 1.0, yOffset - textHeight) + } + drawer.drawStyle.clip = null + + drawer.stroke = ((computedStyle.color as? Color.RGBa)?.color ?: ColorRGBa.WHITE) + drawer.strokeWeight = 1.0 + + drawer.stroke = computedStyle.effectiveColor?.shade(0.25) + drawer.lineCap = LineCap.ROUND + //drawer.lineSegment(0.0, yOffset + 4.0, layout.screenWidth, yOffset + 4.0) + } + } +} + +fun Textfield.bind(property: KMutableProperty0) { + var currentValue = property.get() + + events.valueChanged.listen { + currentValue = it.newValue + property.set(it.newValue) + } + + (root() as Body).controlManager.program.launch { + while (true) { + val cval = property.get() + if (cval != currentValue) { + currentValue = cval + value = cval + } + yield() + } + } +} \ No newline at end of file diff --git a/orx-panel/src/main/kotlin/org/openrndr/panel/elements/Toggle.kt b/orx-panel/src/main/kotlin/org/openrndr/panel/elements/Toggle.kt new file mode 100644 index 00000000..4305724a --- /dev/null +++ b/orx-panel/src/main/kotlin/org/openrndr/panel/elements/Toggle.kt @@ -0,0 +1,118 @@ +package org.openrndr.panel.elements + +import org.openrndr.draw.Drawer +import org.openrndr.draw.FontImageMap +import org.openrndr.draw.LineCap +import org.openrndr.panel.style.* +import org.openrndr.shape.Rectangle +import org.openrndr.text.Writer + +import kotlinx.coroutines.yield +import org.openrndr.events.Event +import org.openrndr.launch +import kotlin.reflect.KMutableProperty0 + +class Toggle : Element(ElementType("toggle")) { + var label = "" + var value = false + + class ValueChangedEvent(val source: Toggle, + val oldValue: Boolean, + val newValue: Boolean) + + class Events { + val valueChanged = Event("toggle-value-changed") + } + + val events = Events() + + override val widthHint: Double? + get() { + computedStyle.let { style -> + val fontUrl = (root() as? Body)?.controlManager?.fontManager?.resolve(style.fontFamily) ?: "broken" + val fontSize = (style.fontSize as? LinearDimension.PX)?.value ?: 14.0 + val fontMap = FontImageMap.fromUrl(fontUrl, fontSize) + + val writer = Writer(null) + + writer.box = Rectangle(0.0, + 0.0, + Double.POSITIVE_INFINITY, + Double.POSITIVE_INFINITY) + + writer.drawStyle.fontMap = fontMap + writer.newLine() + writer.text(label, visible = false) + + return writer.cursor.x + (computedStyle.height as LinearDimension.PX).value - 8.0 + 5.0 + } + } + + init { + mouse.pressed.listen { + it.cancelPropagation() + } + mouse.clicked.listen { + value = !value + draw.dirty = true + events.valueChanged.trigger(Toggle.ValueChangedEvent(this, !value, value)) + it.cancelPropagation() + } + } + + /** + * Emits the current value through the valueChanged event + */ + fun emit() { + events.valueChanged.trigger(Toggle.ValueChangedEvent(this, value, value)) + } + + override fun draw(drawer: Drawer) { + drawer.pushModel() + val checkBoxSize = layout.screenHeight - 8.0 + drawer.translate(0.0, (layout.screenHeight - checkBoxSize) / 2.0) + drawer.strokeWeight = 1.0 + drawer.stroke = computedStyle.effectiveColor + drawer.fill = null + drawer.rectangle(0.0, 0.0, checkBoxSize, checkBoxSize) + + if (value) { + drawer.strokeWeight = 2.0 + drawer.stroke = computedStyle.effectiveColor + drawer.fill = null + drawer.lineCap = LineCap.ROUND + drawer.lineSegment(5.0, 5.0, checkBoxSize / 2.0 - 2.0, checkBoxSize / 2.0 - 2.0) + drawer.lineSegment(checkBoxSize / 2.0 + 2.0, checkBoxSize / 2.0 + 2.0, checkBoxSize - 5.0, checkBoxSize - 5.0) + drawer.lineSegment(checkBoxSize - 5.0, 5.0, checkBoxSize / 2.0 + 2.0, checkBoxSize / 2.0 - 2.0) + drawer.lineSegment(checkBoxSize / 2.0 - 2.0, checkBoxSize / 2.0 + 2.0, 5.0, checkBoxSize - 5.0) + } + + drawer.popModel() + drawer.fontMap = (root() as? Body)?.controlManager?.fontManager?.font(computedStyle)!! + drawer.translate(5.0 + checkBoxSize, (layout.screenHeight / 2.0) + drawer.fontMap!!.height / 2.0) + drawer.stroke = null + drawer.fill = computedStyle.effectiveColor + drawer.text(label, 0.0, 0.0) + } +} + +fun Toggle.bind(property: KMutableProperty0) { + var currentValue = property.get() + value = currentValue + + events.valueChanged.listen { + currentValue = it.newValue + property.set(it.newValue) + } + + (root() as Body).controlManager.program.launch { + while (true) { + val cval = property.get() + if (cval != currentValue) { + currentValue = cval + value = cval + } + yield() + } + } +} \ No newline at end of file diff --git a/orx-panel/src/main/kotlin/org/openrndr/panel/elements/XYPad.kt b/orx-panel/src/main/kotlin/org/openrndr/panel/elements/XYPad.kt new file mode 100644 index 00000000..a94b8ae9 --- /dev/null +++ b/orx-panel/src/main/kotlin/org/openrndr/panel/elements/XYPad.kt @@ -0,0 +1,250 @@ +package org.openrndr.panel.elements + +import kotlinx.coroutines.yield +import org.openrndr.* +import org.openrndr.color.ColorRGBa +import org.openrndr.draw.Drawer +import org.openrndr.events.Event +import org.openrndr.math.Vector2 +import org.openrndr.math.clamp +import org.openrndr.math.map +import org.openrndr.panel.style.Color +import org.openrndr.panel.style.color +import org.openrndr.text.Writer +import kotlin.math.pow +import kotlin.math.round +import kotlin.reflect.KMutableProperty0 + + +class XYPad : Element(ElementType("xy-pad")) { + var minX = -1.0 + var minY = -1.0 + var maxX = 1.0 + var maxY = 1.0 + + /** + * The precision of the control, default is 2 + */ + var precision = 2 + + /** + * Should the control visualize the value as a vector?, default is false + */ + var showVector = false + + /** + * Should the control invert the Y-axis?, default is true + */ + var invertY = true + + // The value is derived from the normalized value... + var normalizedValue = Vector2(0.0, 0.0) + + var value: Vector2 + get() = Vector2( + map(-1.0, 1.0, minX, maxX, normalizedValue.x).round(precision), + map(-1.0, 1.0, minY, maxY, normalizedValue.y).round(precision) + ) + set(newValue) { + normalizedValue = Vector2( + clamp(map(minX, maxX, -1.0, 1.0, newValue.x), -1.0, 1.0), + clamp(map(minY, maxY, -1.0, 1.0, newValue.y), -1.0, 1.0) + ) + } + + init { + mouse.clicked.listen { + it.cancelPropagation() + pick(it) + } + + mouse.dragged.listen { + it.cancelPropagation() + pick(it) + } + + mouse.pressed.listen { + it.cancelPropagation() + } + + keyboard.pressed.listen { handleKeyEvent(it) } + keyboard.repeated.listen { handleKeyEvent(it) } + } + + class ValueChangedEvent(val source: XYPad, + val oldValue: Vector2, + val newValue: Vector2) + + + val events = Events() + + class Events { + val valueChanged = Event("xypad-value-changed") + } + + + private fun handleKeyEvent(keyEvent: KeyEvent) { + val keyboardIncrementX = if (KeyModifier.SHIFT in keyEvent.modifiers) { + (maxX - minX) / 10.0 + } else { + 10.0.pow(-(precision - 0.0)) + } + + val keyboardIncrementY = if (KeyModifier.SHIFT in keyEvent.modifiers) { + (maxY - minY) / 10.0 + } else { + 10.0.pow(-(precision - 0.0)) + } + + val old = value + + if (keyEvent.key == KEY_ARROW_RIGHT) { + value = Vector2(value.x + keyboardIncrementX, value.y) + } + + if (keyEvent.key == KEY_ARROW_LEFT) { + value = Vector2(value.x - keyboardIncrementX, value.y) + } + + if (keyEvent.key == KEY_ARROW_UP) { + value = Vector2(value.x, value.y - keyboardIncrementY * if (invertY) -1.0 else 1.0) + } + + if (keyEvent.key == KEY_ARROW_DOWN) { + value = Vector2(value.x, value.y + keyboardIncrementY * if (invertY) -1.0 else 1.0) + } + + requestRedraw() + events.valueChanged.trigger(ValueChangedEvent(this, old, value)) + keyEvent.cancelPropagation() + } + + private fun pick(e: MouseEvent) { + val old = value + + // Difference + val dx = e.position.x - layout.screenX + val dy = e.position.y - layout.screenY + + // Normalize to -1 - 1 + val nx = clamp(dx / layout.screenWidth * 2.0 - 1.0, -1.0, 1.0) + val ny = clamp(dy / layout.screenHeight * 2.0 - 1.0, -1.0, 1.0) * if (invertY) -1.0 else 1.0 + + normalizedValue = Vector2(nx, ny) + + events.valueChanged.trigger(ValueChangedEvent(this, old, value)) + requestRedraw() + } + + override val widthHint: Double? + get() = 200.0 + + + private val ballPosition: Vector2 + get() = Vector2( + map(-1.0, 1.0, 0.0, layout.screenWidth, normalizedValue.x), + if (invertY) { + map(1.0, -1.0, 0.0, layout.screenHeight, normalizedValue.y) + } else { + map(-1.0, 1.0, 0.0, layout.screenHeight, normalizedValue.y) + } + ) + + override fun draw(drawer: Drawer) { + computedStyle.let { + drawer.pushTransforms() + drawer.pushStyle() + drawer.fill = ColorRGBa.GRAY + drawer.stroke = null + drawer.strokeWeight = 0.0 + + drawer.rectangle(0.0, 0.0, layout.screenWidth, layout.screenHeight) + + + // lines grid + drawer.stroke = ColorRGBa.GRAY.shade(1.2) + drawer.strokeWeight = 1.0 + + for (y in 0 until 21) { + drawer.lineSegment( + 0.0, + layout.screenHeight / 20 * y, + layout.screenWidth - 1.0, + layout.screenHeight / 20 * y + ) + } + + for (x in 0 until 21) { + drawer.lineSegment( + layout.screenWidth / 20 * x, + 0.0, + layout.screenWidth / 20 * x, + layout.screenHeight - 1.0 + ) + } + + // cross + drawer.stroke = ColorRGBa.GRAY.shade(1.6) +// drawer.lineSegment(0.0, layout.screenHeight / 2.0, layout.screenWidth, layout.screenHeight / 2.0) +// drawer.lineSegment(layout.screenWidth / 2.0, 0.0, layout.screenWidth / 2.0, layout.screenHeight) + + // angle line from center + if (showVector) { + drawer.lineSegment(Vector2(layout.screenHeight / 2.0, layout.screenWidth / 2.0), ballPosition) + } + + // ball + drawer.fill = ColorRGBa.PINK + drawer.stroke = ColorRGBa.WHITE + drawer.circle(ballPosition, 8.0) + + val label = "${String.format("%.0${precision}f", value.x)}, ${String.format("%.0${precision}f", value.y)}" + (root() as? Body)?.controlManager?.fontManager?.let { + val font = it.font(computedStyle) + val writer = Writer(drawer) + drawer.fontMap = (font) + val textWidth = writer.textWidth(label) + val textHeight = font.ascenderLength + + drawer.fill = ((computedStyle.color as? Color.RGBa)?.color ?: ColorRGBa.WHITE).opacify( + if (disabled in pseudoClasses) 0.25 else 1.0 + ) + + + drawer.text(label, Vector2(layout.screenWidth - textWidth - 4.0, layout.screenHeight - textHeight + 6.0)) + } + + drawer.popStyle() + drawer.popTransforms() + } + } +} + +fun XYPad.bind(property: KMutableProperty0) { + var currentValue: Vector2? = null + + events.valueChanged.listen { + currentValue = it.newValue + property.set(it.newValue) + } + if (root() as? Body == null) { + throw RuntimeException("no body") + } + (root() as? Body)?.controlManager?.program?.launch { + while (true) { + if (property.get() != currentValue) { + val lcur = property.get() + currentValue = lcur + value = lcur + } + yield() + } + } +} + + +fun Double.round(decimals: Int): Double { + var multiplier = 1.0 + repeat(decimals) { multiplier *= 10 } + return round(this * multiplier) / multiplier +} diff --git a/orx-panel/src/main/kotlin/org/openrndr/panel/layout/Layouter.kt b/orx-panel/src/main/kotlin/org/openrndr/panel/layout/Layouter.kt new file mode 100644 index 00000000..37755393 --- /dev/null +++ b/orx-panel/src/main/kotlin/org/openrndr/panel/layout/Layouter.kt @@ -0,0 +1,261 @@ +package org.openrndr.panel.layout + +import org.openrndr.math.Vector2 +import org.openrndr.panel.elements.Element +import org.openrndr.panel.elements.TextNode +import org.openrndr.panel.style.* +import org.openrndr.shape.Rectangle +import java.util.* +import kotlin.comparisons.compareBy +import kotlin.math.max + +class Layouter { + val styleSheets = ArrayList() + val blockLike = setOf(Display.BLOCK, Display.FLEX) + val manualPosition = setOf(Position.FIXED, Position.ABSOLUTE) + + fun positionChildren(element: Element): Rectangle { + return element.computedStyle.let { cs -> + var y = element.layout.screenY - element.scrollTop + element.computedStyle.effectivePaddingTop + + when (cs.display) { + Display.FLEX -> { + when (cs.flexDirection) { + FlexDirection.Row -> { + var maxHeight = 0.0 + var x = element.layout.screenX + element.computedStyle.effectivePaddingLeft + + val totalWidth = element.children.filter { it.computedStyle.display in blockLike && it.computedStyle.position !in manualPosition }.map { width(it) }.sum() + val remainder = (element.layout.screenWidth - totalWidth) + val totalGrow = element.children.filter { it.computedStyle.display in blockLike && it.computedStyle.position !in manualPosition }.map { (it.computedStyle.flexGrow as FlexGrow.Ratio).value }.sum() + + element.children.filter { it.computedStyle.display in blockLike && it.computedStyle.position !in manualPosition }.forEach { + + val elementGrow = (it.computedStyle.flexGrow as FlexGrow.Ratio).value + val growWidth = if (totalGrow > 0) (elementGrow / totalGrow) * remainder else 0.0 + + it.layout.screenY = y + ((it.computedStyle.marginTop as? LinearDimension.PX)?.value + ?: 0.0) + it.layout.screenX = x + ((it.computedStyle.marginLeft as? LinearDimension.PX)?.value + ?: 0.0) + + it.layout.growWidth = growWidth + x += width(it) + growWidth + maxHeight = max(height(it), maxHeight) + } + Rectangle(Vector2(x, y), x - element.layout.screenX, maxHeight) + } + FlexDirection.Column -> { + var maxWidth = 0.0 + var ly = element.layout.screenY + element.computedStyle.effectivePaddingTop + val lx = element.layout.screenX + element.computedStyle.effectivePaddingLeft + + val verticalPadding = element.computedStyle.effectivePaddingTop + element.computedStyle.effectivePaddingBottom + val totalHeight = element.children + .filter { it.computedStyle.display in blockLike && it.computedStyle.position !in manualPosition } + .sumByDouble { height(it) } + val remainder = ((element.layout.screenHeight - verticalPadding) - totalHeight) + val totalGrow = element.children + .filter { it.computedStyle.display in blockLike && it.computedStyle.position !in manualPosition } + .sumByDouble { (it.computedStyle.flexGrow as FlexGrow.Ratio).value } + + element.children.filter { it.computedStyle.display in blockLike && it.computedStyle.position !in manualPosition }.forEach { + val elementGrow = (it.computedStyle.flexGrow as FlexGrow.Ratio).value + val growHeight = if (totalGrow > 0) (elementGrow / totalGrow) * remainder else 0.0 + + it.layout.screenY = ly + ((it.computedStyle.marginTop as? LinearDimension.PX)?.value + ?: 0.0) + it.layout.screenX = lx + ((it.computedStyle.marginLeft as? LinearDimension.PX)?.value + ?: 0.0) + + it.layout.growHeight = growHeight + ly += height(it) + growHeight + maxWidth = max(height(it), maxWidth) + + } + + Rectangle(Vector2(lx, ly), maxWidth, ly - element.layout.screenY) + } + else -> Rectangle(Vector2(element.layout.screenX, element.layout.screenY), 0.0, 0.0) + } + } + else -> { + val x = element.layout.screenX + element.computedStyle.effectivePaddingLeft + var maxWidth = 0.0 + element.children.forEach { + if (it.computedStyle.display in blockLike && it.computedStyle.position !in manualPosition) { + it.layout.screenY = y + ((it.computedStyle.marginTop as? LinearDimension.PX)?.value ?: 0.0) + it.layout.screenX = x + ((it.computedStyle.marginLeft as? LinearDimension.PX)?.value ?: 0.0) + maxWidth = max(0.0, width(it)) + y += height(it) + } else if (it.computedStyle.position == Position.ABSOLUTE) { + it.layout.screenX = element.layout.screenX + ((it.computedStyle.left as? LinearDimension.PX)?.value + ?: 0.0) + it.layout.screenY = element.layout.screenY + ((it.computedStyle.top as? LinearDimension.PX)?.value + ?: 0.0) + } + } + Rectangle(Vector2(element.layout.screenX, element.layout.screenY), maxWidth, y - element.layout.screenY) + } + } + } + } + + fun computeStyles(element: Element) { + val matcher = Matcher() + + if (element is TextNode) { + // TODO: figure out why this is needed + element.computedStyle = element.parent?.computedStyle?.cascadeOnto(StyleSheet(CompoundSelector.DUMMY)) + ?: StyleSheet(CompoundSelector.DUMMY) + } else { + element.computedStyle = + styleSheets + .filter { + it.selector.let { + matcher.matches(it, element) + } + } + .sortedWith(compareBy({ it.precedence.component1() }, + { it.precedence.component2() }, + { it.precedence.component3() }, + { it.precedence.component4() })) + .reversed() + .fold(StyleSheet(CompoundSelector.DUMMY), { a, b -> a.cascadeOnto(b) }) + + element.style?.let { + element.computedStyle = it.cascadeOnto(element.computedStyle) + } + } + element.computedStyle.let { cs -> + + element.parent?.let { p -> + cs.properties.forEach { (k, v) -> + if ((v.value as? PropertyValue)?.inherit == true) { + cs.properties[k] = p.computedStyle.getProperty(k) ?: v + } + } + PropertyBehaviours.behaviours.forEach { (k, v) -> + if (v.inheritance == PropertyInheritance.INHERIT && k !in cs.properties) { + if (k in p.computedStyle.properties) { + cs.properties[k] = p.computedStyle.getProperty(k)!! + } + } + } + } + } + + element.children.forEach { computeStyles(it) } + } + + fun margin(element: Element, f: (StyleSheet) -> LinearDimension): Double { + val value = f(element.computedStyle) + return when (value) { + is LinearDimension.PX -> value.value + else -> 0.0 + } + } + + fun padding(element: Element?, f: (StyleSheet) -> LinearDimension): Double { + return if (element != null) { + val value = f(element.computedStyle) + when (value) { + is LinearDimension.PX -> value.value + else -> 0.0 + } + } else 0.0 + } + + fun marginTop(element: Element) = margin(element, StyleSheet::marginTop) + fun marginBottom(element: Element) = margin(element, StyleSheet::marginBottom) + fun marginLeft(element: Element) = margin(element, StyleSheet::marginLeft) + fun marginRight(element: Element) = margin(element, StyleSheet::marginRight) + + fun paddingTop(element: Element?) = padding(element, StyleSheet::paddingTop) + fun paddingBottom(element: Element?) = padding(element, StyleSheet::paddingBottom) + fun paddingLeft(element: Element?) = padding(element, StyleSheet::paddingLeft) + fun paddingRight(element: Element?) = padding(element, StyleSheet::paddingRight) + + fun height(element: Element, includeMargins: Boolean = true): Double { + if (element.computedStyle.display == Display.NONE) { + return 0.0 + } + + if (element is TextNode) { + return element.sizeHint().height + if (includeMargins) marginBottom(element) + marginTop(element) else 0.0 + } + + return element.computedStyle.let { + it.height.let { + when (it) { + is LinearDimension.PX -> it.value + is LinearDimension.Percent -> { + val parentHeight = element.parent?.layout?.screenHeight ?: 0.0 + val parentPadding = element.parent?.computedStyle?.effectivePaddingHeight ?: 0.0 + val margins = marginTop(element) + marginBottom(element) + val effectiveHeight = (parentHeight - parentPadding) * (it.value / 100.0) - margins + effectiveHeight + } + is LinearDimension.Auto -> { + val padding = paddingTop(element) + paddingBottom(element) + positionChildren(element).height + padding + } + else -> throw RuntimeException("not supported") + } + } + if (includeMargins) ((it.marginTop as? LinearDimension.PX)?.value + ?: 0.0) + ((it.marginBottom as? LinearDimension.PX)?.value ?: 0.0) else 0.0 + } + } + + fun width(element: Element, includeMargins: Boolean = true): Double = element.computedStyle.let { + if (element.computedStyle.display == Display.NONE) { + return 0.0 + } + + val result = + it.width.let { + when (it) { + is LinearDimension.PX -> it.value + is LinearDimension.Percent -> { + val parentWidth = element.parent?.layout?.screenWidth ?: 0.0 + val parentPadding = element.parent?.computedStyle?.effectivePaddingWidth ?: 0.0 + val margins = marginLeft(element) + marginRight(element) + val effectiveWidth = (parentWidth - parentPadding) * (it.value / 100.0) - margins + effectiveWidth + } + is LinearDimension.Auto -> (element.widthHint ?: positionChildren(element).width) + + paddingRight(element) + paddingLeft(element) + else -> throw RuntimeException("not supported") + } + } + if (includeMargins) marginLeft(element) + marginRight(element) else 0.0 + result + } + + fun layout(element: Element) { + element.computedStyle.also { cs -> + cs.display.let { if (it == Display.NONE) return } + + when (cs.position) { + Position.FIXED -> { + element.layout.screenX = (cs.left as? LinearDimension.PX)?.value ?: 0.0 + element.layout.screenY = (cs.top as? LinearDimension.PX)?.value ?: 0.0 + } + else -> { + } + } + val lzi = cs.zIndex + element.layout.zIndex = when (lzi) { + is ZIndex.Value -> lzi.value + is ZIndex.Auto -> element.parent?.layout?.zIndex ?: 0 + is ZIndex.Inherit -> element.parent?.layout?.zIndex ?: 0 + } + + element.layout.screenWidth = width(element, includeMargins = false) + element.layout.screenHeight = height(element, includeMargins = false) + element.layout.screenWidth += element.layout.growWidth + element.layout.screenHeight += element.layout.growHeight + positionChildren(element) + } + element.children.forEach { layout(it) } + } +} \ No newline at end of file diff --git a/orx-panel/src/main/kotlin/org/openrndr/panel/style/DefaultStyles.kt b/orx-panel/src/main/kotlin/org/openrndr/panel/style/DefaultStyles.kt new file mode 100644 index 00000000..629b5ec1 --- /dev/null +++ b/orx-panel/src/main/kotlin/org/openrndr/panel/style/DefaultStyles.kt @@ -0,0 +1,200 @@ +package org.openrndr.panel.style + +import org.openrndr.color.ColorRGBa + +fun defaultStyles( + controlBackground: ColorRGBa = ColorRGBa(0.5, 0.5, 0.5), + controlHoverBackground: ColorRGBa = controlBackground.shade(1.5), + controlTextColor: Color = Color.RGBa(ColorRGBa.WHITE.shade(0.8)), + controlActiveColor : Color = Color.RGBa(ColorRGBa.fromHex(0xf88379 )), + controlFontSize: Double = 14.0 +) = listOf( + styleSheet(has type "item") { + display = Display.NONE + }, + + styleSheet(has type "textfield") { + width = 100.percent + height = 64.px + and(has state "active") { + color = controlActiveColor + } + }, + + styleSheet(has type "dropdown-button") { + width = LinearDimension.Auto + height = 32.px + background = Color.RGBa(controlBackground) + marginLeft = 5.px + marginRight = 5.px + marginTop = 5.px + marginBottom = 5.px + fontSize = controlFontSize.px + + and(has state "hover") { + background = Color.RGBa(controlHoverBackground) + } + + descendant(has type "button") { + width = 100.percent + height = 24.px + marginBottom = 0.px + marginTop = 0.px + marginLeft = 0.px + marginRight = 0.px + } + }, + + styleSheet(has type "colorpicker-button") { + width = 100.px + height = 32.px + background = Color.RGBa(controlBackground) + marginLeft = 5.px + marginRight = 5.px + marginTop = 5.px + marginBottom = 5.px + + and(has state "hover") { + background = Color.RGBa(controlHoverBackground) + } + }, + + styleSheet(has type "envelope-button") { + width = 100.px + height = 40.px + background = Color.RGBa(controlBackground) + marginLeft = 5.px + marginRight = 5.px + marginTop = 5.px + marginBottom = 5.px + }, + + styleSheet(has type "body") { + fontSize = 18.px + fontFamily = "default" + }, + + styleSheet(has type "slider") { + height = 32.px + width = 100.percent + marginTop = 5.px + marginBottom = 5.px + marginLeft = 5.px + marginRight = 5.px + fontSize = controlFontSize.px + color = controlTextColor + + and(has state "active") { + color = controlActiveColor + } + }, + + styleSheet(has type "envelope-editor") { + height = 60.px + width = 100.percent + marginTop = 5.px + marginBottom = 15.px + marginLeft = 5.px + marginRight = 5.px + }, + + styleSheet(has type "sequence-editor") { + height = 60.px + width = 100.percent + marginTop = 5.px + marginBottom = 15.px + marginLeft = 5.px + marginRight = 5.px + }, + + styleSheet(has type "colorpicker") { + height = 80.px + width = 100.percent + marginTop = 5.px + marginBottom = 15.px + marginLeft = 5.px + marginRight = 5.px + }, + + styleSheet(has type "xy-pad") { + display = Display.BLOCK + background = Color.RGBa(ColorRGBa.GRAY) + width = 175.px + height = 175.px + marginLeft = 5.px + marginRight = 5.px + marginTop = 5.px + marginBottom = 5.px + fontFamily = "default" + + and(has state "hover") { + display = Display.BLOCK + background = Color.RGBa(ColorRGBa.GRAY.shade(1.5)) + } + }, + + styleSheet(has type "overlay") { + zIndex = ZIndex.Value(1) + }, + + styleSheet(has type "toggle") { + height = 32.px + width = LinearDimension.Auto + marginTop = 5.px + marginBottom = 5.px + marginLeft = 5.px + marginRight = 5.px + fontSize = controlFontSize.px + color = controlTextColor + }, + + styleSheet(has type "h1") { + fontSize = 24.px + width = 100.percent + height = LinearDimension.Auto + display = Display.BLOCK + }, + + styleSheet(has type "h2") { + fontSize = 20.px + width = 100.percent + height = LinearDimension.Auto + display = Display.BLOCK + }, + + styleSheet(has type "h3") { + fontSize = 16.px + width = 100.percent + height = LinearDimension.Auto + display = Display.BLOCK + }, + + styleSheet(has type "p") { + fontSize = 16.px + width = 100.percent + height = LinearDimension.Auto + display = Display.BLOCK + }, + styleSheet(has type "button") { + display = Display.BLOCK + background = Color.RGBa(controlBackground) + width = LinearDimension.Auto + height = 32.px + paddingLeft = 10.px + paddingRight = 10.px + marginLeft = 5.px + marginRight = 5.px + marginTop = 5.px + marginBottom = 5.px + fontSize = controlFontSize.px + + and(has state "selected") { + display = Display.BLOCK + background = controlActiveColor + } + and(has state "hover") { + display = Display.BLOCK + background = Color.RGBa(controlHoverBackground) + } + } +) diff --git a/orx-panel/src/main/kotlin/org/openrndr/panel/style/Matcher.kt b/orx-panel/src/main/kotlin/org/openrndr/panel/style/Matcher.kt new file mode 100644 index 00000000..4ef51d31 --- /dev/null +++ b/orx-panel/src/main/kotlin/org/openrndr/panel/style/Matcher.kt @@ -0,0 +1,54 @@ +package org.openrndr.panel.style + +import org.openrndr.panel.elements.Element + +class Matcher { + enum class MatchingResult { + MATCHED, NOT_MATCHED, RESTART_FROM_CLOSEST_DESCENDANT, RESTART_FROM_CLOSEST_LATER_SIBLING + } + + fun matches(selector: CompoundSelector, element: Element): Boolean { + return matchesCompound(selector, element) == MatchingResult.MATCHED + } + + private fun matchesCompound(selector: CompoundSelector, element: Element): MatchingResult { + if (selector.selectors.any { !it.accept(element) }) { + return MatchingResult.RESTART_FROM_CLOSEST_LATER_SIBLING + } + + if (selector.previous == null) { + return MatchingResult.MATCHED + } + + val (siblings, candidateNotFound) = + when (selector.previous?.first) { + Combinator.NEXT_SIBLING, Combinator.LATER_SIBLING -> Pair(true, MatchingResult.RESTART_FROM_CLOSEST_DESCENDANT) + else -> Pair(false, MatchingResult.NOT_MATCHED) + } + + var node = element + while (true) { + val nextNode = if (siblings) node.previousSibling() else node.parent + + if (nextNode == null) { + return candidateNotFound + } else { + node = nextNode + } + + val result = matchesCompound(selector.previous?.second!!, node) + + if (result == MatchingResult.MATCHED || result == MatchingResult.NOT_MATCHED) { + return result + } + + when (selector.previous?.first) { + Combinator.CHILD -> return MatchingResult.RESTART_FROM_CLOSEST_DESCENDANT + Combinator.NEXT_SIBLING -> return result + Combinator.LATER_SIBLING -> if (result == MatchingResult.RESTART_FROM_CLOSEST_DESCENDANT) { + return result + } + } + } + } +} \ No newline at end of file diff --git a/orx-panel/src/main/kotlin/org/openrndr/panel/style/Selector.kt b/orx-panel/src/main/kotlin/org/openrndr/panel/style/Selector.kt new file mode 100644 index 00000000..1cdc6c5e --- /dev/null +++ b/orx-panel/src/main/kotlin/org/openrndr/panel/style/Selector.kt @@ -0,0 +1,129 @@ +package org.openrndr.panel.style + +import org.openrndr.panel.elements.Element +import org.openrndr.panel.elements.ElementClass +import org.openrndr.panel.elements.ElementPseudoClass +import org.openrndr.panel.elements.ElementType + +data class SelectorPrecedence(var inlineStyle: Int = 0, var id: Int = 0, var classOrAttribute: Int = 0, var type: Int = 0) + +abstract class Selector { + abstract fun accept(element: Element): Boolean +} + +class CompoundSelector { + companion object { + val DUMMY = CompoundSelector() + } + var previous: Pair? + var selectors: MutableList + + constructor() { + previous = null + selectors = mutableListOf() + } + + constructor(previous: Pair?, selectors: List) { + this.previous = previous + this.selectors = ArrayList() + selectors.forEach { this.selectors.add(it) } + } + + fun precedence(p: SelectorPrecedence = SelectorPrecedence()): SelectorPrecedence { + + selectors.forEach { + when (it) { + is IdentitySelector -> p.id++ + is ClassSelector, is PseudoClassSelector -> p.classOrAttribute++ + is TypeSelector -> p.type++ + else -> { + } + } + } + var r = p + previous?.let { + r = it.second.precedence(p) + } + return r + } + + override fun toString(): String { + return "CompoundSelector(previous=$previous, selectors=$selectors)" + } + +} + +enum class Combinator { + CHILD, DESCENDANT, NEXT_SIBLING, LATER_SIBLING +} + +class IdentitySelector(val id: String) : Selector() { + override fun accept(element: Element): Boolean = if (element.id != null) { + element.id.equals(id) + } else { + false + } + + override fun toString(): String { + return "IdentitySelector(id='$id')" + } + +} + +class ClassSelector(val c: ElementClass) : Selector() { + override fun accept(element: Element): Boolean = c in element.classes + override fun toString(): String { + return "ClassSelector(c=$c)" + } +} + +class TypeSelector(val type: ElementType) : Selector() { + override fun accept(element: Element): Boolean = element.type == type + override fun toString(): String { + return "TypeSelector(type=$type)" + } +} + +class PseudoClassSelector(val c: ElementPseudoClass) : Selector() { + override fun accept(element: Element): Boolean = c in element.pseudoClasses + override fun toString(): String { + return "PseudoClassSelector(c=$c)" + } + +} + +object has { + operator fun invoke (vararg selectors:CompoundSelector) : CompoundSelector { + val active = CompoundSelector() + selectors.forEach { + active.selectors.addAll(it.selectors) + } + return active + } + + infix fun state(q:String):CompoundSelector { + val active = CompoundSelector() + active.selectors.add(PseudoClassSelector(ElementPseudoClass((q)))) + return active + } + + infix fun class_(q:String): CompoundSelector { + val active = CompoundSelector() + active.selectors.add(ClassSelector(ElementClass(q))) + return active + } + + infix fun type(q:String):CompoundSelector { + val active = CompoundSelector() + active.selectors.add(TypeSelector(ElementType(q))) + return active + } +} + +infix fun CompoundSelector.and(other:CompoundSelector):CompoundSelector { + val c = CompoundSelector() + c.previous = previous + c.selectors.addAll(selectors) + c.selectors.addAll(other.selectors) + return c +} \ No newline at end of file diff --git a/orx-panel/src/main/kotlin/org/openrndr/panel/style/StyleSheet.kt b/orx-panel/src/main/kotlin/org/openrndr/panel/style/StyleSheet.kt new file mode 100644 index 00000000..7c6dd3c5 --- /dev/null +++ b/orx-panel/src/main/kotlin/org/openrndr/panel/style/StyleSheet.kt @@ -0,0 +1,221 @@ +package org.openrndr.panel.style + +import org.openrndr.color.ColorRGBa +import org.openrndr.panel.style.PropertyInheritance.INHERIT +import org.openrndr.panel.style.PropertyInheritance.RESET +import java.util.* +import kotlin.reflect.KProperty + +enum class PropertyInheritance { + INHERIT, + RESET +} + +data class Property(val name: String, + val value: Any?) + +open class PropertyValue(val inherit: Boolean = false) + +sealed class Color(inherit: Boolean = false) : PropertyValue(inherit) { + class RGBa(val color: ColorRGBa) : Color() { + override fun toString(): String { + return "RGBa(color=$color)" + } + } + object Inherit : Color(inherit = true) +} + +sealed class LinearDimension(inherit: Boolean = false) : PropertyValue(inherit) { + class PX(val value: Double) : LinearDimension() { + override fun toString(): String { + return "PX(value=$value)" + } + } + class Percent(val value: Double) : LinearDimension() + object Auto : LinearDimension() + object Inherit : LinearDimension(inherit = true) +} + +data class PropertyBehaviour(val inheritance: PropertyInheritance, val intitial: Any) + +object PropertyBehaviours { + + val behaviours = HashMap() +} + +class PropertyHandler( + val name: String, val inheritance: PropertyInheritance, val initial: T +) { + + init { + PropertyBehaviours.behaviours[name] = PropertyBehaviour(inheritance, initial as Any) + } + + @Suppress("USELESS_CAST", "UNCHECKED_CAST") + operator fun getValue(stylesheet: StyleSheet, property: KProperty<*>): T { + val value: T? = stylesheet.getProperty(name)?.value as T? + return value ?: PropertyBehaviours.behaviours[name]!!.intitial as T + + } + + operator fun setValue(stylesheet: StyleSheet, property: KProperty<*>, value: T?) { + stylesheet.setProperty(name, value) + } +} + +enum class Display { + INLINE, + BLOCK, + FLEX, + NONE +} + +enum class Position { + STATIC, + ABSOLUTE, + RELATIVE, + FIXED, + INHERIT +} + +sealed class FlexDirection(inherit: Boolean = false) : PropertyValue(inherit) { + object Row : FlexDirection() + object Column : FlexDirection() + object RowReverse : FlexDirection() + object ColumnReverse : FlexDirection() + object Inherit : FlexDirection(inherit = true) +} + +sealed class Overflow(inherit: Boolean = false) : PropertyValue(inherit) { + object Visible : Overflow() + object Hidden : Overflow() + object Scroll : Overflow() + object Inherit : Overflow(inherit = true) +} + +sealed class ZIndex(inherit: Boolean = false) : PropertyValue(inherit) { + object Auto : ZIndex() + class Value(val value: Int) : ZIndex() + object Inherit : ZIndex(inherit = true) +} + +sealed class FlexGrow(inherit: Boolean = false) : PropertyValue(inherit) { + class Ratio(val value: Double) : FlexGrow() + object Inherit : FlexGrow(inherit = true) +} + +private val dummySelector = CompoundSelector() + +class StyleSheet(val selector: CompoundSelector = CompoundSelector.DUMMY) { + val children = mutableListOf() + val properties = HashMap() + + val precedence by lazy { + selector.precedence() + } + + fun getProperty(name: String) = properties.get(name) + + fun setProperty(name: String, value: Any?) { + properties[name] = Property(name, value) + } + + fun cascadeOnto(onto: StyleSheet): StyleSheet { + val cascaded = StyleSheet(dummySelector) + + cascaded.properties.putAll(onto.properties) + cascaded.properties.putAll(properties) + return cascaded + } + + override fun toString(): String { + return "StyleSheet(properties=$properties)" + } +} + +var StyleSheet.width by PropertyHandler("width", RESET, LinearDimension.Auto) +var StyleSheet.height by PropertyHandler("height", RESET, LinearDimension.Auto) +var StyleSheet.top by PropertyHandler("top", RESET, 0.px) // css default is auto +var StyleSheet.left by PropertyHandler("left", RESET, 0.px) // css default is auto + +var StyleSheet.marginTop by PropertyHandler("margin-top", RESET, 0.px) +var StyleSheet.marginBottom by PropertyHandler("margin-bottom", RESET, 0.px) +var StyleSheet.marginLeft by PropertyHandler("margin-left", RESET, 0.px) +var StyleSheet.marginRight by PropertyHandler("margin-right", RESET, 0.px) + + +var StyleSheet.paddingTop by PropertyHandler("padding-top", RESET, 0.px) +var StyleSheet.paddingBottom by PropertyHandler("padding-bottom", RESET, 0.px) +var StyleSheet.paddingLeft by PropertyHandler("padding-left", RESET, 0.px) +var StyleSheet.paddingRight by PropertyHandler("padding-right", RESET, 0.px) + + +var StyleSheet.position by PropertyHandler("position", RESET, Position.STATIC) +var StyleSheet.display by PropertyHandler("display", RESET, Display.BLOCK) // css default is inline + +var StyleSheet.flexDirection by PropertyHandler("flex-direction", RESET, FlexDirection.Row) +var StyleSheet.flexGrow by PropertyHandler("flex-grow", RESET, FlexGrow.Ratio(0.0)) + + +var StyleSheet.background by PropertyHandler("background-color", RESET, Color.RGBa(ColorRGBa.BLACK.opacify(0.0))) +val StyleSheet.effectiveBackground: ColorRGBa? + get() = (background as? Color.RGBa)?.color + +var StyleSheet.color by PropertyHandler("color", INHERIT, Color.RGBa(ColorRGBa.WHITE)) +val StyleSheet.effectiveColor: ColorRGBa? + get() = (color as? Color.RGBa)?.color + + +val StyleSheet.effectivePaddingLeft: Double + get() = (paddingLeft as? LinearDimension.PX)?.value ?: 0.0 + +val StyleSheet.effectivePaddingRight: Double + get() = (paddingRight as? LinearDimension.PX)?.value ?: 0.0 + +val StyleSheet.effectivePaddingTop: Double + get() = (paddingTop as? LinearDimension.PX)?.value ?: 0.0 + +val StyleSheet.effectivePaddingBottom: Double + get() = (paddingBottom as? LinearDimension.PX)?.value ?: 0.0 + + +val StyleSheet.effectivePaddingHeight: Double + get() = effectivePaddingBottom + effectivePaddingTop + +val StyleSheet.effectivePaddingWidth: Double + get() = effectivePaddingLeft + effectivePaddingRight + +var StyleSheet.fontSize by PropertyHandler("font-size", INHERIT, 14.px) +var StyleSheet.fontFamily by PropertyHandler("font-family", INHERIT, "default") +var StyleSheet.overflow by PropertyHandler("overflow", RESET, Overflow.Visible) +var StyleSheet.zIndex by PropertyHandler("z-index", RESET, ZIndex.Auto) + +val Number.px: LinearDimension.PX get() = LinearDimension.PX(this.toDouble()) +val Number.percent: LinearDimension.Percent get() = LinearDimension.Percent(this.toDouble()) + +fun StyleSheet.child(selector: CompoundSelector, init: StyleSheet.() -> Unit) { + val stylesheet = StyleSheet(selector).apply(init) + stylesheet.selector.previous = Pair(Combinator.CHILD, this.selector) + children.add(stylesheet) +} + +fun StyleSheet.descendant(selector: CompoundSelector, init: StyleSheet.() -> Unit) { + val stylesheet = StyleSheet(selector).apply(init) + stylesheet.selector.previous = Pair(Combinator.DESCENDANT, this.selector) + children.add(stylesheet) +} + +fun StyleSheet.and(selector: CompoundSelector, init: StyleSheet.() -> Unit) { + val stylesheet = StyleSheet(this.selector and selector).apply(init) + this.children.add(stylesheet) +} + +fun StyleSheet.flatten(): List { + return listOf(this) + children.flatMap { it.flatten() } +} + +fun styleSheet(selector: CompoundSelector = CompoundSelector.DUMMY, init: StyleSheet.() -> Unit): StyleSheet { + return StyleSheet(selector).apply { + init() + } +} \ No newline at end of file diff --git a/orx-panel/src/main/kotlin/org/openrndr/panel/tools/Tooltip.kt b/orx-panel/src/main/kotlin/org/openrndr/panel/tools/Tooltip.kt new file mode 100644 index 00000000..9c5ec6b9 --- /dev/null +++ b/orx-panel/src/main/kotlin/org/openrndr/panel/tools/Tooltip.kt @@ -0,0 +1,53 @@ +package org.openrndr.panel.tools + +import org.openrndr.color.ColorRGBa +import org.openrndr.draw.Drawer +import org.openrndr.draw.FontImageMap +import org.openrndr.draw.isolated +import org.openrndr.math.Vector2 +import org.openrndr.panel.ControlManager +import org.openrndr.panel.elements.Body +import org.openrndr.panel.elements.Element +import org.openrndr.text.writer +import kotlin.math.max + +class Tooltip(val parent: Element, val position: Vector2, val message: String) { + fun draw(drawer: Drawer) { + + val fontUrl = (parent.root() as Body).controlManager.fontManager.resolve("default") ?: error("no font") + val fontSize = 14.0 + val fontMap = FontImageMap.fromUrl(fontUrl, fontSize) + val lines = message.split("\n") + + drawer.isolated { + drawer.fontMap = fontMap + + var maxX = 0.0 + var maxY = 0.0 + writer(drawer) { + for (line in lines) { + newLine() + text(line, false) + maxX = max(maxX, cursor.x) + maxY = cursor.y + } + gaplessNewLine() + maxY = cursor.y + } + + drawer.translate(position) + drawer.translate(10.0, 0.0) + drawer.stroke = null + drawer.fill = ColorRGBa.GRAY + drawer.rectangle(0.0, 0.0, maxX + 20.0, maxY) + drawer.fill = ColorRGBa.BLACK + drawer.translate(10.0, 0.0) + writer(drawer) { + for (line in lines) { + newLine() + text(line) + } + } + } + } +} \ No newline at end of file diff --git a/orx-panel/src/main/resources/fonts/Roboto-Medium.ttf b/orx-panel/src/main/resources/fonts/Roboto-Medium.ttf new file mode 100644 index 0000000000000000000000000000000000000000..39c63d7461796094c0b8889ee8fe2706d344a99a GIT binary patch literal 162588 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 z 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 GERq0N(MvP{ literal 0 HcmV?d00001 diff --git a/orx-panel/src/main/resources/fonts/Roboto-Regular.ttf b/orx-panel/src/main/resources/fonts/Roboto-Regular.ttf new file mode 100644 index 0000000000000000000000000000000000000000..8c082c8de090865264d37594e396c4d6c0099fe4 GIT binary patch literal 162876 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 button +// val cs = selector(class_="panel") withChild selector(type="button", class_="fancy") +// +// val root = Element(ElementType("body")) +// val panel = Element(ElementType("div")).apply { +// classes+= ElementClass("panel") +// } +// val button = Element(ElementType("button")) +// val button2 = Element(ElementType("button")).apply { +// classes+= ElementClass("fancy") +// } +// +// root.append(panel) +// panel.append(button) +// panel.append(button2) +// +// it("should work") { +// assert(cs.selectors.size == 1) +// assertTrue(cs.selectors[0] is TypeSelector) +// assertNotNull(cs.previous) +// +// assertFalse(Matcher().matches(cs, button)) +// assertFalse(Matcher().matches(cs, panel)) +// assertTrue(Matcher().matches(cs, button2)) +// } +// +// it("should have precedences") { +// println(cs.precedence()) +// +// +// } +// +// } +// +//}) +// diff --git a/orx-panel/src/test/java/org/openrndr/panel/test/StyleSheetTest.kt b/orx-panel/src/test/java/org/openrndr/panel/test/StyleSheetTest.kt new file mode 100644 index 00000000..f01aded4 --- /dev/null +++ b/orx-panel/src/test/java/org/openrndr/panel/test/StyleSheetTest.kt @@ -0,0 +1,18 @@ +//package org.openrndr.panel.test +// +//import net.lustlab.panel.style.* +//import org.jetbrains.spek.api.Spek +//import org.jetbrains.spek.api.dsl.describe +// +//class StyleSheetTest : Spek({ +// +// describe("stylesheet") { +// val styleSheet = StyleSheet() +// styleSheet.width = 5.px +// styleSheet.height = 5.px +// styleSheet.left = 10.px +// styleSheet.top = 10.percent +// styleSheet.position = Position.FIXED +// var a = styleSheet.precedence +// } +//}) diff --git a/settings.gradle b/settings.gradle index 005d1930..0235c1ee 100644 --- a/settings.gradle +++ b/settings.gradle @@ -23,6 +23,7 @@ include 'orx-camera', 'orx-olive', 'orx-osc', 'orx-palette', + 'orx-panel', 'orx-poisson-fill', 'orx-runway', 'orx-shader-phrases',