All Downloads are FREE. Search and download functionalities are using the official Maven repository.

commonMain.jetbrains.datalore.plot.builder.guide.LegendComponentLayout.kt Maven / Gradle / Ivy

/*
 * Copyright (c) 2020. JetBrains s.r.o.
 * Use of this source code is governed by the MIT license that can be found in the LICENSE file.
 */

package jetbrains.datalore.plot.builder.guide

import jetbrains.datalore.base.gcommon.base.Preconditions.checkState
import jetbrains.datalore.base.geometry.DoubleRectangle
import jetbrains.datalore.base.geometry.DoubleVector
import jetbrains.datalore.plot.builder.layout.GeometryUtil
import kotlin.math.max

abstract class LegendComponentLayout(title: String,
                                     protected val breaks: List,
                                     val keySize: DoubleVector,
                                     legendDirection: LegendDirection
) : LegendBoxLayout(title, legendDirection) {

    private var myContentSize: DoubleVector? = null
    private val myKeyLabelBoxes = ArrayList()
    private val myLabelBoxes = ArrayList()

    var isFillByRow = false
    var rowCount = 0
        set(rowCount) {
            checkState(rowCount > 0, "Row count must be greater than 0, was $rowCount")
            field = rowCount
        }
    var colCount = 0
        set(colCount) {
            checkState(colCount > 0, "Col count must be greater than 0, was $colCount")
            field = colCount
        }

    override val graphSize: DoubleVector
        get() {
            ensureInited()
            return myContentSize!!
        }

    val keyLabelBoxes: List
        get() {
            ensureInited()
            return myKeyLabelBoxes
        }

    val labelBoxes: List
        get() {
            ensureInited()
            return myLabelBoxes
        }

    private fun ensureInited() {
        if (myContentSize == null) {
            doLayout()
        }
    }

    private fun doLayout() {
        val labelHeight = LABEL_SPEC.height()
        val labelLeftMargin = LABEL_SPEC.width(1) / 2
        val labelHOffset = keySize.x + labelLeftMargin
        val labelVOffset = (keySize.y - labelHeight) / 2

        val contentOrigin = DoubleVector.ZERO
        var breakBoxBounds: DoubleRectangle? = null
        for (i in breaks.indices) {
            val labelSize = labelSize(i)
            val breakBoxSize = DoubleVector(labelHOffset + labelSize.x, keySize.y)
            breakBoxBounds = DoubleRectangle(
                    breakBoxBounds?.let { breakBoxOrigin(i, it) } ?: contentOrigin,
                    breakBoxSize
            )

            myKeyLabelBoxes.add(breakBoxBounds)
            myLabelBoxes.add(DoubleRectangle(
                    labelHOffset, labelVOffset,
                    labelSize.x, labelSize.y
            ))
        }

        myContentSize = GeometryUtil.union(DoubleRectangle(contentOrigin, DoubleVector.ZERO), myKeyLabelBoxes).dimension
    }

    protected abstract fun breakBoxOrigin(index: Int, prevBreakBoxBounds: DoubleRectangle): DoubleVector

    protected abstract fun labelSize(index: Int): DoubleVector

    private class MyHorizontal internal constructor(title: String, breaks: List, keySize: DoubleVector) : LegendComponentLayout(title, breaks, keySize,
        LegendDirection.HORIZONTAL
    ) {
        init {
            colCount = breaks.size
            rowCount = 1
        }

        override fun breakBoxOrigin(index: Int, prevBreakBoxBounds: DoubleRectangle): DoubleVector {
            return DoubleVector(prevBreakBoxBounds.right, 0.0)
        }

        override fun labelSize(index: Int): DoubleVector {
            val label = breaks[index].label
            return DoubleVector(LABEL_SPEC.width(label.length), LABEL_SPEC.height())
        }
    }

    private class MyHorizontalMultiRow internal constructor(title: String, breaks: List, keySize: DoubleVector) : MyMultiRow(title, breaks, keySize,
        LegendDirection.HORIZONTAL
    ) {
        init {
            colCount = breaks.size
            rowCount = 1
        }
    }

    private class MyVertical internal constructor(title: String, breaks: List, keySize: DoubleVector) : MyMultiRow(title, breaks, keySize,
        LegendDirection.VERTICAL
    ) {
        init {
            colCount = 1
            rowCount = breaks.size
        }
    }

    private abstract class MyMultiRow internal constructor(title: String, breaks: List, keySize: DoubleVector, legendDirection: LegendDirection) : LegendComponentLayout(title, breaks, keySize, legendDirection) {
        private var myMaxLabelWidth = 0.0

        init {
            for (br in breaks) {
                myMaxLabelWidth = max(myMaxLabelWidth, LABEL_SPEC.width(br.label.length))
            }
        }

        override fun breakBoxOrigin(index: Int, prevBreakBoxBounds: DoubleRectangle): DoubleVector {
            if (isFillByRow) {
                return if (index % colCount == 0) {
                    DoubleVector(0.0, prevBreakBoxBounds.bottom)
                } else DoubleVector(prevBreakBoxBounds.right, prevBreakBoxBounds.top)
            }

            // fill by column
            return if (index % rowCount == 0) {
                DoubleVector(prevBreakBoxBounds.right, 0.0)
            } else DoubleVector(prevBreakBoxBounds.left, prevBreakBoxBounds.bottom)

        }

        override fun labelSize(index: Int): DoubleVector {
            return DoubleVector(myMaxLabelWidth, LABEL_SPEC.height())
        }
    }

    companion object {
        fun horizontal(title: String, breaks: List, keySize: DoubleVector): LegendComponentLayout {
            return MyHorizontal(
                title,
                breaks,
                keySize
            )
        }

        fun horizontalMultiRow(title: String, breaks: List, keySize: DoubleVector): LegendComponentLayout {
            return MyHorizontalMultiRow(
                title,
                breaks,
                keySize
            )
        }

        fun vertical(title: String, breaks: List, keySize: DoubleVector): LegendComponentLayout {
            return MyVertical(
                title,
                breaks,
                keySize
            )
        }
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy