Skip to content

Commit

Permalink
Framecontext comeback
Browse files Browse the repository at this point in the history
  • Loading branch information
davesmith00000 committed Oct 27, 2023
1 parent dc70f16 commit c47cba5
Show file tree
Hide file tree
Showing 3 changed files with 143 additions and 105 deletions.
12 changes: 6 additions & 6 deletions paint/src/main/scala/roguepaint/PaintScene.scala
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ object PaintScene extends Scene[Size, Model, ViewModel]:
model: PaintModel
): GlobalEvent => Outcome[PaintModel] =
case e =>
val updated = model.windowManager.update(e)
val updated = model.windowManager.update(context.frameContext, e)

updated.map(w => model.copy(windowManager = w))

Expand Down Expand Up @@ -71,19 +71,19 @@ object PaintScene extends Scene[Size, Model, ViewModel]:
) |+| tiles
)

final case class PaintModel(windowManager: WindowManagerModel)
final case class PaintModel(windowManager: WindowManagerModel[Size])
object PaintModel:
private val screenSize: Size = Size(1280, 720) / 10

val initial: PaintModel =
PaintModel(
WindowManagerModel.initial
.add(
WindowModel(WindowId("fixed"))
WindowModel[Size](WindowId("fixed"))
.moveTo((screenSize.toPoint / 2) - 8)
.resizeTo(16, 16)
.isStatic
.withContents { bounds =>
.present { (_, bounds, _) =>
SceneUpdateFragment(
Shape.Circle(
Circle(bounds.center, Math.min(bounds.size.width, bounds.size.height) / 2),
Expand Down Expand Up @@ -116,7 +116,7 @@ object PaintModel:
.isCloseable
.isDraggable
.focus
.withContents { bounds =>
.present { (_, bounds, _) =>
SceneUpdateFragment(
Shape.Circle(
Circle(bounds.center, Math.min(bounds.size.width, bounds.size.height) / 2),
Expand All @@ -127,7 +127,7 @@ object PaintModel:
)
)

final case class PaintViewModel(windowManager: WindowManagerViewModel, bg: BlankEntity)
final case class PaintViewModel(windowManager: WindowManagerViewModel[Size], bg: BlankEntity)
object PaintViewModel:
def initial(viewportSize: Size): PaintViewModel =
PaintViewModel(
Expand Down
177 changes: 104 additions & 73 deletions paint/src/main/scala/roguepaint/components/Window.scala
Original file line number Diff line number Diff line change
Expand Up @@ -16,9 +16,10 @@ object Window:
TerminalText(Assets.assets.AnikkiSquare10x10, RGBA.White, RGBA.Black)
)

def updateModel(
model: WindowModel
): GlobalEvent => Outcome[WindowModel] =
def updateModel[Ctx, A](
frameContext: FrameContext[Ctx],
model: WindowModel[Ctx, A]
): GlobalEvent => Outcome[WindowModel[Ctx, A]] =
case WindowEvent.MoveBy(id, dragData) if model.id == id =>
Outcome(
model.copy(
Expand All @@ -33,13 +34,13 @@ object Window:
)
)

case _ =>
Outcome(model)
case e =>
model.updateContentModel(frameContext, model.contentModel)(e).map(model.withModel)

def calculateDragBy(mousePosition: Point, windowPosition: Point): Point =
(mousePosition / charSize) - windowPosition

def redraw(model: WindowModel, viewModel: WindowViewModel): WindowViewModel =
def redraw[Ctx, A](model: WindowModel[Ctx, A], viewModel: WindowViewModel): WindowViewModel =
val tempModel =
model.copy(
bounds = model.bounds
Expand All @@ -66,8 +67,8 @@ object Window:

vm.copy(terminalClones = clones, modelHashCode = model.bounds.hashCode())

def updateViewModel(
model: WindowModel,
def updateViewModel[Ctx, A](
model: WindowModel[Ctx, A],
viewModel: WindowViewModel
): GlobalEvent => Outcome[WindowViewModel] =
case FrameTick
Expand Down Expand Up @@ -162,131 +163,158 @@ object Window:
case _ =>
Outcome(viewModel)

def present(model: WindowModel, viewModel: WindowViewModel): SceneUpdateFragment =
def present[Ctx, A](
frameContext: FrameContext[Ctx],
model: WindowModel[Ctx, A],
viewModel: WindowViewModel
): SceneUpdateFragment =
val b = model.bounds
.resize(
model.bounds.size + viewModel.resizeData
.map(d => d.by - d.offset)
.getOrElse(Point.zero)
.toSize
)
.moveBy(
viewModel.dragData
.map(d => d.by - d.offset)
.getOrElse(Point.zero)
)

val rect =
if model.title.isDefined then
b
.resize(((b.size - Size(2, 4)) * charSize).max(Size.zero))
.moveTo((b.position + Point(1, 3)) * charSize)
else
b
.resize(((b.size - Size(2, 2)) * charSize).max(Size.zero))
.moveTo((b.position + Point(1, 1)) * charSize)

SceneUpdateFragment(
viewModel.terminalClones.clones
).addCloneBlanks(viewModel.terminalClones.blanks) |+|
model.contents {
val b = model.bounds
.resize(
model.bounds.size + viewModel.resizeData
.map(d => d.by - d.offset)
.getOrElse(Point.zero)
.toSize
)
.moveBy(
viewModel.dragData
.map(d => d.by - d.offset)
.getOrElse(Point.zero)
)

if model.title.isDefined then
b
.resize(((b.size - Size(2, 4)) * charSize).max(Size.zero))
.moveTo((b.position + Point(1, 3)) * charSize)
else
b
.resize(((b.size - Size(2, 2)) * charSize).max(Size.zero))
.moveTo((b.position + Point(1, 1)) * charSize)
}
model.presentContentModel(frameContext, rect, model.contentModel)

opaque type WindowId = String
object WindowId:
def apply(id: String): WindowId = id
extension (id: WindowId) def toString: String = id

final case class WindowModel(
final case class WindowModel[Ctx, A](
id: WindowId,
bounds: Rectangle,
title: Option[String],
contents: Rectangle => SceneUpdateFragment,
contentModel: A,
updateContentModel: (FrameContext[Ctx], A) => GlobalEvent => Outcome[A],
presentContentModel: (FrameContext[Ctx], Rectangle, A) => SceneUpdateFragment,
draggable: Boolean,
resizable: Boolean,
closeable: Boolean,
hasFocus: Boolean,
static: Boolean
):

def withId(value: WindowId): WindowModel =
def withId(value: WindowId): WindowModel[Ctx, A] =
this.copy(id = value)

def withBounds(value: Rectangle): WindowModel =
def withBounds(value: Rectangle): WindowModel[Ctx, A] =
this.copy(bounds = value)

def withPosition(value: Point): WindowModel =
def withPosition(value: Point): WindowModel[Ctx, A] =
withBounds(bounds.withPosition(value))
def moveTo(position: Point): WindowModel =
def moveTo(position: Point): WindowModel[Ctx, A] =
withPosition(position)
def moveTo(x: Int, y: Int): WindowModel =
def moveTo(x: Int, y: Int): WindowModel[Ctx, A] =
moveTo(Point(x, y))
def moveBy(amount: Point): WindowModel =
def moveBy(amount: Point): WindowModel[Ctx, A] =
withPosition(bounds.position + amount)
def moveBy(x: Int, y: Int): WindowModel =
def moveBy(x: Int, y: Int): WindowModel[Ctx, A] =
moveBy(Point(x, y))

def withSize(value: Size): WindowModel =
def withSize(value: Size): WindowModel[Ctx, A] =
withBounds(bounds.withSize(value))
def resizeTo(size: Size): WindowModel =
def resizeTo(size: Size): WindowModel[Ctx, A] =
withSize(size)
def resizeTo(x: Int, y: Int): WindowModel =
def resizeTo(x: Int, y: Int): WindowModel[Ctx, A] =
resizeTo(Size(x, y))
def resizeBy(amount: Size): WindowModel =
def resizeBy(amount: Size): WindowModel[Ctx, A] =
withSize(bounds.size + amount)
def resizeBy(x: Int, y: Int): WindowModel =
def resizeBy(x: Int, y: Int): WindowModel[Ctx, A] =
resizeBy(Size(x, y))

def withTitle(value: String): WindowModel =
def withTitle(value: String): WindowModel[Ctx, A] =
this.copy(title = Option(value))

def withContents(f: Rectangle => SceneUpdateFragment): WindowModel =
this.copy(contents = f)
def withModel(value: A): WindowModel[Ctx, A] =
this.copy(contentModel = value)

def updateModel(f: (FrameContext[Ctx], A) => GlobalEvent => Outcome[A]): WindowModel[Ctx, A] =
this.copy(updateContentModel = f)

def present(f: (FrameContext[Ctx], Rectangle, A) => SceneUpdateFragment): WindowModel[Ctx, A] =
this.copy(presentContentModel = f)

def withDraggable(value: Boolean): WindowModel =
def withDraggable(value: Boolean): WindowModel[Ctx, A] =
this.copy(draggable = value)
def isDraggable: WindowModel =
def isDraggable: WindowModel[Ctx, A] =
withDraggable(true)
def notDraggable: WindowModel =
def notDraggable: WindowModel[Ctx, A] =
withDraggable(false)

def withResizable(value: Boolean): WindowModel =
def withResizable(value: Boolean): WindowModel[Ctx, A] =
this.copy(resizable = value)
def isResizable: WindowModel =
def isResizable: WindowModel[Ctx, A] =
withResizable(true)
def notResizable: WindowModel =
def notResizable: WindowModel[Ctx, A] =
withResizable(false)

def withCloseable(value: Boolean): WindowModel =
def withCloseable(value: Boolean): WindowModel[Ctx, A] =
this.copy(closeable = value)
def isCloseable: WindowModel =
def isCloseable: WindowModel[Ctx, A] =
withCloseable(true)
def notCloseable: WindowModel =
def notCloseable: WindowModel[Ctx, A] =
withCloseable(false)

def withFocus(value: Boolean): WindowModel =
def withFocus(value: Boolean): WindowModel[Ctx, A] =
this.copy(hasFocus = value)
def focus: WindowModel =
def focus: WindowModel[Ctx, A] =
withFocus(true)
def blur: WindowModel =
def blur: WindowModel[Ctx, A] =
withFocus(false)

def withStatic(value: Boolean): WindowModel =
def withStatic(value: Boolean): WindowModel[Ctx, A] =
this.copy(static = value)
def isStatic: WindowModel =
def isStatic: WindowModel[Ctx, A] =
withStatic(true)
def notStatic: WindowModel =
def notStatic: WindowModel[Ctx, A] =
withStatic(false)

def update(event: GlobalEvent): Outcome[WindowModel] =
Window.updateModel(this)(event)

object WindowModel:

def apply(id: WindowId): WindowModel =
def apply[Ctx, A](id: WindowId, content: A): WindowModel[Ctx, A] =
WindowModel(
id,
Rectangle(Point.zero, Size.zero),
None,
contentModel = content,
updateContentModel = (_, _) => _ => Outcome(content),
presentContentModel = (_, _, _) => SceneUpdateFragment.empty,
false,
false,
false,
false,
false
)

def apply[Ctx](id: WindowId): WindowModel[Ctx, Unit] =
WindowModel(
id,
Rectangle(Point.zero, Size.zero),
None,
(r: Rectangle) => SceneUpdateFragment.empty,
contentModel = (),
updateContentModel = (_, _) => _ => Outcome(()),
presentContentModel = (_, _, _) => SceneUpdateFragment.empty,
false,
false,
false,
Expand All @@ -303,13 +331,13 @@ final case class WindowViewModel(
resizeData: Option[DragData]
):

def update(
model: WindowModel,
def update[Ctx, A](
model: WindowModel[Ctx, A],
event: GlobalEvent
): Outcome[WindowViewModel] =
Window.updateViewModel(model, this)(event)

def resize(model: WindowModel): WindowViewModel =
def resize[Ctx, A](model: WindowModel[Ctx, A]): WindowViewModel =
this.copy(terminal = WindowViewModel.makeWindowTerminal(model, terminal))

object WindowViewModel:
Expand All @@ -324,7 +352,10 @@ object WindowViewModel:
None
)

def makeWindowTerminal(model: WindowModel, current: TerminalEmulator): TerminalEmulator =
def makeWindowTerminal[Ctx, A](
model: WindowModel[Ctx, A],
current: TerminalEmulator
): TerminalEmulator =
val validSize = model.bounds.size.max(if model.title.isDefined then Size(3) else Size(2))

val tiles: Batch[(Point, MapTile)] =
Expand Down
Loading

0 comments on commit c47cba5

Please sign in to comment.