Merge branch 'feature/player-nicknames' into 'develop'

Allow to change player/user name

See merge request cc-ru/ocelot/ocelot-desktop!18
This commit is contained in:
Dmitry Zhidenkov 2022-06-24 09:05:12 +00:00
commit 3ccb68633e
10 changed files with 122 additions and 22 deletions

View File

@ -3,7 +3,7 @@ package ocelot.desktop
import li.flor.nativejfilechooser.NativeJFileChooser
import ocelot.desktop.audio.{Audio, SoundSource}
import ocelot.desktop.ui.UiHandler
import ocelot.desktop.ui.widget.{NotificationDialog, ExitConfirmationDialog, RootWidget, SettingsDialog}
import ocelot.desktop.ui.widget.{AddPlayerDialog, ExitConfirmationDialog, NotificationDialog, RootWidget, SettingsDialog}
import ocelot.desktop.util.FileUtils.getOcelotConfigDirectory
import ocelot.desktop.util._
import org.apache.commons.io.FileUtils
@ -11,19 +11,23 @@ import org.apache.logging.log4j.LogManager
import totoro.ocelot.brain.Ocelot
import totoro.ocelot.brain.event.FileSystemActivityType.Floppy
import totoro.ocelot.brain.event._
import totoro.ocelot.brain.nbt.{CompressedStreamTools, NBTTagCompound}
import totoro.ocelot.brain.nbt.ExtendedNBT.{extendNBTTagCompound, extendNBTTagList}
import totoro.ocelot.brain.nbt.{CompressedStreamTools, NBT, NBTTagCompound, NBTTagString}
import totoro.ocelot.brain.user.User
import totoro.ocelot.brain.workspace.Workspace
import java.io._
import java.nio.file.{Files, Path, Paths}
import java.util.concurrent.locks.{Lock, ReentrantLock}
import javax.swing.JFileChooser
import scala.collection.mutable.ArrayBuffer
import scala.io.Source
import scala.jdk.CollectionConverters._
import scala.util.Random
object OcelotDesktop extends Logging {
var root: RootWidget = _
val players: ArrayBuffer[User] = ArrayBuffer(User("myself"))
val tpsCounter = new FPSCalculator
val ticker = new Ticker
@ -109,6 +113,7 @@ object OcelotDesktop extends Logging {
val frontendNBT = new NBTTagCompound
workspace.save(backendNBT)
root.workspaceView.save(frontendNBT)
frontendNBT.setNewTagList("players", players.map(player => new NBTTagString(player.nickname)))
nbt.setTag("back", backendNBT)
nbt.setTag("front", frontendNBT)
})
@ -116,9 +121,12 @@ object OcelotDesktop extends Logging {
private def loadWorld(nbt: NBTTagCompound): Unit = withTickLockAcquired(() => {
val backendNBT = nbt.getCompoundTag("back")
val frontendNBT = nbt.getCompoundTag("front")
workspace.load(backendNBT)
root.workspaceView.load(frontendNBT)
if (frontendNBT.hasKey("players")) {
players.clear()
players.addAll(frontendNBT.getTagList("players", NBT.TAG_STRING).map((player: NBTTagString) => User(player.getString)))
}
})
private var savePath: Option[Path] = None
@ -218,6 +226,29 @@ object OcelotDesktop extends Logging {
}).start()
}
def addPlayerDialog(): Unit = {
UiHandler.root.modalDialogPool.pushDialog(new AddPlayerDialog())
}
def player: User = if (players.nonEmpty) players.head else User("myself")
def selectPlayer(name: String): Unit = {
players.indexWhere(_.nickname == name) match {
case -1 => players.prepend(User(name))
case i =>
val player = players(i)
players.remove(i)
players.prepend(player)
}
}
def removePlayer(name: String): Unit = {
players.indexWhere(_.nickname == name) match {
case -1 =>
case i => players.remove(i)
}
}
def settings(): Unit = {
UiHandler.root.modalDialogPool.pushDialog(new SettingsDialog())
}

View File

@ -19,6 +19,7 @@ class SetLabelDialog(node: Node) extends ModalDialog {
override def onInput(text: String): Unit = {
node.label = if (text.isEmpty) None else Some(text)
}
override def onConfirm(): Unit = close()
}, Padding2D(bottom = 8))
children :+= new Widget {

View File

@ -1,6 +1,6 @@
package ocelot.desktop.node.nodes
import ocelot.desktop.ColorScheme
import ocelot.desktop.{ColorScheme, OcelotDesktop}
import ocelot.desktop.color.{IntColor, RGBAColor}
import ocelot.desktop.geometry.{Rect2D, Size2D, Vector2D}
import ocelot.desktop.graphics.Graphics
@ -42,13 +42,13 @@ class ScreenWindow(screenNode: ScreenNode) extends BasicWindow with Logging {
case event: KeyEvent if shouldHandleKeys =>
event.state match {
case KeyEvent.State.Press | KeyEvent.State.Repeat =>
screen.keyDown(event.char, event.code, User("myself"))
screen.keyDown(event.char, event.code, OcelotDesktop.player)
// note: in OpenComputers, key_down signal is fired __before__ clipboard signal
if (event.code == Keyboard.KEY_INSERT)
screen.clipboard(UiHandler.clipboard, User("myself"))
screen.clipboard(UiHandler.clipboard, OcelotDesktop.player)
case KeyEvent.State.Release =>
screen.keyUp(event.char, event.code, User("myself"))
screen.keyUp(event.char, event.code, OcelotDesktop.player)
}
case event: MouseEvent if shouldHandleKeys =>
@ -60,15 +60,15 @@ class ScreenWindow(screenNode: ScreenNode) extends BasicWindow with Logging {
event.state match {
case MouseEvent.State.Press if inside && screenNode.screen.tier > Tier.One =>
screen.mouseDown(pos.x, pos.y, event.button.id, User("myself"))
screen.mouseDown(pos.x, pos.y, event.button.id, OcelotDesktop.player)
sentTouchEvent = true
case MouseEvent.State.Release =>
if (event.button == MouseEvent.Button.Middle && inside)
screen.clipboard(UiHandler.clipboard, User("myself"))
screen.clipboard(UiHandler.clipboard, OcelotDesktop.player)
if (sentTouchEvent) {
screen.mouseUp(lastMousePos.x, lastMousePos.y, event.button.id, User("myself"))
screen.mouseUp(lastMousePos.x, lastMousePos.y, event.button.id, OcelotDesktop.player)
sentTouchEvent = false
} else if (closeButtonBounds.contains(UiHandler.mousePosition)) {
hide()
@ -78,7 +78,7 @@ class ScreenWindow(screenNode: ScreenNode) extends BasicWindow with Logging {
}
case event: ScrollEvent if shouldHandleKeys && screenNode.screen.tier > Tier.One =>
screen.mouseScroll(lastMousePos.x, lastMousePos.y, event.offset, User("myself"))
screen.mouseScroll(lastMousePos.x, lastMousePos.y, event.offset, OcelotDesktop.player)
case ev@DragEvent(DragEvent.State.Start, MouseEvent.Button.Left, _) =>
if (scaleDragRegion.contains(ev.start)) {
@ -176,7 +176,7 @@ class ScreenWindow(screenNode: ScreenNode) extends BasicWindow with Logging {
if (isFocused && screenNode.screen.tier > Tier.One)
for (button <- MouseEvents.pressedButtons) {
screen.mouseDrag(lastMousePos.x, lastMousePos.y, button.id, User("myself"))
screen.mouseDrag(lastMousePos.x, lastMousePos.y, button.id, OcelotDesktop.player)
}
}

View File

@ -0,0 +1,42 @@
package ocelot.desktop.ui.widget
import ocelot.desktop.OcelotDesktop
import ocelot.desktop.geometry.Padding2D
import ocelot.desktop.ui.layout.LinearLayout
import ocelot.desktop.ui.widget.modal.ModalDialog
import ocelot.desktop.util.Orientation
class AddPlayerDialog() extends ModalDialog {
var name = ""
private def confirm(): Unit = {
OcelotDesktop.selectPlayer(name)
close()
}
children :+= new PaddingBox(new Widget {
override val layout = new LinearLayout(this, orientation = Orientation.Vertical)
children :+= new PaddingBox(new Label {
override def text = "Add new player"
}, Padding2D(bottom = 16))
children :+= new PaddingBox(new TextInput("") {
focus()
override def onInput(text: String): Unit = name = text
override def onConfirm(): Unit = confirm()
}, Padding2D(bottom = 8))
children :+= new Widget {
children :+= new Filler
children :+= new Button {
override def text: String = "Cancel"
override def onClick(): Unit = close()
}
children :+= new PaddingBox(new Button {
override def text: String = "Ok"
override def onClick(): Unit = confirm()
}, Padding2D(left = 8))
}
}, Padding2D.equal(16))
}

View File

@ -9,6 +9,12 @@ import ocelot.desktop.util.Orientation
class ChangeSimulationSpeedDialog() extends ModalDialog {
private var tickInterval: Option[Long] = Some(OcelotDesktop.ticker.tickInterval)
private def confirm(): Unit = {
if (tickInterval.isDefined)
OcelotDesktop.ticker.tickInterval = tickInterval.get
close()
}
children :+= new PaddingBox(new Widget {
override val layout = new LinearLayout(this, orientation = Orientation.Vertical)
@ -42,6 +48,8 @@ class ChangeSimulationSpeedDialog() extends ModalDialog {
case _: NumberFormatException => false
}
}
override def onConfirm(): Unit = confirm()
}
inputTPS = new TextInput(formatTPS(OcelotDesktop.ticker.tickInterval)) {
@ -63,6 +71,8 @@ class ChangeSimulationSpeedDialog() extends ModalDialog {
case _: NumberFormatException => false
}
}
override def onConfirm(): Unit = confirm()
}
children :+= new Label {
@ -84,11 +94,7 @@ class ChangeSimulationSpeedDialog() extends ModalDialog {
children :+= new Button {
override def text: String = "Apply"
override def onClick(): Unit = {
if (tickInterval.isDefined)
OcelotDesktop.ticker.tickInterval = tickInterval.get
close()
}
override def onClick(): Unit = confirm()
}
}
}, Padding2D.equal(16))

View File

@ -2,7 +2,7 @@ package ocelot.desktop.ui.widget
import ocelot.desktop.geometry.{Padding2D, Size2D}
import ocelot.desktop.graphics.Graphics
import ocelot.desktop.ui.widget.contextmenu.ContextMenuEntry
import ocelot.desktop.ui.widget.contextmenu.{ContextMenuEntry, ContextMenuSubmenu}
import ocelot.desktop.{ColorScheme, OcelotDesktop}
class MenuBar extends Widget {
@ -23,6 +23,19 @@ class MenuBar extends Widget {
menu.addEntry(new ContextMenuEntry("Exit", () => OcelotDesktop.exit()))
}))
addEntry(new MenuBarSubmenu("Player", menu => {
menu.addEntry(new ContextMenuEntry("Add...", () => OcelotDesktop.addPlayerDialog()))
menu.addSeparator()
OcelotDesktop.players.foreach(player => {
menu.addEntry(new ContextMenuSubmenu(
(if (player == OcelotDesktop.players.head) "● " else " ") + player.nickname,
() => OcelotDesktop.selectPlayer(player.nickname)
) {
addEntry(new ContextMenuEntry("Remove", () => OcelotDesktop.removePlayer(player.nickname)))
})
})
}))
addEntry(new MenuBarButton("Settings", () => OcelotDesktop.settings()))
addEntry(new Widget {

View File

@ -15,6 +15,7 @@ import scala.collection.mutable.ArrayBuffer
class TextInput(val initialText: String = "") extends Widget with ClickHandler {
def onInput(text: String): Unit = {}
def onConfirm(): Unit = {}
def isInputValid(text: String): Boolean = true
var isFocused = false
@ -65,6 +66,9 @@ class TextInput(val initialText: String = "") extends Widget with ClickHandler {
else
events += new WriteChar(ch)
case KeyEvent(KeyEvent.State.Press, Keyboard.KEY_RETURN, _) if isFocused =>
onConfirm()
case KeyEvent(KeyEvent.State.Press | KeyEvent.State.Repeat, _, char) if isFocused =>
if (!char.isControl)
events += new WriteChar(char)

View File

@ -8,8 +8,9 @@ import ocelot.desktop.ui.UiHandler
import ocelot.desktop.ui.event.HoverEvent
class ContextMenuSubmenu(label: String,
onClick: () => Unit = null,
icon: Option[IconDef] = None)
extends ContextMenuEntry(label + " ", icon = icon)
extends ContextMenuEntry(label + " ", if (onClick != null) onClick else () => {}, icon)
{
private val parentEntry = this
private val submenu = new ContextMenu {
@ -28,7 +29,9 @@ class ContextMenuSubmenu(label: String,
submenu.addSeparator()
}
override def clicked(): Unit = {}
override def clicked(): Unit = {
if (onClick != null) super.clicked()
}
override def leave(): Unit = {
if (submenu.isClosed) super.leave()

View File

@ -41,7 +41,7 @@ class CPUSlot(owner: Inventory#Slot, node: ComputerNode, val tier: Int) extends
if (tier < Tier.Two) return
menu.addEntry(new ContextMenuSubmenu("APU (CPU + GPU)", Some(new IconDef("items/GraphicsCard1"))) {
menu.addEntry(new ContextMenuSubmenu("APU (CPU + GPU)", icon = Some(new IconDef("items/GraphicsCard1"))) {
addEntry(new ContextMenuEntry("Tier 2",
() => item = new APU(Tier.One),
icon = Some(new IconDef("items/APU0", animation = APUAnimation))))

View File

@ -39,7 +39,7 @@ class CardSlot(owner: Inventory#Slot, val tier: Int) extends InventorySlot[Entit
if (nextEntry.isDefined && nextEntry.get.name == entry.name) {
val groupName = entry.name
if (tier >= entry.tier) {
menu.addEntry(new ContextMenuSubmenu(groupName, Some(nextEntry.get.icon)) {
menu.addEntry(new ContextMenuSubmenu(groupName, icon = Some(nextEntry.get.icon)) {
entries.view.slice(i, entries.length).takeWhile(_.name == groupName).foreach(entry => {
val name = if (entry.tier == Tier.Four) "Creative" else "Tier " + (entry.tier + 1)
if (tier >= entry.tier) {