Add support for calculate height
This commit is contained in:
@@ -26,7 +26,7 @@ val disabled = ElementPseudoClass("disabled")
|
||||
class FocusEvent
|
||||
|
||||
interface DisposableElement {
|
||||
var disposed : Boolean
|
||||
var disposed: Boolean
|
||||
|
||||
fun dispose() {
|
||||
disposed = true
|
||||
@@ -44,6 +44,12 @@ open class Element(val type: ElementType) {
|
||||
return null
|
||||
}
|
||||
|
||||
|
||||
open val heightHint: Double?
|
||||
get() {
|
||||
return null
|
||||
}
|
||||
|
||||
class MouseObservables {
|
||||
val clicked = Event<MouseEvent>("element-mouse-clicked")
|
||||
val doubleClicked = Event<MouseEvent>("element-mouse-double-clicked")
|
||||
@@ -236,7 +242,7 @@ open class Element(val type: ElementType) {
|
||||
}
|
||||
}
|
||||
|
||||
fun findNext(premise: (Element) -> Boolean) : Element? {
|
||||
fun findNext(premise: (Element) -> Boolean): Element? {
|
||||
return parent?.let { p ->
|
||||
val index = p.children.indexOf(this)
|
||||
val siblingCount = p.children.size
|
||||
@@ -249,10 +255,10 @@ open class Element(val type: ElementType) {
|
||||
}
|
||||
}
|
||||
|
||||
fun findPrevious(premise: (Element) -> Boolean) : Element? {
|
||||
fun findPrevious(premise: (Element) -> Boolean): Element? {
|
||||
return parent?.let { p ->
|
||||
val index = p.children.indexOf(this)
|
||||
for (i in index-1 downTo 0) {
|
||||
for (i in index - 1 downTo 0) {
|
||||
if (premise(p.children[i])) {
|
||||
return p.children[i]
|
||||
}
|
||||
@@ -319,7 +325,7 @@ fun Element.enable() {
|
||||
|
||||
fun Element.isDisabled(): Boolean = disabled in pseudoClasses
|
||||
|
||||
fun Element.findAll(predicate: (Element) -> Boolean) : List<Element> {
|
||||
fun Element.findAll(predicate: (Element) -> Boolean): List<Element> {
|
||||
val results = mutableListOf<Element>()
|
||||
visit {
|
||||
if (predicate(this)) {
|
||||
@@ -329,7 +335,7 @@ fun Element.findAll(predicate: (Element) -> Boolean) : List<Element> {
|
||||
return results
|
||||
}
|
||||
|
||||
fun Element.findAllVisible(predicate: (Element) -> Boolean) : List<Element> {
|
||||
fun Element.findAllVisible(predicate: (Element) -> Boolean): List<Element> {
|
||||
val results = mutableListOf<Element>()
|
||||
visitVisible {
|
||||
if (predicate(this)) {
|
||||
|
||||
@@ -14,7 +14,8 @@ class Layouter {
|
||||
val blockLike = setOf(Display.BLOCK, Display.FLEX)
|
||||
val manualPosition = setOf(Position.FIXED, Position.ABSOLUTE)
|
||||
|
||||
fun positionChildren(element: Element): Rectangle {
|
||||
fun positionChildren(element: Element, knownWidth:Double? = null): Rectangle {
|
||||
|
||||
return element.computedStyle.let { cs ->
|
||||
var y = element.layout.screenY - element.scrollTop + element.computedStyle.effectivePaddingTop
|
||||
|
||||
@@ -26,22 +27,23 @@ class Layouter {
|
||||
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 remainder = (knownWidth?: 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
|
||||
element.children.filter { it.computedStyle.display in blockLike && it.computedStyle.position !in manualPosition }.forEach { child ->
|
||||
val elementGrow = (child.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
|
||||
child.layout.screenY = y + ((child.computedStyle.marginTop as? LinearDimension.PX)?.value
|
||||
?: 0.0)
|
||||
it.layout.screenX = x + ((it.computedStyle.marginLeft as? LinearDimension.PX)?.value
|
||||
child.layout.screenX = x + ((child.computedStyle.marginLeft as? LinearDimension.PX)?.value
|
||||
?: 0.0)
|
||||
|
||||
it.layout.growWidth = growWidth
|
||||
x += width(it) + growWidth
|
||||
maxHeight = max(height(it), maxHeight)
|
||||
child.layout.growWidth = growWidth
|
||||
|
||||
val effectiveWidth = width(child) + growWidth
|
||||
x += effectiveWidth
|
||||
maxHeight = max(height(child, effectiveWidth), maxHeight)
|
||||
}
|
||||
Rectangle(Vector2(x, y), x - element.layout.screenX, maxHeight)
|
||||
}
|
||||
@@ -53,25 +55,26 @@ class Layouter {
|
||||
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) }
|
||||
.sumByDouble { height(it, width(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
|
||||
element.children.filter { it.computedStyle.display in blockLike && it.computedStyle.position !in manualPosition }.forEach { child ->
|
||||
val elementGrow = (child.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
|
||||
child.layout.screenY = ly + ((child.computedStyle.marginTop as? LinearDimension.PX)?.value
|
||||
?: 0.0)
|
||||
it.layout.screenX = lx + ((it.computedStyle.marginLeft as? LinearDimension.PX)?.value
|
||||
child.layout.screenX = lx + ((child.computedStyle.marginLeft as? LinearDimension.PX)?.value
|
||||
?: 0.0)
|
||||
|
||||
it.layout.growHeight = growHeight
|
||||
ly += height(it) + growHeight
|
||||
maxWidth = max(height(it), maxWidth)
|
||||
child.layout.growHeight = growHeight
|
||||
|
||||
val effectHeight = height(child) + growHeight
|
||||
ly += effectHeight
|
||||
maxWidth = max(width(child), maxWidth)
|
||||
}
|
||||
|
||||
Rectangle(Vector2(lx, ly), maxWidth, ly - element.layout.screenY)
|
||||
@@ -86,8 +89,9 @@ class Layouter {
|
||||
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)
|
||||
val effectiveWidth = width(it)
|
||||
maxWidth = max(effectiveWidth, maxWidth)
|
||||
y += height(it, effectiveWidth)
|
||||
} else if (it.computedStyle.position == Position.ABSOLUTE) {
|
||||
it.layout.screenX = element.layout.screenX + ((it.computedStyle.left as? LinearDimension.PX)?.value
|
||||
?: 0.0)
|
||||
@@ -176,7 +180,7 @@ class Layouter {
|
||||
fun paddingLeft(element: Element?) = padding(element, StyleSheet::paddingLeft)
|
||||
fun paddingRight(element: Element?) = padding(element, StyleSheet::paddingRight)
|
||||
|
||||
fun height(element: Element, includeMargins: Boolean = true): Double {
|
||||
fun height(element: Element, width: Double? = null, includeMargins: Boolean = true): Double {
|
||||
if (element.computedStyle.display == Display.NONE) {
|
||||
return 0.0
|
||||
}
|
||||
@@ -186,8 +190,8 @@ class Layouter {
|
||||
}
|
||||
|
||||
return element.computedStyle.let {
|
||||
it.height.let {
|
||||
when (it) {
|
||||
it.height.let { ld ->
|
||||
when (val it = ld) {
|
||||
is LinearDimension.PX -> it.value
|
||||
is LinearDimension.Percent -> {
|
||||
val parentHeight = element.parent?.layout?.screenHeight ?: 0.0
|
||||
@@ -198,7 +202,12 @@ class Layouter {
|
||||
}
|
||||
is LinearDimension.Auto -> {
|
||||
val padding = paddingTop(element) + paddingBottom(element)
|
||||
positionChildren(element).height + padding
|
||||
(element.heightHint ?: positionChildren(element, width).height) + padding
|
||||
}
|
||||
is LinearDimension.Calculate -> {
|
||||
val context = CalculateContext(width, null)
|
||||
it.function(context)
|
||||
|
||||
}
|
||||
else -> throw RuntimeException("not supported")
|
||||
}
|
||||
@@ -207,11 +216,10 @@ class Layouter {
|
||||
}
|
||||
}
|
||||
|
||||
fun width(element: Element, includeMargins: Boolean = true): Double = element.computedStyle.let {
|
||||
fun width(element: Element, height: Double? = null, includeMargins: Boolean = true): Double = element.computedStyle.let {
|
||||
if (element.computedStyle.display == Display.NONE) {
|
||||
return 0.0
|
||||
}
|
||||
|
||||
val result =
|
||||
it.width.let {
|
||||
when (it) {
|
||||
@@ -223,17 +231,30 @@ class Layouter {
|
||||
val effectiveWidth = (parentWidth - parentPadding) * (it.value / 100.0) - margins
|
||||
effectiveWidth
|
||||
}
|
||||
// is LinearDimension.Calculate -> {
|
||||
// val context = CalculateContext(null, height)
|
||||
// it.function(context)
|
||||
//
|
||||
// }
|
||||
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
|
||||
|
||||
// TODO: find out why this hack is needed, I added this because somewhere in the layout process
|
||||
// this information is lost
|
||||
element.layout.screenWidth = result - 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 }
|
||||
element.layout.screenWidth = width(element, includeMargins = false)
|
||||
element.layout.screenWidth += element.layout.growWidth
|
||||
element.layout.screenHeight = height(element, element.layout.screenWidth, includeMargins = false)
|
||||
element.layout.screenHeight += element.layout.growHeight
|
||||
|
||||
when (cs.position) {
|
||||
Position.FIXED -> {
|
||||
@@ -249,12 +270,7 @@ class Layouter {
|
||||
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)
|
||||
val result = positionChildren(element)
|
||||
}
|
||||
element.children.forEach { layout(it) }
|
||||
}
|
||||
|
||||
@@ -25,6 +25,8 @@ sealed class Color(inherit: Boolean = false) : PropertyValue(inherit) {
|
||||
object Inherit : Color(inherit = true)
|
||||
}
|
||||
|
||||
class CalculateContext(val elementWidth:Double?, val elementHeight:Double?)
|
||||
|
||||
sealed class LinearDimension(inherit: Boolean = false) : PropertyValue(inherit) {
|
||||
class PX(val value: Double) : LinearDimension() {
|
||||
override fun toString(): String {
|
||||
@@ -32,10 +34,13 @@ sealed class LinearDimension(inherit: Boolean = false) : PropertyValue(inherit)
|
||||
}
|
||||
}
|
||||
class Percent(val value: Double) : LinearDimension()
|
||||
class Calculate(val function: (CalculateContext) -> Double) : LinearDimension()
|
||||
object Auto : LinearDimension()
|
||||
object Inherit : LinearDimension(inherit = true)
|
||||
}
|
||||
|
||||
|
||||
|
||||
data class PropertyBehaviour(val inheritance: PropertyInheritance, val intitial: Any)
|
||||
|
||||
object PropertyBehaviours {
|
||||
|
||||
Reference in New Issue
Block a user