aboutsummaryrefslogtreecommitdiff
path: root/src/main/kotlin/pl/treksoft/kvision/panel/GridPanel.kt
blob: f7adfe8f4dfc22cba8498fda5c229c9167097367 (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
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
package pl.treksoft.kvision.panel

import com.github.snabbdom.VNode
import pl.treksoft.kvision.core.Container
import pl.treksoft.kvision.core.Widget
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 GRIDTYPE {
    BOOTSTRAP,
    DSG
}

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

const val FULLPERCENT = 100
const val MAX_COLUMNS = 12

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

open class GridPanel(private val gridtype: GRIDTYPE = GRIDTYPE.BOOTSTRAP, private val gridsize: GRIDSIZE = GRIDSIZE.MD,
                     protected var rows: Int = 0, protected var cols: Int = 0, align: ALIGN = ALIGN.NONE,
                     classes: Set<String> = setOf()) : Container(classes) {
    private 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: Widget, row: Int, col: Int, size: Int = 0, offset: Int = 0): Container {
        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
        return this
    }

    override fun add(child: Widget): Container {
        return this.add(child, 0, this.cols)
    }

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

    override fun remove(child: Widget): Container {
        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)
                    }
                }
            }
        }
        return this
    }

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

    override fun removeAt(index: Int): Container {
        return this.removeAt(0, index)
    }

    override fun childrenVNodes(): Array<VNode> {
        return if (gridtype == GRIDTYPE.BOOTSTRAP) {
            childrenVNodesBts()
        } else {
            childrenVNodesDsg()
        }
    }

    @Suppress("NestedBlockDepth", "LoopToCallChain")
    protected open fun childrenVNodesDsg(): Array<VNode> {
        val ret = mutableListOf<VNode>()
        val num = FULLPERCENT / cols
        for (i in 0 until rows) {
            val rowContainer = Container(setOf("dsgrow"))
            val row = map[i]
            if (row != null) {
                for (j in 0 until cols) {
                    val wp = row[j]
                    val widget = wp?.widget?.let { WidgetWrapper(it, setOf("dsgcol")) } ?:
                            Tag(TAG.DIV, classes = setOf("dsgcol"))
                    widget.widthPercent = num
                    if (align != ALIGN.NONE) {
                        widget.addCssClass(align.className)
                    }
                    rowContainer.add(widget)
                }
            }
            ret.add(rowContainer.render())
        }
        return ret.toTypedArray()
    }

    @Suppress("NestedBlockDepth", "LoopToCallChain")
    private fun childrenVNodesBts(): Array<VNode> {
        val ret = mutableListOf<VNode>()
        val num = MAX_COLUMNS / cols
        for (i in 0 until rows) {
            val rowContainer = Container(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))
                        if (align != ALIGN.NONE) {
                            widget.addCssClass(align.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)
                            }
                            if (align != ALIGN.NONE) {
                                widget.addCssClass(align.className)
                            }
                            rowContainer.add(widget)
                        }
                    }
                }
            }
            ret.add(rowContainer.render())
        }
        return ret.toTypedArray()
    }
}