Remove the old slot implementation

Yahoo.
This commit is contained in:
Fingercomp 2023-06-10 23:27:49 +07:00
parent 82dead6b9b
commit 861c752fb8
No known key found for this signature in database
GPG Key ID: BBC71CEE45D86E37
20 changed files with 121 additions and 834 deletions

View File

@ -15,7 +15,7 @@ import ocelot.desktop.ui.event.sources.KeyEvents
import ocelot.desktop.ui.event.{BrainEvent, ClickEvent, MouseEvent}
import ocelot.desktop.ui.widget.Label
import ocelot.desktop.ui.widget.contextmenu.{ContextMenu, ContextMenuEntry, ContextMenuSubmenu}
import ocelot.desktop.ui.widget.slot.reimpl._
import ocelot.desktop.ui.widget.slot._
import ocelot.desktop.util.{Logging, Messages, TierColor}
import ocelot.desktop.windows.ComputerWindow
import org.lwjgl.input.Keyboard

View File

@ -5,7 +5,7 @@ import ocelot.desktop.graphics.Graphics
import ocelot.desktop.inventory.SyncedInventory
import ocelot.desktop.inventory.item.{FloppyItem, FloppyItemFactory}
import ocelot.desktop.node.Node
import ocelot.desktop.ui.widget.slot.reimpl.FloppySlotWidget
import ocelot.desktop.ui.widget.slot.FloppySlotWidget
import ocelot.desktop.windows.DiskDriveWindow
import totoro.ocelot.brain.entity.FloppyDiskDrive
import totoro.ocelot.brain.entity.traits.Inventory

View File

@ -1,76 +0,0 @@
package ocelot.desktop.ui.widget.slot
import ocelot.desktop.graphics.{IconDef, Icons}
import ocelot.desktop.node.nodes.ComputerNode
import ocelot.desktop.ui.widget.contextmenu.{ContextMenu, ContextMenuEntry, ContextMenuSubmenu}
import totoro.ocelot.brain.entity.machine.MachineAPI
import totoro.ocelot.brain.entity.traits.{Entity, GenericCPU, Inventory}
import totoro.ocelot.brain.entity.{APU, CPU}
import totoro.ocelot.brain.util.Tier
import totoro.ocelot.brain.util.Tier.Tier
class CPUSlot(owner: Inventory#Slot, node: ComputerNode, val tier: Tier) extends InventorySlot[GenericCPU with Entity](owner) {
override def itemIcon: Option[IconDef] = item match {
case Some(cpu: CPU) => Some(Icons.Cpu(cpu.tier))
case Some(apu: APU) => Some(Icons.Apu(apu.tier))
case _ => None
}
override def icon: IconDef = Icons.CpuIcon
override def tierIcon: Option[IconDef] = Some(Icons.TierIcon(tier))
override def fillLmbMenu(menu: ContextMenu): Unit = {
for (tier <- Tier.One to Tier.Three if this.tier >= tier) {
menu.addEntry(new ContextMenuEntry(s"CPU (${tier.label})",
() => item = new CPU(tier),
icon = Some(Icons.Cpu(tier))))
}
if (tier < Tier.Two) return
menu.addEntry(new ContextMenuSubmenu("APU (CPU + GPU)", icon = Some(Icons.GraphicsCard(Tier.Two))) {
addEntry(new ContextMenuEntry("Tier 2",
() => item = new APU(Tier.One),
icon = Some(Icons.Apu(Tier.One))))
if (tier >= Tier.Three) {
addEntry(new ContextMenuEntry("Tier 3",
() => item = new APU(Tier.Two),
icon = Some(Icons.Apu(Tier.Two))))
addEntry(new ContextMenuEntry("Creative",
() => item = new APU(Tier.Three),
icon = Some(Icons.Apu(Tier.Three))))
}
})
}
override def fillRmbMenu(menu: ContextMenu): Unit = {
if (item.isEmpty) return
val cpu = item.get
menu.addEntry(new ContextMenuSubmenu("Set architecture") {
for (arch <- cpu.allArchitectures) {
val name = MachineAPI.getArchitectureName(arch) +
(if (arch == cpu.architecture) " (current)" else "")
addEntry(new ContextMenuEntry(name, () => {
val machine = node.computer.machine
if (machine.isRunning) {
machine.stop()
cpu.setArchitecture(arch)
machine.start()
} else {
cpu.setArchitecture(arch)
}
}))
}
})
super.fillRmbMenu(menu)
}
override def lmbMenuEnabled: Boolean = true
}

View File

@ -1,72 +0,0 @@
package ocelot.desktop.ui.widget.slot
import ocelot.desktop.graphics.{IconDef, Icons}
import totoro.ocelot.brain.entity.sound_card.SoundCard
import totoro.ocelot.brain.entity.traits.{Entity, Tiered, TieredPersistable}
import totoro.ocelot.brain.entity.{DataCard, GraphicsCard, InternetCard, LinkedCard, NetworkCard, Redstone, SelfDestructingCard, WirelessNetworkCard}
import totoro.ocelot.brain.util.Tier
import totoro.ocelot.brain.util.Tier.Tier
import scala.collection.mutable
import scala.reflect.{ClassTag, classTag}
object CardRegistry {
case class Entry(name: String, tier: Tier, icon: IconDef, factory: () => Entity)
val iconByClass: mutable.HashMap[String, IconDef] = mutable.HashMap()
val tierByClass: mutable.HashMap[String, Tier] = mutable.HashMap()
val iconByClassAndTier: mutable.HashMap[(String, Tier), IconDef] = mutable.HashMap()
val entries: mutable.ArrayBuffer[Entry] = mutable.ArrayBuffer()
def addEntry[T <: Entity : ClassTag](name: String, tier: Tier, icon: IconDef, factory: () => T): Unit = {
val entry = Entry(name, tier, icon, factory)
entries += entry
val clazz = classTag[T].runtimeClass.getName
iconByClass.addOne((clazz, icon))
tierByClass.addOne((clazz, tier))
iconByClassAndTier.addOne(((clazz, entry.tier), icon))
}
def getIcon(entity: Entity): Option[IconDef] = {
val clazz = entity.getClass.getName
entity match {
case t: TieredPersistable => iconByClassAndTier.get((clazz, t.tier))
case _ => iconByClass.get(clazz)
}
}
def getTier(entity: Entity): Tier = {
val clazz = entity.getClass.getName
entity match {
case t: Tiered => t.tier
case _ => tierByClass.getOrElse(clazz, Tier.One)
}
}
for (tier <- Tier.One to Tier.Three) {
addEntry("Graphics Card", tier, Icons.GraphicsCard(tier), () => new GraphicsCard(tier))
}
addEntry("Network Card", Tier.One, Icons.NetworkCard, () => new NetworkCard)
addEntry("Wireless Net. Card", Tier.One, Icons.WirelessNetworkCard(Tier.One),
() => new WirelessNetworkCard.Tier1)
addEntry("Wireless Net. Card", Tier.Two, Icons.WirelessNetworkCard(Tier.Two),
() => new WirelessNetworkCard.Tier2)
addEntry("Linked Card", Tier.Three, Icons.LinkedCard, () => new LinkedCard)
addEntry("Internet Card", Tier.Two, Icons.InternetCard, () => new InternetCard)
addEntry("Redstone Card", Tier.One, Icons.RedstoneCard(Tier.One), () => new Redstone.Tier1)
addEntry("Redstone Card", Tier.Two, Icons.RedstoneCard(Tier.Two), () => new Redstone.Tier2)
addEntry("Data Card", Tier.One, Icons.DataCard(Tier.One), () => new DataCard.Tier1)
addEntry("Data Card", Tier.Two, Icons.DataCard(Tier.Two), () => new DataCard.Tier2)
addEntry("Data Card", Tier.Three, Icons.DataCard(Tier.Three), () => new DataCard.Tier3)
addEntry("Sound Card", Tier.Two, Icons.SoundCard, () => new SoundCard)
addEntry("Self-Destructing Card", Tier.Two, Icons.SelfDestructingCard, () => new SelfDestructingCard)
}

View File

@ -1,84 +0,0 @@
package ocelot.desktop.ui.widget.slot
import ocelot.desktop.color.Color
import ocelot.desktop.graphics.{IconDef, Icons}
import ocelot.desktop.ui.UiHandler
import ocelot.desktop.ui.widget.card.{Redstone1Window, Redstone2Window, SoundCardWindow}
import ocelot.desktop.ui.widget.contextmenu.{ContextMenu, ContextMenuEntry, ContextMenuSubmenu}
import ocelot.desktop.ui.widget.{Label, TunnelDialog, Widget}
import totoro.ocelot.brain.entity.sound_card.SoundCard
import totoro.ocelot.brain.entity.traits.{Entity, Inventory}
import totoro.ocelot.brain.entity.{LinkedCard, Redstone}
import totoro.ocelot.brain.util.Tier.Tier
class CardSlot(owner: Inventory#Slot, val tier: Tier) extends InventorySlot[Entity](owner) {
override def itemIcon: Option[IconDef] = item.flatMap(it => CardRegistry.getIcon(it))
override def icon: IconDef = Icons.CardIcon
override def tierIcon: Option[IconDef] = Some(Icons.TierIcon(tier))
override def fillRmbMenu(menu: ContextMenu): Unit = {
val pool = UiHandler.root.workspaceView.windowPool
item match {
case Some(card: Redstone.Tier2) =>
menu.addEntry(new ContextMenuEntry("Redstone I/O", () => pool.openWindow(new Redstone1Window(card))))
menu.addEntry(new ContextMenuEntry("Bundled I/O", () => pool.openWindow(new Redstone2Window(card))))
case Some(card: Redstone.Tier1) =>
menu.addEntry(new ContextMenuEntry("Redstone I/O", () => pool.openWindow(new Redstone1Window(card))))
case Some(card: LinkedCard) =>
menu.addEntry(new ContextMenuEntry("Set channel", () => new TunnelDialog(
tunnel => card.tunnel = tunnel,
card.tunnel
).show()))
case Some(card: SoundCard) =>
menu.addEntry(new ContextMenuEntry("Open", () => pool.openWindow(new SoundCardWindow(card))))
case _ =>
}
super.fillRmbMenu(menu)
}
override def fillLmbMenu(menu: ContextMenu): Unit = {
val entries = CardRegistry.entries
var i = 0
while (i < entries.length) {
val entry = entries(i)
val nextEntry = entries.lift(i + 1)
if (nextEntry.isDefined && nextEntry.get.name == entry.name) {
val groupName = entry.name
if (tier >= entry.tier) {
menu.addEntry(new ContextMenuSubmenu(groupName, icon = Some(nextEntry.get.icon)) {
entries.view.slice(i, entries.length).takeWhile(_.name == groupName).foreach(entry => {
if (tier >= entry.tier) {
addEntry(new ContextMenuEntry(entry.tier.label, () => item = entry.factory(), Some(entry.icon)))
}
i += 1
})
})
}
} else {
if (tier >= entry.tier) {
menu.addEntry(new ContextMenuEntry(entry.name, () => item = entry.factory(), Some(entry.icon)))
}
i += 1
}
}
}
override def lmbMenuEnabled: Boolean = true
override def tooltipChildrenAdder(inner: Widget): Unit = {
super.tooltipChildrenAdder(inner)
item match {
case Some(card: LinkedCard) =>
inner.children :+= new Label {
override def text: String = s"Channel: ${card.tunnel}"
override def color: Color = Color.Grey
}
case _ =>
}
}
}

View File

@ -1,4 +1,4 @@
package ocelot.desktop.ui.widget.slot.reimpl
package ocelot.desktop.ui.widget.slot
import ocelot.desktop.graphics.{IconDef, Icons}
import ocelot.desktop.inventory.Inventory

View File

@ -1,4 +1,4 @@
package ocelot.desktop.ui.widget.slot.reimpl
package ocelot.desktop.ui.widget.slot
import ocelot.desktop.graphics.{IconDef, Icons}
import ocelot.desktop.inventory.Inventory

View File

@ -1,29 +0,0 @@
package ocelot.desktop.ui.widget.slot
import ocelot.desktop.OcelotDesktop
import ocelot.desktop.ui.widget.contextmenu.{ContextMenu, ContextMenuEntry}
import totoro.ocelot.brain.entity.traits.{DiskManaged, Entity}
import javax.swing.JFileChooser
import scala.util.Try
trait DiskOrFloppySlot {
def addSetDirectoryEntryToRmbMenu(menu: ContextMenu, slot: InventorySlot[DiskManaged with Entity]): Unit = {
menu.addEntry(new ContextMenuEntry(
"Set directory",
() => OcelotDesktop.showFileChooserDialog(JFileChooser.OPEN_DIALOG, JFileChooser.DIRECTORIES_ONLY) { dir =>
Try {
if (dir.isDefined && slot.item.isDefined) {
val item = slot.item
// first - unload the item with old filesystem (triggers 'component_removed' signal)
slot.item = None
// then - trigger filesystem rebuild with a new path
item.get.customRealPath = Some(dir.get.toPath.toAbsolutePath)
// finally - add the item back (triggers 'component_added' signal)
slot.item = item
}
}
}
))
}
}

View File

@ -1,33 +0,0 @@
package ocelot.desktop.ui.widget.slot
import ocelot.desktop.graphics.{IconDef, Icons}
import ocelot.desktop.ui.widget.contextmenu.{ContextMenu, ContextMenuEntry}
import totoro.ocelot.brain.entity.HDDManaged
import totoro.ocelot.brain.entity.traits.{DiskManaged, Entity, Inventory}
import totoro.ocelot.brain.util.Tier
import totoro.ocelot.brain.util.Tier.Tier
class DiskSlot(owner: Inventory#Slot, val tier: Tier) extends InventorySlot[HDDManaged](owner) with DiskOrFloppySlot {
override def itemIcon: Option[IconDef] = item.map(disk => Icons.HardDiskDrive(disk.tier))
override def icon: IconDef = Icons.HddIcon
override def tierIcon: Option[IconDef] = Some(Icons.TierIcon(tier))
override def fillLmbMenu(menu: ContextMenu): Unit = {
for (tier <- Tier.One to Tier.Three if this.tier >= tier) {
menu.addEntry(new ContextMenuEntry(s"HDD (${tier.label})",
() => item = new HDDManaged(tier),
icon = Some(Icons.HardDiskDrive(tier))))
}
}
override def lmbMenuEnabled: Boolean = true
override def fillRmbMenu(menu: ContextMenu): Unit = {
addSetDirectoryEntryToRmbMenu(menu, this.asInstanceOf[InventorySlot[DiskManaged with Entity]])
super.fillRmbMenu(menu)
}
override def tooltipLine1Text: String = getTooltipDeviceInfoText(item.get.fileSystem, item.get.tier)
}

View File

@ -1,102 +0,0 @@
package ocelot.desktop.ui.widget.slot
import ocelot.desktop.OcelotDesktop.showFileChooserDialog
import ocelot.desktop.color.Color
import ocelot.desktop.graphics.{IconDef, Icons}
import ocelot.desktop.ui.widget.contextmenu.{ContextMenu, ContextMenuEntry, ContextMenuSubmenu}
import ocelot.desktop.ui.widget.{InputDialog, Label, Widget}
import totoro.ocelot.brain.entity.EEPROM
import totoro.ocelot.brain.entity.traits.Inventory
import totoro.ocelot.brain.loot.Loot
import java.net.{MalformedURLException, URL}
import javax.swing.JFileChooser
import scala.util.Try
class EEPROMSlot(owner: Inventory#Slot) extends InventorySlot[EEPROM](owner) {
override def itemIcon: Option[IconDef] = item.map(_ => Icons.Eeprom)
override def icon: IconDef = Icons.EepromIcon
override def lmbMenuEnabled: Boolean = true
override def fillLmbMenu(menu: ContextMenu): Unit = {
menu.addEntry(new ContextMenuEntry("Lua BIOS",
() => item = Loot.LuaBiosEEPROM.create(),
icon = Some(Icons.Eeprom)
))
menu.addEntry(new ContextMenuEntry("AdvLoader",
() => item = Loot.AdvLoaderEEPROM.create(),
icon = Some(Icons.Eeprom)
))
menu.addEntry(new ContextMenuEntry("Cyan BIOS",
() => item = Loot.CyanBIOSEEPROM.create(),
icon = Some(Icons.Eeprom)
))
menu.addEntry(new ContextMenuEntry("Empty",
() => item = new EEPROM,
icon = Some(Icons.Eeprom)
))
}
override def fillRmbMenu(menu: ContextMenu): Unit = {
val dataSourceMenu = new ContextMenuSubmenu("External data source")
dataSourceMenu.addEntry(new ContextMenuEntry(
"Local file",
() => showFileChooserDialog(JFileChooser.OPEN_DIALOG, JFileChooser.FILES_ONLY) { file =>
Try {
if (file.isDefined)
item.get.codePath = Some(file.get.toPath)
}
}
))
dataSourceMenu.addEntry(new ContextMenuEntry("File via URL", () =>
new InputDialog(
title = "File via URL",
text => item.get.codeURL = Some(new URL(text)),
inputValidator = text => {
try {
new URL(text)
true
}
catch {
case _: MalformedURLException => false
}
}
).show()
))
if (item.get.codePath.isDefined || item.get.codeURL.isDefined)
dataSourceMenu.addEntry(new ContextMenuEntry("Detach", () => item.get.codeBytes = Some(Array.empty[Byte])))
menu.addEntry(dataSourceMenu)
super.fillRmbMenu(menu)
}
override def tooltipLine1Text: String = getTooltipSuffixedText(getTooltipDeviceInfoText(item.get), item.get.label)
override def tooltipChildrenAdder(inner: Widget): Unit = {
super.tooltipChildrenAdder(inner)
if (item.get.codePath.isEmpty && item.get.codeURL.isEmpty)
return
inner.children :+= new Label {
override def text: String = {
if (item.isDefined) {
if (item.get.codePath.isDefined) s"Source path: ${item.get.codePath.get.toString}"
else if (item.get.codeURL.isDefined) s"Source URL: ${item.get.codeURL.get.toString}"
else ""
} else ""
}
override def color: Color = Color.Grey
}
}
}

View File

@ -1,4 +1,4 @@
package ocelot.desktop.ui.widget.slot.reimpl
package ocelot.desktop.ui.widget.slot
import ocelot.desktop.graphics.{IconDef, Icons}
import ocelot.desktop.inventory.Inventory

View File

@ -1,64 +0,0 @@
package ocelot.desktop.ui.widget.slot
import ocelot.desktop.audio.{SoundBuffers, SoundCategory, SoundSource}
import ocelot.desktop.graphics.{IconDef, Icons}
import ocelot.desktop.ui.widget.contextmenu.{ContextMenu, ContextMenuEntry}
import totoro.ocelot.brain.entity.FloppyManaged
import totoro.ocelot.brain.entity.traits.{DiskManaged, Entity, Floppy, Inventory}
import totoro.ocelot.brain.loot.Loot
import totoro.ocelot.brain.loot.Loot.LootFloppy
import totoro.ocelot.brain.util.DyeColor
class FloppySlot(owner: Inventory#Slot) extends InventorySlot[Floppy](owner) with DiskOrFloppySlot {
private val soundFloppyInsert = SoundSource.fromBuffer(SoundBuffers.MachineFloppyInsert, SoundCategory.Environment)
private val soundFloppyEject = SoundSource.fromBuffer(SoundBuffers.MachineFloppyEject, SoundCategory.Environment)
override def itemIcon: Option[IconDef] = item.map(fl => Icons.FloppyDisk(fl.color))
override def icon: IconDef = Icons.FloppyIcon
override def fillLmbMenu(menu: ContextMenu): Unit = {
for (f <- FloppySlot.FloppyFactories) {
menu.addEntry(new ContextMenuEntry(f.name,
f.create,
icon = Some(Icons.FloppyDisk(f.color))))
}
menu.addEntry(new ContextMenuEntry("Empty",
() => item = new FloppyManaged(None, DyeColor.Gray),
icon = Some(Icons.FloppyDisk(DyeColor.Gray))))
}
override def lmbMenuEnabled: Boolean = true
override def fillRmbMenu(menu: ContextMenu): Unit = {
item match {
case Some(_: LootFloppy) =>
// don't allow mounting a directory for loot floppies (it's just too weird)
case Some(_: FloppyManaged) =>
addSetDirectoryEntryToRmbMenu(menu, this.asInstanceOf[InventorySlot[DiskManaged with Entity]])
case _ =>
}
super.fillRmbMenu(menu)
}
override def onAdded(item: Floppy): Unit = {
super.onAdded(item)
soundFloppyInsert.play()
}
override def onRemoved(item: Floppy): Unit = {
super.onRemoved(item)
soundFloppyEject.play()
}
override def tooltipLine1Text: String = item.get.label.labelOption.getOrElse("Floppy Disk")
}
object FloppySlot {
private val FloppyFactories = Array(Loot.OpenOsFloppy, Loot.Plan9kFloppy, Loot.OPPMFloppy,
Loot.OpenLoaderFloppy, Loot.NetworkFloppy, Loot.IrcFloppy, Loot.DataFloppy, Loot.HpmFloppy)
}

View File

@ -1,4 +1,4 @@
package ocelot.desktop.ui.widget.slot.reimpl
package ocelot.desktop.ui.widget.slot
import ocelot.desktop.audio.{SoundBuffers, SoundCategory, SoundSource}
import ocelot.desktop.graphics.{IconDef, Icons}

View File

@ -1,4 +1,4 @@
package ocelot.desktop.ui.widget.slot.reimpl
package ocelot.desktop.ui.widget.slot
import ocelot.desktop.graphics.{IconDef, Icons}
import ocelot.desktop.inventory.Inventory

View File

@ -1,127 +0,0 @@
package ocelot.desktop.ui.widget.slot
import ocelot.desktop.color.Color
import ocelot.desktop.geometry.Padding2D
import ocelot.desktop.ui.UiHandler
import ocelot.desktop.ui.layout.LinearLayout
import ocelot.desktop.ui.widget.contextmenu.{ContextMenu, ContextMenuEntry}
import ocelot.desktop.ui.widget.tooltip.Tooltip
import ocelot.desktop.ui.widget.{Label, PaddingBox, Widget}
import ocelot.desktop.util.Orientation
import totoro.ocelot.brain.entity.HDDManaged
import totoro.ocelot.brain.entity.traits.{DeviceInfo, Entity, Environment, Inventory, Tiered}
import totoro.ocelot.brain.util.Tier
import totoro.ocelot.brain.util.Tier.Tier
abstract class InventorySlot[T <: Entity](val owner: Inventory#Slot) extends SlotWidget[T] {
reloadItem()
override def onAdded(item: T): Unit = {
super.onAdded(item)
owner.put(item)
}
override def onRemoved(item: T): Unit = {
super.onRemoved(item)
owner.remove()
}
override def fillRmbMenu(menu: ContextMenu): Unit = {
item match {
case Some(env: Environment) =>
menu.addEntry(new ContextMenuEntry("Copy address", () => {
UiHandler.clipboard = env.node.address
}))
case _ =>
}
super.fillRmbMenu(menu)
}
// --------------------------- Tooltip ---------------------------
private var tooltip: Option[Tooltip] = None
def tooltipLine1Color: Color = item match {
case Some(tiered: Tiered) =>
tiered.tier match {
case Tier.Two => Color.Yellow
case Tier.Three => Color.Cyan
// TODO: creative???
case _ => Color.White
}
case _ => Color.White
}
final protected def getTooltipSuffixedText(part1: String, part2: String): String = s"$part1 ($part2)"
final protected def getTooltipTieredText(tier: Tier): String = tier.label
final protected def getTooltipDeviceInfoText(deviceInfo: DeviceInfo): String =
deviceInfo.getDeviceInfo(DeviceInfo.DeviceAttribute.Description)
final protected def getTooltipDeviceInfoText(deviceInfo: DeviceInfo, part2: String): String =
getTooltipSuffixedText(getTooltipDeviceInfoText(deviceInfo), part2)
final protected def getTooltipDeviceInfoText(deviceInfo: DeviceInfo, tier: Tier): String =
getTooltipDeviceInfoText(deviceInfo, getTooltipTieredText(tier))
def tooltipLine1Text: String = item.get match {
case deviceInfoTiered: DeviceInfo with Tiered =>
getTooltipDeviceInfoText(deviceInfoTiered, deviceInfoTiered.tier)
case deviceInfo: DeviceInfo =>
deviceInfo.getDeviceInfo(DeviceInfo.DeviceAttribute.Description)
case _ =>
""
}
def tooltipChildrenAdder(inner: Widget): Unit = {
inner.children :+= new Label {
override def text: String = tooltipLine1Text
override def color: Color = tooltipLine1Color
}
item match {
case Some(environment: Environment) =>
inner.children :+= new Label {
override def text: String = s"Address: ${environment.node.address}"
override def color: Color = Color.Grey
}
case _ =>
}
item match {
case Some(hddManaged: HDDManaged) =>
if (hddManaged.customRealPath.isDefined) {
inner.children :+= new Label {
override def text: String = s"Source path: ${hddManaged.customRealPath.get}"
override def color: Color = Color.Grey
}
}
case _ =>
}
}
override def onHoverEnter(): Unit = {
super.onHoverEnter()
// Showing tooltip only if item is present in slot
if (item.isEmpty)
return
tooltip = Some(new Tooltip())
val inner: Widget = new Widget {
override val layout = new LinearLayout(this, orientation = Orientation.Vertical)
}
tooltipChildrenAdder(inner)
tooltip.get.children :+= new PaddingBox(inner, Padding2D.equal(5))
root.get.tooltipPool.addTooltip(tooltip.get)
}
override def onHoverLeave(): Unit = {
super.onHoverLeave()
tooltip.foreach(root.get.tooltipPool.closeTooltip(_))
}
def reloadItem(): Unit = _item = owner.get.map(_.asInstanceOf[T])
}

View File

@ -3,7 +3,6 @@ package ocelot.desktop.ui.widget.slot
import ocelot.desktop.inventory.item._
import ocelot.desktop.inventory.{Item, ItemFactory}
import ocelot.desktop.ui.widget.contextmenu.{ContextMenu, ContextMenuEntry, ContextMenuSubmenu}
import ocelot.desktop.ui.widget.slot.reimpl.SlotWidget
import totoro.ocelot.brain.loot.Loot
import totoro.ocelot.brain.util.ExtendedTier.ExtendedTier
import totoro.ocelot.brain.util.{ExtendedTier, Tier}

View File

@ -1,39 +0,0 @@
package ocelot.desktop.ui.widget.slot
import ocelot.desktop.color.Color
import ocelot.desktop.graphics.{IconDef, Icons}
import ocelot.desktop.ui.widget.contextmenu.{ContextMenu, ContextMenuEntry}
import totoro.ocelot.brain.entity.Memory
import totoro.ocelot.brain.entity.traits.{Inventory, Tiered}
import totoro.ocelot.brain.util.Tier.Tier
import totoro.ocelot.brain.util.{ExtendedTier, Tier}
class MemorySlot(owner: Inventory#Slot, val tier: Tier) extends InventorySlot[Memory](owner) {
override def itemIcon: Option[IconDef] = item.map(_.memoryTier).map(Icons.Memory)
override def icon: IconDef = Icons.MemoryIcon
override def tierIcon: Option[IconDef] = Some(Icons.TierIcon(tier))
override def fillLmbMenu(menu: ContextMenu): Unit = {
for (tier <- ExtendedTier.One to ExtendedTier.ThreeHalf if this.tier >= tier.toTier) {
menu.addEntry(new ContextMenuEntry(s"RAM (${tier.label})",
() => item = new Memory(tier),
icon = Some(Icons.Memory(tier))))
}
}
override def lmbMenuEnabled: Boolean = true
override def tooltipLine1Color: Color = item.get match {
case tiered: Tiered => tiered.tier match {
case Tier.One => Color.White
case Tier.Two => Color.Yellow
case Tier.Three => Color.Cyan
case _ => Color.Cyan
}
case _ => Color.White
}
override def tooltipLine1Text: String = getTooltipDeviceInfoText(item.get, item.get.memoryTier.label)
}

View File

@ -1,4 +1,4 @@
package ocelot.desktop.ui.widget.slot.reimpl
package ocelot.desktop.ui.widget.slot
import ocelot.desktop.graphics.{IconDef, Icons}
import ocelot.desktop.inventory.Inventory

View File

@ -2,84 +2,151 @@ package ocelot.desktop.ui.widget.slot
import ocelot.desktop.audio.SoundSources
import ocelot.desktop.geometry.Size2D
import ocelot.desktop.graphics.{Graphics, IconDef}
import ocelot.desktop.graphics.{Graphics, IconDef, Icons}
import ocelot.desktop.inventory.{Inventory, Item, ItemFactory}
import ocelot.desktop.ui.event.handlers.{ClickHandler, HoverHandler}
import ocelot.desktop.ui.event.{ClickEvent, HoverEvent, MouseEvent}
import ocelot.desktop.ui.widget.Widget
import ocelot.desktop.ui.widget.contextmenu.{ContextMenu, ContextMenuEntry}
import ocelot.desktop.ui.widget.tooltip.Tooltip
import totoro.ocelot.brain.util.Tier
import totoro.ocelot.brain.util.Tier.Tier
abstract class SlotWidget[T] extends Widget with ClickHandler with HoverHandler {
def icon: IconDef
import scala.math.Ordering.Implicits.infixOrderingOps
import scala.reflect.ClassTag
def tierIcon: Option[IconDef] = None
class SlotWidget[I <: Item](private val slot: Inventory#Slot)(implicit slotItemTag: ClassTag[I])
extends Widget
with ClickHandler
with HoverHandler {
def itemIcon: Option[IconDef] = None
slotWidget =>
def onRemoved(item: T): Unit = {}
// NOTE: this must remain as a separate object
// (i. e. don't you dare inline it into the addObserver call below):
// this is the only strong reference to the observer
private val observer = new Inventory.SlotObserver {
override def onItemAdded(): Unit = {
slotWidget.onItemAdded()
}
def onAdded(item: T): Unit = {}
override def onItemRemoved(removedItem: Item, replacedBy: Option[Item]): Unit = {
slotWidget.onItemRemoved(removedItem.asInstanceOf[I], replacedBy.map(_.asInstanceOf[I]))
}
def fillLmbMenu(menu: ContextMenu): Unit = {}
def fillRmbMenu(menu: ContextMenu): Unit = {
menu.addEntry(new ContextMenuEntry("Remove", () => item = None, sound = SoundSources.InterfaceClickLow))
override def onItemSpecificEvent(payload: AnyRef): Unit = {
slotWidget.onItemSpecificEvent(payload)
}
}
def lmbMenuEnabled: Boolean = false
slot.addObserver(observer)
def rmbMenuEnabled: Boolean = _item.isDefined
final var _item: Option[T] = None
final def item_=(v: Option[T]): Unit = {
if (_item.isDefined)
onRemoved(_item.get)
_item = v
if (v.isDefined)
onAdded(v.get)
def dispose(): Unit = {
closeTooltip()
slot.removeObserver(observer)
}
final def item_=(v: T): Unit = item = Some(v)
def ghostIcon: Option[IconDef] = None
final def item: Option[T] = _item
def slotTier: Option[Tier] = None
final override def minimumSize: Size2D = Size2D(36, 36)
final override def maximumSize: Size2D = minimumSize
def tierIcon: Option[IconDef] = slotTier.map(Icons.TierIcon)
final override def receiveMouseEvents: Boolean = true
def itemIcon: Option[IconDef] = item.map(_.icon)
def item: Option[I] = slot.get.map(_.asInstanceOf[I])
def item_=(item: Option[I]): Unit = {
slot.set(item.map(_.asInstanceOf[slot.inventory.I]))
}
def item_=(item: I): Unit = {
slot.put(item.asInstanceOf[slot.inventory.I])
}
def isItemAccepted(factory: ItemFactory): Boolean = {
// yes, you can compare Options. isn't it nice?
slotItemTag.runtimeClass.isAssignableFrom(factory.itemClass) && factory.tier.map(_ min Tier.Three) <= slotTier
}
protected def onItemAdded(): Unit = {}
protected def onItemRemoved(removedItem: I, replacedBy: Option[I]): Unit = {
closeTooltip()
}
protected def onItemSpecificEvent(payload: AnyRef): Unit = {}
final override val minimumSize, maximumSize = Size2D(36, 36)
final override val receiveMouseEvents: Boolean = true
protected def lmbMenuEnabled: Boolean = true
protected def rmbMenuEnabled: Boolean = item.nonEmpty
protected def fillRmbMenu(menu: ContextMenu): Unit = {
for (item <- item) {
item.fillRmbMenu(menu)
menu.addEntry(
ContextMenuEntry("Remove", sound = SoundSources.InterfaceClickLow) {
slot.remove()
},
)
}
}
private var _tooltip: Option[Tooltip] = None
def onHoverEnter(): Unit = {
for (item <- item) {
// just in case
// closeTooltip()
val tooltip = item.tooltip
_tooltip = Some(tooltip)
root.get.tooltipPool.addTooltip(tooltip)
}
}
def onHoverLeave(): Unit = {
closeTooltip()
}
private def closeTooltip(): Unit = {
for (tooltip <- _tooltip) {
root.get.tooltipPool.closeTooltip(tooltip)
}
}
eventHandlers += {
case ClickEvent(MouseEvent.Button.Left, _) if lmbMenuEnabled =>
val menu = new ContextMenu
fillLmbMenu(menu)
root.get.contextMenus.open(menu)
root.get.contextMenus.open(new ItemChooser(this))
case ClickEvent(MouseEvent.Button.Right, _) if rmbMenuEnabled =>
val menu = new ContextMenu
fillRmbMenu(menu)
root.get.contextMenus.open(menu)
case HoverEvent(state) =>
if (state == HoverEvent.State.Enter)
onHoverEnter()
else
onHoverLeave()
case HoverEvent(HoverEvent.State.Enter) => onHoverEnter()
case HoverEvent(HoverEvent.State.Leave) => onHoverLeave()
}
def onHoverEnter(): Unit = {}
def onHoverLeave(): Unit = {}
final override def draw(g: Graphics): Unit = {
g.sprite("EmptySlot", bounds)
val iconBounds = bounds.inflate(-2)
if (itemIcon.isDefined) {
g.sprite(itemIcon.get, iconBounds)
} else {
if (tierIcon.isDefined) g.sprite(tierIcon.get, iconBounds)
g.sprite(icon, iconBounds)
itemIcon match {
case Some(itemIcon) => g.sprite(itemIcon, iconBounds)
case None =>
for (tierIcon <- tierIcon) {
g.sprite(tierIcon, iconBounds)
}
for (ghostIcon <- ghostIcon) {
g.sprite(ghostIcon, iconBounds)
}
}
}
}

View File

@ -1,153 +0,0 @@
package ocelot.desktop.ui.widget.slot.reimpl
import ocelot.desktop.audio.SoundSources
import ocelot.desktop.geometry.Size2D
import ocelot.desktop.graphics.{Graphics, IconDef, Icons}
import ocelot.desktop.inventory.{Inventory, Item, ItemFactory}
import ocelot.desktop.ui.event.handlers.{ClickHandler, HoverHandler}
import ocelot.desktop.ui.event.{ClickEvent, HoverEvent, MouseEvent}
import ocelot.desktop.ui.widget.Widget
import ocelot.desktop.ui.widget.contextmenu.{ContextMenu, ContextMenuEntry}
import ocelot.desktop.ui.widget.slot.ItemChooser
import ocelot.desktop.ui.widget.tooltip.Tooltip
import totoro.ocelot.brain.util.Tier
import totoro.ocelot.brain.util.Tier.Tier
import scala.math.Ordering.Implicits.infixOrderingOps
import scala.reflect.ClassTag
class SlotWidget[I <: Item](private val slot: Inventory#Slot)(implicit slotItemTag: ClassTag[I])
extends Widget
with ClickHandler
with HoverHandler {
slotWidget =>
// NOTE: this must remain as a separate object
// (i. e. don't you dare inline it into the addObserver call below):
// this is the only strong reference to the observer
private val observer = new Inventory.SlotObserver {
override def onItemAdded(): Unit = {
slotWidget.onItemAdded()
}
override def onItemRemoved(removedItem: Item, replacedBy: Option[Item]): Unit = {
slotWidget.onItemRemoved(removedItem.asInstanceOf[I], replacedBy.map(_.asInstanceOf[I]))
}
override def onItemSpecificEvent(payload: AnyRef): Unit = {
slotWidget.onItemSpecificEvent(payload)
}
}
slot.addObserver(observer)
def dispose(): Unit = {
closeTooltip()
slot.removeObserver(observer)
}
def ghostIcon: Option[IconDef] = None
def slotTier: Option[Tier] = None
def tierIcon: Option[IconDef] = slotTier.map(Icons.TierIcon)
def itemIcon: Option[IconDef] = item.map(_.icon)
def item: Option[I] = slot.get.map(_.asInstanceOf[I])
def item_=(item: Option[I]): Unit = {
slot.set(item.map(_.asInstanceOf[slot.inventory.I]))
}
def item_=(item: I): Unit = {
slot.put(item.asInstanceOf[slot.inventory.I])
}
def isItemAccepted(factory: ItemFactory): Boolean = {
// yes, you can compare Options. isn't it nice?
slotItemTag.runtimeClass.isAssignableFrom(factory.itemClass) && factory.tier.map(_ min Tier.Three) <= slotTier
}
protected def onItemAdded(): Unit = {}
protected def onItemRemoved(removedItem: I, replacedBy: Option[I]): Unit = {
closeTooltip()
}
protected def onItemSpecificEvent(payload: AnyRef): Unit = {}
final override val minimumSize, maximumSize = Size2D(36, 36)
final override val receiveMouseEvents: Boolean = true
protected def lmbMenuEnabled: Boolean = true
protected def rmbMenuEnabled: Boolean = item.nonEmpty
protected def fillRmbMenu(menu: ContextMenu): Unit = {
for (item <- item) {
item.fillRmbMenu(menu)
menu.addEntry(
ContextMenuEntry("Remove", sound = SoundSources.InterfaceClickLow) {
slot.remove()
},
)
}
}
private var _tooltip: Option[Tooltip] = None
def onHoverEnter(): Unit = {
for (item <- item) {
// just in case
// closeTooltip()
val tooltip = item.tooltip
_tooltip = Some(tooltip)
root.get.tooltipPool.addTooltip(tooltip)
}
}
def onHoverLeave(): Unit = {
closeTooltip()
}
private def closeTooltip(): Unit = {
for (tooltip <- _tooltip) {
root.get.tooltipPool.closeTooltip(tooltip)
}
}
eventHandlers += {
case ClickEvent(MouseEvent.Button.Left, _) if lmbMenuEnabled =>
root.get.contextMenus.open(new ItemChooser(this))
case ClickEvent(MouseEvent.Button.Right, _) if rmbMenuEnabled =>
val menu = new ContextMenu
fillRmbMenu(menu)
root.get.contextMenus.open(menu)
case HoverEvent(HoverEvent.State.Enter) => onHoverEnter()
case HoverEvent(HoverEvent.State.Leave) => onHoverLeave()
}
final override def draw(g: Graphics): Unit = {
g.sprite("EmptySlot", bounds)
val iconBounds = bounds.inflate(-2)
itemIcon match {
case Some(itemIcon) => g.sprite(itemIcon, iconBounds)
case None =>
for (tierIcon <- tierIcon) {
g.sprite(tierIcon, iconBounds)
}
for (ghostIcon <- ghostIcon) {
g.sprite(ghostIcon, iconBounds)
}
}
}
}