Adding column/row insert/delete
parent
2478523622
commit
fc8b106200
19
build.sc
19
build.sc
|
@ -91,6 +91,19 @@ object cells extends Module {
|
|||
.map { PathRef(_) }
|
||||
}
|
||||
|
||||
def css =
|
||||
T.sources {
|
||||
os.walk(millSourcePath / "css")
|
||||
.filter { _.ext == "css" }
|
||||
.map { PathRef(_) }
|
||||
}
|
||||
|
||||
def fonts =
|
||||
T.sources {
|
||||
os.walk(millSourcePath / "fonts")
|
||||
.map { PathRef(_) }
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
def resources =
|
||||
|
@ -110,13 +123,15 @@ object cells extends Module {
|
|||
)
|
||||
|
||||
os.write(
|
||||
target / "app" / "cells.css",
|
||||
target / "app" / "css" / "cells.css",
|
||||
ui.compiledSass(),
|
||||
createFolders = true
|
||||
)
|
||||
|
||||
val assets =
|
||||
ui.html().map { x => (x.path -> os.rel / x.path.last) }
|
||||
ui.html().map { x => (x.path -> os.rel / x.path.last) }++
|
||||
ui.css().map { x => (x.path -> os.rel / "css" / x.path.last) }++
|
||||
ui.fonts().map { x => (x.path -> os.rel / "fonts" / x.path.last) }
|
||||
|
||||
for((asset, assetTarget) <- assets){
|
||||
os.copy.over(
|
||||
|
|
|
@ -7,6 +7,8 @@ import net.okennedy.cells.WebsocketConnection
|
|||
object CellsServer extends cask.MainRoutes
|
||||
{
|
||||
|
||||
override def port: Int = 4444
|
||||
|
||||
var layout = new state.Canvas()
|
||||
layout.addTable(rows = 5, cols = 3)
|
||||
|
||||
|
@ -31,10 +33,6 @@ object CellsServer extends cask.MainRoutes
|
|||
def app(request: cask.Request) =
|
||||
serveResource("app/cells.js", "Content-Type" -> "application/javascript")
|
||||
|
||||
@cask.get("/cells.css")
|
||||
def css(request: cask.Request) =
|
||||
serveResource("app/cells.css", "Content-Type" -> "text/css")
|
||||
|
||||
@cask.get("/out.js.map")
|
||||
def appMap(request: cask.Request) =
|
||||
serveResource("app/out.js.map", "Content-Type" -> "application/javascript")
|
||||
|
@ -49,8 +47,15 @@ object CellsServer extends cask.MainRoutes
|
|||
}
|
||||
}
|
||||
|
||||
@cask.staticResources("/app")
|
||||
def staticResourceRoutes() = "app"
|
||||
@cask.staticResources("/css",
|
||||
headers = Seq("Content-Type" -> "text/css")
|
||||
)
|
||||
def cssResourceRoutes() = "app/css"
|
||||
|
||||
@cask.staticResources("/fonts",
|
||||
// headers = Seq("Content-Type" -> "text/css")
|
||||
)
|
||||
def fontResourceRoutes() = "app/fonts"
|
||||
|
||||
initialize()
|
||||
}
|
|
@ -13,6 +13,8 @@ class WebsocketConnection(val id: Int, channel: WsChannelActor)
|
|||
{
|
||||
event match {
|
||||
case Ws.Text(data) =>
|
||||
|
||||
println(s"ZZZ: $data")
|
||||
Json.parse(data).as[WebsocketRequest] match {
|
||||
case WebsocketHello(_) =>
|
||||
for(table <- CellsServer.layout.tables.values)
|
||||
|
|
|
@ -5,10 +5,8 @@ import net.okennedy.cells.Identifier
|
|||
import net.okennedy.cells.serialized
|
||||
import net.okennedy.cells.TableRequest
|
||||
import net.okennedy.cells.RequestSetTablePosition
|
||||
import net.okennedy.cells.RequestAppendColumn
|
||||
import net.okennedy.cells.RequestAppendRow
|
||||
import net.okennedy.cells.RequestUpdateColumn
|
||||
import net.okennedy.cells.RequestUpdateRow
|
||||
import net.okennedy.cells.RequestUpdateColumns
|
||||
import net.okennedy.cells.RequestUpdateRows
|
||||
import net.okennedy.cells.SetTablePosition
|
||||
import net.okennedy.cells.WebsocketConnection
|
||||
import net.okennedy.cells.serialized.ColSpec
|
||||
|
@ -55,48 +53,48 @@ class Table(val id: Identifier)
|
|||
return id
|
||||
}
|
||||
|
||||
def updateColumns(op: SeqOp[ColSpec]): Unit =
|
||||
{
|
||||
val opWithValidId =
|
||||
op match {
|
||||
case SeqInsert(_, _) => op.map { _.copy(id = genSafeColId()) }
|
||||
case SeqReplace(pos, _) => op.map { _.copy(id = columns(pos).id) }
|
||||
case SeqDelete(_) => op
|
||||
}
|
||||
println(s"Update: $op")
|
||||
opWithValidId.bufferApply(columns)
|
||||
WebsocketConnection.broadcast(
|
||||
UpdateTableColumns(id, opWithValidId)
|
||||
)
|
||||
}
|
||||
|
||||
def addColumn(width: Int = 100): Unit =
|
||||
{
|
||||
val col = ColSpec(
|
||||
id = genSafeColId(),
|
||||
width = width
|
||||
)
|
||||
columns.append(col)
|
||||
updateColumns(SeqInsert(columns.length,
|
||||
ColSpec(id = null, width = width)
|
||||
))
|
||||
}
|
||||
|
||||
def updateRows(op: SeqOp[RowSpec]): Unit =
|
||||
{
|
||||
val opWithValidId =
|
||||
op match {
|
||||
case SeqInsert(_, _) => op.map { _.copy(id = genSafeRowId()) }
|
||||
case SeqReplace(pos, _) => op.map { _.copy(id = rows(pos).id) }
|
||||
case SeqDelete(_) => op
|
||||
}
|
||||
|
||||
opWithValidId.bufferApply(rows)
|
||||
WebsocketConnection.broadcast(
|
||||
UpdateTableColumns(id, SeqInsert(columns.size-1, col))
|
||||
UpdateTableRows(id, opWithValidId)
|
||||
)
|
||||
}
|
||||
|
||||
def addRow(height: Int = 30): Unit =
|
||||
{
|
||||
val row = RowSpec(
|
||||
id = genSafeColId(),
|
||||
height = height
|
||||
)
|
||||
rows.append(row)
|
||||
WebsocketConnection.broadcast(
|
||||
UpdateTableRows(id, SeqInsert(rows.size-1, row))
|
||||
)
|
||||
}
|
||||
|
||||
def updateColumn(spec: ColSpec): Unit =
|
||||
{
|
||||
val idx = columns.indexWhere { _.id == spec.id }
|
||||
if(idx < 0){ return }
|
||||
columns.update(idx, spec)
|
||||
WebsocketConnection.broadcast(
|
||||
UpdateTableColumns(id, SeqReplace(idx, spec))
|
||||
)
|
||||
}
|
||||
|
||||
def updateRow(spec: RowSpec): Unit =
|
||||
{
|
||||
val idx = rows.indexWhere { _.id == spec.id }
|
||||
if(idx < 0){ return }
|
||||
rows.update(idx, spec)
|
||||
WebsocketConnection.broadcast(
|
||||
UpdateTableRows(id, SeqReplace(idx, spec))
|
||||
)
|
||||
updateRows(SeqInsert(rows.length,
|
||||
RowSpec(id = null, height = height)
|
||||
))
|
||||
}
|
||||
|
||||
def setPosition(x: Int, y: Int): Unit =
|
||||
|
@ -109,12 +107,11 @@ class Table(val id: Identifier)
|
|||
|
||||
def update(op: TableRequest): Unit =
|
||||
{
|
||||
println(s"Table update: $op")
|
||||
op match {
|
||||
case RequestSetTablePosition(_, x, y) => setPosition(x, y)
|
||||
case RequestAppendColumn(_) => addColumn()
|
||||
case RequestAppendRow(_) => addRow()
|
||||
case RequestUpdateColumn(_, spec) => updateColumn(spec)
|
||||
case RequestUpdateRow(_, spec) => updateRow(spec)
|
||||
case RequestUpdateColumns(_, cop) => updateColumns(cop)
|
||||
case RequestUpdateRows(_, rop) => updateRows(rop)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
package net.okennedy.cells
|
||||
|
||||
import scala.collection.mutable
|
||||
import play.api.libs.json.Json
|
||||
import play.api.libs.json.Format
|
||||
import play.api.libs.json.JsResult
|
||||
|
@ -12,6 +13,7 @@ sealed trait SeqOp[T]
|
|||
{
|
||||
def apply(seq: Seq[T]): Seq[T]
|
||||
def map[B](op: T => B): SeqOp[B]
|
||||
def bufferApply(seq: mutable.Buffer[T]): Unit
|
||||
}
|
||||
|
||||
|
||||
|
@ -23,6 +25,8 @@ case class SeqInsert[T](position: Int, value: T) extends SeqOp[T]
|
|||
(before :+ value) ++ after
|
||||
}
|
||||
def map[B](op: T => B): SeqOp[B] = SeqInsert[B](position, op(value))
|
||||
def bufferApply(seq: mutable.Buffer[T]): Unit =
|
||||
seq.insert(position, value)
|
||||
}
|
||||
case class SeqDelete[T](position: Int) extends SeqOp[T]
|
||||
{
|
||||
|
@ -32,6 +36,8 @@ case class SeqDelete[T](position: Int) extends SeqOp[T]
|
|||
before ++ after.drop(1)
|
||||
}
|
||||
def map[B](op: T => B): SeqOp[B] = SeqDelete(position)
|
||||
def bufferApply(seq: mutable.Buffer[T]): Unit =
|
||||
seq.remove(position)
|
||||
}
|
||||
case class SeqReplace[T](position: Int, value: T) extends SeqOp[T]
|
||||
{
|
||||
|
@ -41,6 +47,8 @@ case class SeqReplace[T](position: Int, value: T) extends SeqOp[T]
|
|||
(before :+ value) ++ after.drop(1)
|
||||
}
|
||||
def map[B](op: T => B): SeqOp[B] = SeqReplace[B](position, op(value))
|
||||
def bufferApply(seq: mutable.Buffer[T]): Unit =
|
||||
seq(position) = value
|
||||
}
|
||||
|
||||
object SeqOp
|
||||
|
|
|
@ -16,19 +16,15 @@ sealed trait TableRequest extends CanvasRequest
|
|||
}
|
||||
|
||||
case class RequestSetTablePosition(table: Identifier, x: Int, y: Int) extends TableRequest
|
||||
case class RequestAppendColumn(table: Identifier) extends TableRequest
|
||||
case class RequestUpdateColumn(table: Identifier, spec: serialized.ColSpec) extends TableRequest
|
||||
case class RequestAppendRow(table: Identifier) extends TableRequest
|
||||
case class RequestUpdateRow(table: Identifier, spec: serialized.RowSpec) extends TableRequest
|
||||
case class RequestUpdateColumns(table: Identifier, op: SeqOp[serialized.ColSpec]) extends TableRequest
|
||||
case class RequestUpdateRows(table: Identifier, op: SeqOp[serialized.RowSpec]) extends TableRequest
|
||||
|
||||
object WebsocketRequest
|
||||
{
|
||||
implicit val WebsocketHelloFormat: Format[WebsocketHello] = Json.format
|
||||
implicit val RequestAddTableFormat: Format[RequestAddTable] = Json.format
|
||||
implicit val RequestSetTablePositionFormat: Format[RequestSetTablePosition] = Json.format
|
||||
implicit val RequestAppendColumnFormat: Format[RequestAppendColumn] = Json.format
|
||||
implicit val RequestUpdateColumnFormat: Format[RequestUpdateColumn] = Json.format
|
||||
implicit val RequestAppendRowFormat: Format[RequestAppendRow] = Json.format
|
||||
implicit val RequestUpdateRowFormat: Format[RequestUpdateRow] = Json.format
|
||||
implicit val RequestUpdateColumnsFormat: Format[RequestUpdateColumns] = Json.format
|
||||
implicit val RequestUpdateRowsFormat: Format[RequestUpdateRows] = Json.format
|
||||
implicit val WebsocketRequestFormat: Format[WebsocketRequest] = Json.format
|
||||
}
|
|
@ -117,6 +117,44 @@ body
|
|||
margin-top: -5px;
|
||||
cursor: row-resize;
|
||||
}
|
||||
|
||||
.addRemoveColumnWidget
|
||||
{
|
||||
$addRemoveColumnWidgetOffset: 16px;
|
||||
position: absolute;
|
||||
right: -1px-$addRemoveColumnWidgetOffset;
|
||||
top: 0px;
|
||||
width: $addRemoveColumnWidgetOffset;
|
||||
height: 20px;
|
||||
background-color: #eee;
|
||||
text-align: center;
|
||||
border-top-right-radius: 4px;
|
||||
border-bottom-right-radius: 4px;
|
||||
cursor: ew-resize;
|
||||
visibility: hidden;
|
||||
}
|
||||
|
||||
.addRemoveRowWidget
|
||||
{
|
||||
$addRemoveRowWidgetOffset: 16px;
|
||||
position: absolute;
|
||||
left: 0px;
|
||||
bottom: -1px-$addRemoveRowWidgetOffset;
|
||||
height: $addRemoveRowWidgetOffset;
|
||||
width: 20px;
|
||||
background-color: #eee;
|
||||
text-align: center;
|
||||
border-top-right-radius: 4px;
|
||||
border-bottom-right-radius: 4px;
|
||||
cursor: ns-resize;
|
||||
visibility: hidden;
|
||||
}
|
||||
|
||||
&:hover
|
||||
{
|
||||
.addRemoveColumnWidget { visibility: visible; }
|
||||
.addRemoveRowWidget { visibility: visible; }
|
||||
}
|
||||
}
|
||||
|
||||
.widgets
|
||||
|
|
File diff suppressed because one or more lines are too long
Binary file not shown.
File diff suppressed because it is too large
Load Diff
After Width: | Height: | Size: 434 KiB |
Binary file not shown.
Binary file not shown.
Binary file not shown.
|
@ -4,7 +4,8 @@
|
|||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
<title>Cells</title>
|
||||
<link rel="stylesheet" type="text/css" href="cells.css">
|
||||
<link rel="stylesheet" type="text/css" href="css/cells.css">
|
||||
<link rel="stylesheet" type="text/css" href="css/font-awesome.min.css"/>
|
||||
</head>
|
||||
<body>
|
||||
<script type="text/javascript" src="cells.js"></script>
|
||||
|
|
|
@ -14,7 +14,7 @@ object CellsUI
|
|||
@JSExport("run")
|
||||
def run(): Unit =
|
||||
{
|
||||
val conn = new network.Connection("ws://localhost:8080/ws")
|
||||
val conn = new network.Connection("ws://localhost:4444/ws")
|
||||
|
||||
dom.window.onload = { (evt: dom.Event) =>
|
||||
val container: dom.Element =
|
||||
|
|
|
@ -5,4 +5,10 @@ object Constants
|
|||
val GUTTER_HEIGHT = 20
|
||||
val GUTTER_WIDTH = 30
|
||||
val BORDER = 1
|
||||
|
||||
val DEFAULT_CELL_WIDTH = 100
|
||||
val DEFAULT_CELL_HEIGHT = 30
|
||||
|
||||
val NULL_UUID =
|
||||
java.util.UUID(0, 0)
|
||||
}
|
|
@ -20,8 +20,14 @@ import net.okennedy.cells.network.Connection
|
|||
import net.okennedy.cells.RequestSetTablePosition
|
||||
import net.okennedy.cells.UpdateTableColumns
|
||||
import net.okennedy.cells.UpdateTableRows
|
||||
import net.okennedy.cells.RequestUpdateRow
|
||||
import net.okennedy.cells.RequestUpdateColumn
|
||||
import net.okennedy.cells.RequestUpdateRows
|
||||
import net.okennedy.cells.RequestUpdateColumns
|
||||
import net.okennedy.cells.widgets.Icon
|
||||
import scala.collection.Searching.Found
|
||||
import scala.collection.Searching.InsertionPoint
|
||||
import net.okennedy.cells.SeqReplace
|
||||
import net.okennedy.cells.SeqInsert
|
||||
import net.okennedy.cells.SeqDelete
|
||||
|
||||
class Table(val id: Identifier, connection: Connection)
|
||||
{
|
||||
|
@ -50,8 +56,10 @@ class Table(val id: Identifier, connection: Connection)
|
|||
x.set(newX); y.set(newY)
|
||||
)
|
||||
case UpdateTableColumns(_, update) =>
|
||||
println(s"ColUpdate??? : $update")
|
||||
columns.set(update(columns.now()))
|
||||
case UpdateTableRows(_, update) =>
|
||||
println(s"RowUpdate??? : $update")
|
||||
rows.set(update(rows.now()))
|
||||
}
|
||||
}
|
||||
|
@ -106,6 +114,43 @@ class Table(val id: Identifier, connection: Connection)
|
|||
rows.signal.map { _.foldLeft(0)( (h, row) => h + row.height) }
|
||||
.observe
|
||||
|
||||
def snapIndex(snaps: Seq[Int], excessStep: Int, value: Int): Int =
|
||||
{
|
||||
// println(s"Snap $value")
|
||||
if(snaps.size > 0 && value < snaps.last){
|
||||
snaps.search(value) match {
|
||||
case Found(foundIndex) =>
|
||||
// println(s"Found: $foundIndex");
|
||||
foundIndex
|
||||
case InsertionPoint(insertionPoint) =>
|
||||
if(insertionPoint == 0) {
|
||||
// println(s"Insert @ start");
|
||||
0
|
||||
} else if(insertionPoint >= snaps.length) {
|
||||
// println(s"Insert @ end");
|
||||
snaps.length - 1
|
||||
} else {
|
||||
val lowDiff = value - snaps(insertionPoint - 1)
|
||||
val highDiff = snaps(insertionPoint) - value
|
||||
// println(s"Insert @ [${insertionPoint-1}, $insertionPoint] : $lowDiff <-> $highDiff");
|
||||
if(lowDiff > highDiff){ insertionPoint }
|
||||
else { insertionPoint-1 }
|
||||
}
|
||||
}
|
||||
} else {
|
||||
val excess = value - snaps.lastOption.getOrElse(0) + (excessStep / 2)
|
||||
// println(s"Over with excess: $excess")
|
||||
(snaps.length - 1) + (excess / excessStep).toInt
|
||||
}
|
||||
}
|
||||
|
||||
def snapTo(snaps: Seq[Int], excessStep: Int, value: Int): Int =
|
||||
{
|
||||
val idx = snapIndex(snaps, excessStep, value)
|
||||
if(idx < snaps.length){ snaps(idx) }
|
||||
else { snaps.lastOption.getOrElse(0) + excessStep * (idx - (snaps.length -1)) }
|
||||
}
|
||||
|
||||
def root = div(
|
||||
className("dataTable"),
|
||||
|
||||
|
@ -228,8 +273,8 @@ class Table(val id: Identifier, connection: Connection)
|
|||
// Display the resizing bars - Up<->Down
|
||||
|
||||
children <--
|
||||
rowGutters.map { _.map {
|
||||
case (rowKey, rowStream) =>
|
||||
rowGutters.map { _.zipWithIndex.map {
|
||||
case ((rowKey, rowStream), rowIdx) =>
|
||||
div(
|
||||
className("rowResizeBar"),
|
||||
styleAttr <--
|
||||
|
@ -260,12 +305,15 @@ class Table(val id: Identifier, connection: Connection)
|
|||
) { newHeight =>
|
||||
println(s"Drag $rowKey @ ($pos, ${pos+height}) -> $newHeight")
|
||||
connection.send(
|
||||
RequestUpdateRow(
|
||||
RequestUpdateRows(
|
||||
id,
|
||||
SeqReplace(
|
||||
rowIdx,
|
||||
rows.now().find { _.id == rowKey }.get
|
||||
.copy( height = newHeight )
|
||||
)
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
evt.stopPropagation()
|
||||
|
@ -276,8 +324,8 @@ class Table(val id: Identifier, connection: Connection)
|
|||
// Display the resizing bars - Left<->Right
|
||||
|
||||
children <--
|
||||
columnGutters.map { _.map {
|
||||
case (colKey, colStream) =>
|
||||
columnGutters.map { _.zipWithIndex.map {
|
||||
case ((colKey, colStream), colIdx) =>
|
||||
div(
|
||||
className("columnResizeBar"),
|
||||
styleAttr <--
|
||||
|
@ -308,17 +356,146 @@ class Table(val id: Identifier, connection: Connection)
|
|||
) { newWidth =>
|
||||
println(s"Drag $colKey @ ($pos, ${pos+width}) -> $newWidth")
|
||||
connection.send(
|
||||
RequestUpdateColumn(
|
||||
RequestUpdateColumns(
|
||||
id,
|
||||
SeqReplace(
|
||||
colIdx,
|
||||
columns.now().find { _.id == colKey }.get
|
||||
.copy( width = newWidth )
|
||||
)
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
evt.stopPropagation()
|
||||
}
|
||||
)
|
||||
} }
|
||||
} },
|
||||
|
||||
// Display the add/remove column widget
|
||||
|
||||
div(
|
||||
className("addRemoveColumnWidget"),
|
||||
Icon("caret-right"),
|
||||
onMouseDown --> {
|
||||
(evt) =>
|
||||
if(evt.button == 0){
|
||||
val snaps =
|
||||
columns.now()
|
||||
.foldLeft( Seq[Int]() ){
|
||||
(accum, col) =>
|
||||
accum :+ (accum.lastOption.getOrElse(0) + col.width )
|
||||
}
|
||||
// println(s"Snaps: ${snaps.mkString(", ")}")
|
||||
DragFrame.snapWidth(
|
||||
x.now()+Constants.GUTTER_WIDTH,
|
||||
y.now(),
|
||||
width.now(),
|
||||
height.now()+Constants.GUTTER_HEIGHT,
|
||||
evt
|
||||
)(snapTo(snaps, Constants.DEFAULT_CELL_WIDTH, _)) { snap =>
|
||||
val oldColCount = columns.now().length
|
||||
val newColCount = snapIndex(snaps, Constants.DEFAULT_CELL_WIDTH, snap) + 1
|
||||
|
||||
var i = 0
|
||||
if(oldColCount < newColCount)
|
||||
{
|
||||
for(i <- oldColCount until newColCount)
|
||||
{
|
||||
println(s"Adding column $i")
|
||||
connection.send(
|
||||
RequestUpdateColumns(
|
||||
id,
|
||||
SeqInsert(
|
||||
i,
|
||||
serialized.ColSpec(
|
||||
id = Constants.NULL_UUID,
|
||||
width = Constants.DEFAULT_CELL_WIDTH
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
}
|
||||
} else if(oldColCount > newColCount)
|
||||
{
|
||||
for(i <- (oldColCount-1) to newColCount by -1)
|
||||
{
|
||||
println(s"Removing column $i")
|
||||
connection.send(
|
||||
RequestUpdateColumns(
|
||||
id,
|
||||
SeqDelete(i)
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
evt.stopPropagation()
|
||||
}
|
||||
}
|
||||
),
|
||||
|
||||
div(
|
||||
className("addRemoveRowWidget"),
|
||||
Icon("caret-down"),
|
||||
onMouseDown --> {
|
||||
(evt) =>
|
||||
if(evt.button == 0){
|
||||
val snaps =
|
||||
rows.now()
|
||||
.foldLeft( Seq[Int]() ){
|
||||
(accum, row) =>
|
||||
accum :+ (accum.lastOption.getOrElse(0) + row.height )
|
||||
}
|
||||
// println(s"Snaps: ${snaps.mkString(", ")}")
|
||||
DragFrame.snapHeight(
|
||||
x.now(),
|
||||
y.now()+Constants.GUTTER_HEIGHT,
|
||||
width.now()+Constants.GUTTER_WIDTH,
|
||||
height.now(),
|
||||
evt
|
||||
)(snapTo(snaps, Constants.DEFAULT_CELL_HEIGHT, _)) { snap =>
|
||||
val oldRowCount = rows.now().length
|
||||
val newRowCount = snapIndex(snaps, Constants.DEFAULT_CELL_HEIGHT, snap) + 1
|
||||
|
||||
var i = 0
|
||||
if(oldRowCount < newRowCount)
|
||||
{
|
||||
for(i <- oldRowCount until newRowCount)
|
||||
{
|
||||
println(s"Adding row $i")
|
||||
connection.send(
|
||||
RequestUpdateRows(
|
||||
id,
|
||||
SeqInsert(
|
||||
i,
|
||||
serialized.RowSpec(
|
||||
id = Constants.NULL_UUID,
|
||||
height = Constants.DEFAULT_CELL_HEIGHT
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
}
|
||||
} else if(oldRowCount > newRowCount)
|
||||
{
|
||||
for(i <- (oldRowCount-1) to newRowCount by -1)
|
||||
{
|
||||
println(s"Removing row $i")
|
||||
connection.send(
|
||||
RequestUpdateRows(
|
||||
id,
|
||||
SeqDelete(i)
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
evt.stopPropagation()
|
||||
}
|
||||
}
|
||||
)
|
||||
)
|
||||
}
|
|
@ -17,12 +17,24 @@ object DragFrame
|
|||
Widgets.register(frame)
|
||||
}
|
||||
|
||||
def snapWidth(x: Int, y: Int, width: Int, height: Int, evt: org.scalajs.dom.MouseEvent)(doSnap: Int => Int)(callback: (Int) => Unit) =
|
||||
{
|
||||
val frame = new Width(x, y, width, height, evt.pageX, evt.pageY, callback) { override def snap(x: Int) = doSnap(x+width)-width }
|
||||
Widgets.register(frame)
|
||||
}
|
||||
|
||||
def height(x: Int, y: Int, width: Int, height: Int, evt: org.scalajs.dom.MouseEvent)(callback: (Int) => Unit) =
|
||||
{
|
||||
val frame = new Height(x, y, width, height, evt.pageX, evt.pageY, callback)
|
||||
Widgets.register(frame)
|
||||
}
|
||||
|
||||
def snapHeight(x: Int, y: Int, width: Int, height: Int, evt: org.scalajs.dom.MouseEvent)(doSnap: Int => Int)(callback: (Int) => Unit) =
|
||||
{
|
||||
val frame = new Height(x, y, width, height, evt.pageX, evt.pageY, callback) { override def snap(x: Int) = doSnap(x+height)-height }
|
||||
Widgets.register(frame)
|
||||
}
|
||||
|
||||
class Position(initX: Int, initY: Int, width: Int, height: Int, cursorX: Double, cursorY: Double, callback: (Int, Int) => Unit)
|
||||
extends Widget
|
||||
{
|
||||
|
@ -55,6 +67,8 @@ object DragFrame
|
|||
{
|
||||
val curr = Var[Int](initial = width)
|
||||
|
||||
def snap(v: Int): Int = v
|
||||
|
||||
val root = div(
|
||||
className("dragFrame"),
|
||||
styleAttr <--
|
||||
|
@ -69,7 +83,7 @@ object DragFrame
|
|||
},
|
||||
documentEvents.onMouseMove --> {
|
||||
(evt) =>
|
||||
curr.set( (width) + (evt.pageX - cursorX).toInt )
|
||||
curr.set( (width) + snap( (evt.pageX - cursorX).toInt ) )
|
||||
}
|
||||
)
|
||||
}
|
||||
|
@ -79,6 +93,8 @@ object DragFrame
|
|||
{
|
||||
val curr = Var[Int](initial = height)
|
||||
|
||||
def snap(v: Int): Int = v
|
||||
|
||||
val root = div(
|
||||
className("dragFrame"),
|
||||
styleAttr <--
|
||||
|
@ -93,7 +109,7 @@ object DragFrame
|
|||
},
|
||||
documentEvents.onMouseMove --> {
|
||||
(evt) =>
|
||||
curr.set( (height) + (evt.pageY - cursorY).toInt )
|
||||
curr.set( (height) + snap( (evt.pageY - cursorY).toInt ) )
|
||||
}
|
||||
)
|
||||
}
|
||||
|
|
|
@ -0,0 +1,14 @@
|
|||
package net.okennedy.cells.widgets
|
||||
|
||||
import org.scalajs.dom
|
||||
import com.raquo.laminar.api.L._
|
||||
import com.raquo.laminar.nodes.ReactiveHtmlElement
|
||||
|
||||
object Icon
|
||||
{
|
||||
def apply(name: String): ReactiveHtmlElement[dom.html.Element]=
|
||||
i(
|
||||
className(s"fa fa-${name}"),
|
||||
aria.hidden(true)
|
||||
)
|
||||
}
|
Loading…
Reference in New Issue