From c77a31e716b91d4871f04c272a03eb5588bba70d Mon Sep 17 00:00:00 2001 From: neddy Date: Fri, 28 Jun 2024 01:13:02 -0700 Subject: [PATCH] - [Docs] Fixed text in TabStrip docs. --- DocApps/src/jsMain/kotlin/main.kt | 4 +- .../io/nacular/doodle/examples/PhotosApp.kt | 73 +++++++++---------- PhotosRunner/src/jsMain/kotlin/main.kt | 4 +- .../kotlin/io/nacular/doodle/examples/main.kt | 4 +- PhotosRunner/src/wasmJsMain/kotlin/main.kt | 4 +- .../io/nacular/doodle/examples/TabStrip.kt | 51 +++++-------- gradle/libs.versions.toml | 4 +- 7 files changed, 65 insertions(+), 79 deletions(-) diff --git a/DocApps/src/jsMain/kotlin/main.kt b/DocApps/src/jsMain/kotlin/main.kt index 14ae711..b9a975b 100644 --- a/DocApps/src/jsMain/kotlin/main.kt +++ b/DocApps/src/jsMain/kotlin/main.kt @@ -47,7 +47,7 @@ import io.nacular.doodle.examples.contacts.showcase import io.nacular.doodle.examples.contacts.showcaseModules import io.nacular.doodle.theme.basic.BasicTheme.Companion.basicCircularProgressIndicatorBehavior import io.nacular.doodle.theme.basic.BasicTheme.Companion.basicLabelBehavior -import io.nacular.doodle.theme.basic.BasicTheme.Companion.basicMutableSpinnerBehavior +import io.nacular.doodle.theme.basic.BasicTheme.Companion.basicMutableSpinButtonBehavior import io.nacular.doodle.theme.native.NativeTheme.Companion.nativeHyperLinkBehavior import io.nacular.doodle.theme.native.NativeTheme.Companion.nativeScrollPanelBehavior import io.nacular.doodle.theme.native.NativeTheme.Companion.nativeTextFieldBehavior @@ -106,7 +106,7 @@ fun photos(element: HTMLElement) { DragDropModule, basicLabelBehavior(), nativeTextFieldBehavior(spellCheck = false), - basicMutableSpinnerBehavior(), + basicMutableSpinButtonBehavior(), basicCircularProgressIndicatorBehavior(thickness = 18.0), Module(name = "AppModule") { bindSingleton { AnimatorImpl (instance(), instance()) } diff --git a/Photos/src/commonMain/kotlin/io/nacular/doodle/examples/PhotosApp.kt b/Photos/src/commonMain/kotlin/io/nacular/doodle/examples/PhotosApp.kt index bf831b2..70b80bf 100644 --- a/Photos/src/commonMain/kotlin/io/nacular/doodle/examples/PhotosApp.kt +++ b/Photos/src/commonMain/kotlin/io/nacular/doodle/examples/PhotosApp.kt @@ -8,11 +8,11 @@ import io.nacular.doodle.application.Application import io.nacular.doodle.controls.buttons.PushButton import io.nacular.doodle.controls.itemVisualizer import io.nacular.doodle.controls.range.CircularSlider -import io.nacular.doodle.controls.spinner.MutableIntSpinnerModel -import io.nacular.doodle.controls.spinner.MutableSpinner -import io.nacular.doodle.controls.spinner.Spinner -import io.nacular.doodle.controls.spinner.SpinnerModel -import io.nacular.doodle.controls.spinner.spinnerEditor +import io.nacular.doodle.controls.spinner.MutableIntSpinButtonModel +import io.nacular.doodle.controls.spinner.MutableSpinButton +import io.nacular.doodle.controls.spinner.SpinButton +import io.nacular.doodle.controls.spinner.SpinButtonModel +import io.nacular.doodle.controls.spinner.spinButtonEditor import io.nacular.doodle.controls.text.Label import io.nacular.doodle.controls.theme.simpleButtonRenderer import io.nacular.doodle.core.Container @@ -54,11 +54,12 @@ import io.nacular.doodle.layout.WidthSource.Parent import io.nacular.doodle.layout.constraints.Bounds import io.nacular.doodle.layout.constraints.ConstraintDslContext import io.nacular.doodle.layout.constraints.constrain +import io.nacular.doodle.layout.constraints.fill import io.nacular.doodle.system.Cursor.Companion.Text import io.nacular.doodle.theme.ThemeManager import io.nacular.doodle.theme.adhoc.DynamicTheme import io.nacular.doodle.theme.basic.range.BasicCircularSliderBehavior -import io.nacular.doodle.theme.basic.spinner.SpinnerTextEditOperation +import io.nacular.doodle.theme.basic.spinner.SpinButtonTextEditOperation import io.nacular.doodle.utils.Dimension.Width import io.nacular.doodle.utils.PropertyObserver import io.nacular.doodle.utils.PropertyObservers @@ -86,17 +87,17 @@ import io.nacular.doodle.datatransport.Image as ImageType * Panel used to display editable properties of an image. */ private class PropertyPanel(private val focusManager: FocusManager): Container() { - private val spinnerHeight = 24.0 + private val spinButtonHeight = 24.0 /** - * Simple View with a [MutableSpinner] and [Label] that displays a numeric property. + * Simple View with a [MutableSpinButton] and [Label] that displays a numeric property. */ private inner class Property( private val property : KMutableProperty0, private val updateWhen: PropertyObservers, suffix : String = "" ): View() { - private fun > spinnerVisualizer(suffix: String = "") = itemVisualizer { item: Int, previous: View?, context: Spinner -> + private fun > spinButtonVisualizer(suffix: String = "") = itemVisualizer { item: Int, previous: View?, context: SpinButton -> when (previous) { is Label -> previous.also { it.text = "$item$suffix" } else -> Label("$item$suffix").apply { @@ -106,9 +107,9 @@ private class PropertyPanel(private val focusManager: FocusManager): Container() foregroundColor = previous?.foregroundColor backgroundColor = previous?.backgroundColor ?: Transparent - (context as? MutableSpinner<*,*>)?.let { spinner -> + (context as? MutableSpinButton<*,*>)?.let { spinButton -> pointerFilter += pressed { event -> - spinner.startEditing() + spinButton.startEditing() event.consume() } } @@ -116,17 +117,15 @@ private class PropertyPanel(private val focusManager: FocusManager): Container() } } - private val spinner = MutableSpinner( - MutableIntSpinnerModel(Int.MIN_VALUE..Int.MAX_VALUE, property.get().toInt()), - spinnerVisualizer(suffix) + private val spinButton = MutableSpinButton( + MutableIntSpinButtonModel(Int.MIN_VALUE..Int.MAX_VALUE, property.get().toInt()), + spinButtonVisualizer(suffix) ).apply { - cellAlignment = { - it.edges eq parent.edges - } + cellAlignment = fill - // Make the spinner editable - editor = spinnerEditor { spinner, value, current -> - object: SpinnerTextEditOperation(focusManager, ToStringIntEncoder, spinner, value, current) { + // Make the spinButton editable + editor = spinButtonEditor { button, value, current -> + object: SpinButtonTextEditOperation(focusManager, ToStringIntEncoder, button, value, current) { init { textField.selectionBackgroundColor = Darkgray } @@ -142,22 +141,22 @@ private class PropertyPanel(private val focusManager: FocusManager): Container() } } - private val callBack: PropertyObserver = { _,_,_ -> spinner.set(property.get().toInt()) } + private val callBack: PropertyObserver = { _,_,_ -> spinButton.set(property.get().toInt()) } init { updateWhen += callBack - children += listOf(spinner, Label(property.name.replaceFirstChar { if (it.isLowerCase()) it.titlecase() else it.toString() })) - - // Label is centered below spinner, which is stretched to fit its parent's width - layout = constrain(children[0], children[1]) { spinner, label -> - spinner.top eq 0 - spinner.left eq 0 - spinner.right eq parent.right - spinner.height eq spinnerHeight - label.top eq spinner.bottom + 2 - label.centerX eq parent.centerX - label.height eq label.height.readOnly + children += listOf(spinButton, Label(property.name.replaceFirstChar { if (it.isLowerCase()) it.titlecase() else it.toString() })) + + // Label is centered below spinButton, which is stretched to fit its parent's width + layout = constrain(children[0], children[1]) { spinButton, label -> + spinButton.top eq 0 + spinButton.left eq 0 + spinButton.right eq parent.right + spinButton.height eq spinButtonHeight + label.top eq spinButton.bottom + 2 + label.centerX eq parent.centerX + label.height eq label.height.readOnly } } @@ -177,7 +176,7 @@ private class PropertyPanel(private val focusManager: FocusManager): Container() layout = constrain(children[0], property1, property2) { label, first, second -> label.top eq second.top label.left eq spacing - label.height eq spinnerHeight + label.height eq spinButtonHeight first.centerY eq parent.centerY.writable first.right eq second.left - spacing first.width eq second.width @@ -218,16 +217,16 @@ private class PropertyPanel(private val focusManager: FocusManager): Container() } } - val rotationSlider = CircularSlider(0.0 .. 359.0).apply { + val rotationSlider = CircularSlider(0 * degrees .. 360 * degrees).apply { size = Size(50) - value = photoAngle.angle + value = photoAngle.angle * degrees behavior = BasicCircularSliderBehavior(thickness = 18.0) - changed += { _,_,new -> photoAngle.angle = new } + changed += { _,_,new -> photoAngle.angle = new `in` degrees } } photo.transformChanged += { _,_,_ -> photoAngle.angle = computeAngle(photo) `in` degrees - rotationSlider.value = photoAngle.angle + rotationSlider.value = photoAngle.angle * degrees } children += propertyGroup("Size", Property(photo::width, photoBoundsChanged), Property(photo::height, photoBoundsChanged )) diff --git a/PhotosRunner/src/jsMain/kotlin/main.kt b/PhotosRunner/src/jsMain/kotlin/main.kt index 6c3ede3..783e334 100644 --- a/PhotosRunner/src/jsMain/kotlin/main.kt +++ b/PhotosRunner/src/jsMain/kotlin/main.kt @@ -9,7 +9,7 @@ import io.nacular.doodle.application.Modules.Companion.KeyboardModule import io.nacular.doodle.application.application import io.nacular.doodle.theme.basic.BasicTheme.Companion.basicCircularProgressIndicatorBehavior import io.nacular.doodle.theme.basic.BasicTheme.Companion.basicLabelBehavior -import io.nacular.doodle.theme.basic.BasicTheme.Companion.basicMutableSpinnerBehavior +import io.nacular.doodle.theme.basic.BasicTheme.Companion.basicMutableSpinButtonBehavior import io.nacular.doodle.theme.native.NativeTheme.Companion.nativeTextFieldBehavior import org.kodein.di.DI.Module import org.kodein.di.bindSingleton @@ -27,7 +27,7 @@ fun main() { DragDropModule, basicLabelBehavior(), nativeTextFieldBehavior(spellCheck = false), - basicMutableSpinnerBehavior(), + basicMutableSpinButtonBehavior(), basicCircularProgressIndicatorBehavior(thickness = 18.0), Module(name = "AppModule") { bindSingleton { AnimatorImpl(instance(), instance()) } diff --git a/PhotosRunner/src/jvmMain/kotlin/io/nacular/doodle/examples/main.kt b/PhotosRunner/src/jvmMain/kotlin/io/nacular/doodle/examples/main.kt index 03b0cb6..707164b 100644 --- a/PhotosRunner/src/jvmMain/kotlin/io/nacular/doodle/examples/main.kt +++ b/PhotosRunner/src/jvmMain/kotlin/io/nacular/doodle/examples/main.kt @@ -9,7 +9,7 @@ import io.nacular.doodle.application.Modules.Companion.KeyboardModule import io.nacular.doodle.application.application import io.nacular.doodle.theme.basic.BasicTheme.Companion.basicCircularProgressIndicatorBehavior import io.nacular.doodle.theme.basic.BasicTheme.Companion.basicLabelBehavior -import io.nacular.doodle.theme.basic.BasicTheme.Companion.basicMutableSpinnerBehavior +import io.nacular.doodle.theme.basic.BasicTheme.Companion.basicMutableSpinButtonBehavior import io.nacular.doodle.theme.native.NativeTheme.Companion.nativeTextFieldBehavior import org.kodein.di.DI.Module import org.kodein.di.bindSingleton @@ -23,7 +23,7 @@ fun main() { DragDropModule, basicLabelBehavior(), nativeTextFieldBehavior(), - basicMutableSpinnerBehavior(), + basicMutableSpinButtonBehavior(), basicCircularProgressIndicatorBehavior(thickness = 18.0), Module(name = "AppModule") { bindSingleton { AnimatorImpl(instance(), instance()) } diff --git a/PhotosRunner/src/wasmJsMain/kotlin/main.kt b/PhotosRunner/src/wasmJsMain/kotlin/main.kt index 03b0d14..eb77ca7 100644 --- a/PhotosRunner/src/wasmJsMain/kotlin/main.kt +++ b/PhotosRunner/src/wasmJsMain/kotlin/main.kt @@ -9,7 +9,7 @@ import io.nacular.doodle.application.Modules.Companion.KeyboardModule import io.nacular.doodle.application.application import io.nacular.doodle.theme.basic.BasicTheme.Companion.basicCircularProgressIndicatorBehavior import io.nacular.doodle.theme.basic.BasicTheme.Companion.basicLabelBehavior -import io.nacular.doodle.theme.basic.BasicTheme.Companion.basicMutableSpinnerBehavior +import io.nacular.doodle.theme.basic.BasicTheme.Companion.basicMutableSpinButtonBehavior import io.nacular.doodle.theme.native.NativeTheme.Companion.nativeTextFieldBehavior import org.kodein.di.DI.Module import org.kodein.di.bindSingleton @@ -26,7 +26,7 @@ fun main() { DragDropModule, basicLabelBehavior(), nativeTextFieldBehavior(spellCheck = false), - basicMutableSpinnerBehavior(), + basicMutableSpinButtonBehavior(), basicCircularProgressIndicatorBehavior(thickness = 18.0), Module(name = "AppModule") { bindSingleton { AnimatorImpl(instance(), instance()) } diff --git a/TabStrip/src/commonMain/kotlin/io/nacular/doodle/examples/TabStrip.kt b/TabStrip/src/commonMain/kotlin/io/nacular/doodle/examples/TabStrip.kt index 50e4cd9..09a8a7a 100644 --- a/TabStrip/src/commonMain/kotlin/io/nacular/doodle/examples/TabStrip.kt +++ b/TabStrip/src/commonMain/kotlin/io/nacular/doodle/examples/TabStrip.kt @@ -111,21 +111,14 @@ class TabStrip(private val animate: Animator, private val pathMetrics: PathMetri // Overall animation handle private var animation: Animation<*>? by autoCanceling() - private val secondaryAnimations = mutableSetOf>() // Monitor changes to the selected item to handle animation private var selectedItem by observable(items.first()) { _,selected -> - // cancel any ongoing secondary animations and hide droplet + // hide droplet dropletYAboveIndicator = 0.0 - secondaryAnimations.forEach { it.cancel() } - secondaryAnimations.clear() // Animation blocks roll all top-level animations (those created while in the block) into a common // parent animation. Canceling that animation cancels all the children. - // However, our code creates additional animations that are created when top-level ones are completed. - // These animations are NOT tracked as part of the returned animation group. So they need to be tracked - // separately, so we can cancel them if anything changes mid-flight. - // We do that using the secondaryAnimations set. animation = animate { // All deselected items move back to normal items.filter { it != selected && !it.atDefaults }.forEach { deselected -> @@ -134,34 +127,31 @@ class TabStrip(private val animate: Animator, private val pathMetrics: PathMetri } // Indicator moves to selected item - (indicatorCenter.x to selected.centerX using (tweenDouble(easeInOutCubic, slideDuration)) { indicatorCenter = Point(it, height) }).onCompleted { + indicatorCenter.x to selected.centerX using (tweenDouble(easeInOutCubic, slideDuration)) { indicatorCenter = Point(it, height) } then { // Selected item moves down - (selected.moveProgress to 1f using (tweenFloat(linear, itemMoveDownDuration)) { selected.moveProgress = it }).also { secondaryAnimations += it } + selected.moveProgress to 1f using (tweenFloat(linear, itemMoveDownDuration)) { selected.moveProgress = it } } // Indicator primes as it travels to selected item - (indicatorHeight to minIndicatorHeight using (tweenDouble(linear, primeDuration)) { indicatorHeight = it }).onCompleted { - // NOTE: All these are secondary animations that won't be attached to the outer animation, since it would have been - // completed at this point. So they need to be tracked using our secondaryAnimation set. - + indicatorHeight to minIndicatorHeight using (tweenDouble(linear, primeDuration)) { indicatorHeight = it } then { // Indicator fires at selected item - (indicatorHeight to maxIndicatorHeight using (tweenDouble(linear, fireDuration)) { indicatorHeight = it }).onCompleted { + indicatorHeight to maxIndicatorHeight using (tweenDouble(linear, fireDuration)) { indicatorHeight = it } then { // Indicator height returns to normal - (indicatorHeight to defaultIndicatorHeight using (tweenDouble(linear, recoilDuration)) { indicatorHeight = it }).also { secondaryAnimations += it } + indicatorHeight to defaultIndicatorHeight using (tweenDouble(linear, recoilDuration)) { indicatorHeight = it } // Droplet moves up to item - (dropletYAboveIndicator to dropletMaxY using (tweenDouble(linear, dropletTravelDuration)) { dropletYAboveIndicator = it }).onCompleted { + dropletYAboveIndicator to dropletMaxY using (tweenDouble(linear, dropletTravelDuration)) { dropletYAboveIndicator = it } then { // Droplet is instantly hidden dropletYAboveIndicator = 0.0 // Selected item moves up - (selected.moveProgress to 0f using (tweenFloat(linear, itemMoveUpDuration)) { selected.moveProgress = it }).also { secondaryAnimations += it } + selected.moveProgress to 0f using (tweenFloat(linear, itemMoveUpDuration)) { selected.moveProgress = it } // Selected item animates droplet within it - (selected.selectionProgress to 1f using (tweenFloat(linear, itemFillDuration)) { selected.selectionProgress = it }).also { secondaryAnimations += it } - }.also { secondaryAnimations += it } - }.also { secondaryAnimations += it } - }.also { secondaryAnimations += it } + selected.selectionProgress to 1f using (tweenFloat(linear, itemFillDuration)) { selected.selectionProgress = it } + } + } + } } } @@ -275,20 +265,17 @@ class TabStrip(private val animate: Animator, private val pathMetrics: PathMetri private fun updateIndicatorPath() { val indicatorHalfWidth = indicatorWidth / 2 - val controlPoint1 = Point(x = -indicatorHalfWidth) + Point(19.6113, -5.2466) - val controlPoint2 = Point(x = -11.4078, -indicatorHeight) - val controlPoint3 = controlPoint2 + Point(x = 2 * 11.4078) - val controlPoint4 = Point(x = indicatorHalfWidth) + Point(-19.6113, -5.2466) + val offset = Point(19.6113, -5.2466) + val controlPoint2X = -11.4078 + + val controlPoint1 = Point(x = -indicatorHalfWidth) + offset + val controlPoint2 = Point(x = controlPoint2X, -indicatorHeight) + val controlPoint3 = controlPoint2 + Point(x = 2 * -controlPoint2X) + val controlPoint4 = Point(x = indicatorHalfWidth) + offset.run { Point(x = -x, y) } indicatorPath = path(Point(x = -indicatorHalfWidth)). cubicTo(Point(y = -indicatorHeight ), controlPoint1, controlPoint2). cubicTo(Point(x = indicatorHalfWidth), controlPoint3, controlPoint4). close() } - - private fun Animation.onCompleted(block: () -> Unit): Animation = this.apply { - completed += { - block() - } - } } \ No newline at end of file diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index d6d12d2..13162c7 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -1,8 +1,8 @@ [versions] -kotlinVersion = { strictly = "1.9.22" } +kotlinVersion = { strictly = "1.9.23" } coroutinesVersion = { strictly = "1.8.0" } kodeinVersion = { strictly = "7.21.1" } -doodleVersion = { strictly = "0.10.1" } +doodleVersion = { strictly = "0.10.2" } slf4jVersion = { strictly = "2.0.9" } mockkVersion = { strictly = "1.13.7" } jupiterVersion = { strictly = "5.10.0" }