Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fixes to grid layout #503

Merged
merged 1 commit into from
Sep 30, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
360 changes: 67 additions & 293 deletions src/commonMain/kotlin/baaahs/ui/gridlayout/Layout.kt

Large diffs are not rendered by default.

92 changes: 72 additions & 20 deletions src/commonMain/kotlin/baaahs/ui/gridlayout/types.kt
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,32 @@ data class LayoutItem(
}
}

/**
* Sort layout items by row ascending then column ascending.
*/
fun List<LayoutItem>.sortLayoutItemsByRowCol(reverse: Boolean = false): List<LayoutItem> =
sortedWith { a, b ->
when {
a.y == b.y && a.x == b.x -> 0
a.y == b.y && a.x > b.x -> 1
if (reverse) b.y > a.y else a.y > b.y -> 1
else -> -1
}
}

/**
* Sort layout items by column ascending then row ascending.
*/
fun List<LayoutItem>.sortLayoutItemsByColRow(reverse: Boolean = false): List<LayoutItem> =
sortedWith { a, b ->
when {
a.x == b.x && a.y == b.y -> 0
a.x == b.x && a.y > b.y -> 1
if (reverse) a.x > b.x else b.x > a.x -> 1
else -> -1
}
}

data class LayoutItemSize(
val width: Int,
val height: Int
Expand All @@ -53,31 +79,57 @@ data class Position(
val height: Int
)

enum class CompactType {
Horizontal,
Vertical,
None;
enum class Direction(
val xIncr: Int, val yIncr: Int
) {
North(0, -1) {
override val opposite: Direction get() = South

val isHorizontal get() = this == Horizontal
val isVertical get() = this == Vertical
override fun sort(collisions: List<LayoutItem>): List<LayoutItem> =
collisions.sortLayoutItemsByRowCol(reverse = true)
},

companion object {
fun LayoutItem.determineFrom(newX: Int, newY: Int) =
if (newX != x) Horizontal else Vertical
}
}
South(0, 1) {
override val opposite: Direction get() = North

enum class Axis {
x {
override fun incr(item: LayoutItem) = item.copy(x = item.x + 1)
override fun set(item: LayoutItem, value: Int): LayoutItem = item.copy(x = value)
override fun sort(collisions: List<LayoutItem>): List<LayoutItem> =
collisions.sortLayoutItemsByRowCol()

},
y {
override fun incr(item: LayoutItem) = item.copy(y = item.y + 1)
override fun set(item: LayoutItem, value: Int): LayoutItem = item.copy(y = value)

East(1, 0) {
override val opposite: Direction get() = West

override fun sort(collisions: List<LayoutItem>): List<LayoutItem> =
collisions.sortLayoutItemsByRowCol()

},

West(-1, 0) {
override val opposite: Direction get() = East

override fun sort(collisions: List<LayoutItem>): List<LayoutItem> =
collisions.sortLayoutItemsByRowCol(reverse = true)

};

abstract fun incr(item: LayoutItem): LayoutItem
abstract fun set(item: LayoutItem, value: Int): LayoutItem
val isHorizontal get() = xIncr != 0
val isVertical get() = yIncr != 0
abstract val opposite: Direction

abstract fun sort(collisions: List<LayoutItem>): List<LayoutItem>

companion object {
fun rankedPushOptions(x: Int, y: Int): Array<Direction> {
return when {
x > 0 && y == 0 -> arrayOf(West, East, South, North)
x < 0 && y == 0 -> arrayOf(East, West, South, North)
x == 0 && y > 0 -> arrayOf(North, South, East, West)
x == 0 && y < 0 -> arrayOf(South, North, East, West)
else -> arrayOf(South, North, East, West)
}
}
}
}

class ImpossibleLayoutException : Exception()
10 changes: 7 additions & 3 deletions src/commonTest/kotlin/baaahs/ui/gridlayout/GridSpec.kt
Original file line number Diff line number Diff line change
Expand Up @@ -74,13 +74,17 @@ fun String.toLayout(): Layout {
fun Layout.stringify(): String {
if (items.isEmpty()) return "[Empty]"

val gridWidth = items.maxOf { it.x + it.w }
val gridHeight = items.maxOf { it.y + it.h }
val gridWidth = if (cols == Int.MAX_VALUE) items.maxOf { it.x + it.w } else cols
val gridHeight = if (rows == Int.MAX_VALUE) items.maxOf { it.y + it.h } else rows
val cells = Array(gridHeight) { Array(gridWidth) { "." } }
items.forEach {
(0 until it.h).forEach { row ->
(0 until it.w).forEach { col ->
cells[it.y + row][it.x + col] = it.i
if (cells[it.y + row][it.x + col] != ".") {
cells[it.y + row][it.x + col] = "!"
} else {
cells[it.y + row][it.x + col] = it.i
}
}
}
}
Expand Down
68 changes: 54 additions & 14 deletions src/commonTest/kotlin/baaahs/ui/gridlayout/LayoutSpec.kt
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
package baaahs.ui.gridlayout

import baaahs.describe
import baaahs.gl.override
import baaahs.toEqual
import baaahs.ui.gridlayout.CompactType.Companion.determineFrom
import ch.tutteli.atrium.api.fluent.en_GB.toThrow
import ch.tutteli.atrium.api.verbs.expect
import org.spekframework.spek2.Spek

Expand All @@ -19,49 +20,88 @@ object LayoutSpec : Spek({
val move by value {
{ id: String, x: Int, y: Int ->
val item = layout.find(id)!!
val compactType = item.determineFrom(x, y)
layout.moveElement(item, x, y, false, compactType)
layout.moveElement(item, item.x + x, item.y + y)
.stringify()
}
}

it("moving A one space down shifts D down") {
expect(move("A", 0, 1).stringify()).toEqual("""
.BC.
it("moving A one space down swaps A and D") {
expect(move("A", 0, 1)).toEqual("""
DBC.
AEFG
DHI.
.HI.
""".trimIndent())
}

it("moving C to E's spot fails") {
expect { (move("C", -1, -1)) }.toThrow<ImpossibleLayoutException>()
}

it("moving A two spaces down leaves the rest undisturbed") {
expect(move("A", 0, 2).stringify()).toEqual("""
expect(move("A", 0, 2)).toEqual("""
.BC.
DEFG
AHI.
""".trimIndent())
}

it("moving A one space right shifts B and C over, because there's room to the right") {
expect(move("A", 1, 0).stringify()).toEqual("""
.ABC
it("moving A one space right swaps A and B") {
expect(move("A", 1, 0)).toEqual("""
BAC.
DEFG
.HI.
""".trimIndent())
}

it("moving A two spaces right shifts C over") {
expect(move("A", 2, 0).stringify()).toEqual("""
.BAC
expect(move("A", 2, 0)).toEqual("""
BCA.
DEFG
.HI.
""".trimIndent())
}

it("moving D one space right shifts E into its place") {
expect(move("D", 1, 1).stringify()).toEqual("""
expect(move("D", 1, 0)).toEqual("""
ABC.
EDFG
.HI.
""".trimIndent())
}

it("moving B one space down and left shifts E down") {
expect(move("B", -1, 1)).toEqual("""
A.C.
BEFG
DHI.
""".trimIndent())
}

context("with ABCDEF in one row") {
override(layout) { "ABCDEF".toLayout() }
it("moving B two spaces over") {
expect(move("B", 2, 0)).toEqual("ACDBEF")
}
}

context("with .ABBC.") {
override(layout) { ".ABBC.".toLayout() }

xit("moving A one space right should swap A and B") {
expect(move("A", 1, 0)).toEqual(".BBAC.")
}

it("moving A two spaces right should swap A and B") {
expect(move("A", 2, 0)).toEqual(".BBAC.")
}

xit("moving C one space left should swap B and C") {
expect(move("C", -1, 0)).toEqual(".ACBB.")
}

it("moving C two spaces left should swap B and C") {
expect(move("C", -2, 0)).toEqual(".ACBB.")
}
}
}
})
2 changes: 0 additions & 2 deletions src/jsMain/kotlin/baaahs/app/ui/ControlsPalette.kt
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@ import baaahs.show.live.ControlProps
import baaahs.show.live.LegacyControlDisplay
import baaahs.show.live.OpenShow
import baaahs.ui.*
import baaahs.ui.gridlayout.CompactType
import baaahs.ui.gridlayout.Layout
import baaahs.ui.gridlayout.LayoutItem
import baaahs.ui.gridlayout.gridLayout
Expand Down Expand Up @@ -101,7 +100,6 @@ val ControlsPalette = xComponent<ControlsPaletteProps>("ControlsPalette") { prop
attrs.margin = 5 to 5
attrs.layout = layout
// attrs.onLayoutChange = handleLayoutChange
attrs.compactType = CompactType.None
attrs.disableDrag = !editMode.isOn
attrs.disableResize = true
attrs.isDroppable = editMode.isOn
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -182,7 +182,6 @@ private val GridButtonGroupControlView = xComponent<GridButtonGroupProps>("GridB
attrs.margin = 5 to 5
attrs.layout = layout
attrs.onLayoutChange = handleLayoutChange
attrs.compactType = CompactType.None
attrs.resizeHandle = ::buildResizeHandle
attrs.disableDrag = !editMode.isOn
attrs.disableResize = !editMode.isOn
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -160,7 +160,6 @@ private val GridTabLayoutView = xComponent<GridTabLayoutProps>("GridTabLayout")
attrs.margin = 5 to 5
attrs.layout = layoutGrid.layout
attrs.onLayoutChange = handleLayoutChange
attrs.compactType = CompactType.None
attrs.resizeHandle = ::buildResizeHandle
attrs.disableDrag = !editMode.isOn
attrs.disableResize = !editMode.isOn
Expand Down
19 changes: 19 additions & 0 deletions src/jsMain/kotlin/baaahs/app/ui/layout/LayoutStyles.kt
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,7 @@ class LayoutStyles(val theme: Theme) : StyleSheet("app-ui-layout", isStatic = tr
border(3.px, BorderStyle.solid, theme.palette.text.primary.asColor().withAlpha(.25))
transition(::opacity, transitionTime)
transition(::border, transitionTime)
cursor = Cursor.default

// outlineWidth = 3.px
// put("outlineStyle", "dashed")
Expand Down Expand Up @@ -158,6 +159,7 @@ class LayoutStyles(val theme: Theme) : StyleSheet("app-ui-layout", isStatic = tr
bottom = (-2).px + (2.5).em
zIndex = StyleConstants.Layers.aboveSharedGlCanvas
filter = "drop-shadow(1px 1px 2px rgba(0, 0, 0, .9))"
cursor = Cursor.default

child("svg") {
width = .75.em
Expand All @@ -170,6 +172,7 @@ class LayoutStyles(val theme: Theme) : StyleSheet("app-ui-layout", isStatic = tr
bottom = (-2).px + 1.em
zIndex = StyleConstants.Layers.aboveSharedGlCanvas
filter = "drop-shadow(1px 1px 2px rgba(0, 0, 0, .9))"
cursor = Cursor.default

child("svg") {
width = .75.em
Expand Down Expand Up @@ -290,6 +293,10 @@ class LayoutStyles(val theme: Theme) : StyleSheet("app-ui-layout", isStatic = tr
borderBottom = "2px solid rgba(0, 0, 0, 0.4)"
}

".react-draggable > .app-ui-controls-controlRoot" {
pointerEvents = PointerEvents.none
}

".react-draggable-dragging, .react-draggable-dragging *" {
pointerEvents = PointerEvents.none
transition(::top, 0.s)
Expand All @@ -298,6 +305,18 @@ class LayoutStyles(val theme: Theme) : StyleSheet("app-ui-layout", isStatic = tr
transition(::height, 0.s)
}

".react-draggable" {
cursor = Cursor.grab
}

".react-draggable-dragging" {
cursor = Cursor.grabbing
}

".react-draggable-not-droppable-here" {
cursor = Cursor.noDrop
}

val inset = 2.px

".react-resizable-hide > .app-ui-layout-resize-handle" {
Expand Down
2 changes: 2 additions & 0 deletions src/jsMain/kotlin/baaahs/ui/gridlayout/GridItem.kt
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ external interface GridItemProps : Props {
var usePercentages: Boolean?
var transformScale: Double
var droppingPosition: DroppingPosition?
var notDroppableHere: Boolean?

var className: String
var style: Any?
Expand Down Expand Up @@ -611,6 +612,7 @@ class GridItem(
this["react-draggable-dragging"] = state.dragging
this.dropping = droppingPosition
this.cssTransforms = useCSSTransforms
this["react-draggable-not-droppable-here"] = props.notDroppableHere == true
}
)
// We can set the width and height on the child, but unfortunately we can't set the position.
Expand Down
Loading