aboutsummaryrefslogtreecommitdiff
path: root/src/main/kotlin/pl/treksoft/kvision/panel/ResponsiveGridPanel.kt
blob: 740a208f2c2bb7d277076ca00a0c810c4188f18e (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
package pl.treksoft.kvision.panel

import pl.treksoft.kvision.core.Component
import pl.treksoft.kvision.core.WidgetWrapper
import pl.treksoft.kvision.html.ALIGN
import pl.treksoft.kvision.html.TAG
import pl.treksoft.kvision.html.Tag

enum class GRIDSIZE(val size: String) {
    XS("xs"),
    SM("sm"),
    MD("md"),
    LG("lg")
}

const val MAX_COLUMNS = 12

internal data class WidgetParam(val widget: Component, val size: Int, val offset: Int)

open class ResponsiveGridPanel(
    private val gridsize: GRIDSIZE = GRIDSIZE.MD,
    private var rows: Int = 0, private var cols: Int = 0, align: ALIGN? = null,
    classes: Set<String> = setOf()
) : SimplePanel(classes) {
    protected var align = align
        set(value) {
            field = value
            refresh()
        }

    internal val map = mutableMapOf<Int, MutableMap<Int, WidgetParam>>()
    private var auto: Boolean = true

    open fun add(child: Component, row: Int, col: Int, size: Int = 0, offset: Int = 0): ResponsiveGridPanel {
        val cRow = if (row < 0) 0 else row
        val cCol = if (col < 0) 0 else col
        if (row > rows - 1) rows = cRow + 1
        if (col > cols - 1) cols = cCol + 1
        map.getOrPut(cRow, { mutableMapOf() }).put(cCol, WidgetParam(child, size, offset))
        if (size > 0 || offset > 0) auto = false
        refreshRowContainers()
        return this
    }

    override fun add(child: Component): ResponsiveGridPanel {
        return this.add(child, 0, this.cols)
    }

    override fun addAll(children: List<Component>): ResponsiveGridPanel {
        children.forEach { this.add(it) }
        return this
    }

    @Suppress("NestedBlockDepth")
    override fun remove(child: Component): ResponsiveGridPanel {
        for (i in 0 until rows) {
            val row = map[i]
            if (row != null) {
                for (j in 0 until cols) {
                    val wp = row[j]
                    if (wp != null) {
                        if (wp.widget == child) row.remove(j)
                    }
                }
            }
        }
        refreshRowContainers()
        return this
    }

    open fun removeAt(row: Int, col: Int): ResponsiveGridPanel {
        map[row]?.remove(col)
        refreshRowContainers()
        return this
    }

    @Suppress("ComplexMethod", "NestedBlockDepth")
    protected open fun refreshRowContainers() {
        singleRender {
            clearRowContainers()
            val num = MAX_COLUMNS / cols
            for (i in 0 until rows) {
                val rowContainer = SimplePanel(setOf("row"))
                val row = map[i]
                if (row != null) {
                    for (j in 0 until cols) {
                        val wp = row[j]
                        if (auto) {
                            val widget = wp?.widget?.let {
                                WidgetWrapper(it, setOf("col-" + gridsize.size + "-" + num))
                            } ?: Tag(TAG.DIV, classes = setOf("col-" + gridsize.size + "-" + num))
                            align?.let {
                                widget.addCssClass(it.className)
                            }
                            rowContainer.add(widget)
                        } else {
                            if (wp != null) {
                                val s = if (wp.size > 0) wp.size else num
                                val widget = WidgetWrapper(wp.widget, setOf("col-" + gridsize.size + "-" + s))
                                if (wp.offset > 0) {
                                    widget.addCssClass("col-" + gridsize.size + "-offset-" + wp.offset)
                                }
                                align?.let {
                                    widget.addCssClass(it.className)
                                }
                                rowContainer.add(widget)
                            }
                        }
                    }
                }
                addInternal(rowContainer)
            }
        }
    }

    private fun clearRowContainers() {
        children.forEach { it.dispose() }
        removeAll()
    }
}