Work in progress on the formula editor
parent
fc8b106200
commit
6df1b5900c
|
@ -14,7 +14,7 @@ class WebsocketConnection(val id: Int, channel: WsChannelActor)
|
|||
event match {
|
||||
case Ws.Text(data) =>
|
||||
|
||||
println(s"ZZZ: $data")
|
||||
// println(s"ZZZ: $data")
|
||||
Json.parse(data).as[WebsocketRequest] match {
|
||||
case WebsocketHello(_) =>
|
||||
for(table <- CellsServer.layout.tables.values)
|
||||
|
|
|
@ -61,7 +61,7 @@ class Table(val id: Identifier)
|
|||
case SeqReplace(pos, _) => op.map { _.copy(id = columns(pos).id) }
|
||||
case SeqDelete(_) => op
|
||||
}
|
||||
println(s"Update: $op")
|
||||
// println(s"Update: $op")
|
||||
opWithValidId.bufferApply(columns)
|
||||
WebsocketConnection.broadcast(
|
||||
UpdateTableColumns(id, opWithValidId)
|
||||
|
@ -101,13 +101,13 @@ class Table(val id: Identifier)
|
|||
{
|
||||
this.x = x
|
||||
this.y = y
|
||||
println(s"Position now $x, $y")
|
||||
// println(s"Position now $x, $y")
|
||||
WebsocketConnection.broadcast(SetTablePosition(id, x, y))
|
||||
}
|
||||
|
||||
def update(op: TableRequest): Unit =
|
||||
{
|
||||
println(s"Table update: $op")
|
||||
// println(s"Table update: $op")
|
||||
op match {
|
||||
case RequestSetTablePosition(_, x, y) => setPosition(x, y)
|
||||
case RequestUpdateColumns(_, cop) => updateColumns(cop)
|
||||
|
|
|
@ -167,4 +167,78 @@ body
|
|||
margin-top: 2px;
|
||||
border: dashed lightgrey 2px;
|
||||
}
|
||||
|
||||
.formulaEditor
|
||||
{
|
||||
position: absolute;
|
||||
|
||||
.pointer
|
||||
{
|
||||
position: absolute;
|
||||
top: -10px;
|
||||
left: -4px;
|
||||
color: #aaa;
|
||||
font-size: 20px;
|
||||
}
|
||||
.editorBody
|
||||
{
|
||||
$editorWidth: 200px;
|
||||
$buttonSize: 20px;
|
||||
$spacing: 8px;
|
||||
$editorPadding: 2px;
|
||||
|
||||
position: absolute;
|
||||
border: solid 1px #aaa;
|
||||
border-radius: 2px;
|
||||
top: 5px;
|
||||
left: -16px;
|
||||
vertical-align: middle;
|
||||
padding: 8px;
|
||||
background-color: #ddd;
|
||||
width: $editorWidth;
|
||||
height: $buttonSize + 4px;
|
||||
|
||||
.inputArea
|
||||
{
|
||||
position: absolute;
|
||||
left: $spacing;
|
||||
top: $spacing;
|
||||
width: $editorWidth - 2 * $buttonSize - 3 * $spacing;
|
||||
height: $buttonSize;
|
||||
background-color: white;
|
||||
padding: 2px;
|
||||
border: 1px solid #ccc;
|
||||
cursor: text;
|
||||
|
||||
&:focus
|
||||
{
|
||||
border: 1px solid #aaa;
|
||||
}
|
||||
}
|
||||
|
||||
.button
|
||||
{
|
||||
position: absolute;
|
||||
top: $editorPadding + $spacing;
|
||||
width: $buttonSize;
|
||||
height: $buttonSize;
|
||||
border-radius: $buttonSize / 2;
|
||||
text-align: center;
|
||||
color: white;
|
||||
cursor: pointer;
|
||||
|
||||
&.cancel
|
||||
{
|
||||
right: $buttonSize + 2 * $spacing;
|
||||
background: red;
|
||||
}
|
||||
|
||||
&.accept
|
||||
{
|
||||
right: $spacing;
|
||||
background: green;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -28,6 +28,7 @@ import scala.collection.Searching.InsertionPoint
|
|||
import net.okennedy.cells.SeqReplace
|
||||
import net.okennedy.cells.SeqInsert
|
||||
import net.okennedy.cells.SeqDelete
|
||||
import net.okennedy.cells.widgets.FormulaEditor
|
||||
|
||||
class Table(val id: Identifier, connection: Connection)
|
||||
{
|
||||
|
@ -46,6 +47,7 @@ class Table(val id: Identifier, connection: Connection)
|
|||
this.columns.set(ser.columns)
|
||||
this.rows.set(ser.rows)
|
||||
)
|
||||
startEditing(columns.now()(1).id, rows.now()(1).id)
|
||||
}
|
||||
|
||||
def process(op: TableOp): Unit =
|
||||
|
@ -114,6 +116,28 @@ class Table(val id: Identifier, connection: Connection)
|
|||
rows.signal.map { _.foldLeft(0)( (h, row) => h + row.height) }
|
||||
.observe
|
||||
|
||||
def positionAndHeightOfRow(rowKey: Identifier): (Int, Int) =
|
||||
{
|
||||
rows.now().foldLeft[Either[Int, (Int, Int)]]( Left(0) ) {
|
||||
case (Left(x), row) if row.id == rowKey =>
|
||||
Right(x -> row.height)
|
||||
case (Left(x), row) =>
|
||||
Left(x + row.height)
|
||||
case (x@Right(pos, height), _) => x
|
||||
}.right.get
|
||||
}
|
||||
|
||||
def positionAndWidthOfColumn(colKey: Identifier): (Int, Int) =
|
||||
{
|
||||
columns.now().foldLeft[Either[Int, (Int, Int)]]( Left(0) ) {
|
||||
case (Left(x), col) if col.id == colKey =>
|
||||
Right(x -> col.width)
|
||||
case (Left(x), col) =>
|
||||
Left(x + col.width)
|
||||
case (x@Right(pos, width), _) => x
|
||||
}.right.get
|
||||
}
|
||||
|
||||
def snapIndex(snaps: Seq[Int], excessStep: Int, value: Int): Int =
|
||||
{
|
||||
// println(s"Snap $value")
|
||||
|
@ -151,6 +175,20 @@ class Table(val id: Identifier, connection: Connection)
|
|||
else { snaps.lastOption.getOrElse(0) + excessStep * (idx - (snaps.length -1)) }
|
||||
}
|
||||
|
||||
def startEditing(colKey: Identifier, rowKey: Identifier): Unit =
|
||||
{
|
||||
val (cellX, cellWidth) =
|
||||
positionAndWidthOfColumn(colKey)
|
||||
val (cellY, cellHeight) =
|
||||
positionAndHeightOfRow(rowKey)
|
||||
|
||||
println(s"Editing $colKey x $rowKey")
|
||||
FormulaEditor(
|
||||
cellX+x.now()+Constants.GUTTER_WIDTH+(cellWidth/2),
|
||||
cellY+y.now()+Constants.GUTTER_HEIGHT+cellHeight
|
||||
)
|
||||
}
|
||||
|
||||
def root = div(
|
||||
className("dataTable"),
|
||||
|
||||
|
@ -262,7 +300,17 @@ class Table(val id: Identifier, connection: Connection)
|
|||
div(className("cellBody empty"), "")
|
||||
)
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
// onMouseDown is handled before onClick, so
|
||||
// avoid the MouseDown event propagating to the
|
||||
// parent container and triggering a drag
|
||||
onMouseDown --> {
|
||||
evt => evt.stopPropagation()
|
||||
},
|
||||
onClick --> {
|
||||
evt => startEditing(colKey, rowKey)
|
||||
}
|
||||
)
|
||||
|
||||
} }
|
||||
|
@ -288,13 +336,7 @@ class Table(val id: Identifier, connection: Connection)
|
|||
// We can't peek into colStream without violating ownership, so just
|
||||
// recompute the position
|
||||
val (pos, height) =
|
||||
rows.now().foldLeft[Either[Int, (Int, Int)]]( Left(0) ) {
|
||||
case (Left(x), row) if row.id == rowKey =>
|
||||
Right(x -> row.height)
|
||||
case (Left(x), row) =>
|
||||
Left(x + row.height)
|
||||
case (x@Right(pos, width), _) => x
|
||||
}.right.get
|
||||
positionAndHeightOfRow(rowKey)
|
||||
|
||||
DragFrame.height(
|
||||
x.now(),
|
||||
|
@ -339,13 +381,7 @@ class Table(val id: Identifier, connection: Connection)
|
|||
// We can't peek into rowStream without violating ownership, so just
|
||||
// recompute the position
|
||||
val (pos, width) =
|
||||
columns.now().foldLeft[Either[Int, (Int, Int)]]( Left(0) ) {
|
||||
case (Left(x), col) if col.id == colKey =>
|
||||
Right(x -> col.width)
|
||||
case (Left(x), col) =>
|
||||
Left(x + col.width)
|
||||
case (x@Right(pos, width), _) => x
|
||||
}.right.get
|
||||
positionAndWidthOfColumn(colKey)
|
||||
|
||||
DragFrame.width(
|
||||
x.now()+pos+Constants.GUTTER_WIDTH,
|
||||
|
|
|
@ -0,0 +1,57 @@
|
|||
package net.okennedy.cells.widgets
|
||||
|
||||
import org.scalajs.dom
|
||||
import com.raquo.laminar.api.L._
|
||||
import com.raquo.laminar.nodes.ReactiveHtmlElement
|
||||
|
||||
class FormulaEditor(x: Int, y: Int)
|
||||
extends Widget
|
||||
{
|
||||
val formula = Var[String](initial = "Hihihihi")
|
||||
|
||||
val inputArea =
|
||||
input(
|
||||
className("inputArea"),
|
||||
`type`("text"),
|
||||
controlled(
|
||||
value <-- formula,
|
||||
onInput.mapToValue --> formula.writer
|
||||
)
|
||||
)
|
||||
|
||||
def cancel(): Unit =
|
||||
{
|
||||
println("Cancelled")
|
||||
}
|
||||
|
||||
def accept(): Unit =
|
||||
{
|
||||
println(s"Accepted with ${formula.now()}")
|
||||
}
|
||||
|
||||
val root =
|
||||
div(
|
||||
className("formulaEditor"),
|
||||
styleAttr(s"left: ${x}px; top: ${y}px"),
|
||||
div(
|
||||
className("pointer"),
|
||||
Icon("caret-up")
|
||||
),
|
||||
div(
|
||||
className("editorBody"),
|
||||
inputArea,
|
||||
div( className("cancel button"), Icon("times"),
|
||||
onClick --> { evt => cancel() }
|
||||
),
|
||||
div( className("accept button"), Icon("check"),
|
||||
onClick --> { evt => accept() }
|
||||
)
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
object FormulaEditor
|
||||
{
|
||||
def apply(x: Int, y: Int) =
|
||||
Widgets.register(new FormulaEditor(x, y))
|
||||
}
|
Loading…
Reference in New Issue