19 Commits
c59d48f6ec
...
5b50f161d2
34 changed files with 1005 additions and 357 deletions
-
12build.sbt
-
342src/main/resources/static/css/main.css
-
7src/main/scala/nova/monadic_sfx/Main.scala
-
274src/main/scala/nova/monadic_sfx/MainApp.scala
-
14src/main/scala/nova/monadic_sfx/MainModule.scala
-
77src/main/scala/nova/monadic_sfx/implicits/JavaFxMonixObservables.scala
-
36src/main/scala/nova/monadic_sfx/implicits/MySfxObservableImplicits.scala
-
62src/main/scala/nova/monadic_sfx/implicits/package.scala
-
2src/main/scala/nova/monadic_sfx/ui/DefaultUI.scala
-
3src/main/scala/nova/monadic_sfx/ui/MyFxApp.scala
-
102src/main/scala/nova/monadic_sfx/ui/components/router/FXRouter.scala
-
10src/main/scala/nova/monadic_sfx/ui/components/todo/TodoListComponentOld.scala
-
6src/main/scala/nova/monadic_sfx/ui/components/todo/TodoListStore.scala
-
106src/main/scala/nova/monadic_sfx/ui/components/todo/TodoListView.scala
-
12src/main/scala/nova/monadic_sfx/ui/controller/TodoController.scala
-
21src/main/scala/nova/monadic_sfx/ui/screens/HomeScreen.scala
-
31src/main/scala/nova/monadic_sfx/util/History.scala
-
44src/main/scala/nova/monadic_sfx/util/SynchedObject.scala
-
4src/main/scala/nova/monadic_sfx/util/controls/ActionObservable.scala
-
2src/main/scala/nova/monadic_sfx/util/controls/FontIcon.scala
-
5src/main/scala/nova/monadic_sfx/util/controls/JFXButton.scala
-
2src/main/scala/nova/monadic_sfx/util/controls/JFXListCell.scala
-
4src/main/scala/nova/monadic_sfx/util/controls/JFXListView.scala
-
2src/main/scala/nova/monadic_sfx/util/controls/JFXSpinner.scala
-
2src/main/scala/nova/monadic_sfx/util/controls/JFXTextArea.scala
-
2src/main/scala/nova/monadic_sfx/util/controls/JFXTextField.scala
-
2src/main/scala/nova/monadic_sfx/util/controls/JFXTreeTableView.scala
-
6src/main/scala/nova/monadic_sfx/util/controls/MenuItem.scala
-
7src/main/scala/nova/monadic_sfx/util/reactive/store/Middlewares.scala
-
2src/main/scala/nova/monadic_sfx/util/reactive/store/MonixProSubject.scala
-
2src/main/scala/nova/monadic_sfx/util/reactive/store/Reducer.scala
-
39src/main/scala/nova/monadic_sfx/util/reactive/store/Store.scala
-
4src/main/scala/nova/monadic_sfx/util/reactive/store/package.scala
-
116src/test/scala/MutHistoryTest.scala
@ -0,0 +1,342 @@ |
|||
.root { |
|||
-fx-font-family: Roboto; |
|||
src: "/resources/roboto/Roboto-Regular.ttf"; |
|||
} |
|||
|
|||
/* Burgers Demo */ |
|||
|
|||
.jfx-hamburger { |
|||
-fx-spacing: 5; |
|||
-fx-cursor: hand; |
|||
} |
|||
|
|||
.jfx-hamburger StackPane { |
|||
-fx-pref-width: 40px; |
|||
-fx-pref-height: 7px; |
|||
-fx-background-color: #D63333; |
|||
-fx-background-radius: 5px; |
|||
} |
|||
|
|||
/* Input Demo */ |
|||
|
|||
.text-field { |
|||
-fx-max-width: 300; |
|||
} |
|||
|
|||
.jfx-text-field, .jfx-password-field { |
|||
-fx-background-color: WHITE; |
|||
-fx-font-weight: BOLD; |
|||
-fx-prompt-text-fill: #808080; |
|||
-fx-alignment: top-left; |
|||
-jfx-focus-color: #4059A9; |
|||
-jfx-unfocus-color: #4d4d4d; |
|||
-fx-max-width: 300; |
|||
} |
|||
|
|||
.jfx-decorator { |
|||
-fx-decorator-color: RED; |
|||
} |
|||
|
|||
.jfx-decorator .jfx-decorator-buttons-container { |
|||
-fx-background-color: -fx-decorator-color; |
|||
} |
|||
|
|||
.jfx-decorator .resize-border { |
|||
-fx-border-color: -fx-decorator-color; |
|||
-fx-border-width: 0 4 4 4; |
|||
} |
|||
|
|||
.jfx-text-area, .text-area { |
|||
-fx-font-weight: BOLD; |
|||
} |
|||
|
|||
.jfx-text-field:error, .jfx-password-field:error, .jfx-text-area:error { |
|||
-jfx-focus-color: #D34336; |
|||
-jfx-unfocus-color: #D34336; |
|||
} |
|||
|
|||
.jfx-text-field .error-label, .jfx-password-field .error-label, .jfx-text-area .error-label { |
|||
-fx-text-fill: #D34336; |
|||
-fx-font-size: 0.75em; |
|||
} |
|||
|
|||
.jfx-text-field .error-icon, .jfx-password-field .error-icon, .jfx-text-area .error-icon { |
|||
-fx-text-fill: #D34336; |
|||
-fx-font-size: 1em; |
|||
} |
|||
|
|||
/* Progress Bar Demo */ |
|||
|
|||
.progress-bar > .bar { |
|||
-fx-min-width: 500; |
|||
} |
|||
|
|||
.jfx-progress-bar > .bar { |
|||
-fx-min-width: 500; |
|||
} |
|||
|
|||
.jfx-progress-bar { |
|||
-fx-progress-color: #0F9D58; |
|||
-fx-stroke-width: 3; |
|||
} |
|||
|
|||
/* Icons Demo */ |
|||
.icon { |
|||
-fx-text-fill: #FE774D; |
|||
-fx-padding: 10; |
|||
-fx-cursor: hand; |
|||
} |
|||
|
|||
.icons-rippler { |
|||
-jfx-rippler-fill: BLUE; |
|||
-jfx-mask-type: CIRCLE; |
|||
} |
|||
|
|||
.icons-rippler:hover { |
|||
-fx-cursor: hand; |
|||
} |
|||
|
|||
.jfx-check-box { |
|||
-fx-font-weight: BOLD; |
|||
} |
|||
|
|||
.custom-jfx-check-box { |
|||
-jfx-checked-color: RED; |
|||
-jfx-unchecked-color: BLACK; |
|||
} |
|||
|
|||
/* Button */ |
|||
.button { |
|||
-fx-padding: 0.7em 0.57em; |
|||
-fx-font-size: 14px; |
|||
} |
|||
|
|||
.button-raised { |
|||
-fx-padding: 0.7em 0.57em; |
|||
-fx-font-size: 14px; |
|||
-jfx-button-type: RAISED; |
|||
-fx-background-color: rgb(77, 102, 204); |
|||
-fx-pref-width: 200; |
|||
-fx-text-fill: WHITE; |
|||
} |
|||
|
|||
/* The main scrollbar **track** CSS class */ |
|||
.mylistview .scroll-bar:horizontal .track, |
|||
.mylistview .scroll-bar:vertical .track { |
|||
-fx-background-color: transparent; |
|||
-fx-border-color: transparent; |
|||
-fx-background-radius: 0em; |
|||
-fx-border-radius: 2em; |
|||
} |
|||
|
|||
/* The increment and decrement button CSS class of scrollbar */ |
|||
.mylistview .scroll-bar:horizontal .increment-button, |
|||
.mylistview .scroll-bar:horizontal .decrement-button { |
|||
-fx-background-color: transparent; |
|||
-fx-background-radius: 0em; |
|||
-fx-padding: 0 0 10 0; |
|||
} |
|||
|
|||
/* The increment and decrement button CSS class of scrollbar */ |
|||
|
|||
.mylistview .scroll-bar:vertical .increment-button, |
|||
.mylistview .scroll-bar:vertical .decrement-button { |
|||
-fx-background-color: transparent; |
|||
-fx-background-radius: 0em; |
|||
-fx-padding: 0 10 0 0; |
|||
|
|||
} |
|||
|
|||
.mylistview .scroll-bar .increment-arrow, |
|||
.mylistview .scroll-bar .decrement-arrow { |
|||
-fx-shape: " "; |
|||
-fx-padding: 0; |
|||
} |
|||
|
|||
/* The main scrollbar **thumb** CSS class which we drag every time (movable) */ |
|||
.mylistview .scroll-bar:horizontal .thumb, |
|||
.mylistview .scroll-bar:vertical .thumb { |
|||
-fx-background-color: derive(black, 90%); |
|||
-fx-background-insets: 2, 0, 0; |
|||
-fx-background-radius: 2em; |
|||
} |
|||
|
|||
.jfx-list-cell-container { |
|||
-fx-alignment: center-left; |
|||
} |
|||
|
|||
.jfx-list-cell-container > .label { |
|||
-fx-text-fill: BLACK; |
|||
} |
|||
|
|||
.jfx-list-cell:odd:selected > .jfx-rippler > StackPane, .jfx-list-cell:even:selected > .jfx-rippler > StackPane { |
|||
-fx-background-color: rgba(0, 0, 255, 0.2); |
|||
} |
|||
|
|||
.jfx-list-cell { |
|||
-fx-background-insets: 0.0; |
|||
-fx-text-fill: BLACK; |
|||
} |
|||
|
|||
.jfx-list-cell:odd, .jfx-list-cell:even { |
|||
-fx-background-color: WHITE; |
|||
} |
|||
|
|||
.jfx-list-cell:filled:hover { |
|||
-fx-text-fill: black; |
|||
} |
|||
|
|||
.jfx-list-cell .jfx-rippler { |
|||
-jfx-rippler-fill: BLUE; |
|||
} |
|||
|
|||
.jfx-list-view { |
|||
-fx-background-insets: 0; |
|||
-jfx-cell-horizontal-margin: 0.0; |
|||
-jfx-cell-vertical-margin: 5.0; |
|||
-jfx-vertical-gap: 10; |
|||
-jfx-expanded: false; |
|||
-fx-pref-width: 200; |
|||
} |
|||
|
|||
.jfx-toggle-button { |
|||
-jfx-toggle-color: RED; |
|||
} |
|||
|
|||
.jfx-tool-bar { |
|||
-fx-font-size: 20; |
|||
-fx-font-weight: BOLD; |
|||
-fx-background-color: #5264AE; |
|||
-fx-pref-width: 100%; |
|||
-fx-pref-height: 64px; |
|||
} |
|||
|
|||
.jfx-tool-bar HBox { |
|||
-fx-alignment: center; |
|||
-fx-spacing: 25; |
|||
-fx-padding: 0 10; |
|||
} |
|||
|
|||
.jfx-tool-bar Label { |
|||
-fx-text-fill: WHITE; |
|||
} |
|||
|
|||
.jfx-popup-container { |
|||
-fx-background-color: WHITE; |
|||
} |
|||
|
|||
.jfx-snackbar-content { |
|||
-fx-background-color: #323232; |
|||
-fx-padding: 5; |
|||
-fx-spacing: 5; |
|||
} |
|||
|
|||
.jfx-snackbar-toast { |
|||
-fx-text-fill: WHITE; |
|||
} |
|||
|
|||
.jfx-snackbar-action { |
|||
-fx-text-fill: #ff4081; |
|||
} |
|||
|
|||
.jfx-list-cell-content-container { |
|||
-fx-alignment: center-left; |
|||
} |
|||
|
|||
.jfx-list-cell-container .label { |
|||
-fx-text-fill: BLACK; |
|||
} |
|||
|
|||
.combo-box-popup .list-view .jfx-list-cell:odd:selected .jfx-list-cell-container, |
|||
.combo-box-popup .list-view .jfx-list-cell:even:selected .jfx-list-cell-container { |
|||
-fx-background-color: rgba(0.0, 0.0, 255.0, 0.2); |
|||
} |
|||
|
|||
.combo-box-popup .list-view .jfx-list-cell { |
|||
-fx-background-insets: 0.0; |
|||
-fx-text-fill: BLACK; |
|||
} |
|||
|
|||
.combo-box-popup .list-view .jfx-list-cell:odd, |
|||
.combo-box-popup .list-view .jfx-list-cell:even { |
|||
-fx-background-color: WHITE; |
|||
} |
|||
|
|||
.combo-box-popup .list-view .jfx-list-cell:filled:hover { |
|||
-fx-text-fill: black; |
|||
} |
|||
|
|||
/*.combo-box .combo-box-button-container{ |
|||
-fx-border-color:BLACK;-fx-border-width: 0 0 1 0; |
|||
} |
|||
.combo-box .combo-box-selected-value-container{ |
|||
-fx-border-color:BLACK; |
|||
} */ |
|||
|
|||
/* |
|||
* TREE TABLE CSS |
|||
*/ |
|||
|
|||
.tree-table-view { |
|||
-fx-tree-table-color: rgba(255, 0, 0, 0.2); |
|||
-fx-tree-table-rippler-color: rgba(255, 0, 0, 0.4); |
|||
} |
|||
|
|||
.tree-table-view .jfx-text-field{ |
|||
-fx-background-color: transparent; |
|||
} |
|||
|
|||
.animated-option-button { |
|||
-fx-background-color: #F1F1F1; |
|||
-fx-background-radius: 50px; |
|||
-fx-pref-height: 50px; |
|||
-fx-pref-width: 50px; |
|||
-fx-min-width: -fx-pref-width; |
|||
-fx-max-width: -fx-pref-width; |
|||
-fx-min-height: -fx-pref-height; |
|||
-fx-max-height: -fx-pref-height; |
|||
-jfx-button-type: RAISED; |
|||
} |
|||
.animated-option-button .jfx-rippler{ |
|||
-jfx-rippler-fill: rgb(113, 118, 114); |
|||
} |
|||
.sub-icon{ |
|||
-fx-fill: rgb(113, 118, 114); |
|||
} |
|||
|
|||
.main-button { |
|||
-fx-pref-width: 60px; |
|||
-fx-background-color: #0F9D58; |
|||
-fx-background-radius: 60px; |
|||
-fx-pref-height: 60px; |
|||
-fx-min-width: -fx-pref-width; |
|||
-fx-max-width: -fx-pref-width; |
|||
-fx-min-height: -fx-pref-height; |
|||
-fx-max-height: -fx-pref-height; |
|||
-jfx-button-type: RAISED; |
|||
} |
|||
.main-button .jfx-rippler{ |
|||
-jfx-rippler-fill: rgba(255,255,255, .87); |
|||
} |
|||
.main-icon{ |
|||
-fx-fill: rgba(255,255,255, .87); |
|||
} |
|||
|
|||
|
|||
.animated-option-sub-button { |
|||
-fx-background-color: #43609C; |
|||
} |
|||
|
|||
.animated-option-sub-button2 { |
|||
-fx-background-color: rgb(203, 104, 96); |
|||
} |
|||
|
|||
.tree-table-view .menu-item:focused { |
|||
-fx-background-color: -fx-tree-table-color; |
|||
|
|||
} |
|||
|
|||
.tree-table-view .menu-item .label { |
|||
-fx-padding: 5 0 5 0; |
|||
} |
|||
|
@ -1,50 +1,20 @@ |
|||
package nova.monadic_sfx |
|||
|
|||
import javafx.event.ActionEvent |
|||
import monix.execution.Ack |
|||
import monix.execution.Cancelable |
|||
import monix.reactive.Observable |
|||
import monix.reactive.OverflowStrategy |
|||
import scalafx.scene.control._ |
|||
package object implicits |
|||
extends MySfxObservableImplicits |
|||
with JavaFXMonixObservables |
|||
|
|||
package object implicits { |
|||
// implicit class NodeExt(val node: Node) { |
|||
// def lookup2[T <: SFXDelegate[_]]( |
|||
// selector: String |
|||
// )(implicit c: ClassTag[T]) = { |
|||
// val t = c.runtimeClass |
|||
// Option(node.delegate.lookup(selector)) match { |
|||
// case Some(value) => |
|||
// if (value.getClass == t) Some(value) else None |
|||
// case None => None |
|||
// } |
|||
// } |
|||
|
|||
implicit class MyButtonExt(val button: Button) extends AnyVal { |
|||
def observableAction(): Observable[ActionEvent] = { |
|||
import monix.execution.cancelables.SingleAssignCancelable |
|||
Observable.create(OverflowStrategy.Unbounded) { sub => |
|||
val c = SingleAssignCancelable() |
|||
val l = new javafx.event.EventHandler[ActionEvent] { |
|||
override def handle(event: ActionEvent): Unit = { |
|||
if (sub.onNext(event) == Ack.Stop) c.cancel() |
|||
} |
|||
} |
|||
|
|||
button.onAction = l |
|||
c := Cancelable(() => |
|||
button.removeEventHandler( |
|||
ActionEvent.ACTION, |
|||
l |
|||
) |
|||
) |
|||
c |
|||
} |
|||
} |
|||
} |
|||
|
|||
// implicit class NodeExt(val node: Node) { |
|||
// def lookup2[T <: SFXDelegate[_]]( |
|||
// selector: String |
|||
// )(implicit c: ClassTag[T]) = { |
|||
// val t = c.runtimeClass |
|||
// Option(node.delegate.lookup(selector)) match { |
|||
// case Some(value) => |
|||
// if (value.getClass == t) Some(value) else None |
|||
// case None => None |
|||
// } |
|||
// } |
|||
|
|||
// val x = node.lookup2("") |
|||
// } |
|||
|
|||
} |
|||
// val x = node.lookup2("") |
|||
// } |
@ -0,0 +1,31 @@ |
|||
package nova.monadic_sfx.util |
|||
|
|||
class MutHistory[T](initValue: T) { |
|||
private var _values = Vector(initValue) |
|||
def values = _values |
|||
private var _sp = 0 |
|||
def sp = _sp |
|||
|
|||
// def current = if (ints.isEmpty) None else Some(ints(sp)) |
|||
def current = _values(_sp) |
|||
|
|||
def push(v: T) = { |
|||
if (_sp < _values.length - 1) { |
|||
_values = _values.splitAt(_sp)._1 |
|||
_values = _values :+ v |
|||
} else { |
|||
_values = _values :+ v |
|||
_sp = _values.length - 1 |
|||
} |
|||
} |
|||
|
|||
def forward() = { |
|||
if (!_values.isEmpty && _sp < _values.length - 1) _sp += 1 |
|||
} |
|||
|
|||
def backward() = { |
|||
if (_sp > 0) { |
|||
_sp -= 1 |
|||
} |
|||
} |
|||
} |
@ -0,0 +1,44 @@ |
|||
package nova.monadic_sfx.util |
|||
|
|||
import monix.bio.Task |
|||
import monix.bio.UIO |
|||
import monix.catnap.MVar |
|||
|
|||
/** |
|||
* Synchronization wrapper for a mutable object |
|||
* |
|||
* @param obj the mutable object |
|||
* @param lock lock for synchronization |
|||
*/ |
|||
class SynchedObject[A](obj: A, lock: MLock) { |
|||
|
|||
def modify(f: A => Task[Unit]): Task[Unit] = |
|||
lock.greenLight(f(obj)) |
|||
|
|||
def get: Task[A] = lock.greenLight(Task(obj)) |
|||
} |
|||
|
|||
object SynchedObject { |
|||
def apply[A](obj: A) = |
|||
MVar[Task] |
|||
.of(()) |
|||
.map(m => new MLock(m)) |
|||
.flatMap(lock => Task(new SynchedObject(obj, lock))) |
|||
} |
|||
|
|||
final class MLock(mvar: MVar[Task, Unit]) { |
|||
def acquire: Task[Unit] = |
|||
mvar.take |
|||
|
|||
def release: Task[Unit] = |
|||
mvar.put(()) |
|||
|
|||
def greenLight[A](fa: Task[A]): Task[A] = |
|||
for { |
|||
_ <- acquire |
|||
a <- fa.doOnCancel( |
|||
release.onErrorHandleWith(ex => UIO(println(ex.getMessage()))) |
|||
) |
|||
_ <- release |
|||
} yield a |
|||
} |
@ -1,4 +1,4 @@ |
|||
package nova.monadic_sfx.implicits |
|||
package nova.monadic_sfx.util.controls |
|||
|
|||
import javafx.{scene => jfxs} |
|||
import org.kordamp.ikonli.{javafx => ikonlifx} |
@ -1,4 +1,4 @@ |
|||
package nova.monadic_sfx.implicits |
|||
package nova.monadic_sfx.util.controls |
|||
|
|||
import com.jfoenix.{controls => jfoenixc} |
|||
import javafx.scene.{control => jfxsc} |
@ -1,4 +1,4 @@ |
|||
package nova.monadic_sfx.implicits |
|||
package nova.monadic_sfx.util.controls |
|||
|
|||
import com.jfoenix.{controls => jfoenixc} |
|||
import scalafx.scene.control.ProgressIndicator |
@ -1,4 +1,4 @@ |
|||
package nova.monadic_sfx.implicits |
|||
package nova.monadic_sfx.util.controls |
|||
|
|||
import com.jfoenix.{controls => jfoenixc} |
|||
import scalafx.Includes._ |
@ -1,4 +1,4 @@ |
|||
package nova.monadic_sfx.implicits |
|||
package nova.monadic_sfx.util.controls |
|||
|
|||
import com.jfoenix.{controls => jfoenixc} |
|||
import scalafx.Includes._ |
@ -1,4 +1,4 @@ |
|||
package nova.monadic_sfx.implicits |
|||
package nova.monadic_sfx.util.controls |
|||
|
|||
import com.jfoenix.controls.datamodels.treetable.RecursiveTreeObject |
|||
import com.jfoenix.{controls => jfoenixc} |
@ -1,9 +1,7 @@ |
|||
package nova.monadic_sfx.implicits |
|||
package nova.monadic_sfx.util.controls |
|||
|
|||
import nova.monadic_sfx.implicits._ |
|||
import scalafx.scene.{control => sfxc} |
|||
|
|||
import JavaFXMonixObservables._ |
|||
|
|||
class MenuItem extends sfxc.MenuItem { |
|||
def obsAction = new ActionObservableBuilder(this.observableAction) |
|||
} |
@ -1,4 +1,4 @@ |
|||
package nova.monadic_sfx.util.reactive |
|||
package nova.monadic_sfx.util.reactive.store |
|||
|
|||
import scala.concurrent.Future |
|||
|
@ -1,4 +1,4 @@ |
|||
package nova.monadic_sfx.util.reactive |
|||
package nova.monadic_sfx.util.reactive.store |
|||
|
|||
import cats.implicits._ |
|||
import monix.reactive.Observable |
@ -1,9 +1,9 @@ |
|||
package nova.monadic_sfx.util |
|||
package nova.monadic_sfx.util.reactive |
|||
|
|||
import monix.reactive.Observable |
|||
import monix.reactive.Observer |
|||
|
|||
package object reactive { |
|||
package object store { |
|||
type MonixProSubject[-I, +O] = Observable[O] with Observer[I] |
|||
type Middleware[A, M] = Observable[(A, M)] => Observable[(A, M)] |
|||
type Store[A, M] = MonixProSubject[A, (A, M)] |
@ -0,0 +1,116 @@ |
|||
import org.scalatest.funsuite.AnyFunSuite |
|||
import nova.monadic_sfx.util.MutHistory |
|||
import com.typesafe.scalalogging.LazyLogging |
|||
class MutHistoryTest extends AnyFunSuite with LazyLogging { |
|||
val h = new MutHistory(0) |
|||
|
|||
test("init") { |
|||
assert(h.values == Vector(0)) |
|||
assert(h.sp == 0) |
|||
assert(h.current == 0) |
|||
} |
|||
test("push 1") { |
|||
h.push(1) |
|||
// logger.debug(mutHistory.ints.toString) |
|||
assert(h.values == Vector(0, 1)) |
|||
assert(h.values.length - 1 == h.sp) |
|||
assert(h.current == 1) |
|||
} |
|||
test("push 2") { |
|||
h.push(2) |
|||
// logger.debug(mutHistory.ints.toString) |
|||
assert(h.values == Vector(0, 1, 2)) |
|||
assert(h.values.length - 1 == h.sp) |
|||
assert(h.current == 2) |
|||
} |
|||
test("first forward") { |
|||
// logger.debug(mutHistory.ints.toString) |
|||
// logger.debug(mutHistory.sp.toString) |
|||
h.forward() |
|||
assert(h.values == Vector(0, 1, 2)) |
|||
assert(h.sp == 2) |
|||
assert(h.current == 2) |
|||
} |
|||
test("second forward") { |
|||
// logger.debug(mutHistory.ints.toString) |
|||
// logger.debug(mutHistory.sp.toString) |
|||
h.forward() |
|||
assert(h.values == Vector(0, 1, 2)) |
|||
assert(h.sp == 2) |
|||
assert(h.current == 2) |
|||
} |
|||
|
|||
test("first backward") { |
|||
h.backward() |
|||
assert(h.values == Vector(0, 1, 2)) |
|||
assert(h.sp == 1) |
|||
assert(h.current == 1) |
|||
} |
|||
test("second backward") { |
|||
h.backward() |
|||
assert(h.values == Vector(0, 1, 2)) |
|||
assert(h.sp == 0) |
|||
assert(h.current == 0) |
|||
} |
|||
test("third backward") { |
|||
h.backward() |
|||
assert(h.values == Vector(0, 1, 2)) |
|||
assert(h.sp == 0) |
|||
assert(h.current == 0) |
|||
} |
|||
test("push 3") { |
|||
h.push(3) |
|||
assert(h.sp == 0) |
|||
assert(h.values == Vector(3)) |
|||
assert(h.current == 3) |
|||
} |
|||
test("fourth backward") { |
|||
h.backward() |
|||
assert(h.values == Vector(3)) |
|||
assert(h.sp == 0) |
|||
assert(h.current == 3) |
|||
} |
|||
test("lastly") { |
|||
h.push(4) |
|||
h.push(5) |
|||
h.push(6) |
|||
h.push(7) |
|||
h.push(8) |
|||
assert(h.values == Vector(3, 4, 5, 6, 7, 8)) |
|||
assert(h.sp == 5) |
|||
assert(h.current == 8) |
|||
h.backward() |
|||
h.backward() |
|||
assert(h.current == 6) |
|||
assert(h.sp == 3) |
|||
h.push(9) |
|||
assert(h.values == Vector(3, 4, 5, 9)) |
|||
assert(h.sp == 3) |
|||
assert(h.current == 9) |
|||
for (i <- 1 to 4) h.backward() |
|||
// assert(h.current == None) |
|||
// assert(h.ints == Vector.empty) |
|||
assert(h.sp == 0) |
|||
assert(h.current == 3) |
|||
h.push(1) |
|||
assert(h.current == 1) |
|||
assert(h.sp == 0) |
|||
|
|||
} |
|||
} |
|||
|
|||
// test("main") { |
|||
// assert(mutHistory.ints == Vector.empty) |
|||
// assert(mutHistory.sp == -1) |
|||
// mutHistory.push(1) |
|||
// assert(mutHistory.ints == Vector(1)) |
|||
// assert(mutHistory.sp == 0) |
|||
// mutHistory.push(2) |
|||
// assert(mutHistory.ints == Vector(1, 2)) |
|||
// assert(mutHistory.sp == 1) |
|||
// // mutHistory.forward() |
|||
// // assert(mutHistory.sp == 1) |
|||
// // mutHistory.forward() |
|||
// // assert(mutHistory.sp == 1) |
|||
// } |
|||
// |
Write
Preview
Loading…
Cancel
Save
Reference in new issue