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