diff --git a/src/main/scala/ocelot/desktop/node/nodes/ComputerNode.scala b/src/main/scala/ocelot/desktop/node/nodes/ComputerNode.scala index a194fbd..d68575c 100644 --- a/src/main/scala/ocelot/desktop/node/nodes/ComputerNode.scala +++ b/src/main/scala/ocelot/desktop/node/nodes/ComputerNode.scala @@ -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 diff --git a/src/main/scala/ocelot/desktop/node/nodes/DiskDriveNode.scala b/src/main/scala/ocelot/desktop/node/nodes/DiskDriveNode.scala index 4928755..f94cd7c 100644 --- a/src/main/scala/ocelot/desktop/node/nodes/DiskDriveNode.scala +++ b/src/main/scala/ocelot/desktop/node/nodes/DiskDriveNode.scala @@ -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 diff --git a/src/main/scala/ocelot/desktop/ui/widget/slot/CPUSlot.scala b/src/main/scala/ocelot/desktop/ui/widget/slot/CPUSlot.scala deleted file mode 100644 index f3b9d9d..0000000 --- a/src/main/scala/ocelot/desktop/ui/widget/slot/CPUSlot.scala +++ /dev/null @@ -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 -} diff --git a/src/main/scala/ocelot/desktop/ui/widget/slot/CardRegistry.scala b/src/main/scala/ocelot/desktop/ui/widget/slot/CardRegistry.scala deleted file mode 100644 index c4f0664..0000000 --- a/src/main/scala/ocelot/desktop/ui/widget/slot/CardRegistry.scala +++ /dev/null @@ -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) -} - diff --git a/src/main/scala/ocelot/desktop/ui/widget/slot/CardSlot.scala b/src/main/scala/ocelot/desktop/ui/widget/slot/CardSlot.scala deleted file mode 100644 index 2200c0a..0000000 --- a/src/main/scala/ocelot/desktop/ui/widget/slot/CardSlot.scala +++ /dev/null @@ -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 _ => - } - } -} diff --git a/src/main/scala/ocelot/desktop/ui/widget/slot/reimpl/CardSlotWidget.scala b/src/main/scala/ocelot/desktop/ui/widget/slot/CardSlotWidget.scala similarity index 89% rename from src/main/scala/ocelot/desktop/ui/widget/slot/reimpl/CardSlotWidget.scala rename to src/main/scala/ocelot/desktop/ui/widget/slot/CardSlotWidget.scala index d2507d9..46f76a1 100644 --- a/src/main/scala/ocelot/desktop/ui/widget/slot/reimpl/CardSlotWidget.scala +++ b/src/main/scala/ocelot/desktop/ui/widget/slot/CardSlotWidget.scala @@ -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 diff --git a/src/main/scala/ocelot/desktop/ui/widget/slot/reimpl/CpuSlotWidget.scala b/src/main/scala/ocelot/desktop/ui/widget/slot/CpuSlotWidget.scala similarity index 94% rename from src/main/scala/ocelot/desktop/ui/widget/slot/reimpl/CpuSlotWidget.scala rename to src/main/scala/ocelot/desktop/ui/widget/slot/CpuSlotWidget.scala index de7ffb4..ee2794c 100644 --- a/src/main/scala/ocelot/desktop/ui/widget/slot/reimpl/CpuSlotWidget.scala +++ b/src/main/scala/ocelot/desktop/ui/widget/slot/CpuSlotWidget.scala @@ -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 diff --git a/src/main/scala/ocelot/desktop/ui/widget/slot/DiskOrFloppySlot.scala b/src/main/scala/ocelot/desktop/ui/widget/slot/DiskOrFloppySlot.scala deleted file mode 100644 index c6dbdff..0000000 --- a/src/main/scala/ocelot/desktop/ui/widget/slot/DiskOrFloppySlot.scala +++ /dev/null @@ -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 - } - } - } - )) - } -} diff --git a/src/main/scala/ocelot/desktop/ui/widget/slot/DiskSlot.scala b/src/main/scala/ocelot/desktop/ui/widget/slot/DiskSlot.scala deleted file mode 100644 index f81afc0..0000000 --- a/src/main/scala/ocelot/desktop/ui/widget/slot/DiskSlot.scala +++ /dev/null @@ -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) -} diff --git a/src/main/scala/ocelot/desktop/ui/widget/slot/EEPROMSlot.scala b/src/main/scala/ocelot/desktop/ui/widget/slot/EEPROMSlot.scala deleted file mode 100644 index d15e1bb..0000000 --- a/src/main/scala/ocelot/desktop/ui/widget/slot/EEPROMSlot.scala +++ /dev/null @@ -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 - } - } -} diff --git a/src/main/scala/ocelot/desktop/ui/widget/slot/reimpl/EepromSlotWidget.scala b/src/main/scala/ocelot/desktop/ui/widget/slot/EepromSlotWidget.scala similarity index 86% rename from src/main/scala/ocelot/desktop/ui/widget/slot/reimpl/EepromSlotWidget.scala rename to src/main/scala/ocelot/desktop/ui/widget/slot/EepromSlotWidget.scala index 458bc64..a5a4cce 100644 --- a/src/main/scala/ocelot/desktop/ui/widget/slot/reimpl/EepromSlotWidget.scala +++ b/src/main/scala/ocelot/desktop/ui/widget/slot/EepromSlotWidget.scala @@ -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 diff --git a/src/main/scala/ocelot/desktop/ui/widget/slot/FloppySlot.scala b/src/main/scala/ocelot/desktop/ui/widget/slot/FloppySlot.scala deleted file mode 100644 index f59d8a3..0000000 --- a/src/main/scala/ocelot/desktop/ui/widget/slot/FloppySlot.scala +++ /dev/null @@ -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) -} \ No newline at end of file diff --git a/src/main/scala/ocelot/desktop/ui/widget/slot/reimpl/FloppySlotWidget.scala b/src/main/scala/ocelot/desktop/ui/widget/slot/FloppySlotWidget.scala similarity index 95% rename from src/main/scala/ocelot/desktop/ui/widget/slot/reimpl/FloppySlotWidget.scala rename to src/main/scala/ocelot/desktop/ui/widget/slot/FloppySlotWidget.scala index 709e841..534228c 100644 --- a/src/main/scala/ocelot/desktop/ui/widget/slot/reimpl/FloppySlotWidget.scala +++ b/src/main/scala/ocelot/desktop/ui/widget/slot/FloppySlotWidget.scala @@ -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} diff --git a/src/main/scala/ocelot/desktop/ui/widget/slot/reimpl/HddSlotWidget.scala b/src/main/scala/ocelot/desktop/ui/widget/slot/HddSlotWidget.scala similarity index 89% rename from src/main/scala/ocelot/desktop/ui/widget/slot/reimpl/HddSlotWidget.scala rename to src/main/scala/ocelot/desktop/ui/widget/slot/HddSlotWidget.scala index 2b20749..c8a1db3 100644 --- a/src/main/scala/ocelot/desktop/ui/widget/slot/reimpl/HddSlotWidget.scala +++ b/src/main/scala/ocelot/desktop/ui/widget/slot/HddSlotWidget.scala @@ -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 diff --git a/src/main/scala/ocelot/desktop/ui/widget/slot/InventorySlot.scala b/src/main/scala/ocelot/desktop/ui/widget/slot/InventorySlot.scala deleted file mode 100644 index 691732d..0000000 --- a/src/main/scala/ocelot/desktop/ui/widget/slot/InventorySlot.scala +++ /dev/null @@ -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]) -} diff --git a/src/main/scala/ocelot/desktop/ui/widget/slot/ItemChooser.scala b/src/main/scala/ocelot/desktop/ui/widget/slot/ItemChooser.scala index af15bdf..d024b2c 100644 --- a/src/main/scala/ocelot/desktop/ui/widget/slot/ItemChooser.scala +++ b/src/main/scala/ocelot/desktop/ui/widget/slot/ItemChooser.scala @@ -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} diff --git a/src/main/scala/ocelot/desktop/ui/widget/slot/MemorySlot.scala b/src/main/scala/ocelot/desktop/ui/widget/slot/MemorySlot.scala deleted file mode 100644 index bb36798..0000000 --- a/src/main/scala/ocelot/desktop/ui/widget/slot/MemorySlot.scala +++ /dev/null @@ -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) -} diff --git a/src/main/scala/ocelot/desktop/ui/widget/slot/reimpl/MemorySlotWidget.scala b/src/main/scala/ocelot/desktop/ui/widget/slot/MemorySlotWidget.scala similarity index 89% rename from src/main/scala/ocelot/desktop/ui/widget/slot/reimpl/MemorySlotWidget.scala rename to src/main/scala/ocelot/desktop/ui/widget/slot/MemorySlotWidget.scala index dc4583a..a94379d 100644 --- a/src/main/scala/ocelot/desktop/ui/widget/slot/reimpl/MemorySlotWidget.scala +++ b/src/main/scala/ocelot/desktop/ui/widget/slot/MemorySlotWidget.scala @@ -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 diff --git a/src/main/scala/ocelot/desktop/ui/widget/slot/SlotWidget.scala b/src/main/scala/ocelot/desktop/ui/widget/slot/SlotWidget.scala index f89ad9f..b0f551a 100644 --- a/src/main/scala/ocelot/desktop/ui/widget/slot/SlotWidget.scala +++ b/src/main/scala/ocelot/desktop/ui/widget/slot/SlotWidget.scala @@ -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) + } } } } diff --git a/src/main/scala/ocelot/desktop/ui/widget/slot/reimpl/SlotWidget.scala b/src/main/scala/ocelot/desktop/ui/widget/slot/reimpl/SlotWidget.scala deleted file mode 100644 index 28e5ceb..0000000 --- a/src/main/scala/ocelot/desktop/ui/widget/slot/reimpl/SlotWidget.scala +++ /dev/null @@ -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) - } - } - } -}