From 8beb0a9ae5157e2604686ffea003aaf7fd00f9d2 Mon Sep 17 00:00:00 2001 From: alyosha-tas Date: Mon, 7 Oct 2019 20:04:57 -0400 Subject: [PATCH 001/166] GBHawk: MBC3: fix RTC --- .../Nintendo/GBHawk/Mappers/Mapper_MBC3.cs | 24 ++++++++++--------- 1 file changed, 13 insertions(+), 11 deletions(-) diff --git a/BizHawk.Emulation.Cores/Consoles/Nintendo/GBHawk/Mappers/Mapper_MBC3.cs b/BizHawk.Emulation.Cores/Consoles/Nintendo/GBHawk/Mappers/Mapper_MBC3.cs index 378d156429..2cf79faa8c 100644 --- a/BizHawk.Emulation.Cores/Consoles/Nintendo/GBHawk/Mappers/Mapper_MBC3.cs +++ b/BizHawk.Emulation.Cores/Consoles/Nintendo/GBHawk/Mappers/Mapper_MBC3.cs @@ -61,7 +61,7 @@ namespace BizHawk.Emulation.Cores.Nintendo.GBHawk { if (RAM_enable) { - if ((Core.cart_RAM != null) && (RAM_bank < 3)) + if ((Core.cart_RAM != null) && (RAM_bank <= RAM_mask)) { if (((addr - 0xA000) + RAM_bank * 0x2000) < Core.cart_RAM.Length) { @@ -73,18 +73,18 @@ namespace BizHawk.Emulation.Cores.Nintendo.GBHawk } } - if ((RAM_bank >= 8) && (RAM_bank < 0xC)) + if ((RAM_bank >= 8) && (RAM_bank <= 0xC)) { return RTC_regs_latch[RAM_bank - 8]; } else { - return 0xFF; + return 0x0; } } else { - return 0xFF; + return 0x0; } } } @@ -103,7 +103,7 @@ namespace BizHawk.Emulation.Cores.Nintendo.GBHawk { if (RAM_enable) { - if ((Core.cart_RAM != null) && (RAM_bank < 3)) + if ((Core.cart_RAM != null) && (RAM_bank <= RAM_mask)) { if (((addr - 0xA000) + RAM_bank * 0x2000) < Core.cart_RAM.Length) { @@ -115,7 +115,7 @@ namespace BizHawk.Emulation.Cores.Nintendo.GBHawk } } - if ((RAM_bank >= 8) && (RAM_bank < 0xC)) + if ((RAM_bank >= 8) && (RAM_bank <= 0xC)) { return; } @@ -141,7 +141,7 @@ namespace BizHawk.Emulation.Cores.Nintendo.GBHawk if (addr < 0x8000) { if (addr < 0x2000) - { + { RAM_enable = ((value & 0xA) == 0xA); } else if (addr < 0x4000) @@ -156,7 +156,7 @@ namespace BizHawk.Emulation.Cores.Nintendo.GBHawk } else if (addr < 0x6000) { - RAM_bank = value & 3; + RAM_bank = value; } else { @@ -175,17 +175,19 @@ namespace BizHawk.Emulation.Cores.Nintendo.GBHawk { if (RAM_enable) { - if ((Core.cart_RAM != null) && (RAM_bank <= 3)) + if ((Core.cart_RAM != null) && (RAM_bank <= RAM_mask)) { if (((addr - 0xA000) + RAM_bank * 0x2000) < Core.cart_RAM.Length) { Core.cart_RAM[(addr - 0xA000) + RAM_bank * 0x2000] = value; } } - else if ((RAM_bank >= 8) && (RAM_bank < 0xC)) + else if ((RAM_bank >= 8) && (RAM_bank <= 0xC)) { RTC_regs[RAM_bank - 8] = value; + RTC_low_clock = RTC_timer = 0; + halt = (RTC_regs[4] & 0x40) > 0; } } @@ -219,6 +221,7 @@ namespace BizHawk.Emulation.Cores.Nintendo.GBHawk RTC_low_clock = 0; RTC_regs[0]++; + if (RTC_regs[0] > 59) { RTC_regs[0] = 0; @@ -255,7 +258,6 @@ namespace BizHawk.Emulation.Cores.Nintendo.GBHawk } } - public override void SyncState(Serializer ser) { ser.Sync(nameof(ROM_bank), ref ROM_bank); From 1c07d3d2adf2618ece6712c6449d877fe2ad0a4e Mon Sep 17 00:00:00 2001 From: alyosha-tas Date: Tue, 8 Oct 2019 08:54:50 -0400 Subject: [PATCH 002/166] GBHawk: fix IRQ clear timing --- .../CPUs/LR35902/Interrupts.cs | 5 +-- .../CPUs/LR35902/LR35902.cs | 31 ++++++++++++------- 2 files changed, 22 insertions(+), 14 deletions(-) diff --git a/BizHawk.Emulation.Cores/CPUs/LR35902/Interrupts.cs b/BizHawk.Emulation.Cores/CPUs/LR35902/Interrupts.cs index 12979e363d..57db8fea0d 100644 --- a/BizHawk.Emulation.Cores/CPUs/LR35902/Interrupts.cs +++ b/BizHawk.Emulation.Cores/CPUs/LR35902/Interrupts.cs @@ -25,7 +25,7 @@ namespace BizHawk.Emulation.Common.Components.LR35902 IDLE, TR, PCl, W, ASGN, PCh, 0, - IDLE, + IRQ_CLEAR, OP }; } @@ -54,13 +54,14 @@ namespace BizHawk.Emulation.Common.Components.LR35902 IDLE, IDLE, IDLE, - IDLE, + IRQ_CLEAR, OP }; } private static ushort[] INT_vectors = new ushort[] {0x40, 0x48, 0x50, 0x58, 0x60, 0x00}; public ushort int_src; + public byte int_clear; public int stop_time; public bool stop_check; public bool is_GBC; // GBC automatically adds a NOP to avoid the HALT bug (according to Sinimas) diff --git a/BizHawk.Emulation.Cores/CPUs/LR35902/LR35902.cs b/BizHawk.Emulation.Cores/CPUs/LR35902/LR35902.cs index 5977a4cabf..941179ed58 100644 --- a/BizHawk.Emulation.Cores/CPUs/LR35902/LR35902.cs +++ b/BizHawk.Emulation.Cores/CPUs/LR35902/LR35902.cs @@ -58,6 +58,7 @@ namespace BizHawk.Emulation.Common.Components.LR35902 public const ushort EI_RETI = 43; // reti has no delay in interrupt enable public const ushort INT_GET = 44; public const ushort HALT_CHK = 45; // when in halt mode, actually check I Flag here + public const ushort IRQ_CLEAR = 46; public LR35902() { @@ -520,15 +521,14 @@ namespace BizHawk.Emulation.Common.Components.LR35902 case INT_GET: // check if any interrupts got cancelled along the way // interrupt src = 5 sets the PC to zero as observed + // also the triggering interrupt seems like it is held low (i.e. annot trigger I flag) until the interrupt is serviced - if (interrupt_src.Bit(0) && interrupt_enable.Bit(0)) { int_src = 0; interrupt_src -= 1; } - else if (interrupt_src.Bit(1) && interrupt_enable.Bit(1)) { int_src = 1; interrupt_src -= 2; } - else if (interrupt_src.Bit(2) && interrupt_enable.Bit(2)) { int_src = 2; interrupt_src -= 4; } - else if (interrupt_src.Bit(3) && interrupt_enable.Bit(3)) { int_src = 3; interrupt_src -= 8; } - else if (interrupt_src.Bit(4) && interrupt_enable.Bit(4)) { int_src = 4; interrupt_src -= 16; } - else { int_src = 5; } - - if ((interrupt_src & interrupt_enable) == 0) { FlagI = false; } + if (interrupt_src.Bit(0) && interrupt_enable.Bit(0)) { int_src = 0; int_clear = 1; } + else if (interrupt_src.Bit(1) && interrupt_enable.Bit(1)) { int_src = 1; int_clear = 2; } + else if (interrupt_src.Bit(2) && interrupt_enable.Bit(2)) { int_src = 2; int_clear = 4; } + else if (interrupt_src.Bit(3) && interrupt_enable.Bit(3)) { int_src = 3; int_clear = 8; } + else if (interrupt_src.Bit(4) && interrupt_enable.Bit(4)) { int_src = 4; int_clear = 16; } + else { int_src = 5; int_clear = 0; } Regs[cur_instr[instr_pntr++]] = INT_vectors[int_src]; break; @@ -543,6 +543,12 @@ namespace BizHawk.Emulation.Common.Components.LR35902 } Halt_bug_2 = false; + break; + case IRQ_CLEAR: + if (interrupt_src.Bit(int_src)) { interrupt_src -= int_clear; } + + if ((interrupt_src & interrupt_enable) == 0) { FlagI = false; } + break; } TotalExecutedCycles++; @@ -591,23 +597,24 @@ namespace BizHawk.Emulation.Common.Components.LR35902 { ser.BeginSection(nameof(LR35902)); ser.Sync(nameof(Regs), ref Regs, false); - ser.Sync("IRQ", ref interrupts_enabled); + ser.Sync(nameof(interrupts_enabled), ref interrupts_enabled); ser.Sync(nameof(I_use), ref I_use); ser.Sync(nameof(skip_once), ref skip_once); ser.Sync(nameof(Halt_bug_2), ref Halt_bug_2); ser.Sync(nameof(Halt_bug_3), ref Halt_bug_3); - ser.Sync("Halted", ref halted); + ser.Sync(nameof(halted), ref halted); ser.Sync(nameof(TotalExecutedCycles), ref TotalExecutedCycles); ser.Sync(nameof(EI_pending), ref EI_pending); ser.Sync(nameof(int_src), ref int_src); + ser.Sync(nameof(int_clear), ref int_clear); ser.Sync(nameof(stop_time), ref stop_time); ser.Sync(nameof(stop_check), ref stop_check); ser.Sync(nameof(is_GBC), ref is_GBC); ser.Sync(nameof(instr_pntr), ref instr_pntr); ser.Sync(nameof(cur_instr), ref cur_instr, false); - ser.Sync("CB Prefix", ref CB_prefix); - ser.Sync("Stopped", ref stopped); + ser.Sync(nameof(CB_prefix), ref CB_prefix); + ser.Sync(nameof(stopped), ref stopped); ser.Sync(nameof(opcode), ref opcode); ser.Sync(nameof(jammed), ref jammed); ser.Sync(nameof(LY), ref LY); From a8080d129d5cd7309fddb26aeb8ed783914e107c Mon Sep 17 00:00:00 2001 From: alyosha-tas Date: Tue, 8 Oct 2019 19:21:40 -0400 Subject: [PATCH 003/166] GBHawK: HDMA and IRQ work --- .../CPUs/LR35902/Interrupts.cs | 14 +-- .../Consoles/Nintendo/GBHawk/GBC_PPU.cs | 93 ++++++++++--------- .../Consoles/Nintendo/GBHawk/GBC_PPU_GB.cs | 85 ++++++++++------- 3 files changed, 105 insertions(+), 87 deletions(-) diff --git a/BizHawk.Emulation.Cores/CPUs/LR35902/Interrupts.cs b/BizHawk.Emulation.Cores/CPUs/LR35902/Interrupts.cs index 57db8fea0d..ef770c94dd 100644 --- a/BizHawk.Emulation.Cores/CPUs/LR35902/Interrupts.cs +++ b/BizHawk.Emulation.Cores/CPUs/LR35902/Interrupts.cs @@ -13,13 +13,13 @@ namespace BizHawk.Emulation.Common.Components.LR35902 WR, SPl, SPh, PCh, IDLE, DEC16, SPl, SPh, - INT_GET, W,// NOTE: here is where we check for a cancelled IRQ + IDLE, WR, SPl, SPh, PCl, IDLE, IDLE, IDLE, IDLE, - IDLE, + INT_GET, W,// NOTE: here is where we check for a cancelled IRQ IDLE, IDLE, IDLE, @@ -37,23 +37,23 @@ namespace BizHawk.Emulation.Common.Components.LR35902 IDLE, WR, SPl, SPh, PCh, IDLE, - INT_GET, W,// NOTE: here is where we check for a cancelled IRQ DEC16, SPl, SPh, + IDLE, WR, SPl, SPh, PCl, IDLE, IDLE, IDLE, IDLE, + IDLE, + INT_GET, W,// NOTE: here is where we check for a cancelled IRQ + IDLE, TR, PCl, W, + IDLE, ASGN, PCh, 0, IDLE, IDLE, IDLE, IDLE, - IDLE, - IDLE, - IDLE, - IDLE, IRQ_CLEAR, OP }; } diff --git a/BizHawk.Emulation.Cores/Consoles/Nintendo/GBHawk/GBC_PPU.cs b/BizHawk.Emulation.Cores/Consoles/Nintendo/GBHawk/GBC_PPU.cs index b01c838a25..4984fa8ea3 100644 --- a/BizHawk.Emulation.Cores/Consoles/Nintendo/GBHawk/GBC_PPU.cs +++ b/BizHawk.Emulation.Cores/Consoles/Nintendo/GBHawk/GBC_PPU.cs @@ -275,12 +275,16 @@ namespace BizHawk.Emulation.Cores.Nintendo.GBHawk // Do HDMA ticks if (HDMA_active) { - if (HDMA_countdown == 0) + if (HDMA_length > 0) { - if (HDMA_length > 0) + if (!HDMA_mode) { - if (!HDMA_mode) + if (HDMA_countdown > 0) { + HDMA_countdown--; + } + else + { // immediately transfer bytes, 2 bytes per cycles if ((HDMA_tick % 2) == 0) { @@ -296,25 +300,32 @@ namespace BizHawk.Emulation.Cores.Nintendo.GBHawk HDMA_tick++; } - else + } + else + { + // only transfer during mode 0, and only 16 bytes at a time + if (((STAT & 3) == 0) && (LY != last_HBL) && HBL_test && (LY_inc == 1) && (cycle > 4)) { - // only transfer during mode 0, and only 16 bytes at a time - if (((STAT & 3) == 0) && (LY != last_HBL) && HBL_test && (LY_inc == 1) && (cycle > 4)) - { - HBL_HDMA_go = true; - HBL_test = false; - } - else if (HDMA_run_once) - { - HBL_HDMA_go = true; - HBL_test = false; - HDMA_run_once = false; - } + HBL_HDMA_go = true; + HBL_test = false; + } + else if (HDMA_run_once) + { + HBL_HDMA_go = true; + HBL_test = false; + HDMA_run_once = false; + } - if (HBL_HDMA_go && (HBL_HDMA_count > 0)) - { - Core.HDMA_transfer = true; + if (HBL_HDMA_go && (HBL_HDMA_count > 0)) + { + Core.HDMA_transfer = true; + if (HDMA_countdown > 0) + { + HDMA_countdown--; + } + else + { if ((HDMA_tick % 2) == 0) { HDMA_byte = Core.ReadMemory(cur_DMA_src); @@ -338,25 +349,20 @@ namespace BizHawk.Emulation.Cores.Nintendo.GBHawk } HDMA_tick++; - } - else - { - Core.HDMA_transfer = false; - } - } - } - else - { - HDMA_active = false; - Core.HDMA_transfer = false; - } + } + } + else + { + Core.HDMA_transfer = false; + } + } } else { - HDMA_countdown--; + HDMA_active = false; + Core.HDMA_transfer = false; } - } - + } // the ppu only does anything if it is turned on via bit 7 of LCDC if (LCDC.Bit(7)) @@ -643,15 +649,13 @@ namespace BizHawk.Emulation.Cores.Nintendo.GBHawk { if (Core.REG_FFFF.Bit(1)) { Core.cpu.FlagI = true; } Core.REG_FF0F |= 0x02; - - /* - if (Core.cpu.cur_instr[Core.cpu.instr_pntr] == 46) - { - Console.Write(VBL_INT + " " + LYC_INT + " " + HBL_INT + " " + OAM_INT + " "); + + //if (Core.cpu.cur_instr[Core.cpu.instr_pntr] == 46) + //{ + //Console.Write(VBL_INT + " " + LYC_INT + " " + HBL_INT + " " + OAM_INT + " "); //Core.last_rise = Core.cpu.TotalExecutedCycles; - Console.WriteLine(STAT + " " + cycle + " " + Core.cpu.TotalExecutedCycles); - } - */ + //Console.WriteLine(STAT + " " + cycle + " " + Core.cpu.TotalExecutedCycles); + //} } stat_line_old = stat_line; @@ -1103,6 +1107,7 @@ namespace BizHawk.Emulation.Cores.Nintendo.GBHawk if (hbl_countdown > 0) { hbl_countdown--; + if (hbl_countdown == 0) { STAT &= 0xFC; @@ -1482,8 +1487,8 @@ namespace BizHawk.Emulation.Cores.Nintendo.GBHawk public override void SyncState(Serializer ser) { - ser.Sync("pal_transfer_byte", ref BG_transfer_byte); - ser.Sync("spr_transfer_byte", ref OBJ_transfer_byte); + ser.Sync(nameof(BG_transfer_byte), ref BG_transfer_byte); + ser.Sync(nameof(OBJ_transfer_byte), ref OBJ_transfer_byte); ser.Sync(nameof(HDMA_src_hi), ref HDMA_src_hi); ser.Sync(nameof(HDMA_src_lo), ref HDMA_src_lo); ser.Sync(nameof(HDMA_dest_hi), ref HDMA_dest_hi); diff --git a/BizHawk.Emulation.Cores/Consoles/Nintendo/GBHawk/GBC_PPU_GB.cs b/BizHawk.Emulation.Cores/Consoles/Nintendo/GBHawk/GBC_PPU_GB.cs index 2783900a95..368a86460e 100644 --- a/BizHawk.Emulation.Cores/Consoles/Nintendo/GBHawk/GBC_PPU_GB.cs +++ b/BizHawk.Emulation.Cores/Consoles/Nintendo/GBHawk/GBC_PPU_GB.cs @@ -48,6 +48,7 @@ namespace BizHawk.Emulation.Cores.Nintendo.GBHawk public int VRAM_sel; public bool BG_V_flip; public bool HDMA_mode; + public bool HDMA_run_once; public ushort cur_DMA_src; public ushort cur_DMA_dest; public int HDMA_length; @@ -211,17 +212,15 @@ namespace BizHawk.Emulation.Cores.Nintendo.GBHawk HBL_HDMA_count = 0x10; // TODO: DOES HDMA start if triggered in mode 0 immediately? (for now assume no) - if ((STAT & 3) == 0) - { - last_HBL = LY; - } - else - { - last_HBL = LY - 1; - } - + last_HBL = LY - 1; + HBL_test = true; HBL_HDMA_go = false; + + if (!LCDC.Bit(7)) + { + HDMA_run_once = true; + } } else { @@ -278,11 +277,15 @@ namespace BizHawk.Emulation.Cores.Nintendo.GBHawk // Do HDMA ticks if (HDMA_active) { - if (HDMA_countdown == 0) + if (HDMA_length > 0) { - if (HDMA_length > 0) + if (!HDMA_mode) { - if (!HDMA_mode) + if (HDMA_countdown > 0) + { + HDMA_countdown--; + } + else { // immediately transfer bytes, 2 bytes per cycles if ((HDMA_tick % 2) == 0) @@ -299,19 +302,32 @@ namespace BizHawk.Emulation.Cores.Nintendo.GBHawk HDMA_tick++; } - else + } + else + { + // only transfer during mode 0, and only 16 bytes at a time + if (((STAT & 3) == 0) && (LY != last_HBL) && HBL_test && (LY_inc == 1) && (cycle > 4)) { - // only transfer during mode 0, and only 16 bytes at a time - if (((STAT & 3) == 0) && (LY != last_HBL) && HBL_test && (LY_inc == 1)) + HBL_HDMA_go = true; + HBL_test = false; + } + else if (HDMA_run_once) + { + HBL_HDMA_go = true; + HBL_test = false; + HDMA_run_once = false; + } + + if (HBL_HDMA_go && (HBL_HDMA_count > 0)) + { + Core.HDMA_transfer = true; + + if (HDMA_countdown > 0) { - HBL_HDMA_go = true; - HBL_test = false; + HDMA_countdown--; } - - if (HBL_HDMA_go && (HBL_HDMA_count > 0)) + else { - Core.HDMA_transfer = true; - if ((HDMA_tick % 2) == 0) { HDMA_byte = Core.ReadMemory(cur_DMA_src); @@ -327,6 +343,7 @@ namespace BizHawk.Emulation.Cores.Nintendo.GBHawk if ((HBL_HDMA_count == 0) && (HDMA_length != 0)) { + HBL_test = true; last_HBL = LY; HBL_HDMA_count = 0x10; @@ -335,25 +352,20 @@ namespace BizHawk.Emulation.Cores.Nintendo.GBHawk HDMA_tick++; } - else - { - Core.HDMA_transfer = false; - } - } - } - else - { - HDMA_active = false; - Core.HDMA_transfer = false; + } + else + { + Core.HDMA_transfer = false; + } } } else { - HDMA_countdown--; + HDMA_active = false; + Core.HDMA_transfer = false; } } - - + // the ppu only does anything if it is turned on via bit 7 of LCDC if (LCDC.Bit(7)) { @@ -1535,8 +1547,8 @@ namespace BizHawk.Emulation.Cores.Nintendo.GBHawk public override void SyncState(Serializer ser) { - ser.Sync("pal_transfer_byte", ref BG_transfer_byte); - ser.Sync("spr_transfer_byte", ref OBJ_transfer_byte); + ser.Sync(nameof(BG_transfer_byte), ref BG_transfer_byte); + ser.Sync(nameof(OBJ_transfer_byte), ref OBJ_transfer_byte); ser.Sync(nameof(HDMA_src_hi), ref HDMA_src_hi); ser.Sync(nameof(HDMA_src_lo), ref HDMA_src_lo); ser.Sync(nameof(HDMA_dest_hi), ref HDMA_dest_hi); @@ -1547,6 +1559,7 @@ namespace BizHawk.Emulation.Cores.Nintendo.GBHawk ser.Sync(nameof(VRAM_sel), ref VRAM_sel); ser.Sync(nameof(BG_V_flip), ref BG_V_flip); ser.Sync(nameof(HDMA_mode), ref HDMA_mode); + ser.Sync(nameof(HDMA_run_once), ref HDMA_run_once); ser.Sync(nameof(cur_DMA_src), ref cur_DMA_src); ser.Sync(nameof(cur_DMA_dest), ref cur_DMA_dest); ser.Sync(nameof(HDMA_length), ref HDMA_length); From 724a3783f1385259591a22326117513319f0d497 Mon Sep 17 00:00:00 2001 From: alyosha-tas Date: Tue, 8 Oct 2019 20:26:24 -0400 Subject: [PATCH 004/166] GBHawk: more hdma work --- BizHawk.Emulation.Cores/Consoles/Nintendo/GBHawk/GBC_PPU.cs | 1 + BizHawk.Emulation.Cores/Consoles/Nintendo/GBHawk/GBC_PPU_GB.cs | 1 + 2 files changed, 2 insertions(+) diff --git a/BizHawk.Emulation.Cores/Consoles/Nintendo/GBHawk/GBC_PPU.cs b/BizHawk.Emulation.Cores/Consoles/Nintendo/GBHawk/GBC_PPU.cs index 4984fa8ea3..59592a9834 100644 --- a/BizHawk.Emulation.Cores/Consoles/Nintendo/GBHawk/GBC_PPU.cs +++ b/BizHawk.Emulation.Cores/Consoles/Nintendo/GBHawk/GBC_PPU.cs @@ -346,6 +346,7 @@ namespace BizHawk.Emulation.Cores.Nintendo.GBHawk last_HBL = LY; HBL_HDMA_count = 0x10; HBL_HDMA_go = false; + HDMA_countdown = 4; } HDMA_tick++; diff --git a/BizHawk.Emulation.Cores/Consoles/Nintendo/GBHawk/GBC_PPU_GB.cs b/BizHawk.Emulation.Cores/Consoles/Nintendo/GBHawk/GBC_PPU_GB.cs index 368a86460e..2f92074551 100644 --- a/BizHawk.Emulation.Cores/Consoles/Nintendo/GBHawk/GBC_PPU_GB.cs +++ b/BizHawk.Emulation.Cores/Consoles/Nintendo/GBHawk/GBC_PPU_GB.cs @@ -348,6 +348,7 @@ namespace BizHawk.Emulation.Cores.Nintendo.GBHawk last_HBL = LY; HBL_HDMA_count = 0x10; HBL_HDMA_go = false; + HDMA_countdown = 4; } HDMA_tick++; From f765e4257843ebd9dc6844817e445f322b7ceedc Mon Sep 17 00:00:00 2001 From: alyosha-tas Date: Wed, 9 Oct 2019 12:46:48 -0400 Subject: [PATCH 005/166] GBHawk: more IRQ timing --- .../CPUs/LR35902/Interrupts.cs | 16 +++++----- .../Consoles/Nintendo/GBHawk/Audio.cs | 31 +++++-------------- .../Consoles/Nintendo/GBHawk/GBC_PPU.cs | 8 +++-- .../Consoles/Nintendo/GBHawk/GBC_PPU_GB.cs | 4 +-- 4 files changed, 22 insertions(+), 37 deletions(-) diff --git a/BizHawk.Emulation.Cores/CPUs/LR35902/Interrupts.cs b/BizHawk.Emulation.Cores/CPUs/LR35902/Interrupts.cs index ef770c94dd..2f2d8a5185 100644 --- a/BizHawk.Emulation.Cores/CPUs/LR35902/Interrupts.cs +++ b/BizHawk.Emulation.Cores/CPUs/LR35902/Interrupts.cs @@ -19,13 +19,13 @@ namespace BizHawk.Emulation.Common.Components.LR35902 IDLE, IDLE, IDLE, - INT_GET, W,// NOTE: here is where we check for a cancelled IRQ IDLE, - IDLE, - IDLE, - TR, PCl, W, ASGN, PCh, 0, + IDLE, + INT_GET, W,// NOTE: here is where we check for a cancelled IRQ + TR, PCl, W, IRQ_CLEAR, + IDLE, OP }; } @@ -45,16 +45,16 @@ namespace BizHawk.Emulation.Common.Components.LR35902 IDLE, IDLE, IDLE, + IDLE, + IDLE, + IDLE, INT_GET, W,// NOTE: here is where we check for a cancelled IRQ IDLE, TR, PCl, W, IDLE, ASGN, PCh, 0, - IDLE, - IDLE, - IDLE, - IDLE, IRQ_CLEAR, + IDLE, OP }; } diff --git a/BizHawk.Emulation.Cores/Consoles/Nintendo/GBHawk/Audio.cs b/BizHawk.Emulation.Cores/Consoles/Nintendo/GBHawk/Audio.cs index 537f03ae7b..b653dac9c2 100644 --- a/BizHawk.Emulation.Cores/Consoles/Nintendo/GBHawk/Audio.cs +++ b/BizHawk.Emulation.Cores/Consoles/Nintendo/GBHawk/Audio.cs @@ -91,7 +91,6 @@ namespace BizHawk.Emulation.Cores.Nintendo.GBHawk public ushort SQ1_len_cntr, SQ2_len_cntr, WAVE_len_cntr, NOISE_len_cntr; // computed public int SQ1_output, SQ2_output, WAVE_output, NOISE_output; - public float WAVE_output_decay, WAVE_output_decay_L, WAVE_output_decay_R; // Contol Variables public bool AUD_CTRL_vin_L_en; @@ -665,7 +664,6 @@ namespace BizHawk.Emulation.Cores.Nintendo.GBHawk } WAVE_output = sample; - WAVE_output_decay = WAVE_output; // NOTE: The sample buffer is only reloaded after the current sample is played, even if just triggered WAVE_wave_cntr++; @@ -673,13 +671,6 @@ namespace BizHawk.Emulation.Cores.Nintendo.GBHawk sample = Wave_RAM[WAVE_wave_cntr >> 1]; } } - else - { - // there is a considerable decay time involved in turning off a channel - WAVE_output_decay = (float)(WAVE_output_decay * 0.999958); - WAVE_output = (int)Math.Round(WAVE_output_decay); - } - // calculate noise output if (NOISE_enable) @@ -710,14 +701,12 @@ namespace BizHawk.Emulation.Cores.Nintendo.GBHawk if (AUD_CTRL_sq1_L_en) { L_final += SQ1_output; } if (AUD_CTRL_sq2_L_en) { L_final += SQ2_output; } - if (AUD_CTRL_wave_L_en) { L_final += WAVE_output; WAVE_output_decay_L = WAVE_output; } - else { L_final += (int)Math.Round(WAVE_output_decay_L); WAVE_output_decay_L = (float)(WAVE_output_decay_L * 0.999985); } + if (AUD_CTRL_wave_L_en) { L_final += WAVE_output;} if (AUD_CTRL_noise_L_en) { L_final += NOISE_output; } if (AUD_CTRL_sq1_R_en) { R_final += SQ1_output; } if (AUD_CTRL_sq2_R_en) { R_final += SQ2_output; } - if (AUD_CTRL_wave_R_en) { R_final += WAVE_output; WAVE_output_decay_R = WAVE_output; } - else { R_final += (int)Math.Round(WAVE_output_decay_R); WAVE_output_decay_R = (float)(WAVE_output_decay_R * 0.999985); } + if (AUD_CTRL_wave_R_en) { R_final += WAVE_output; } if (AUD_CTRL_noise_R_en) { R_final += NOISE_output; } L_final *= (AUD_CTRL_vol_L + 1) * 40; @@ -957,12 +946,12 @@ namespace BizHawk.Emulation.Cores.Nintendo.GBHawk public void SyncState(Serializer ser) { ser.Sync(nameof(Audio_Regs), ref Audio_Regs, false); - ser.Sync("Wave_Ram", ref Wave_RAM, false); + ser.Sync(nameof(Wave_RAM), ref Wave_RAM, false); ser.Sync(nameof(SQ1_vol_done), ref SQ1_vol_done); ser.Sync(nameof(SQ1_calc_done), ref SQ1_calc_done); ser.Sync(nameof(SQ1_swp_enable), ref SQ1_swp_enable); - ser.Sync("SQ1_length_counter", ref SQ1_len_cntr); + ser.Sync(nameof(SQ1_len_cntr), ref SQ1_len_cntr); ser.Sync(nameof(SQ1_enable), ref SQ1_enable); ser.Sync(nameof(SQ1_vol_state), ref SQ1_vol_state); ser.Sync(nameof(SQ1_duty_cntr), ref SQ1_duty_cntr); @@ -985,7 +974,7 @@ namespace BizHawk.Emulation.Cores.Nintendo.GBHawk ser.Sync(nameof(SQ1_output), ref SQ1_output); ser.Sync(nameof(SQ2_vol_done), ref SQ2_vol_done); - ser.Sync("SQ2_length_counter", ref SQ2_len_cntr); + ser.Sync(nameof(SQ2_len_cntr), ref SQ2_len_cntr); ser.Sync(nameof(SQ2_enable), ref SQ2_enable); ser.Sync(nameof(SQ2_vol_state), ref SQ2_vol_state); ser.Sync(nameof(SQ2_duty_cntr), ref SQ2_duty_cntr); @@ -1003,7 +992,7 @@ namespace BizHawk.Emulation.Cores.Nintendo.GBHawk ser.Sync(nameof(SQ2_output), ref SQ2_output); ser.Sync(nameof(WAVE_can_get), ref WAVE_can_get); - ser.Sync("WAVE_length_counter", ref WAVE_len_cntr); + ser.Sync(nameof(WAVE_len_cntr), ref WAVE_len_cntr); ser.Sync(nameof(WAVE_enable), ref WAVE_enable); ser.Sync(nameof(WAVE_wave_cntr), ref WAVE_wave_cntr); ser.Sync(nameof(WAVE_intl_cntr), ref WAVE_intl_cntr); @@ -1017,7 +1006,7 @@ namespace BizHawk.Emulation.Cores.Nintendo.GBHawk ser.Sync(nameof(WAVE_output), ref WAVE_output); ser.Sync(nameof(NOISE_vol_done), ref NOISE_vol_done); - ser.Sync("NOISE_length_counter", ref NOISE_len_cntr); + ser.Sync(nameof(NOISE_len_cntr), ref NOISE_len_cntr); ser.Sync(nameof(NOISE_enable), ref NOISE_enable); ser.Sync(nameof(NOISE_vol_state), ref NOISE_vol_state); ser.Sync(nameof(NOISE_intl_cntr), ref NOISE_intl_cntr); @@ -1059,17 +1048,13 @@ namespace BizHawk.Emulation.Cores.Nintendo.GBHawk ser.Sync(nameof(AUD_CTRL_power), ref AUD_CTRL_power); ser.Sync(nameof(AUD_CTRL_vol_L), ref AUD_CTRL_vol_L); ser.Sync(nameof(AUD_CTRL_vol_R), ref AUD_CTRL_vol_R); - - ser.Sync(nameof(WAVE_output_decay), ref WAVE_output_decay); - ser.Sync(nameof(WAVE_output_decay_L), ref WAVE_output_decay_L); - ser.Sync(nameof(WAVE_output_decay_R), ref WAVE_output_decay_R); } public byte Read_NR52() { return (byte)( ((AUD_CTRL_power ? 1 : 0) << 7) | - ((SQ1_enable ? 1 : 0)) | + (SQ1_enable ? 1 : 0) | ((SQ2_enable ? 1 : 0) << 1) | ((WAVE_enable ? 1 : 0) << 2) | ((NOISE_enable ? 1 : 0) << 3)); diff --git a/BizHawk.Emulation.Cores/Consoles/Nintendo/GBHawk/GBC_PPU.cs b/BizHawk.Emulation.Cores/Consoles/Nintendo/GBHawk/GBC_PPU.cs index 59592a9834..09442d581e 100644 --- a/BizHawk.Emulation.Cores/Consoles/Nintendo/GBHawk/GBC_PPU.cs +++ b/BizHawk.Emulation.Cores/Consoles/Nintendo/GBHawk/GBC_PPU.cs @@ -1108,19 +1108,21 @@ namespace BizHawk.Emulation.Cores.Nintendo.GBHawk if (hbl_countdown > 0) { hbl_countdown--; - + if (hbl_countdown == 0) { STAT &= 0xFC; STAT |= 0x00; - if (STAT.Bit(3)) { HBL_INT = true; } - OAM_access_read = true; OAM_access_write = true; VRAM_access_read = true; VRAM_access_write = true; } + else + { + if (STAT.Bit(3)) { HBL_INT = true; } + } } break; diff --git a/BizHawk.Emulation.Cores/Consoles/Nintendo/GBHawk/GBC_PPU_GB.cs b/BizHawk.Emulation.Cores/Consoles/Nintendo/GBHawk/GBC_PPU_GB.cs index 2f92074551..f5e7b86a11 100644 --- a/BizHawk.Emulation.Cores/Consoles/Nintendo/GBHawk/GBC_PPU_GB.cs +++ b/BizHawk.Emulation.Cores/Consoles/Nintendo/GBHawk/GBC_PPU_GB.cs @@ -1144,12 +1144,10 @@ namespace BizHawk.Emulation.Cores.Nintendo.GBHawk hbl_countdown--; if (hbl_countdown == 0) { - - OAM_access_read = true; OAM_access_write = true; VRAM_access_read = true; - VRAM_access_write = true; + VRAM_access_write = true; } else { From 78cbb9aac50bfbce4d857b1b9868645940982ef3 Mon Sep 17 00:00:00 2001 From: alyosha-tas Date: Wed, 9 Oct 2019 16:37:09 -0400 Subject: [PATCH 006/166] GBHawk: fix window timing, special cases still need work --- .../Consoles/Nintendo/GBHawk/GBC_PPU.cs | 20 ++++++++++++++----- .../Consoles/Nintendo/GBHawk/GBC_PPU_GB.cs | 13 ++++++++++-- .../Consoles/Nintendo/GBHawk/GB_PPU.cs | 11 ++++++++-- 3 files changed, 35 insertions(+), 9 deletions(-) diff --git a/BizHawk.Emulation.Cores/Consoles/Nintendo/GBHawk/GBC_PPU.cs b/BizHawk.Emulation.Cores/Consoles/Nintendo/GBHawk/GBC_PPU.cs index 09442d581e..75f1324678 100644 --- a/BizHawk.Emulation.Cores/Consoles/Nintendo/GBHawk/GBC_PPU.cs +++ b/BizHawk.Emulation.Cores/Consoles/Nintendo/GBHawk/GBC_PPU.cs @@ -651,10 +651,10 @@ namespace BizHawk.Emulation.Cores.Nintendo.GBHawk if (Core.REG_FFFF.Bit(1)) { Core.cpu.FlagI = true; } Core.REG_FF0F |= 0x02; - //if (Core.cpu.cur_instr[Core.cpu.instr_pntr] == 46) + //if (LY == 46) //{ - //Console.Write(VBL_INT + " " + LYC_INT + " " + HBL_INT + " " + OAM_INT + " "); - //Core.last_rise = Core.cpu.TotalExecutedCycles; + //Console.Write(VBL_INT + " " + LYC_INT + " " + HBL_INT + " " + OAM_INT + " " + LY + " "); + //Console.Write(render_offset + " " + scroll_x + " " + total_counter + " "); //Console.WriteLine(STAT + " " + cycle + " " + Core.cpu.TotalExecutedCycles); //} } @@ -718,6 +718,8 @@ namespace BizHawk.Emulation.Cores.Nintendo.GBHawk window_pre_render = false; window_latch = LCDC.Bit(5); + total_counter = 0; + // TODO: If Window is turned on midscanline what happens? When is this check done exactly? if ((window_started && window_latch) || (window_is_reset && !window_latch && (LY >= window_y))) { @@ -750,17 +752,25 @@ namespace BizHawk.Emulation.Cores.Nintendo.GBHawk Console.Write(" "); Console.WriteLine(pixel_counter); */ - if (window_x_latch <= 7) + if (window_x_latch == 0) { // if the window starts at zero, we still do the first access to the BG // but then restart all over again at the window - read_case = 9; + if ((render_offset % 7) <= 6) + { + read_case = 9; + } + else + { + read_case = 9; + } } else { // otherwise, just restart the whole process as if starting BG again read_case = 4; } + window_pre_render = true; window_counter = 0; diff --git a/BizHawk.Emulation.Cores/Consoles/Nintendo/GBHawk/GBC_PPU_GB.cs b/BizHawk.Emulation.Cores/Consoles/Nintendo/GBHawk/GBC_PPU_GB.cs index f5e7b86a11..b47861885d 100644 --- a/BizHawk.Emulation.Cores/Consoles/Nintendo/GBHawk/GBC_PPU_GB.cs +++ b/BizHawk.Emulation.Cores/Consoles/Nintendo/GBHawk/GBC_PPU_GB.cs @@ -713,6 +713,8 @@ namespace BizHawk.Emulation.Cores.Nintendo.GBHawk window_pre_render = false; window_latch = LCDC.Bit(5); + total_counter = 0; + // TODO: If Window is turned on midscanline what happens? When is this check done exactly? if ((window_started && window_latch) || (window_is_reset && !window_latch && (LY >= window_y))) { @@ -745,11 +747,18 @@ namespace BizHawk.Emulation.Cores.Nintendo.GBHawk Console.Write(" "); Console.WriteLine(pixel_counter); */ - if (window_x_latch <= 7) + if (window_x_latch == 0) { // if the window starts at zero, we still do the first access to the BG // but then restart all over again at the window - read_case = 9; + if ((render_offset % 7) <= 6) + { + read_case = 9; + } + else + { + read_case = 9; + } } else { diff --git a/BizHawk.Emulation.Cores/Consoles/Nintendo/GBHawk/GB_PPU.cs b/BizHawk.Emulation.Cores/Consoles/Nintendo/GBHawk/GB_PPU.cs index a436d4045b..97bf6eb17e 100644 --- a/BizHawk.Emulation.Cores/Consoles/Nintendo/GBHawk/GB_PPU.cs +++ b/BizHawk.Emulation.Cores/Consoles/Nintendo/GBHawk/GB_PPU.cs @@ -495,11 +495,18 @@ namespace BizHawk.Emulation.Cores.Nintendo.GBHawk Console.Write(" "); Console.WriteLine(pixel_counter); */ - if (window_x_latch <= 7) + if (window_x_latch == 0) { // if the window starts at zero, we still do the first access to the BG // but then restart all over again at the window - read_case = 9; + if ((render_offset % 7) <= 6) + { + read_case = 9; + } + else + { + read_case = 9; + } } else { From 931a4dcde94613342f86a581f5d9dee584129019 Mon Sep 17 00:00:00 2001 From: alyosha-tas Date: Thu, 10 Oct 2019 09:57:40 -0400 Subject: [PATCH 007/166] GBHawk: window timing fixes --- .../Consoles/Nintendo/GBHawk/GBC_PPU.cs | 77 +++++++++++++------ .../Consoles/Nintendo/GBHawk/GBC_PPU_GB.cs | 46 +++++++++-- .../Consoles/Nintendo/GBHawk/GB_PPU.cs | 45 +++++++++-- .../Consoles/Nintendo/GBHawk/PPU.cs | 2 + 4 files changed, 131 insertions(+), 39 deletions(-) diff --git a/BizHawk.Emulation.Cores/Consoles/Nintendo/GBHawk/GBC_PPU.cs b/BizHawk.Emulation.Cores/Consoles/Nintendo/GBHawk/GBC_PPU.cs index 75f1324678..9bc4589dbd 100644 --- a/BizHawk.Emulation.Cores/Consoles/Nintendo/GBHawk/GBC_PPU.cs +++ b/BizHawk.Emulation.Cores/Consoles/Nintendo/GBHawk/GBC_PPU.cs @@ -398,6 +398,7 @@ namespace BizHawk.Emulation.Cores.Nintendo.GBHawk // meaning it will pick up where it left off if re-enabled later // so we don't reset it in the scanline loop window_y_tile = 0; + window_y_latch = window_y; window_y_tile_inc = 0; window_started = false; if (!LCDC.Bit(5)) { window_is_reset = true; } @@ -721,7 +722,7 @@ namespace BizHawk.Emulation.Cores.Nintendo.GBHawk total_counter = 0; // TODO: If Window is turned on midscanline what happens? When is this check done exactly? - if ((window_started && window_latch) || (window_is_reset && !window_latch && (LY >= window_y))) + if ((window_started && window_latch) || (window_is_reset && !window_latch && (LY >= window_y_latch))) { window_y_tile_inc++; if (window_y_tile_inc==8) @@ -739,19 +740,22 @@ namespace BizHawk.Emulation.Cores.Nintendo.GBHawk } // before anything else, we have to check if windowing is in effect - if (window_latch && !window_started && (LY >= window_y) && (pixel_counter >= (window_x_latch - 7)) && (window_x_latch < 167)) - { + if (window_latch && !window_started && (LY >= window_y_latch) && (pixel_counter >= (window_x_latch - 7)) && (window_x_latch < 167)) + { /* - Console.Write(LY); - Console.Write(" "); - Console.Write(cycle); - Console.Write(" "); - Console.Write(window_y_tile_inc); - Console.Write(" "); - Console.Write(window_x_latch); - Console.Write(" "); - Console.WriteLine(pixel_counter); + Console.Write(LY); + Console.Write(" "); + Console.Write(cycle); + Console.Write(" "); + Console.Write(window_y_tile); + Console.Write(" "); + Console.Write(render_offset); + Console.Write(" "); + Console.Write(window_x_latch); + Console.Write(" "); + Console.WriteLine(pixel_counter); */ + if (window_x_latch == 0) { // if the window starts at zero, we still do the first access to the BG @@ -762,12 +766,11 @@ namespace BizHawk.Emulation.Cores.Nintendo.GBHawk } else { - read_case = 9; + read_case = 10; } } else { - // otherwise, just restart the whole process as if starting BG again read_case = 4; } @@ -1086,13 +1089,30 @@ namespace BizHawk.Emulation.Cores.Nintendo.GBHawk // here we set up rendering // unlike for the normal background case, there is no pre-render period for the window // so start shifting in data to the screen right away - render_offset = 0; - render_counter = 8; + if (window_x_latch <= 7) + { + if (render_offset == 0) + { + read_case = 4; + } + else + { + read_case = 9 + render_offset - 1; + } + render_counter = 8 - render_offset; + + render_offset = 0; + } + else + { + render_offset = 0; + read_case = 4; + render_counter = 8; + } + latch_counter = 0; latch_new_data = true; - - window_pre_render = false; - read_case = 4; + window_pre_render = false; } else { @@ -1121,16 +1141,16 @@ namespace BizHawk.Emulation.Cores.Nintendo.GBHawk if (hbl_countdown == 0) { - STAT &= 0xFC; - STAT |= 0x00; - OAM_access_read = true; OAM_access_write = true; VRAM_access_read = true; VRAM_access_write = true; + + STAT &= 0xFC; + STAT |= 0x00; } else - { + { if (STAT.Bit(3)) { HBL_INT = true; } } } @@ -1143,6 +1163,16 @@ namespace BizHawk.Emulation.Cores.Nintendo.GBHawk // for it in read case 0 read_case = 4; break; + case 10: + case 11: + case 12: + case 13: + case 14: + case 15: + case 16: + case 17: + read_case--; + break; } internal_cycle++; @@ -1552,6 +1582,7 @@ namespace BizHawk.Emulation.Cores.Nintendo.GBHawk window_y = 0x0; window_x = 0x0; window_x_latch = 0xFF; + window_y_latch = 0xFF; LY_inc = 1; no_scan = false; OAM_access_read = true; diff --git a/BizHawk.Emulation.Cores/Consoles/Nintendo/GBHawk/GBC_PPU_GB.cs b/BizHawk.Emulation.Cores/Consoles/Nintendo/GBHawk/GBC_PPU_GB.cs index b47861885d..684f3c0790 100644 --- a/BizHawk.Emulation.Cores/Consoles/Nintendo/GBHawk/GBC_PPU_GB.cs +++ b/BizHawk.Emulation.Cores/Consoles/Nintendo/GBHawk/GBC_PPU_GB.cs @@ -400,6 +400,7 @@ namespace BizHawk.Emulation.Cores.Nintendo.GBHawk // meaning it will pick up where it left off if re-enabled later // so we don't reset it in the scanline loop window_y_tile = 0; + window_y_latch = window_y; window_y_tile_inc = 0; window_started = false; if (!LCDC.Bit(5)) { window_is_reset = true; } @@ -716,7 +717,7 @@ namespace BizHawk.Emulation.Cores.Nintendo.GBHawk total_counter = 0; // TODO: If Window is turned on midscanline what happens? When is this check done exactly? - if ((window_started && window_latch) || (window_is_reset && !window_latch && (LY >= window_y))) + if ((window_started && window_latch) || (window_is_reset && !window_latch && (LY >= window_y_latch))) { window_y_tile_inc++; if (window_y_tile_inc==8) @@ -734,7 +735,7 @@ namespace BizHawk.Emulation.Cores.Nintendo.GBHawk } // before anything else, we have to check if windowing is in effect - if (window_latch && !window_started && (LY >= window_y) && (pixel_counter >= (window_x_latch - 7)) && (window_x_latch < 167)) + if (window_latch && !window_started && (LY >= window_y_latch) && (pixel_counter >= (window_x_latch - 7)) && (window_x_latch < 167)) { /* Console.Write(LY); @@ -757,14 +758,14 @@ namespace BizHawk.Emulation.Cores.Nintendo.GBHawk } else { - read_case = 9; + read_case = 10; } } else { - // otherwise, just restart the whole process as if starting BG again read_case = 4; } + window_pre_render = true; window_counter = 0; @@ -1120,13 +1121,30 @@ namespace BizHawk.Emulation.Cores.Nintendo.GBHawk // here we set up rendering // unlike for the normal background case, there is no pre-render period for the window // so start shifting in data to the screen right away - render_offset = 0; - render_counter = 8; + if (window_x_latch <= 7) + { + if (render_offset == 0) + { + read_case = 4; + } + else + { + read_case = 9 + render_offset - 1; + } + render_counter = 8 - render_offset; + + render_offset = 0; + } + else + { + render_offset = 0; + read_case = 4; + render_counter = 8; + } + latch_counter = 0; latch_new_data = true; - window_pre_render = false; - read_case = 4; } else { @@ -1175,6 +1193,16 @@ namespace BizHawk.Emulation.Cores.Nintendo.GBHawk // for it in read case 0 read_case = 4; break; + case 10: + case 11: + case 12: + case 13: + case 14: + case 15: + case 16: + case 17: + read_case--; + break; } internal_cycle++; @@ -1605,6 +1633,7 @@ namespace BizHawk.Emulation.Cores.Nintendo.GBHawk window_y = 0x0; window_x = 0x0; window_x_latch = 0xFF; + window_y_latch = 0xFF; LY_inc = 1; no_scan = false; OAM_access_read = true; @@ -1722,6 +1751,7 @@ namespace BizHawk.Emulation.Cores.Nintendo.GBHawk obj_pal_0 = ppu2.obj_pal_0; obj_pal_1 = ppu2.obj_pal_1; window_y = ppu2.window_y; + window_y_latch = ppu2.window_y_latch; window_x = ppu2.window_x; DMA_start = ppu2.DMA_start; DMA_clock = ppu2.DMA_clock; diff --git a/BizHawk.Emulation.Cores/Consoles/Nintendo/GBHawk/GB_PPU.cs b/BizHawk.Emulation.Cores/Consoles/Nintendo/GBHawk/GB_PPU.cs index 97bf6eb17e..4fffeb388b 100644 --- a/BizHawk.Emulation.Cores/Consoles/Nintendo/GBHawk/GB_PPU.cs +++ b/BizHawk.Emulation.Cores/Consoles/Nintendo/GBHawk/GB_PPU.cs @@ -160,6 +160,7 @@ namespace BizHawk.Emulation.Cores.Nintendo.GBHawk // meaning it will pick up where it left off if re-enabled later // so we don't reset it in the scanline loop window_y_tile = 0; + window_y_latch = window_y; window_y_tile_inc = 0; window_started = false; if (!LCDC.Bit(5)) { window_is_reset = true; } @@ -464,7 +465,7 @@ namespace BizHawk.Emulation.Cores.Nintendo.GBHawk total_counter = 0; // TODO: If Window is turned on midscanline what happens? When is this check done exactly? - if ((window_started && window_latch) || (window_is_reset && !window_latch && (LY >= window_y))) + if ((window_started && window_latch) || (window_is_reset && !window_latch && (LY >= window_y_latch))) { window_y_tile_inc++; if (window_y_tile_inc==8) @@ -482,7 +483,7 @@ namespace BizHawk.Emulation.Cores.Nintendo.GBHawk } // before anything else, we have to check if windowing is in effect - if (window_latch && !window_started && (LY >= window_y) && (pixel_counter >= (window_x_latch - 7)) && (window_x_latch < 167)) + if (window_latch && !window_started && (LY >= window_y_latch) && (pixel_counter >= (window_x_latch - 7)) && (window_x_latch < 167)) { /* Console.Write(LY); @@ -505,14 +506,14 @@ namespace BizHawk.Emulation.Cores.Nintendo.GBHawk } else { - read_case = 9; + read_case = 10; } } else { - // otherwise, just restart the whole process as if starting BG again read_case = 4; } + window_pre_render = true; window_counter = 0; @@ -795,13 +796,30 @@ namespace BizHawk.Emulation.Cores.Nintendo.GBHawk // here we set up rendering // unlike for the normal background case, there is no pre-render period for the window // so start shifting in data to the screen right away - render_offset = 0; - render_counter = 8; + if (window_x_latch <= 7) + { + if (render_offset == 0) + { + read_case = 4; + } + else + { + read_case = 9 + render_offset - 1; + } + render_counter = 8 - render_offset; + + render_offset = 0; + } + else + { + render_offset = 0; + read_case = 4; + render_counter = 8; + } + latch_counter = 0; latch_new_data = true; - window_pre_render = false; - read_case = 4; } else { @@ -841,6 +859,16 @@ namespace BizHawk.Emulation.Cores.Nintendo.GBHawk // for it in read case 0 read_case = 4; break; + case 10: + case 11: + case 12: + case 13: + case 14: + case 15: + case 16: + case 17: + read_case--; + break; } internal_cycle++; @@ -1160,6 +1188,7 @@ namespace BizHawk.Emulation.Cores.Nintendo.GBHawk window_y = 0x0; window_x = 0x0; window_x_latch = 0xFF; + window_y_latch = 0xFF; LY_inc = 1; no_scan = false; OAM_access_read = true; diff --git a/BizHawk.Emulation.Cores/Consoles/Nintendo/GBHawk/PPU.cs b/BizHawk.Emulation.Cores/Consoles/Nintendo/GBHawk/PPU.cs index fecce56c1a..a28ea89fc9 100644 --- a/BizHawk.Emulation.Cores/Consoles/Nintendo/GBHawk/PPU.cs +++ b/BizHawk.Emulation.Cores/Consoles/Nintendo/GBHawk/PPU.cs @@ -103,6 +103,7 @@ namespace BizHawk.Emulation.Cores.Nintendo.GBHawk public int window_x_tile; public int window_y_tile_inc; public int window_x_latch; + public int window_y_latch; public int hbl_countdown; @@ -259,6 +260,7 @@ namespace BizHawk.Emulation.Cores.Nintendo.GBHawk ser.Sync(nameof(window_x_tile), ref window_x_tile); ser.Sync(nameof(window_y_tile_inc), ref window_y_tile_inc); ser.Sync(nameof(window_x_latch), ref window_x_latch); + ser.Sync(nameof(window_y_latch), ref window_y_latch); ser.Sync(nameof(hbl_countdown), ref hbl_countdown); } From 5916b9af174acfa6581ac987b1538a1db3639b80 Mon Sep 17 00:00:00 2001 From: alyosha-tas Date: Thu, 10 Oct 2019 20:12:44 -0400 Subject: [PATCH 008/166] GBHawk: minor bug fixes --- .../Consoles/Nintendo/GBHawk/GBC_PPU_GB.cs | 2 ++ .../Consoles/Nintendo/GBHawk/GBHawk.IEmulator.cs | 10 ++++++++++ .../Consoles/Nintendo/GBHawk/GB_PPU.cs | 2 ++ .../Consoles/Nintendo/GBHawk/HW_Registers.cs | 2 +- .../Consoles/Nintendo/GBHawk/PPU.cs | 2 ++ 5 files changed, 17 insertions(+), 1 deletion(-) diff --git a/BizHawk.Emulation.Cores/Consoles/Nintendo/GBHawk/GBC_PPU_GB.cs b/BizHawk.Emulation.Cores/Consoles/Nintendo/GBHawk/GBC_PPU_GB.cs index 684f3c0790..fef5761b27 100644 --- a/BizHawk.Emulation.Cores/Consoles/Nintendo/GBHawk/GBC_PPU_GB.cs +++ b/BizHawk.Emulation.Cores/Consoles/Nintendo/GBHawk/GBC_PPU_GB.cs @@ -117,6 +117,8 @@ namespace BizHawk.Emulation.Cores.Nintendo.GBHawk VRAM_access_write = true; OAM_access_read = true; OAM_access_write = true; + + clear_screen = true; } if (!LCDC.Bit(7) && value.Bit(7)) diff --git a/BizHawk.Emulation.Cores/Consoles/Nintendo/GBHawk/GBHawk.IEmulator.cs b/BizHawk.Emulation.Cores/Consoles/Nintendo/GBHawk/GBHawk.IEmulator.cs index d726744ea0..96859f3d06 100644 --- a/BizHawk.Emulation.Cores/Consoles/Nintendo/GBHawk/GBHawk.IEmulator.cs +++ b/BizHawk.Emulation.Cores/Consoles/Nintendo/GBHawk/GBHawk.IEmulator.cs @@ -132,6 +132,16 @@ namespace BizHawk.Emulation.Cores.Nintendo.GBHawk in_vblank_old = in_vblank; } + + // turn off the screen so the image doesnt persist + // but dont turn off blank_frame yet, it still needs to be true until the next VBL + // this doesn't run for GBC, some games, ex MIB the series 2, rely on the screens persistence while off to make video look smooth. + // But some GB gams, ex Battletoads, turn off the screen for a long time from the middle of the frame, so need to be cleared. + if (ppu.clear_screen) + { + for (int j = 0; j < frame_buffer.Length; j++) { frame_buffer[j] = (int)color_palette[0]; } + ppu.clear_screen = false; + } } public void do_single_step() diff --git a/BizHawk.Emulation.Cores/Consoles/Nintendo/GBHawk/GB_PPU.cs b/BizHawk.Emulation.Cores/Consoles/Nintendo/GBHawk/GB_PPU.cs index 4fffeb388b..c7c1850d9d 100644 --- a/BizHawk.Emulation.Cores/Consoles/Nintendo/GBHawk/GB_PPU.cs +++ b/BizHawk.Emulation.Cores/Consoles/Nintendo/GBHawk/GB_PPU.cs @@ -39,6 +39,8 @@ namespace BizHawk.Emulation.Cores.Nintendo.GBHawk VRAM_access_write = true; OAM_access_read = true; OAM_access_write = true; + + clear_screen = true; } if (!LCDC.Bit(7) && value.Bit(7)) diff --git a/BizHawk.Emulation.Cores/Consoles/Nintendo/GBHawk/HW_Registers.cs b/BizHawk.Emulation.Cores/Consoles/Nintendo/GBHawk/HW_Registers.cs index 41d6687b4a..326a61cf3c 100644 --- a/BizHawk.Emulation.Cores/Consoles/Nintendo/GBHawk/HW_Registers.cs +++ b/BizHawk.Emulation.Cores/Consoles/Nintendo/GBHawk/HW_Registers.cs @@ -114,7 +114,7 @@ namespace BizHawk.Emulation.Cores.Nintendo.GBHawk case 0xFF4F: // VBK if (GBC_compat) { - ret = VRAM_Bank; + ret = (byte)(0xFE | VRAM_Bank); } else { diff --git a/BizHawk.Emulation.Cores/Consoles/Nintendo/GBHawk/PPU.cs b/BizHawk.Emulation.Cores/Consoles/Nintendo/GBHawk/PPU.cs index a28ea89fc9..6afdad2f57 100644 --- a/BizHawk.Emulation.Cores/Consoles/Nintendo/GBHawk/PPU.cs +++ b/BizHawk.Emulation.Cores/Consoles/Nintendo/GBHawk/PPU.cs @@ -11,6 +11,7 @@ namespace BizHawk.Emulation.Cores.Nintendo.GBHawk public uint[] OBJ_palette = new uint[32]; public bool HDMA_active; + public bool clear_screen; // register variables public byte LCDC; @@ -172,6 +173,7 @@ namespace BizHawk.Emulation.Cores.Nintendo.GBHawk ser.Sync(nameof(BG_palette), ref BG_palette, false); ser.Sync(nameof(OBJ_palette), ref OBJ_palette, false); ser.Sync(nameof(HDMA_active), ref HDMA_active); + ser.Sync(nameof(clear_screen), ref clear_screen); ser.Sync(nameof(LCDC), ref LCDC); ser.Sync(nameof(STAT), ref STAT); From 06d53a106a7134704a47567617c143b5d397fddf Mon Sep 17 00:00:00 2001 From: alyosha-tas Date: Fri, 11 Oct 2019 09:31:21 -0400 Subject: [PATCH 009/166] GBHawk: RTC update --- .../Consoles/Nintendo/GBHawk/Mappers/Mapper_MBC3.cs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/BizHawk.Emulation.Cores/Consoles/Nintendo/GBHawk/Mappers/Mapper_MBC3.cs b/BizHawk.Emulation.Cores/Consoles/Nintendo/GBHawk/Mappers/Mapper_MBC3.cs index 2cf79faa8c..18fb03e603 100644 --- a/BizHawk.Emulation.Cores/Consoles/Nintendo/GBHawk/Mappers/Mapper_MBC3.cs +++ b/BizHawk.Emulation.Cores/Consoles/Nintendo/GBHawk/Mappers/Mapper_MBC3.cs @@ -75,6 +75,7 @@ namespace BizHawk.Emulation.Cores.Nintendo.GBHawk if ((RAM_bank >= 8) && (RAM_bank <= 0xC)) { + //Console.WriteLine("reg: " + (RAM_bank - 8) + " value: " + RTC_regs_latch[RAM_bank - 8] + " cpu: " + Core.cpu.TotalExecutedCycles); return RTC_regs_latch[RAM_bank - 8]; } else @@ -216,7 +217,7 @@ namespace BizHawk.Emulation.Cores.Nintendo.GBHawk RTC_low_clock++; - if (RTC_low_clock == 32768) + if (RTC_low_clock == 32767) // the RTC appears to be off by one cycle (would be 32768) { RTC_low_clock = 0; @@ -228,6 +229,7 @@ namespace BizHawk.Emulation.Cores.Nintendo.GBHawk RTC_regs[1]++; if (RTC_regs[1] > 59) { + RTC_regs[1] = 0; RTC_regs[2]++; if (RTC_regs[2] > 23) { From 1c51f09e6542a7968f2b6683dd86c4ceae2ccf27 Mon Sep 17 00:00:00 2001 From: alyosha-tas Date: Fri, 11 Oct 2019 13:19:40 -0400 Subject: [PATCH 010/166] GBHawk: add RTC offset setting --- .../Nintendo/GBHawk/GBHawk.ISettable.cs | 10 +++++ .../Consoles/Nintendo/GBHawk/GBHawk.cs | 23 ++++++----- .../Nintendo/GBHawk/Mappers/MapperBase.cs | 2 +- .../Nintendo/GBHawk/Mappers/Mapper_HuC3.cs | 2 +- .../Nintendo/GBHawk/Mappers/Mapper_MBC3.cs | 20 ++++++++-- .../GBHawkLink/GBHawkLink.ISettable.cs | 20 ++++++++++ .../Nintendo/GBHawkLink/GBHawkLink.cs | 2 + .../GBHawkLink3x/GBHawkLink3x.ISettable.cs | 30 ++++++++++++++ .../Nintendo/GBHawkLink3x/GBHawkLink3x.cs | 3 ++ .../GBHawkLink4x/GBHawkLink4x.ISettable.cs | 40 +++++++++++++++++++ .../Nintendo/GBHawkLink4x/GBHawkLink4x.cs | 4 ++ 11 files changed, 141 insertions(+), 15 deletions(-) diff --git a/BizHawk.Emulation.Cores/Consoles/Nintendo/GBHawk/GBHawk.ISettable.cs b/BizHawk.Emulation.Cores/Consoles/Nintendo/GBHawk/GBHawk.ISettable.cs index bdc6d40ff0..2aa660953b 100644 --- a/BizHawk.Emulation.Cores/Consoles/Nintendo/GBHawk/GBHawk.ISettable.cs +++ b/BizHawk.Emulation.Cores/Consoles/Nintendo/GBHawk/GBHawk.ISettable.cs @@ -111,6 +111,15 @@ namespace BizHawk.Emulation.Cores.Nintendo.GBHawk set { _RTCInitialTime = Math.Max(0, Math.Min(1024 * 24 * 60 * 60, value)); } } + [DisplayName("RTC Offset")] + [Description("Set error in RTC clocking (-127 to 127)")] + [DefaultValue(0)] + public int RTCOffset + { + get { return _RTCOffset; } + set { _RTCOffset = Math.Max(-127, Math.Min(127, value)); } + } + [DisplayName("Timer Div Initial Time")] [Description("Don't change from 0 unless it's hardware accurate. GBA GBC mode is known to be 8.")] [DefaultValue(8)] @@ -128,6 +137,7 @@ namespace BizHawk.Emulation.Cores.Nintendo.GBHawk [JsonIgnore] private int _RTCInitialTime; + private int _RTCOffset; [JsonIgnore] public ushort _DivInitialTime = 8; diff --git a/BizHawk.Emulation.Cores/Consoles/Nintendo/GBHawk/GBHawk.cs b/BizHawk.Emulation.Cores/Consoles/Nintendo/GBHawk/GBHawk.cs index 5a14b9ea93..3cb80bf96f 100644 --- a/BizHawk.Emulation.Cores/Consoles/Nintendo/GBHawk/GBHawk.cs +++ b/BizHawk.Emulation.Cores/Consoles/Nintendo/GBHawk/GBHawk.cs @@ -470,28 +470,31 @@ namespace BizHawk.Emulation.Cores.Nintendo.GBHawk if (mppr == "MBC3") { Use_MT = true; + + mapper.RTC_Get(_syncSettings.RTCOffset, 5); + int days = (int)Math.Floor(_syncSettings.RTCInitialTime / 86400.0); int days_upper = ((days & 0x100) >> 8) | ((days & 0x200) >> 2); - mapper.RTC_Get((byte)days_upper, 4); - mapper.RTC_Get((byte)(days & 0xFF), 3); + mapper.RTC_Get(days_upper, 4); + mapper.RTC_Get(days & 0xFF, 3); int remaining = _syncSettings.RTCInitialTime - (days * 86400); int hours = (int)Math.Floor(remaining / 3600.0); - mapper.RTC_Get((byte)(hours & 0xFF), 2); + mapper.RTC_Get(hours & 0xFF, 2); remaining = remaining - (hours * 3600); int minutes = (int)Math.Floor(remaining / 60.0); - mapper.RTC_Get((byte)(minutes & 0xFF), 1); + mapper.RTC_Get(minutes & 0xFF, 1); remaining = remaining - (minutes * 60); - mapper.RTC_Get((byte)(remaining & 0xFF), 0); + mapper.RTC_Get(remaining & 0xFF, 0); } if (mppr == "HuC3") @@ -500,23 +503,23 @@ namespace BizHawk.Emulation.Cores.Nintendo.GBHawk int years = (int)Math.Floor(_syncSettings.RTCInitialTime / 31536000.0); - mapper.RTC_Get((byte)years, 24); + mapper.RTC_Get(years, 24); int remaining = _syncSettings.RTCInitialTime - (years * 31536000); int days = (int)Math.Floor(remaining / 86400.0); int days_upper = (days >> 8) & 0xF; - mapper.RTC_Get((byte)days_upper, 20); - mapper.RTC_Get((byte)(days & 0xFF), 12); + mapper.RTC_Get(days_upper, 20); + mapper.RTC_Get(days & 0xFF, 12); remaining = remaining - (days * 86400); int minutes = (int)Math.Floor(remaining / 60.0); int minutes_upper = (minutes >> 8) & 0xF; - mapper.RTC_Get((byte)(minutes_upper), 8); - mapper.RTC_Get((byte)(remaining & 0xFF), 0); + mapper.RTC_Get(minutes_upper, 8); + mapper.RTC_Get(remaining & 0xFF, 0); } } } diff --git a/BizHawk.Emulation.Cores/Consoles/Nintendo/GBHawk/Mappers/MapperBase.cs b/BizHawk.Emulation.Cores/Consoles/Nintendo/GBHawk/Mappers/MapperBase.cs index 73e70d1bb6..be4d482e12 100644 --- a/BizHawk.Emulation.Cores/Consoles/Nintendo/GBHawk/Mappers/MapperBase.cs +++ b/BizHawk.Emulation.Cores/Consoles/Nintendo/GBHawk/Mappers/MapperBase.cs @@ -43,7 +43,7 @@ namespace BizHawk.Emulation.Cores.Nintendo.GBHawk { } - public virtual void RTC_Get(byte value, int index) + public virtual void RTC_Get(int value, int index) { } diff --git a/BizHawk.Emulation.Cores/Consoles/Nintendo/GBHawk/Mappers/Mapper_HuC3.cs b/BizHawk.Emulation.Cores/Consoles/Nintendo/GBHawk/Mappers/Mapper_HuC3.cs index 5347487ed4..6bcc6e6cd3 100644 --- a/BizHawk.Emulation.Cores/Consoles/Nintendo/GBHawk/Mappers/Mapper_HuC3.cs +++ b/BizHawk.Emulation.Cores/Consoles/Nintendo/GBHawk/Mappers/Mapper_HuC3.cs @@ -243,7 +243,7 @@ namespace BizHawk.Emulation.Cores.Nintendo.GBHawk } } - public override void RTC_Get(byte value, int index) + public override void RTC_Get(int value, int index) { time |= (uint)((value & 0xFF) << index); } diff --git a/BizHawk.Emulation.Cores/Consoles/Nintendo/GBHawk/Mappers/Mapper_MBC3.cs b/BizHawk.Emulation.Cores/Consoles/Nintendo/GBHawk/Mappers/Mapper_MBC3.cs index 18fb03e603..1bfb5d0e29 100644 --- a/BizHawk.Emulation.Cores/Consoles/Nintendo/GBHawk/Mappers/Mapper_MBC3.cs +++ b/BizHawk.Emulation.Cores/Consoles/Nintendo/GBHawk/Mappers/Mapper_MBC3.cs @@ -20,6 +20,7 @@ namespace BizHawk.Emulation.Cores.Nintendo.GBHawk public int RTC_timer; public int RTC_low_clock; public bool halt; + public int RTC_offset; public override void Initialize() { @@ -200,9 +201,18 @@ namespace BizHawk.Emulation.Cores.Nintendo.GBHawk WriteMemory(addr, value); } - public override void RTC_Get(byte value, int index) + public override void RTC_Get(int value, int index) { - RTC_regs[index] = value; + if (index < 5) + { + RTC_regs[index] = (byte)value; + } + else + { + RTC_offset = value; + + Console.WriteLine("RTC: " + RTC_offset); + } } public override void Mapper_Tick() @@ -217,10 +227,13 @@ namespace BizHawk.Emulation.Cores.Nintendo.GBHawk RTC_low_clock++; - if (RTC_low_clock == 32767) // the RTC appears to be off by one cycle (would be 32768) + if (RTC_low_clock == 32768) { RTC_low_clock = 0; + // adjust for slight RTC error + RTC_timer = RTC_offset; + RTC_regs[0]++; if (RTC_regs[0] > 59) @@ -273,6 +286,7 @@ namespace BizHawk.Emulation.Cores.Nintendo.GBHawk ser.Sync(nameof(RTC_regs_latch_wr), ref RTC_regs_latch_wr); ser.Sync(nameof(RTC_timer), ref RTC_timer); ser.Sync(nameof(RTC_low_clock), ref RTC_low_clock); + ser.Sync(nameof(RTC_offset), ref RTC_offset); } } } diff --git a/BizHawk.Emulation.Cores/Consoles/Nintendo/GBHawkLink/GBHawkLink.ISettable.cs b/BizHawk.Emulation.Cores/Consoles/Nintendo/GBHawkLink/GBHawkLink.ISettable.cs index 79ab75ecc1..c609a28515 100644 --- a/BizHawk.Emulation.Cores/Consoles/Nintendo/GBHawkLink/GBHawkLink.ISettable.cs +++ b/BizHawk.Emulation.Cores/Consoles/Nintendo/GBHawkLink/GBHawkLink.ISettable.cs @@ -102,6 +102,24 @@ namespace BizHawk.Emulation.Cores.Nintendo.GBHawkLink set { _RTCInitialTime_R = Math.Max(0, Math.Min(1024 * 24 * 60 * 60, value)); } } + [DisplayName("RTC Offset L")] + [Description("Set error in RTC clocking (-127 to 127)")] + [DefaultValue(0)] + public int RTCOffset_L + { + get { return _RTCOffset_L; } + set { _RTCOffset_L = Math.Max(-127, Math.Min(127, value)); } + } + + [DisplayName("RTC Offset R")] + [Description("Set error in RTC clocking (-127 to 127)")] + [DefaultValue(0)] + public int RTCOffset_R + { + get { return _RTCOffset_R; } + set { _RTCOffset_R = Math.Max(-127, Math.Min(127, value)); } + } + [DisplayName("Timer Div Initial Time L")] [Description("Don't change from 0 unless it's hardware accurate. GBA GBC mode is known to be 8.")] [DefaultValue(8)] @@ -128,6 +146,8 @@ namespace BizHawk.Emulation.Cores.Nintendo.GBHawkLink [JsonIgnore] private int _RTCInitialTime_L; private int _RTCInitialTime_R; + private int _RTCOffset_L; + private int _RTCOffset_R; [JsonIgnore] public ushort _DivInitialTime_L = 8; public ushort _DivInitialTime_R = 8; diff --git a/BizHawk.Emulation.Cores/Consoles/Nintendo/GBHawkLink/GBHawkLink.cs b/BizHawk.Emulation.Cores/Consoles/Nintendo/GBHawkLink/GBHawkLink.cs index cfce79de94..a38a4d091e 100644 --- a/BizHawk.Emulation.Cores/Consoles/Nintendo/GBHawkLink/GBHawkLink.cs +++ b/BizHawk.Emulation.Cores/Consoles/Nintendo/GBHawkLink/GBHawkLink.cs @@ -56,6 +56,8 @@ namespace BizHawk.Emulation.Cores.Nintendo.GBHawkLink temp_sync_R.DivInitialTime = linkSyncSettings.DivInitialTime_R; temp_sync_L.RTCInitialTime = linkSyncSettings.RTCInitialTime_L; temp_sync_R.RTCInitialTime = linkSyncSettings.RTCInitialTime_R; + temp_sync_L.RTCOffset = linkSyncSettings.RTCOffset_L; + temp_sync_R.RTCOffset = linkSyncSettings.RTCOffset_R; L = new GBHawk.GBHawk(new CoreComm(comm.ShowMessage, comm.Notify) { CoreFileProvider = comm.CoreFileProvider }, game_L, rom_L, temp_set_L, temp_sync_L); diff --git a/BizHawk.Emulation.Cores/Consoles/Nintendo/GBHawkLink3x/GBHawkLink3x.ISettable.cs b/BizHawk.Emulation.Cores/Consoles/Nintendo/GBHawkLink3x/GBHawkLink3x.ISettable.cs index 8e74c66c2b..9c0adf8f7b 100644 --- a/BizHawk.Emulation.Cores/Consoles/Nintendo/GBHawkLink3x/GBHawkLink3x.ISettable.cs +++ b/BizHawk.Emulation.Cores/Consoles/Nintendo/GBHawkLink3x/GBHawkLink3x.ISettable.cs @@ -122,6 +122,33 @@ namespace BizHawk.Emulation.Cores.Nintendo.GBHawkLink3x set { _RTCInitialTime_R = Math.Max(0, Math.Min(1024 * 24 * 60 * 60, value)); } } + [DisplayName("RTC Offset L")] + [Description("Set error in RTC clocking (-127 to 127)")] + [DefaultValue(0)] + public int RTCOffset_L + { + get { return _RTCOffset_L; } + set { _RTCOffset_L = Math.Max(-127, Math.Min(127, value)); } + } + + [DisplayName("RTC Offset C")] + [Description("Set error in RTC clocking (-127 to 127)")] + [DefaultValue(0)] + public int RTCOffset_C + { + get { return _RTCOffset_C; } + set { _RTCOffset_C = Math.Max(-127, Math.Min(127, value)); } + } + + [DisplayName("RTC Offset R")] + [Description("Set error in RTC clocking (-127 to 127)")] + [DefaultValue(0)] + public int RTCOffset_R + { + get { return _RTCOffset_R; } + set { _RTCOffset_R = Math.Max(-127, Math.Min(127, value)); } + } + [DisplayName("Timer Div Initial Time L")] [Description("Don't change from 0 unless it's hardware accurate. GBA GBC mode is known to be 8.")] [DefaultValue(8)] @@ -158,6 +185,9 @@ namespace BizHawk.Emulation.Cores.Nintendo.GBHawkLink3x private int _RTCInitialTime_L; private int _RTCInitialTime_C; private int _RTCInitialTime_R; + private int _RTCOffset_L; + private int _RTCOffset_C; + private int _RTCOffset_R; [JsonIgnore] public ushort _DivInitialTime_L = 8; public ushort _DivInitialTime_C = 8; diff --git a/BizHawk.Emulation.Cores/Consoles/Nintendo/GBHawkLink3x/GBHawkLink3x.cs b/BizHawk.Emulation.Cores/Consoles/Nintendo/GBHawkLink3x/GBHawkLink3x.cs index f5ef14ac41..e939891b20 100644 --- a/BizHawk.Emulation.Cores/Consoles/Nintendo/GBHawkLink3x/GBHawkLink3x.cs +++ b/BizHawk.Emulation.Cores/Consoles/Nintendo/GBHawkLink3x/GBHawkLink3x.cs @@ -61,6 +61,9 @@ namespace BizHawk.Emulation.Cores.Nintendo.GBHawkLink3x temp_sync_L.RTCInitialTime = Link3xSyncSettings.RTCInitialTime_L; temp_sync_C.RTCInitialTime = Link3xSyncSettings.RTCInitialTime_C; temp_sync_R.RTCInitialTime = Link3xSyncSettings.RTCInitialTime_R; + temp_sync_L.RTCOffset = Link3xSyncSettings.RTCOffset_L; + temp_sync_C.RTCOffset = Link3xSyncSettings.RTCOffset_C; + temp_sync_R.RTCOffset = Link3xSyncSettings.RTCOffset_R; L = new GBHawk.GBHawk(new CoreComm(comm.ShowMessage, comm.Notify) { CoreFileProvider = comm.CoreFileProvider }, game_L, rom_L, temp_set_L, temp_sync_L); diff --git a/BizHawk.Emulation.Cores/Consoles/Nintendo/GBHawkLink4x/GBHawkLink4x.ISettable.cs b/BizHawk.Emulation.Cores/Consoles/Nintendo/GBHawkLink4x/GBHawkLink4x.ISettable.cs index 65239aec31..b509dd1d3c 100644 --- a/BizHawk.Emulation.Cores/Consoles/Nintendo/GBHawkLink4x/GBHawkLink4x.ISettable.cs +++ b/BizHawk.Emulation.Cores/Consoles/Nintendo/GBHawkLink4x/GBHawkLink4x.ISettable.cs @@ -142,6 +142,42 @@ namespace BizHawk.Emulation.Cores.Nintendo.GBHawkLink4x set { _RTCInitialTime_D = Math.Max(0, Math.Min(1024 * 24 * 60 * 60, value)); } } + [DisplayName("RTC Offset A")] + [Description("Set error in RTC clocking (-127 to 127)")] + [DefaultValue(0)] + public int RTCOffset_A + { + get { return _RTCOffset_A; } + set { _RTCOffset_A = Math.Max(-127, Math.Min(127, value)); } + } + + [DisplayName("RTC Offset B")] + [Description("Set error in RTC clocking (-127 to 127)")] + [DefaultValue(0)] + public int RTCOffset_B + { + get { return _RTCOffset_B; } + set { _RTCOffset_B = Math.Max(-127, Math.Min(127, value)); } + } + + [DisplayName("RTC Offset C")] + [Description("Set error in RTC clocking (-127 to 127)")] + [DefaultValue(0)] + public int RTCOffset_C + { + get { return _RTCOffset_C; } + set { _RTCOffset_C = Math.Max(-127, Math.Min(127, value)); } + } + + [DisplayName("RTC Offset D")] + [Description("Set error in RTC clocking (-127 to 127)")] + [DefaultValue(0)] + public int RTCOffset_D + { + get { return _RTCOffset_D; } + set { _RTCOffset_D = Math.Max(-127, Math.Min(127, value)); } + } + [DisplayName("Timer Div Initial Time A")] [Description("Don't change from 0 unless it's hardware accurate. GBA GBC mode is known to be 8.")] [DefaultValue(8)] @@ -188,6 +224,10 @@ namespace BizHawk.Emulation.Cores.Nintendo.GBHawkLink4x private int _RTCInitialTime_B; private int _RTCInitialTime_C; private int _RTCInitialTime_D; + private int _RTCOffset_A; + private int _RTCOffset_B; + private int _RTCOffset_C; + private int _RTCOffset_D; [JsonIgnore] public ushort _DivInitialTime_A = 8; public ushort _DivInitialTime_B = 8; diff --git a/BizHawk.Emulation.Cores/Consoles/Nintendo/GBHawkLink4x/GBHawkLink4x.cs b/BizHawk.Emulation.Cores/Consoles/Nintendo/GBHawkLink4x/GBHawkLink4x.cs index cf104fee68..6249d5f305 100644 --- a/BizHawk.Emulation.Cores/Consoles/Nintendo/GBHawkLink4x/GBHawkLink4x.cs +++ b/BizHawk.Emulation.Cores/Consoles/Nintendo/GBHawkLink4x/GBHawkLink4x.cs @@ -68,6 +68,10 @@ namespace BizHawk.Emulation.Cores.Nintendo.GBHawkLink4x temp_sync_B.RTCInitialTime = Link4xSyncSettings.RTCInitialTime_B; temp_sync_C.RTCInitialTime = Link4xSyncSettings.RTCInitialTime_C; temp_sync_D.RTCInitialTime = Link4xSyncSettings.RTCInitialTime_D; + temp_sync_A.RTCOffset = Link4xSyncSettings.RTCOffset_A; + temp_sync_B.RTCOffset = Link4xSyncSettings.RTCOffset_B; + temp_sync_C.RTCOffset = Link4xSyncSettings.RTCOffset_C; + temp_sync_D.RTCOffset = Link4xSyncSettings.RTCOffset_D; A = new GBHawk.GBHawk(new CoreComm(comm.ShowMessage, comm.Notify) { CoreFileProvider = comm.CoreFileProvider }, game_A, rom_A, temp_set_A, temp_sync_A); From 8384f4298d9976000aaef5937f19d158aabe547d Mon Sep 17 00:00:00 2001 From: alyosha-tas Date: Fri, 11 Oct 2019 21:28:46 -0400 Subject: [PATCH 011/166] GBHawk: another mbc3 fix --- .../Consoles/Nintendo/GBHawk/Mappers/Mapper_MBC3.cs | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/BizHawk.Emulation.Cores/Consoles/Nintendo/GBHawk/Mappers/Mapper_MBC3.cs b/BizHawk.Emulation.Cores/Consoles/Nintendo/GBHawk/Mappers/Mapper_MBC3.cs index 1bfb5d0e29..8204677836 100644 --- a/BizHawk.Emulation.Cores/Consoles/Nintendo/GBHawk/Mappers/Mapper_MBC3.cs +++ b/BizHawk.Emulation.Cores/Consoles/Nintendo/GBHawk/Mappers/Mapper_MBC3.cs @@ -188,7 +188,7 @@ namespace BizHawk.Emulation.Cores.Nintendo.GBHawk { RTC_regs[RAM_bank - 8] = value; - RTC_low_clock = RTC_timer = 0; + if ((RAM_bank - 8) == 0) { RTC_low_clock = RTC_timer = 0; } halt = (RTC_regs[4] & 0x40) > 0; } @@ -210,8 +210,6 @@ namespace BizHawk.Emulation.Cores.Nintendo.GBHawk else { RTC_offset = value; - - Console.WriteLine("RTC: " + RTC_offset); } } @@ -230,8 +228,6 @@ namespace BizHawk.Emulation.Cores.Nintendo.GBHawk if (RTC_low_clock == 32768) { RTC_low_clock = 0; - - // adjust for slight RTC error RTC_timer = RTC_offset; RTC_regs[0]++; From d7ee6ba579aa7e320b30318bdc0f5b6303268df4 Mon Sep 17 00:00:00 2001 From: alyosha-tas Date: Sat, 12 Oct 2019 16:04:13 -0400 Subject: [PATCH 012/166] GBHawk: Misc cleanup --- BizHawk.Emulation.Cores/CPUs/LR35902/LR35902.cs | 9 ++++----- .../Consoles/Nintendo/GBHawk/GBC_PPU.cs | 11 +++++------ .../Consoles/Nintendo/GBHawk/GBC_PPU_GB.cs | 3 +-- 3 files changed, 10 insertions(+), 13 deletions(-) diff --git a/BizHawk.Emulation.Cores/CPUs/LR35902/LR35902.cs b/BizHawk.Emulation.Cores/CPUs/LR35902/LR35902.cs index 941179ed58..79d5e2f62e 100644 --- a/BizHawk.Emulation.Cores/CPUs/LR35902/LR35902.cs +++ b/BizHawk.Emulation.Cores/CPUs/LR35902/LR35902.cs @@ -312,13 +312,12 @@ namespace BizHawk.Emulation.Common.Components.LR35902 if (!Halt_bug_3) { INTERRUPT_GBC_NOP(); - //INTERRUPT_(); } else { INTERRUPT_(); Halt_bug_3 = false; - Console.WriteLine("Hit INT"); + //Console.WriteLine("Hit INT"); } } else @@ -353,7 +352,7 @@ namespace BizHawk.Emulation.Common.Components.LR35902 RegPC++; FetchInstruction(ReadMemory(RegPC)); Halt_bug_3 = false; - Console.WriteLine("Hit un"); + //Console.WriteLine("Hit un"); } else { @@ -538,8 +537,8 @@ namespace BizHawk.Emulation.Common.Components.LR35902 { RegPC--; Halt_bug_3 = true; - Console.WriteLine("Halt_bug_3"); - Console.WriteLine(TotalExecutedCycles); + //Console.WriteLine("Halt_bug_3"); + //Console.WriteLine(TotalExecutedCycles); } Halt_bug_2 = false; diff --git a/BizHawk.Emulation.Cores/Consoles/Nintendo/GBHawk/GBC_PPU.cs b/BizHawk.Emulation.Cores/Consoles/Nintendo/GBHawk/GBC_PPU.cs index 9bc4589dbd..3ffee95b7b 100644 --- a/BizHawk.Emulation.Cores/Consoles/Nintendo/GBHawk/GBC_PPU.cs +++ b/BizHawk.Emulation.Cores/Consoles/Nintendo/GBHawk/GBC_PPU.cs @@ -151,7 +151,6 @@ namespace BizHawk.Emulation.Cores.Nintendo.GBHawk LY = 0; /*reset*/ break; case 0xFF45: // LYC - // tests indicate that latching writes to LYC should take place 4 cycles after the write // otherwise tests around LY boundaries will fail LYC_t = value; @@ -1144,13 +1143,13 @@ namespace BizHawk.Emulation.Cores.Nintendo.GBHawk OAM_access_read = true; OAM_access_write = true; VRAM_access_read = true; - VRAM_access_write = true; - - STAT &= 0xFC; - STAT |= 0x00; + VRAM_access_write = true; } else - { + { + STAT &= 0xFC; + STAT |= 0x00; + if (STAT.Bit(3)) { HBL_INT = true; } } } diff --git a/BizHawk.Emulation.Cores/Consoles/Nintendo/GBHawk/GBC_PPU_GB.cs b/BizHawk.Emulation.Cores/Consoles/Nintendo/GBHawk/GBC_PPU_GB.cs index fef5761b27..717d5d8238 100644 --- a/BizHawk.Emulation.Cores/Consoles/Nintendo/GBHawk/GBC_PPU_GB.cs +++ b/BizHawk.Emulation.Cores/Consoles/Nintendo/GBHawk/GBC_PPU_GB.cs @@ -3,7 +3,7 @@ using BizHawk.Common.NumberExtensions; using BizHawk.Common; // Gameboy compatibility mode for GBC console -// only entered from writing to register 0xFF4C +// seperated out so the GBC ppu can focus on double speed mode // has several quirks not present in GB ppu namespace BizHawk.Emulation.Cores.Nintendo.GBHawk { @@ -155,7 +155,6 @@ namespace BizHawk.Emulation.Cores.Nintendo.GBHawk LY = 0; /*reset*/ break; case 0xFF45: // LYC - // tests indicate that latching writes to LYC should take place 4 cycles after the write // otherwise tests around LY boundaries will fail LYC_t = value; From 77bbc41286257391c49236f8aa9040f554fbd519 Mon Sep 17 00:00:00 2001 From: "J.D. Purcell" Date: Sat, 12 Oct 2019 17:56:20 -0400 Subject: [PATCH 013/166] Fix prerequisites dialog (broken by 42764f00 and 436b6452). --- BizHawk.Client.EmuHawk/Program.cs | 2 +- BizHawk.Common/OSTailoredCode.cs | 7 +------ .../Consoles/Nintendo/N64/NativeApi/mupen64plusCoreApi.cs | 2 ++ 3 files changed, 4 insertions(+), 7 deletions(-) diff --git a/BizHawk.Client.EmuHawk/Program.cs b/BizHawk.Client.EmuHawk/Program.cs index 8da6077bbf..a954845ac9 100644 --- a/BizHawk.Client.EmuHawk/Program.cs +++ b/BizHawk.Client.EmuHawk/Program.cs @@ -49,7 +49,7 @@ namespace BizHawk.Client.EmuHawk }; var box = new BizHawk.Client.EmuHawk.CustomControls.PrereqsAlert(!fail) { - textBox1 = { Text = string.Concat("\n", alertLines) } + textBox1 = { Text = string.Join(Environment.NewLine, alertLines) } }; box.ShowDialog(); if (fail) System.Diagnostics.Process.GetCurrentProcess().Kill(); diff --git a/BizHawk.Common/OSTailoredCode.cs b/BizHawk.Common/OSTailoredCode.cs index 9109daeeda..65b46ff569 100644 --- a/BizHawk.Common/OSTailoredCode.cs +++ b/BizHawk.Common/OSTailoredCode.cs @@ -75,12 +75,7 @@ namespace BizHawk.Common [DllImport("kernel32.dll")] private static extern bool FreeLibrary(IntPtr hModule); // return type was annotated MarshalAs(UnmanagedType.Bool) - public IntPtr LoadPlatformSpecific(string dllToLoad) - { - var p = LoadLibrary(dllToLoad); - if (p == IntPtr.Zero) throw new InvalidOperationException($"got null pointer, error code {GetLastError()}"); - return p; - } + public IntPtr LoadPlatformSpecific(string dllToLoad) => LoadLibrary(dllToLoad); public IntPtr GetProcAddr(IntPtr hModule, string procName) => GetProcAddress(hModule, procName); public int FreePlatformSpecific(IntPtr hModule) => FreeLibrary(hModule) ? 1 : 0; } diff --git a/BizHawk.Emulation.Cores/Consoles/Nintendo/N64/NativeApi/mupen64plusCoreApi.cs b/BizHawk.Emulation.Cores/Consoles/Nintendo/N64/NativeApi/mupen64plusCoreApi.cs index 3cc7b24ec8..c0dfaba506 100644 --- a/BizHawk.Emulation.Cores/Consoles/Nintendo/N64/NativeApi/mupen64plusCoreApi.cs +++ b/BizHawk.Emulation.Cores/Consoles/Nintendo/N64/NativeApi/mupen64plusCoreApi.cs @@ -935,6 +935,8 @@ namespace BizHawk.Emulation.Cores.Nintendo.N64.NativeApi AttachedPlugin plugin; plugin.dllHandle = libLoader.LoadPlatformSpecific(PluginName); + if (plugin.dllHandle == IntPtr.Zero) + throw new InvalidOperationException($"Failed to load plugin {PluginName}"); plugin.dllStartup = (PluginStartup)Marshal.GetDelegateForFunctionPointer(libLoader.GetProcAddr(plugin.dllHandle, "PluginStartup"), typeof(PluginStartup)); plugin.dllShutdown = (PluginShutdown)Marshal.GetDelegateForFunctionPointer(libLoader.GetProcAddr(plugin.dllHandle, "PluginShutdown"), typeof(PluginShutdown)); From 7ef07bac021d0c70aa20c16c42d14306638b38b5 Mon Sep 17 00:00:00 2001 From: "J.D. Purcell" Date: Sat, 12 Oct 2019 19:38:18 -0400 Subject: [PATCH 014/166] Fix DPI scaling. --- .../BizHawk.Client.EmuHawk.csproj | 3 +- BizHawk.Client.EmuHawk/app.config | 9 ++-- BizHawk.Client.EmuHawk/app.manifest | 47 +++++++++++++++++++ 3 files changed, 55 insertions(+), 4 deletions(-) create mode 100644 BizHawk.Client.EmuHawk/app.manifest diff --git a/BizHawk.Client.EmuHawk/BizHawk.Client.EmuHawk.csproj b/BizHawk.Client.EmuHawk/BizHawk.Client.EmuHawk.csproj index 86dcd49b0c..4e5ecd01d7 100644 --- a/BizHawk.Client.EmuHawk/BizHawk.Client.EmuHawk.csproj +++ b/BizHawk.Client.EmuHawk/BizHawk.Client.EmuHawk.csproj @@ -40,7 +40,7 @@ true - true + app.manifest true @@ -1864,6 +1864,7 @@ + diff --git a/BizHawk.Client.EmuHawk/app.config b/BizHawk.Client.EmuHawk/app.config index 9b69721c46..9d91d3673b 100644 --- a/BizHawk.Client.EmuHawk/app.config +++ b/BizHawk.Client.EmuHawk/app.config @@ -3,7 +3,10 @@ - - - + + + + + + diff --git a/BizHawk.Client.EmuHawk/app.manifest b/BizHawk.Client.EmuHawk/app.manifest new file mode 100644 index 0000000000..c86efcb5ad --- /dev/null +++ b/BizHawk.Client.EmuHawk/app.manifest @@ -0,0 +1,47 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + true + + + From 0dcb0b9bb444d05a3241e708752de20db39c4d85 Mon Sep 17 00:00:00 2001 From: "J.D. Purcell" Date: Sat, 12 Oct 2019 22:34:53 -0400 Subject: [PATCH 015/166] Fix DPI scaling issue in custom message boxes (Snex9x/QuickNES accuracy warnings). --- .../CustomControls/MsgBox.cs | 13 +++--- .../CustomControls/MsgBox.designer.cs | 1 - BizHawk.Client.EmuHawk/MainForm.Events.cs | 4 +- BizHawk.Client.EmuHawk/UIHelper.cs | 43 ++++++------------- .../tools/TAStudio/TAStudio.cs | 4 +- 5 files changed, 25 insertions(+), 40 deletions(-) diff --git a/BizHawk.Client.EmuHawk/CustomControls/MsgBox.cs b/BizHawk.Client.EmuHawk/CustomControls/MsgBox.cs index 278fc0c73d..7dabe03020 100644 --- a/BizHawk.Client.EmuHawk/CustomControls/MsgBox.cs +++ b/BizHawk.Client.EmuHawk/CustomControls/MsgBox.cs @@ -47,6 +47,7 @@ namespace BizHawk.Client.EmuHawk.CustomControls { InitializeComponent(); + this.ControlBox = false; // Do not set in designer (causes problems with auto scaling) this.messageLbl.Text = message; this.Text = title; this.m_sysIcon = icon; @@ -58,7 +59,7 @@ namespace BizHawk.Client.EmuHawk.CustomControls public void SetMessageToAutoSize() { this.messageLbl.AutoSize = true; - this.messageLbl.MaximumSize = new Size(this.MaximumSize.Width - this.m_sysIcon.Width - 25, this.MaximumSize.Height); + this.messageLbl.MaximumSize = new Size(this.MaximumSize.Width - this.m_sysIcon.Width - UIHelper.ScaleX(25), this.MaximumSize.Height); } /// @@ -220,11 +221,11 @@ namespace BizHawk.Client.EmuHawk.CustomControls } - const int FORM_Y_MARGIN = 10; - const int FORM_X_MARGIN = 16; - const int BUTTON_SPACE = 5; - const int CHECKBOX_SPACE = 15; - const int TEXT_Y_MARGIN = 30; + private static readonly int FORM_Y_MARGIN = UIHelper.ScaleY(10); + private static readonly int FORM_X_MARGIN = UIHelper.ScaleX(16); + private static readonly int BUTTON_SPACE = UIHelper.ScaleX(5); + private static readonly int CHECKBOX_SPACE = UIHelper.ScaleX(15); + private static readonly int TEXT_Y_MARGIN = UIHelper.ScaleY(30); /// /// Auto fits the dialog box to fit the text and the buttons. diff --git a/BizHawk.Client.EmuHawk/CustomControls/MsgBox.designer.cs b/BizHawk.Client.EmuHawk/CustomControls/MsgBox.designer.cs index 3c58b8066b..ccdd5ea1dd 100644 --- a/BizHawk.Client.EmuHawk/CustomControls/MsgBox.designer.cs +++ b/BizHawk.Client.EmuHawk/CustomControls/MsgBox.designer.cs @@ -105,7 +105,6 @@ this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; this.CancelButton = this.btn1; this.ClientSize = new System.Drawing.Size(485, 149); - this.ControlBox = false; this.Controls.Add(this.btn3); this.Controls.Add(this.chkBx); this.Controls.Add(this.btn1); diff --git a/BizHawk.Client.EmuHawk/MainForm.Events.cs b/BizHawk.Client.EmuHawk/MainForm.Events.cs index 362f9ee24f..3a6f38a98a 100644 --- a/BizHawk.Client.EmuHawk/MainForm.Events.cs +++ b/BizHawk.Client.EmuHawk/MainForm.Events.cs @@ -489,7 +489,7 @@ namespace BizHawk.Client.EmuHawk new[] { "Switch", "Continue" }, new[] { DialogResult.Yes, DialogResult.Cancel }); - box.MaximumSize = new Size(475, 350); + box.MaximumSize = UIHelper.Scale(new Size(475, 350)); box.SetMessageToAutoSize(); var result = box.ShowDialog(); @@ -514,7 +514,7 @@ namespace BizHawk.Client.EmuHawk new[] { "Switch", "Continue" }, new[] { DialogResult.Yes, DialogResult.Cancel }); - box.MaximumSize = new Size(475, 350); + box.MaximumSize = UIHelper.Scale(new Size(475, 350)); box.SetMessageToAutoSize(); var result = box.ShowDialog(); diff --git a/BizHawk.Client.EmuHawk/UIHelper.cs b/BizHawk.Client.EmuHawk/UIHelper.cs index 27fffa4448..f6e01d6f16 100644 --- a/BizHawk.Client.EmuHawk/UIHelper.cs +++ b/BizHawk.Client.EmuHawk/UIHelper.cs @@ -2,42 +2,19 @@ using System.Drawing; using System.Windows.Forms; -namespace BizHawk.Client.Common +namespace BizHawk.Client.EmuHawk { public static class UIHelper { - private static readonly AutoScaleMode _autoScaleMode = AutoScaleMode.Font; - private static readonly SizeF _autoScaleBaseSize = new SizeF(6F, 13F); - private static readonly SizeF _autoScaleCurrentSize = GetCurrentAutoScaleSize(_autoScaleMode); + public static AutoScaleMode AutoScaleMode { get; } = AutoScaleMode.Font; - private static SizeF GetCurrentAutoScaleSize(AutoScaleMode autoScaleMode) - { - using (Form form = new Form()) - { - form.AutoScaleMode = autoScaleMode; - return form.CurrentAutoScaleDimensions; - } - } + public static SizeF AutoScaleBaseSize { get; } = new SizeF(6F, 13F); - public static AutoScaleMode AutoScaleMode - { - get { return _autoScaleMode; } - } + public static SizeF AutoScaleCurrentSize { get; } = GetCurrentAutoScaleSize(AutoScaleMode); - public static SizeF AutoScaleBaseSize - { - get { return _autoScaleBaseSize; } - } + public static float AutoScaleFactorX { get; } = AutoScaleCurrentSize.Width / AutoScaleBaseSize.Width; - public static float AutoScaleFactorX - { - get { return _autoScaleCurrentSize.Width / _autoScaleBaseSize.Width; } - } - - public static float AutoScaleFactorY - { - get { return _autoScaleCurrentSize.Height / _autoScaleBaseSize.Height; } - } + public static float AutoScaleFactorY { get; } = AutoScaleCurrentSize.Height / AutoScaleBaseSize.Height; public static int ScaleX(int size) { @@ -58,5 +35,13 @@ namespace BizHawk.Client.Common { return new Size(ScaleX(s.Width), ScaleY(s.Height)); } + + private static SizeF GetCurrentAutoScaleSize(AutoScaleMode autoScaleMode) + { + using (var form = new Form { AutoScaleMode = autoScaleMode }) + { + return form.CurrentAutoScaleDimensions; + } + } } } diff --git a/BizHawk.Client.EmuHawk/tools/TAStudio/TAStudio.cs b/BizHawk.Client.EmuHawk/tools/TAStudio/TAStudio.cs index 85a08c5ebe..183b37df89 100644 --- a/BizHawk.Client.EmuHawk/tools/TAStudio/TAStudio.cs +++ b/BizHawk.Client.EmuHawk/tools/TAStudio/TAStudio.cs @@ -332,7 +332,7 @@ namespace BizHawk.Client.EmuHawk new[] { "Switch", "Continue" }, new[] { DialogResult.Yes, DialogResult.Cancel }); - box.MaximumSize = new Size(475, 350); + box.MaximumSize = UIHelper.Scale(new Size(475, 350)); box.SetMessageToAutoSize(); var result = box.ShowDialog(); @@ -357,7 +357,7 @@ namespace BizHawk.Client.EmuHawk new[] { "Switch", "Continue" }, new[] { DialogResult.Yes, DialogResult.Cancel }); - box.MaximumSize = new Size(475, 350); + box.MaximumSize = UIHelper.Scale(new Size(475, 350)); box.SetMessageToAutoSize(); var result = box.ShowDialog(); From 9b8db260864404042cd5dfaa2ec848e1e38f8ab5 Mon Sep 17 00:00:00 2001 From: "J.D. Purcell" Date: Sat, 12 Oct 2019 23:27:42 -0400 Subject: [PATCH 016/166] TAStudio: Disable DPI scaling at least until I find a proper fix. It's ugly but now usable at 150% scaling. --- BizHawk.Client.EmuHawk/tools/TAStudio/TAStudio.Designer.cs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/BizHawk.Client.EmuHawk/tools/TAStudio/TAStudio.Designer.cs b/BizHawk.Client.EmuHawk/tools/TAStudio/TAStudio.Designer.cs index 08426ffc74..aec14166a2 100644 --- a/BizHawk.Client.EmuHawk/tools/TAStudio/TAStudio.Designer.cs +++ b/BizHawk.Client.EmuHawk/tools/TAStudio/TAStudio.Designer.cs @@ -1614,8 +1614,7 @@ namespace BizHawk.Client.EmuHawk // TAStudio // this.AllowDrop = true; - this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); - this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; + this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.None; this.ClientSize = new System.Drawing.Size(509, 576); this.Controls.Add(this.MainVertialSplit); this.Controls.Add(this.TasStatusStrip); From 7df71f2c86f14998f11cf8bf641977704fb3f701 Mon Sep 17 00:00:00 2001 From: YoshiRulz Date: Sun, 13 Oct 2019 15:23:14 +1000 Subject: [PATCH 017/166] Properly fix lib loading (builds upon 77bbc4128) Also cleaned up OSTailoredCode.cs and fixed qualifiers in Program.cs --- BizHawk.Client.Common/7z/LibraryManager.cs | 8 +-- BizHawk.Client.EmuHawk/Program.cs | 41 ++++++------- .../BizInvoke/DynamicLibraryImportResolver.cs | 10 ++-- BizHawk.Common/OSTailoredCode.cs | 60 ++++++++++++++----- .../N64/NativeApi/mupen64plusCoreApi.cs | 15 ++--- 5 files changed, 77 insertions(+), 57 deletions(-) diff --git a/BizHawk.Client.Common/7z/LibraryManager.cs b/BizHawk.Client.Common/7z/LibraryManager.cs index 6f2f375862..2f69a5770c 100644 --- a/BizHawk.Client.Common/7z/LibraryManager.cs +++ b/BizHawk.Client.Common/7z/LibraryManager.cs @@ -152,16 +152,16 @@ namespace SevenZip //{ // throw new SevenZipLibraryException("DLL file does not exist."); //} - if ((_modulePtr = libLoader.LoadPlatformSpecific(_libraryFileName)) == IntPtr.Zero) + if ((_modulePtr = libLoader.LoadOrNull(_libraryFileName).Value) == IntPtr.Zero) { //try a different directory string alternateFilename = Path.Combine(Path.Combine(Path.GetDirectoryName(_libraryFileName),"dll"),"7z.dll"); - if ((_modulePtr = libLoader.LoadPlatformSpecific(alternateFilename)) == IntPtr.Zero) + if ((_modulePtr = libLoader.LoadOrNull(_libraryFileName).Value) == IntPtr.Zero) throw new SevenZipLibraryException("failed to load library."); } if (libLoader.GetProcAddr(_modulePtr, "GetHandlerProperty") == IntPtr.Zero) { - libLoader.FreePlatformSpecific(_modulePtr); + libLoader.FreeByPtr(_modulePtr); throw new SevenZipLibraryException("library is invalid."); } } @@ -435,7 +435,7 @@ namespace SevenZip if (_totalUsers == 0) { #if !WINCE && !MONO - libLoader.FreePlatformSpecific(_modulePtr); + libLoader.FreeByPtr(_modulePtr); #endif _modulePtr = IntPtr.Zero; diff --git a/BizHawk.Client.EmuHawk/Program.cs b/BizHawk.Client.EmuHawk/Program.cs index a954845ac9..ca69912195 100644 --- a/BizHawk.Client.EmuHawk/Program.cs +++ b/BizHawk.Client.EmuHawk/Program.cs @@ -30,36 +30,33 @@ namespace BizHawk.Client.EmuHawk //try loading libraries we know we'll need //something in the winforms, etc. code below will cause .net to popup a missing msvcr100.dll in case that one's missing //but oddly it lets us proceed and we'll then catch it here - var d3dx9 = libLoader.LoadPlatformSpecific("d3dx9_43.dll"); - var vc2015 = libLoader.LoadPlatformSpecific("vcruntime140.dll"); - var vc2012 = libLoader.LoadPlatformSpecific("msvcr120.dll"); //TODO - check version? - var vc2010 = libLoader.LoadPlatformSpecific("msvcr100.dll"); //TODO - check version? - var vc2010p = libLoader.LoadPlatformSpecific("msvcp100.dll"); - var fail = vc2015 == IntPtr.Zero || vc2010 == IntPtr.Zero || vc2012 == IntPtr.Zero || vc2010p == IntPtr.Zero; - var warn = d3dx9 == IntPtr.Zero; - if (fail || warn) + var d3dx9 = libLoader.LoadOrNull("d3dx9_43.dll"); + var vc2015 = libLoader.LoadOrNull("vcruntime140.dll"); + var vc2012 = libLoader.LoadOrNull("msvcr120.dll"); //TODO - check version? + var vc2010 = libLoader.LoadOrNull("msvcr100.dll"); //TODO - check version? + var vc2010p = libLoader.LoadOrNull("msvcp100.dll"); + var reqPresent = vc2015.HasValue && vc2010.HasValue && vc2012.HasValue && vc2010p.HasValue; + var optPresent = d3dx9.HasValue; + if (!reqPresent || !optPresent) { var alertLines = new[] { "[ OK ] .NET CLR (You wouldn't even get here without it)", - $"[{(d3dx9 == IntPtr.Zero ? "WARN" : " OK ")}] Direct3d 9", - $"[{(vc2010 == IntPtr.Zero || vc2010p == IntPtr.Zero ? "FAIL" : " OK ")}] Visual C++ 2010 SP1 Runtime", - $"[{(vc2012 == IntPtr.Zero ? "FAIL" : " OK ")}] Visual C++ 2012 Runtime", - $"[{(vc2015 == IntPtr.Zero ? "FAIL" : " OK ")}] Visual C++ 2015 Runtime" + $"[{(d3dx9.HasValue ? " OK " : "WARN")}] Direct3d 9", + $"[{(vc2010.HasValue && vc2010p.HasValue ? " OK " : "FAIL")}] Visual C++ 2010 SP1 Runtime", + $"[{(vc2012.HasValue ? " OK " : "FAIL")}] Visual C++ 2012 Runtime", + $"[{(vc2015.HasValue ? " OK " : "FAIL")}] Visual C++ 2015 Runtime" }; - var box = new BizHawk.Client.EmuHawk.CustomControls.PrereqsAlert(!fail) + var box = new CustomControls.PrereqsAlert(reqPresent) { textBox1 = { Text = string.Join(Environment.NewLine, alertLines) } }; box.ShowDialog(); - if (fail) System.Diagnostics.Process.GetCurrentProcess().Kill(); + if (!reqPresent) Process.GetCurrentProcess().Kill(); } - libLoader.FreePlatformSpecific(d3dx9); - libLoader.FreePlatformSpecific(vc2015); - libLoader.FreePlatformSpecific(vc2012); - libLoader.FreePlatformSpecific(vc2010); - libLoader.FreePlatformSpecific(vc2010p); + foreach (var p in new[] { d3dx9, vc2015, vc2012, vc2010, vc2010p }) + if (p.HasValue) libLoader.FreeByPtr(p.Value); // this will look in subdirectory "dll" to load pinvoked stuff var dllDir = Path.Combine(Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location), "dll"); @@ -110,7 +107,7 @@ namespace BizHawk.Client.EmuHawk } } - BizHawk.Common.TempFileManager.Start(); + TempFileManager.Start(); HawkFile.ArchiveHandlerFactory = new SevenZipSharpArchiveHandler(); @@ -129,8 +126,8 @@ namespace BizHawk.Client.EmuHawk Global.Config.ResolveDefaults(); - BizHawk.Client.Common.StringLogUtil.DefaultToDisk = Global.Config.MoviesOnDisk; - BizHawk.Client.Common.StringLogUtil.DefaultToAWE = Global.Config.MoviesInAWE; + StringLogUtil.DefaultToDisk = Global.Config.MoviesOnDisk; + StringLogUtil.DefaultToAWE = Global.Config.MoviesInAWE; // super hacky! this needs to be done first. still not worth the trouble to make this system fully proper if (Array.Exists(args, arg => arg.StartsWith("--gdi", StringComparison.InvariantCultureIgnoreCase))) diff --git a/BizHawk.Common/BizInvoke/DynamicLibraryImportResolver.cs b/BizHawk.Common/BizInvoke/DynamicLibraryImportResolver.cs index e71a78fbef..b2b3928185 100644 --- a/BizHawk.Common/BizInvoke/DynamicLibraryImportResolver.cs +++ b/BizHawk.Common/BizInvoke/DynamicLibraryImportResolver.cs @@ -5,15 +5,15 @@ using BizHawk.Common; namespace BizHawk.Common.BizInvoke { + /// TODO move this and all in IImportResolver.cs to OSTailoredCode.cs and refactor public class DynamicLibraryImportResolver : IImportResolver, IDisposable { private IntPtr _p; - private readonly OSTailoredCode.ILinkedLibManager libLoader = OSTailoredCode.LinkedLibManager; + private readonly OSTailoredCode.ILinkedLibManager libLoader = OSTailoredCode.LinkedLibManager; //TODO inline? public DynamicLibraryImportResolver(string dllName) { - _p = libLoader.LoadPlatformSpecific(dllName); - if (_p == IntPtr.Zero) throw new InvalidOperationException($"null pointer returned by {nameof(libLoader.LoadPlatformSpecific)}"); + _p = libLoader.LoadOrThrow(dllName); } public IntPtr Resolve(string entryPoint) @@ -23,8 +23,8 @@ namespace BizHawk.Common.BizInvoke private void Free() { - if (_p == IntPtr.Zero) return; - libLoader.FreePlatformSpecific(_p); + if (_p == IntPtr.Zero) return; // already freed + libLoader.FreeByPtr(_p); _p = IntPtr.Zero; } diff --git a/BizHawk.Common/OSTailoredCode.cs b/BizHawk.Common/OSTailoredCode.cs index 65b46ff569..e130cf94e1 100644 --- a/BizHawk.Common/OSTailoredCode.cs +++ b/BizHawk.Common/OSTailoredCode.cs @@ -31,11 +31,13 @@ namespace BizHawk.Common public static ILinkedLibManager LinkedLibManager => _LinkedLibManager.Value; + /// this interface's inheritors hide OS-specific implementation details public interface ILinkedLibManager { - IntPtr LoadPlatformSpecific(string dllToLoad); - IntPtr GetProcAddr(IntPtr hModule, string procName); - int FreePlatformSpecific(IntPtr hModule); + IntPtr? LoadOrNull(string dllToLoad); + IntPtr LoadOrThrow(string dllToLoad); + IntPtr GetProcAddr(IntPtr hModule, string procName); //TODO also split into nullable and throwing? + int FreeByPtr(IntPtr hModule); } /// This class is copied from a tutorial, so don't git blame and then email me expecting insight. @@ -43,41 +45,67 @@ namespace BizHawk.Common { private const int RTLD_NOW = 2; [DllImport("libdl.so.2")] - private static extern IntPtr dlopen(string fileName, int flags); + private static extern int dlclose(IntPtr handle); [DllImport("libdl.so.2")] private static extern IntPtr dlerror(); [DllImport("libdl.so.2")] - private static extern IntPtr dlsym(IntPtr handle, string symbol); + private static extern IntPtr dlopen(string fileName, int flags); [DllImport("libdl.so.2")] - private static extern int dlclose(IntPtr handle); + private static extern IntPtr dlsym(IntPtr handle, string symbol); - public IntPtr LoadPlatformSpecific(string dllToLoad) => dlopen(dllToLoad, RTLD_NOW); public IntPtr GetProcAddr(IntPtr hModule, string procName) { dlerror(); var res = dlsym(hModule, procName); var errPtr = dlerror(); - if (errPtr != IntPtr.Zero) throw new InvalidOperationException($"error in dlsym: {Marshal.PtrToStringAnsi(errPtr)}"); + if (errPtr != IntPtr.Zero) throw new InvalidOperationException($"error in {nameof(dlsym)}: {Marshal.PtrToStringAnsi(errPtr)}"); return res; } - public int FreePlatformSpecific(IntPtr hModule) => dlclose(hModule); + + public int FreeByPtr(IntPtr hModule) => dlclose(hModule); + + public IntPtr? LoadOrNull(string dllToLoad) + { + var p = dlopen(dllToLoad, RTLD_NOW); + return p == IntPtr.Zero ? default(IntPtr?) : p; + } + + public IntPtr LoadOrThrow(string dllToLoad) + { + var p = LoadOrNull(dllToLoad); + if (!p.HasValue) throw new InvalidOperationException($"got null pointer from {nameof(dlopen)}, error: {Marshal.PtrToStringAnsi(dlerror())}"); + return p.Value; + } } private class WindowsLLManager : ILinkedLibManager { // comments reference extern functions removed from SevenZip.NativeMethods [DllImport("kernel32.dll")] + private static extern bool FreeLibrary(IntPtr hModule); // return type was annotated MarshalAs(UnmanagedType.Bool) + [DllImport("kernel32.dll")] private static extern uint GetLastError(); [DllImport("kernel32.dll")] // had BestFitMapping = false, ThrowOnUnmappableChar = true - private static extern IntPtr LoadLibrary(string dllToLoad); // param dllToLoad was annotated `[MarshalAs(UnmanagedType.LPStr)]` - [DllImport("kernel32.dll")] // had BestFitMapping = false, ThrowOnUnmappableChar = true private static extern IntPtr GetProcAddress(IntPtr hModule, string procName); // param procName was annotated `[MarshalAs(UnmanagedType.LPStr)]` - [DllImport("kernel32.dll")] - private static extern bool FreeLibrary(IntPtr hModule); // return type was annotated MarshalAs(UnmanagedType.Bool) + [DllImport("kernel32.dll")] // had BestFitMapping = false, ThrowOnUnmappableChar = true + private static extern IntPtr LoadLibrary(string dllToLoad); // param dllToLoad was annotated `[MarshalAs(UnmanagedType.LPStr)]` - public IntPtr LoadPlatformSpecific(string dllToLoad) => LoadLibrary(dllToLoad); public IntPtr GetProcAddr(IntPtr hModule, string procName) => GetProcAddress(hModule, procName); - public int FreePlatformSpecific(IntPtr hModule) => FreeLibrary(hModule) ? 1 : 0; + + public int FreeByPtr(IntPtr hModule) => FreeLibrary(hModule) ? 1 : 0; + + public IntPtr? LoadOrNull(string dllToLoad) + { + var p = LoadLibrary(dllToLoad); + return p == IntPtr.Zero ? default(IntPtr?) : p; + } + + public IntPtr LoadOrThrow(string dllToLoad) + { + var p = LoadOrNull(dllToLoad); + if (!p.HasValue) throw new InvalidOperationException($"got null pointer from {nameof(LoadLibrary)}, error code: {GetLastError()}"); + return p.Value; + } } public enum DistinctOS : byte @@ -91,7 +119,7 @@ namespace BizHawk.Common /// POSIX $* (space-delimited) /// stdout is discarded if false /// stderr is discarded if false - /// OS is implicit and needs to be checked at callsite, returned has not been started + /// OS is implicit and needs to be checked at callsite. Returned has not been started. public static Process ConstructSubshell(string cmd, string args, bool checkStdout = true, bool checkStderr = false) => new Process { StartInfo = new ProcessStartInfo { diff --git a/BizHawk.Emulation.Cores/Consoles/Nintendo/N64/NativeApi/mupen64plusCoreApi.cs b/BizHawk.Emulation.Cores/Consoles/Nintendo/N64/NativeApi/mupen64plusCoreApi.cs index c0dfaba506..3601c271f3 100644 --- a/BizHawk.Emulation.Cores/Consoles/Nintendo/N64/NativeApi/mupen64plusCoreApi.cs +++ b/BizHawk.Emulation.Cores/Consoles/Nintendo/N64/NativeApi/mupen64plusCoreApi.cs @@ -484,9 +484,7 @@ namespace BizHawk.Emulation.Cores.Nintendo.N64.NativeApi } this.bizhawkCore = bizhawkCore; - CoreDll = libLoader.LoadPlatformSpecific("mupen64plus"); - if (CoreDll == IntPtr.Zero) - throw new InvalidOperationException("Failed to load mupen64plus.dll"); + CoreDll = libLoader.LoadOrThrow("mupen64plus"); connectFunctionPointers(); @@ -914,7 +912,7 @@ namespace BizHawk.Emulation.Cores.Nintendo.N64.NativeApi m64pCoreDoCommandPtr(m64p_command.M64CMD_ROM_CLOSE, 0, IntPtr.Zero); m64pCoreShutdown(); - libLoader.FreePlatformSpecific(CoreDll); + libLoader.FreeByPtr(CoreDll); disposed = true; } @@ -934,10 +932,7 @@ namespace BizHawk.Emulation.Cores.Nintendo.N64.NativeApi DetachPlugin(type); AttachedPlugin plugin; - plugin.dllHandle = libLoader.LoadPlatformSpecific(PluginName); - if (plugin.dllHandle == IntPtr.Zero) - throw new InvalidOperationException($"Failed to load plugin {PluginName}"); - + plugin.dllHandle = libLoader.LoadOrThrow(PluginName); plugin.dllStartup = (PluginStartup)Marshal.GetDelegateForFunctionPointer(libLoader.GetProcAddr(plugin.dllHandle, "PluginStartup"), typeof(PluginStartup)); plugin.dllShutdown = (PluginShutdown)Marshal.GetDelegateForFunctionPointer(libLoader.GetProcAddr(plugin.dllHandle, "PluginShutdown"), typeof(PluginShutdown)); plugin.dllStartup(CoreDll, null, null); @@ -945,7 +940,7 @@ namespace BizHawk.Emulation.Cores.Nintendo.N64.NativeApi m64p_error result = m64pCoreAttachPlugin(type, plugin.dllHandle); if (result != m64p_error.M64ERR_SUCCESS) { - libLoader.FreePlatformSpecific(plugin.dllHandle); + libLoader.FreeByPtr(plugin.dllHandle); throw new InvalidOperationException($"Error during attaching plugin {PluginName}"); } @@ -961,7 +956,7 @@ namespace BizHawk.Emulation.Cores.Nintendo.N64.NativeApi plugins.Remove(type); m64pCoreDetachPlugin(type); plugin.dllShutdown(); - libLoader.FreePlatformSpecific(plugin.dllHandle); + libLoader.FreeByPtr(plugin.dllHandle); } } From 462bd891af18c5900fc5eda0039524474239e5a0 Mon Sep 17 00:00:00 2001 From: YoshiRulz Date: Mon, 14 Oct 2019 00:51:44 +1000 Subject: [PATCH 018/166] Fix SevenZipLibraryManager.LoadLibrary --- BizHawk.Client.Common/7z/LibraryManager.cs | 88 +++++++++++----------- 1 file changed, 44 insertions(+), 44 deletions(-) diff --git a/BizHawk.Client.Common/7z/LibraryManager.cs b/BizHawk.Client.Common/7z/LibraryManager.cs index 2f69a5770c..1f93b0e8c1 100644 --- a/BizHawk.Client.Common/7z/LibraryManager.cs +++ b/BizHawk.Client.Common/7z/LibraryManager.cs @@ -134,54 +134,54 @@ namespace SevenZip /// Archive format public static void LoadLibrary(object user, Enum format) { - lock (_syncRoot) - { - if (_inArchives == null -#if COMPRESS - || _outArchives == null -#endif - ) + lock (_syncRoot) { - Init(); - } + if (_inArchives == null +#if COMPRESS + || _outArchives == null +#endif + ) + { + Init(); + } #if !WINCE && !MONO - if (_modulePtr == IntPtr.Zero) - { - //zero 29-oct-2012 - this check isnt useful since LoadLibrary can pretty much check for the same thing. and it wrecks our dll relocation scheme - //if (!File.Exists(_libraryFileName)) - //{ - // throw new SevenZipLibraryException("DLL file does not exist."); - //} - if ((_modulePtr = libLoader.LoadOrNull(_libraryFileName).Value) == IntPtr.Zero) + if (_modulePtr == IntPtr.Zero) { - //try a different directory - string alternateFilename = Path.Combine(Path.Combine(Path.GetDirectoryName(_libraryFileName),"dll"),"7z.dll"); - if ((_modulePtr = libLoader.LoadOrNull(_libraryFileName).Value) == IntPtr.Zero) - throw new SevenZipLibraryException("failed to load library."); - } - if (libLoader.GetProcAddr(_modulePtr, "GetHandlerProperty") == IntPtr.Zero) - { - libLoader.FreeByPtr(_modulePtr); - throw new SevenZipLibraryException("library is invalid."); - } - } -#endif - if (format is InArchiveFormat) - { - InitUserInFormat(user, (InArchiveFormat) format); - return; - } -#if COMPRESS - if (format is OutArchiveFormat) - { - InitUserOutFormat(user, (OutArchiveFormat) format); - return; - } -#endif - throw new ArgumentException( - "Enum " + format + " is not a valid archive format attribute!"); - } + //zero 29-oct-2012 - this check isnt useful since LoadOrNull can pretty much check for the same thing. and it wrecks our dll relocation scheme + //if (!File.Exists(_libraryFileName)) + //{ + // throw new SevenZipLibraryException("DLL file does not exist."); + //} + var newPtr = libLoader.LoadOrNull(_libraryFileName); + if (!newPtr.HasValue) + { + //try a different directory + newPtr = libLoader.LoadOrNull(Path.Combine(Path.Combine(Path.GetDirectoryName(_libraryFileName), "dll"), "7z.dll")); + if (!newPtr.HasValue) throw new SevenZipLibraryException("failed to load library."); + } + _modulePtr = newPtr.Value; + if (libLoader.GetProcAddr(_modulePtr, "GetHandlerProperty") == IntPtr.Zero) + { + libLoader.FreeByPtr(_modulePtr); + throw new SevenZipLibraryException("library is invalid."); + } + } +#endif + if (format is InArchiveFormat) + { + InitUserInFormat(user, (InArchiveFormat) format); + return; + } +#if COMPRESS + if (format is OutArchiveFormat) + { + InitUserOutFormat(user, (OutArchiveFormat) format); + return; + } +#endif + throw new ArgumentException("Enum " + format + " is not a valid archive format attribute!"); + } } /*/// From 0e9cc431d9c98092982652055d8089005b93e0b1 Mon Sep 17 00:00:00 2001 From: YoshiRulz Date: Tue, 20 Aug 2019 00:36:22 +1000 Subject: [PATCH 019/166] Rewrite IsAvailable, call to Assembly.GetTypes is now lazy --- BizHawk.Client.EmuHawk/Program.cs | 3 + BizHawk.Client.EmuHawk/tools/ToolManager.cs | 65 +++++++-------------- 2 files changed, 25 insertions(+), 43 deletions(-) diff --git a/BizHawk.Client.EmuHawk/Program.cs b/BizHawk.Client.EmuHawk/Program.cs index ca69912195..f38148808b 100644 --- a/BizHawk.Client.EmuHawk/Program.cs +++ b/BizHawk.Client.EmuHawk/Program.cs @@ -72,6 +72,9 @@ namespace BizHawk.Client.EmuHawk //We need to do it here too... otherwise people get exceptions when externaltools we distribute try to startup } + + // Assembly.ReflectionOnlyLoadFrom doesn't automatically load deps, this stops it from throwing when called + AppDomain.CurrentDomain.ReflectionOnlyAssemblyResolve += (sender, args) => Assembly.ReflectionOnlyLoad(args.Name); } [STAThread] diff --git a/BizHawk.Client.EmuHawk/tools/ToolManager.cs b/BizHawk.Client.EmuHawk/tools/ToolManager.cs index 27d1ed70e8..fef10a6b4b 100644 --- a/BizHawk.Client.EmuHawk/tools/ToolManager.cs +++ b/BizHawk.Client.EmuHawk/tools/ToolManager.cs @@ -736,60 +736,39 @@ namespace BizHawk.Client.EmuHawk } } - public bool IsAvailable() - { - return IsAvailable(typeof(T)); - } + private static readonly Lazy> lazyAsmTypes = new Lazy>(() => + Assembly.ReflectionOnlyLoadFrom(Assembly.GetExecutingAssembly().Location) + .GetTypes() + .Select(t => t.AssemblyQualifiedName) + .ToList() + ); - public bool IsAvailable(Type t) + public bool IsAvailable(Type tool) { - if (!ServiceInjector.IsAvailable(Global.Emulator.ServiceProvider, t)) + if (!ServiceInjector.IsAvailable(Global.Emulator.ServiceProvider, tool) + || !lazyAsmTypes.Value.Contains(tool.AssemblyQualifiedName) // not a tool + || (tool == typeof(LuaConsole) && OSTailoredCode.CurrentOS != OSTailoredCode.DistinctOS.Windows)) // simply doesn't work (for now) { return false; } - if (t == typeof(LuaConsole) && OSTailoredCode.CurrentOS != OSTailoredCode.DistinctOS.Windows) return false; - - var tool = Assembly - .GetExecutingAssembly() - .GetTypes() - .FirstOrDefault(type => type == t); - - if (tool == null) // This isn't a tool, must not be available + ToolAttribute attr; + try { - return false; + attr = tool.GetCustomAttributes(false).OfType().Single(); + } + catch (InvalidOperationException e) + { + return true; // no ToolAttribute on given type -> assumed all supported } - var attr = tool.GetCustomAttributes(false) - .OfType() - .FirstOrDefault(); - - // start with the assumption that if no supported systems are mentioned and no unsupported cores are mentioned - // then this is available for all - bool supported = true; - - if (attr?.SupportedSystems != null && attr.SupportedSystems.Any()) - { - // supported systems are available - supported = attr.SupportedSystems.Contains(Global.Emulator.SystemId); - - if (supported) - { - // check for a core not supported override - if (attr.UnsupportedCores.Contains(Global.Emulator.DisplayName())) - supported = false; - } - } - else if (attr?.UnsupportedCores != null && attr.UnsupportedCores.Any()) - { - // no supported system specified, but unsupported cores are - if (attr.UnsupportedCores.Contains(Global.Emulator.DisplayName())) - supported = false; - } - - return supported; + var sysName = Global.Emulator.DisplayName(); + return !attr.UnsupportedCores.Contains(sysName) // not unsupported + && (!attr.SupportedSystems.Any() || attr.SupportedSystems.Contains(sysName)); // supported (no supported list -> assumed all supported) } + public bool IsAvailable() => IsAvailable(typeof(T)); + // Note: Referencing these properties creates an instance of the tool and persists it. They should be referenced by type if this is not desired #region Tools From 90b0574bc385bd4c1cb15a42c2e9b5ce5e06d22b Mon Sep 17 00:00:00 2001 From: James Groom Date: Sun, 13 Oct 2019 15:50:57 +0000 Subject: [PATCH 020/166] Remove unnecessary calls to ToList (e.g. in foreach) squashed PR #1591 --- BizHawk.Client.Common/RecentFiles.cs | 12 +-- BizHawk.Client.Common/config/Binding.cs | 7 +- BizHawk.Client.Common/config/PathEntry.cs | 2 +- .../lua/EmuLuaLibrary.Events.cs | 76 ++++++++----------- .../movie/bk2/Bk2ControllerAdapter.cs | 2 +- BizHawk.Client.Common/tools/CheatList.cs | 9 +-- .../tools/RamSearchEngine.cs | 3 +- .../DATTools/NOINTROParser.cs | 10 +-- BizHawk.Client.DBMan/DATTools/TOSECParser.cs | 10 +-- BizHawk.Client.EmuHawk/Api/ApiManager.cs | 15 ++-- BizHawk.Client.EmuHawk/BizBox.cs | 3 +- .../CustomControls/InputRoll.cs | 23 ++---- BizHawk.Client.EmuHawk/MainForm.Hotkey.cs | 5 +- .../Sound/Output/DirectSoundSoundOutput.cs | 2 +- .../Sound/Output/XAudio2SoundOutput.cs | 4 +- BizHawk.Client.EmuHawk/config/HotkeyConfig.cs | 4 +- .../config/NES/NESSyncSettingsForm.cs | 2 +- BizHawk.Client.EmuHawk/config/PathConfig.cs | 11 ++- BizHawk.Client.EmuHawk/movie/PlayMovie.cs | 18 ++--- .../tools/BasicBot/BasicBot.cs | 8 +- BizHawk.Client.EmuHawk/tools/Cheats/Cheats.cs | 9 ++- .../tools/Debugger/RegisterBoxControl.cs | 47 +++++------- .../tools/HexEditor/HexEditor.cs | 5 +- .../Lua/Libraries/EmuLuaLibrary.Console.cs | 3 +- .../Lua/Libraries/EmuLuaLibrary.Forms.cs | 6 +- .../tools/Lua/Libraries/EmuLuaLibrary.cs | 15 ++-- .../tools/Lua/LuaConsole.cs | 40 ++++------ .../tools/Lua/LuaRegisteredFunctionsList.cs | 2 +- .../MultiDiskBundler/MultiDiskBundler.cs | 4 +- .../tools/TAStudio/TAStudio.MenuItems.cs | 11 +-- .../tools/VirtualPads/VirtualPad.cs | 40 +++++----- .../tools/Watch/RamSearch.cs | 2 +- .../tools/Watch/RamWatch.cs | 6 +- BizHawk.Client.MultiHawk/Mainform.cs | 6 +- BizHawk.Client.MultiHawk/movie/PlayMovie.cs | 18 ++--- BizHawk.Common/BizInvoke/BizExvoker.cs | 3 +- BizHawk.Emulation.Common/ServiceAttributes.cs | 2 +- .../Hardware/Display/AmstradGateArray.cs | 3 +- .../AmstradCPC/Media/Tape/TapeDataBlock.cs | 7 +- .../Media/Disk/IPFFormat/IPFFloppyDisk.cs | 2 +- .../Media/Tape/TapeDataBlock.cs | 7 +- .../Consoles/Atari/2600/Atari2600.cs | 2 +- .../Gameboy/GambatteLink.IDebuggable.cs | 2 +- BizHawk.Emulation.Cores/CoreInventory.cs | 2 +- BizHawk.Emulation.Cores/Waterbox/ElfRunner.cs | 16 ++-- BizHawk.Emulation.DiscSystem/CDFS/ISOFile.cs | 4 +- 46 files changed, 198 insertions(+), 292 deletions(-) diff --git a/BizHawk.Client.Common/RecentFiles.cs b/BizHawk.Client.Common/RecentFiles.cs index b3fa4b91c6..19ca7df854 100644 --- a/BizHawk.Client.Common/RecentFiles.cs +++ b/BizHawk.Client.Common/RecentFiles.cs @@ -89,17 +89,7 @@ namespace BizHawk.Client.Common { if (!Frozen) { - var removed = false; - foreach (var recent in recentlist.ToList()) - { - if (string.Compare(newFile, recent, StringComparison.CurrentCultureIgnoreCase) == 0) - { - recentlist.Remove(newFile); // intentionally keeps iterating after this to remove duplicate instances, though those should never exist in the first place - removed = true; - } - } - - return removed; + return recentlist.RemoveAll(recent => string.Compare(newFile, recent, StringComparison.CurrentCultureIgnoreCase) == 0) != 0; // none removed => return false } return false; diff --git a/BizHawk.Client.Common/config/Binding.cs b/BizHawk.Client.Common/config/Binding.cs index c2ec1c1738..b2d9ad6d6a 100644 --- a/BizHawk.Client.Common/config/Binding.cs +++ b/BizHawk.Client.Common/config/Binding.cs @@ -96,13 +96,8 @@ namespace BizHawk.Client.Common } } - List entriesToRemove = (from entry in Bindings let binding = DefaultValues.FirstOrDefault(b => b.DisplayName == entry.DisplayName) where binding == null select entry).ToList(); - // Remove entries that no longer exist in defaults - foreach (Binding entry in entriesToRemove) - { - Bindings.Remove(entry); - } + Bindings.RemoveAll(entry => DefaultValues.All(b => b.DisplayName != entry.DisplayName)); } private static List _defaultValues; diff --git a/BizHawk.Client.Common/config/PathEntry.cs b/BizHawk.Client.Common/config/PathEntry.cs index 8f8e6776a5..2c91df1807 100644 --- a/BizHawk.Client.Common/config/PathEntry.cs +++ b/BizHawk.Client.Common/config/PathEntry.cs @@ -119,7 +119,7 @@ namespace BizHawk.Client.Common } // Add missing displaynames - var missingDisplayPaths = Paths.Where(p => p.SystemDisplayName == null).ToList(); + var missingDisplayPaths = Paths.Where(p => p.SystemDisplayName == null); foreach (PathEntry path in missingDisplayPaths) { path.SystemDisplayName = DefaultValues.First(p => p.System == path.System).SystemDisplayName; diff --git a/BizHawk.Client.Common/lua/EmuLuaLibrary.Events.cs b/BizHawk.Client.Common/lua/EmuLuaLibrary.Events.cs index 1ec246820e..da03cbd7eb 100644 --- a/BizHawk.Client.Common/lua/EmuLuaLibrary.Events.cs +++ b/BizHawk.Client.Common/lua/EmuLuaLibrary.Events.cs @@ -50,78 +50,66 @@ namespace BizHawk.Client.Common public void CallSaveStateEvent(string name) { - var lfs = _luaFunctions.Where(l => l.Event == "OnSavestateSave").ToList(); - if (lfs.Any()) + var lfs = _luaFunctions.Where(l => l.Event == "OnSavestateSave"); + try { - try + foreach (var lf in lfs) { - foreach (var lf in lfs) - { - lf.Call(name); - } - } - catch (Exception e) - { - Log($"error running function attached by lua function event.onsavestate\nError message: {e.Message}"); + lf.Call(name); } } + catch (Exception e) + { + Log($"error running function attached by lua function event.onsavestate\nError message: {e.Message}"); + } } public void CallLoadStateEvent(string name) { - var lfs = _luaFunctions.Where(l => l.Event == "OnSavestateLoad").ToList(); - if (lfs.Any()) + var lfs = _luaFunctions.Where(l => l.Event == "OnSavestateLoad"); + try { - try + foreach (var lf in lfs) { - foreach (var lf in lfs) - { - lf.Call(name); - } - } - catch (Exception e) - { - Log($"error running function attached by lua function event.onloadstate\nError message: {e.Message}"); + lf.Call(name); } } + catch (Exception e) + { + Log($"error running function attached by lua function event.onloadstate\nError message: {e.Message}"); + } } public void CallFrameBeforeEvent() { - var lfs = _luaFunctions.Where(l => l.Event == "OnFrameStart").ToList(); - if (lfs.Any()) + var lfs = _luaFunctions.Where(l => l.Event == "OnFrameStart"); + try { - try + foreach (var lf in lfs) { - foreach (var lf in lfs) - { - lf.Call(); - } - } - catch (Exception e) - { - Log($"error running function attached by lua function event.onframestart\nError message: {e.Message}"); + lf.Call(); } } + catch (Exception e) + { + Log($"error running function attached by lua function event.onframestart\nError message: {e.Message}"); + } } public void CallFrameAfterEvent() { - var lfs = _luaFunctions.Where(l => l.Event == "OnFrameEnd").ToList(); - if (lfs.Any()) + var lfs = _luaFunctions.Where(l => l.Event == "OnFrameEnd"); + try { - try + foreach (var lf in lfs) { - foreach (var lf in lfs) - { - lf.Call(); - } - } - catch (Exception e) - { - Log($"error running function attached by lua function event.onframeend\nError message: {e.Message}"); + lf.Call(); } } + catch (Exception e) + { + Log($"error running function attached by lua function event.onframeend\nError message: {e.Message}"); + } } private bool N64CoreTypeDynarec() diff --git a/BizHawk.Client.Common/movie/bk2/Bk2ControllerAdapter.cs b/BizHawk.Client.Common/movie/bk2/Bk2ControllerAdapter.cs index 5c49ef6f5d..fbcd18319f 100644 --- a/BizHawk.Client.Common/movie/bk2/Bk2ControllerAdapter.cs +++ b/BizHawk.Client.Common/movie/bk2/Bk2ControllerAdapter.cs @@ -160,7 +160,7 @@ namespace BizHawk.Client.Common { var def = Global.Emulator.ControllerDefinition; var trimmed = mnemonic.Replace("|", ""); - var buttons = Definition.ControlsOrdered.SelectMany(c => c).ToList(); + var buttons = Definition.ControlsOrdered.SelectMany(c => c); var iterator = 0; foreach (var key in buttons) diff --git a/BizHawk.Client.Common/tools/CheatList.cs b/BizHawk.Client.Common/tools/CheatList.cs index 1ec255a96e..79a8cb95c7 100644 --- a/BizHawk.Client.Common/tools/CheatList.cs +++ b/BizHawk.Client.Common/tools/CheatList.cs @@ -222,7 +222,7 @@ namespace BizHawk.Client.Common public void RemoveRange(IEnumerable cheats) { - foreach (var cheat in cheats.ToList()) + foreach (var cheat in cheats.ToList()) // enumerate passed IEnumerable because it may depend on the value of _cheatList { _cheatList.Remove(cheat); } @@ -232,12 +232,7 @@ namespace BizHawk.Client.Common public void RemoveRange(IEnumerable watches) { - var removeList = _cheatList.Where(cheat => watches.Any(w => w == cheat)).ToList(); - foreach (var cheat in removeList) - { - _cheatList.Remove(cheat); - } - + _cheatList.RemoveAll(cheat => watches.Any(w => w == cheat)); Changes = true; } diff --git a/BizHawk.Client.Common/tools/RamSearchEngine.cs b/BizHawk.Client.Common/tools/RamSearchEngine.cs index 945312ff44..c65d589143 100644 --- a/BizHawk.Client.Common/tools/RamSearchEngine.cs +++ b/BizHawk.Client.Common/tools/RamSearchEngine.cs @@ -341,8 +341,7 @@ namespace BizHawk.Client.Common } var addresses = watches.Select(w => w.Address); - var removeList = _watchList.Where(w => addresses.Contains(w.Address)).ToList(); - _watchList = _watchList.Except(removeList).ToList(); + _watchList.RemoveAll(w => addresses.Contains(w.Address)); } public void RemoveRange(IEnumerable indices) diff --git a/BizHawk.Client.DBMan/DATTools/NOINTROParser.cs b/BizHawk.Client.DBMan/DATTools/NOINTROParser.cs index de710c70d2..b64be85b47 100644 --- a/BizHawk.Client.DBMan/DATTools/NOINTROParser.cs +++ b/BizHawk.Client.DBMan/DATTools/NOINTROParser.cs @@ -188,11 +188,11 @@ namespace BizHawk.Client.DBMan // process dump info flags and other info contained in [] if (nameString.Contains("[") && nameString.Contains("]")) { - List e = nameString.ToString().Split('[', ']').ToList(); - // remove first entry (this is the bit before the [] entries start - e.RemoveAt(0); - // remove empty entries - e = e.Where(s => !string.IsNullOrWhiteSpace(s)).Distinct().ToList(); + var e = nameString.Split('[', ']') + .Skip(1) // remove first entry (this is the bit before the [] entries start) + .Where(s => !string.IsNullOrWhiteSpace(s)) // remove empty entries + .Distinct() + .ToList(); if (e.Count > 0) { diff --git a/BizHawk.Client.DBMan/DATTools/TOSECParser.cs b/BizHawk.Client.DBMan/DATTools/TOSECParser.cs index 7ab55b2036..25f2834476 100644 --- a/BizHawk.Client.DBMan/DATTools/TOSECParser.cs +++ b/BizHawk.Client.DBMan/DATTools/TOSECParser.cs @@ -206,11 +206,11 @@ namespace BizHawk.Client.DBMan // process dump info flags and other info contained in [] if (nameString.Contains("[") && nameString.Contains("]")) { - List e = nameString.ToString().Split('[', ']').ToList(); - // remove first entry (this is the bit before the [] entries start - e.RemoveAt(0); - // remove empty entries - e = e.Where(s => !string.IsNullOrWhiteSpace(s)).Distinct().ToList(); + var e = nameString.Split('[', ']') + .Skip(1) // remove first entry (this is the bit before the [] entries start) + .Where(s => !string.IsNullOrWhiteSpace(s)) // remove empty entries + .Distinct() + .ToList(); if (e.Count > 0) { diff --git a/BizHawk.Client.EmuHawk/Api/ApiManager.cs b/BizHawk.Client.EmuHawk/Api/ApiManager.cs index 9dd5b71087..fdb3f836f7 100644 --- a/BizHawk.Client.EmuHawk/Api/ApiManager.cs +++ b/BizHawk.Client.EmuHawk/Api/ApiManager.cs @@ -23,15 +23,12 @@ namespace BizHawk.Client.EmuHawk .Where(t => typeof(IExternalApi).IsAssignableFrom(t)) .Where(t => t.IsSealed) .Where(t => ServiceInjector.IsAvailable(serviceProvider, t)) - .ToList(); - - apis.AddRange( - Assembly - .GetAssembly(typeof(ApiContainer)) - .GetTypes() - .Where(t => typeof(IExternalApi).IsAssignableFrom(t)) - .Where(t => t.IsSealed) - .Where(t => ServiceInjector.IsAvailable(serviceProvider, t))); + .Concat(Assembly + .GetAssembly(typeof(ApiContainer)) + .GetTypes() + .Where(t => typeof(IExternalApi).IsAssignableFrom(t)) + .Where(t => t.IsSealed) + .Where(t => ServiceInjector.IsAvailable(serviceProvider, t))); foreach (var api in apis) { diff --git a/BizHawk.Client.EmuHawk/BizBox.cs b/BizHawk.Client.EmuHawk/BizBox.cs index a233234d1d..9bff885393 100644 --- a/BizHawk.Client.EmuHawk/BizBox.cs +++ b/BizHawk.Client.EmuHawk/BizBox.cs @@ -48,8 +48,7 @@ namespace BizHawk.Client.EmuHawk .Select(t => t.GetCustomAttributes(false).OfType().FirstOrDefault()) .Where(a => a != null) .Where(a => a.Released) - .OrderByDescending(a => a.CoreName.ToLower()) - .ToList(); + .OrderByDescending(a => a.CoreName.ToLower()); foreach (var core in cores) { diff --git a/BizHawk.Client.EmuHawk/CustomControls/InputRoll.cs b/BizHawk.Client.EmuHawk/CustomControls/InputRoll.cs index 5bab6dc2e7..e9489b93bb 100644 --- a/BizHawk.Client.EmuHawk/CustomControls/InputRoll.cs +++ b/BizHawk.Client.EmuHawk/CustomControls/InputRoll.cs @@ -1373,7 +1373,7 @@ namespace BizHawk.Client.EmuHawk { if (SelectedRows.Any() && LetKeysModifySelection && SelectedRows.First() > 0) { - foreach (var row in SelectedRows.ToList()) + foreach (var row in SelectedRows.ToList()) // clones SelectedRows { SelectRow(row - 1, true); SelectRow(row, false); @@ -1384,7 +1384,7 @@ namespace BizHawk.Client.EmuHawk { if (SelectedRows.Any() && LetKeysModifySelection) { - foreach (var row in SelectedRows.Reverse().ToList()) + foreach (var row in SelectedRows.Reverse()) // clones SelectedRows { SelectRow(row + 1, true); SelectRow(row, false); @@ -1695,14 +1695,7 @@ namespace BizHawk.Client.EmuHawk { if (toggle && _selectedItems.Any(x => x.RowIndex.HasValue && x.RowIndex == cell.RowIndex)) { - var items = _selectedItems - .Where(x => x.RowIndex.HasValue && x.RowIndex == cell.RowIndex) - .ToList(); - - foreach (var item in items) - { - _selectedItems.Remove(item); - } + _selectedItems.RemoveWhere(x => x.RowIndex.HasValue && x.RowIndex == cell.RowIndex); } else { @@ -2054,13 +2047,11 @@ namespace BizHawk.Client.EmuHawk { int pos = 0; - var columns = VisibleColumns.ToList(); - - for (int i = 0; i < columns.Count; i++) + foreach (var col in VisibleColumns) { - columns[i].Left = pos; - pos += columns[i].Width.Value; - columns[i].Right = pos; + col.Left = pos; + pos += col.Width.Value; + col.Right = pos; } DoChangeCallback(); diff --git a/BizHawk.Client.EmuHawk/MainForm.Hotkey.cs b/BizHawk.Client.EmuHawk/MainForm.Hotkey.cs index 130d640a0f..464ea13f66 100644 --- a/BizHawk.Client.EmuHawk/MainForm.Hotkey.cs +++ b/BizHawk.Client.EmuHawk/MainForm.Hotkey.cs @@ -347,7 +347,10 @@ namespace BizHawk.Client.EmuHawk type = " (on)"; } - Global.CheatList.ToList().ForEach(x => x.Toggle()); + foreach (var x in Global.CheatList) + { + x.Toggle(); + } GlobalWin.OSD.AddMessage($"Cheats toggled{type}"); } diff --git a/BizHawk.Client.EmuHawk/Sound/Output/DirectSoundSoundOutput.cs b/BizHawk.Client.EmuHawk/Sound/Output/DirectSoundSoundOutput.cs index 21ca8bd90f..ba3ae8ba90 100644 --- a/BizHawk.Client.EmuHawk/Sound/Output/DirectSoundSoundOutput.cs +++ b/BizHawk.Client.EmuHawk/Sound/Output/DirectSoundSoundOutput.cs @@ -42,7 +42,7 @@ namespace BizHawk.Client.EmuHawk public static IEnumerable GetDeviceNames() { - return DirectSound.GetDevices().Select(d => d.Description).ToList(); + return DirectSound.GetDevices().Select(d => d.Description); } private int BufferSizeSamples { get; set; } diff --git a/BizHawk.Client.EmuHawk/Sound/Output/XAudio2SoundOutput.cs b/BizHawk.Client.EmuHawk/Sound/Output/XAudio2SoundOutput.cs index e5bf4f8dc0..5c37748096 100644 --- a/BizHawk.Client.EmuHawk/Sound/Output/XAudio2SoundOutput.cs +++ b/BizHawk.Client.EmuHawk/Sound/Output/XAudio2SoundOutput.cs @@ -49,7 +49,9 @@ namespace BizHawk.Client.EmuHawk { using (XAudio2 device = new XAudio2()) { - return Enumerable.Range(0, device.DeviceCount).Select(n => device.GetDeviceDetails(n).DisplayName).ToList(); + return Enumerable.Range(0, device.DeviceCount) + .Select(n => device.GetDeviceDetails(n).DisplayName) + .ToList(); // enumerate before local var device is disposed } } diff --git a/BizHawk.Client.EmuHawk/config/HotkeyConfig.cs b/BizHawk.Client.EmuHawk/config/HotkeyConfig.cs index 24adc44d21..4713321dc8 100644 --- a/BizHawk.Client.EmuHawk/config/HotkeyConfig.cs +++ b/BizHawk.Client.EmuHawk/config/HotkeyConfig.cs @@ -101,7 +101,7 @@ namespace BizHawk.Client.EmuHawk HotkeyTabControl.TabPages.Clear(); // Buckets - var tabs = Global.Config.HotkeyBindings.Select(x => x.TabGroup).Distinct().ToList(); + var tabs = Global.Config.HotkeyBindings.Select(x => x.TabGroup).Distinct(); foreach (var tab in tabs) { @@ -110,7 +110,7 @@ namespace BizHawk.Client.EmuHawk var tb = new TabPage {Name = tab, Text = tab}; - var bindings = Global.Config.HotkeyBindings.Where(x => x.TabGroup == tab).OrderBy(x => x.Ordinal).ThenBy(x => x.DisplayName).ToList(); + var bindings = Global.Config.HotkeyBindings.Where(x => x.TabGroup == tab).OrderBy(x => x.Ordinal).ThenBy(x => x.DisplayName); int iwOffsetX = UIHelper.ScaleX(110); int iwOffsetY = UIHelper.ScaleY(-4); diff --git a/BizHawk.Client.EmuHawk/config/NES/NESSyncSettingsForm.cs b/BizHawk.Client.EmuHawk/config/NES/NESSyncSettingsForm.cs index b343fe4355..3debf50624 100644 --- a/BizHawk.Client.EmuHawk/config/NES/NESSyncSettingsForm.cs +++ b/BizHawk.Client.EmuHawk/config/NES/NESSyncSettingsForm.cs @@ -64,7 +64,7 @@ namespace BizHawk.Client.EmuHawk typeof(NES.NESSyncSettings.Region), (string)RegionComboBox.SelectedItem); - List oldRam = _syncSettings.InitialWRamStatePattern?.ToList() ?? new List(); + var oldRam = _syncSettings.InitialWRamStatePattern ?? new List(); if (!string.IsNullOrWhiteSpace(RamPatternOverrideBox.Text)) { diff --git a/BizHawk.Client.EmuHawk/config/PathConfig.cs b/BizHawk.Client.EmuHawk/config/PathConfig.cs index b8f438b543..bb3e6e8820 100644 --- a/BizHawk.Client.EmuHawk/config/PathConfig.cs +++ b/BizHawk.Client.EmuHawk/config/PathConfig.cs @@ -114,8 +114,7 @@ namespace BizHawk.Client.EmuHawk var paths = pathCollection .Where(p => p.System == systemId) .OrderBy(p => p.Ordinal) - .ThenBy(p => p.Type) - .ToList(); + .ThenBy(p => p.Type); var y = UIHelper.ScaleY(14); foreach (var path in paths) @@ -243,10 +242,10 @@ namespace BizHawk.Client.EmuHawk private void DoRomToggle() { - AllPathControls - .Where(c => c.Name == "ROM") - .ToList() - .ForEach(control => control.Enabled = !RecentForROMs.Checked); + foreach (var control in AllPathControls.Where(c => c.Name == "ROM")) + { + control.Enabled = !RecentForROMs.Checked; + } } private IEnumerable AllPathBoxes diff --git a/BizHawk.Client.EmuHawk/movie/PlayMovie.cs b/BizHawk.Client.EmuHawk/movie/PlayMovie.cs index 6365304e9f..b99913aeab 100644 --- a/BizHawk.Client.EmuHawk/movie/PlayMovie.cs +++ b/BizHawk.Client.EmuHawk/movie/PlayMovie.cs @@ -306,10 +306,10 @@ namespace BizHawk.Client.EmuHawk { var filePaths = (string[])e.Data.GetData(DataFormats.FileDrop); - filePaths - .Where(path => MovieService.MovieExtensions.Contains(Path.GetExtension(path).Replace(".", ""))) - .ToList() - .ForEach(path => AddMovieToList(path, force: true)); + foreach (var path in filePaths.Where(path => MovieService.MovieExtensions.Contains(Path.GetExtension(path).Replace(".", "")))) + { + AddMovieToList(path, force: true); + } RefreshMovieList(); } @@ -468,11 +468,11 @@ namespace BizHawk.Client.EmuHawk private void EditMenuItem_Click(object sender, EventArgs e) { - MovieView.SelectedIndices - .Cast() - .Select(index => _movieList[index]) - .ToList() - .ForEach(movie => System.Diagnostics.Process.Start(movie.Filename)); + foreach (var movie in MovieView.SelectedIndices.Cast() + .Select(index => _movieList[index])) + { + System.Diagnostics.Process.Start(movie.Filename); + } } #endregion diff --git a/BizHawk.Client.EmuHawk/tools/BasicBot/BasicBot.cs b/BizHawk.Client.EmuHawk/tools/BasicBot/BasicBot.cs index 5f32d9ecc4..9c3361cdaa 100644 --- a/BizHawk.Client.EmuHawk/tools/BasicBot/BasicBot.cs +++ b/BizHawk.Client.EmuHawk/tools/BasicBot/BasicBot.cs @@ -449,10 +449,10 @@ namespace BizHawk.Client.EmuHawk CurrentFileName = ""; _bestBotAttempt = null; - ControlProbabilityPanel.Controls - .OfType() - .ToList() - .ForEach(cp => cp.Probability = 0); + foreach (var cp in ControlProbabilityPanel.Controls.OfType()) + { + cp.Probability = 0; + } FrameLength = 0; MaximizeAddress = 0; diff --git a/BizHawk.Client.EmuHawk/tools/Cheats/Cheats.cs b/BizHawk.Client.EmuHawk/tools/Cheats/Cheats.cs index cbc8cd2efe..ef614a8e74 100644 --- a/BizHawk.Client.EmuHawk/tools/Cheats/Cheats.cs +++ b/BizHawk.Client.EmuHawk/tools/Cheats/Cheats.cs @@ -486,7 +486,7 @@ namespace BizHawk.Client.EmuHawk Global.CheatList.Insert(index - 1, cheat); } - var newindices = indices.Select(t => t - 1).ToList(); + var newindices = indices.Select(t => t - 1); CheatListView.SelectedIndices.Clear(); foreach (var newi in newindices) @@ -515,7 +515,7 @@ namespace BizHawk.Client.EmuHawk UpdateMessageLabel(); - var newindices = indices.Select(t => t + 1).ToList(); + var newindices = indices.Select(t => t + 1); CheatListView.SelectedIndices.Clear(); foreach (var newi in newindices) @@ -533,7 +533,10 @@ namespace BizHawk.Client.EmuHawk private void ToggleMenuItem_Click(object sender, EventArgs e) { - SelectedCheats.ToList().ForEach(x => x.Toggle()); + foreach (var x in SelectedCheats) + { + x.Toggle(); + } CheatListView.Refresh(); } diff --git a/BizHawk.Client.EmuHawk/tools/Debugger/RegisterBoxControl.cs b/BizHawk.Client.EmuHawk/tools/Debugger/RegisterBoxControl.cs index 9f6d273e8f..83dba6a59b 100644 --- a/BizHawk.Client.EmuHawk/tools/Debugger/RegisterBoxControl.cs +++ b/BizHawk.Client.EmuHawk/tools/Debugger/RegisterBoxControl.cs @@ -41,46 +41,37 @@ namespace BizHawk.Client.EmuHawk { if (Controls.OfType().Any(p => p.Name == "FlagPanel")) { - Controls - .OfType() + foreach (var checkbox in Controls.OfType() .First(p => p.Name == "FlagPanel") .Controls - .OfType() - .ToList() - .ForEach(checkbox => + .OfType()) + { + if (checkbox.Name == register.Key) { - if (checkbox.Name == register.Key) - { - checkbox.Checked = register.Value.Value == 1; - } - }); + checkbox.Checked = register.Value.Value == 1; + } + } } if (_canSetCpuRegisters) { - Controls - .OfType() - .ToList() - .ForEach(textbox => + foreach (var textbox in Controls.OfType()) + { + if (textbox.Name == register.Key) { - if (textbox.Name == register.Key) - { - textbox.Text = register.Value.Value.ToHexString(register.Value.BitSize / 4); - } - }); + textbox.Text = register.Value.Value.ToHexString(register.Value.BitSize / 4); + } + } } else { - Controls - .OfType public void SetDataPeriodsArray(int[] periodArray) { - DataPeriods = new List(); - - if (periodArray == null) - return; - - DataPeriods = periodArray.ToList(); + DataPeriods = periodArray?.ToList() ?? new List(); } /// diff --git a/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Media/Disk/IPFFormat/IPFFloppyDisk.cs b/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Media/Disk/IPFFormat/IPFFloppyDisk.cs index c1560f3339..8133e7a66b 100644 --- a/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Media/Disk/IPFFormat/IPFFloppyDisk.cs +++ b/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Media/Disk/IPFFormat/IPFFloppyDisk.cs @@ -65,7 +65,7 @@ namespace BizHawk.Emulation.Cores.Computers.SinclairSpectrum // now process the blocks var infoBlock = blocks.Where(a => a.RecordType == RecordHeaderType.INFO).FirstOrDefault(); var IMGEblocks = blocks.Where(a => a.RecordType == RecordHeaderType.IMGE).ToList(); - var DATAblocks = blocks.Where(a => a.RecordType == RecordHeaderType.DATA).ToList(); + var DATAblocks = blocks.Where(a => a.RecordType == RecordHeaderType.DATA); DiskHeader.NumberOfTracks = (byte)(IMGEblocks.Count()); DiskHeader.NumberOfSides = (byte)(infoBlock.INFOmaxSide + 1); diff --git a/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Media/Tape/TapeDataBlock.cs b/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Media/Tape/TapeDataBlock.cs index d60267bf76..489f425b6e 100644 --- a/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Media/Tape/TapeDataBlock.cs +++ b/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Media/Tape/TapeDataBlock.cs @@ -153,12 +153,7 @@ namespace BizHawk.Emulation.Cores.Computers.SinclairSpectrum /// public void SetDataPeriodsArray(int[] periodArray) { - DataPeriods = new List(); - - if (periodArray == null) - return; - - DataPeriods = periodArray.ToList(); + DataPeriods = periodArray?.ToList() ?? new List(); } /// diff --git a/BizHawk.Emulation.Cores/Consoles/Atari/2600/Atari2600.cs b/BizHawk.Emulation.Cores/Consoles/Atari/2600/Atari2600.cs index 436fdd3371..ef89535611 100644 --- a/BizHawk.Emulation.Cores/Consoles/Atari/2600/Atari2600.cs +++ b/BizHawk.Emulation.Cores/Consoles/Atari/2600/Atari2600.cs @@ -75,7 +75,7 @@ namespace BizHawk.Emulation.Cores.Atari.Atari2600 { Name = _game.Name, System = "A26", - MetaData = "m=" + _mapper.GetType().ToString().Split('.').ToList().Last(), + MetaData = "m=" + _mapper.GetType().ToString().Split('.').Last(), Hash = Rom.HashSHA1(), Region = _game.Region, Status = RomStatus.Unknown diff --git a/BizHawk.Emulation.Cores/Consoles/Nintendo/Gameboy/GambatteLink.IDebuggable.cs b/BizHawk.Emulation.Cores/Consoles/Nintendo/Gameboy/GambatteLink.IDebuggable.cs index 363895ef05..92759e216d 100644 --- a/BizHawk.Emulation.Cores/Consoles/Nintendo/Gameboy/GambatteLink.IDebuggable.cs +++ b/BizHawk.Emulation.Cores/Consoles/Nintendo/Gameboy/GambatteLink.IDebuggable.cs @@ -16,7 +16,7 @@ namespace BizHawk.Emulation.Cores.Nintendo.Gameboy var right = R.GetCpuFlagsAndRegisters() .Select(reg => new KeyValuePair("Right " + reg.Key, reg.Value)); - return left.Union(right).ToList().ToDictionary(pair => pair.Key, pair => pair.Value); + return left.Union(right).ToDictionary(pair => pair.Key, pair => pair.Value); } public void SetCpuRegister(string register, int value) diff --git a/BizHawk.Emulation.Cores/CoreInventory.cs b/BizHawk.Emulation.Cores/CoreInventory.cs index b093b81bb8..2c08e760e1 100644 --- a/BizHawk.Emulation.Cores/CoreInventory.cs +++ b/BizHawk.Emulation.Cores/CoreInventory.cs @@ -165,7 +165,7 @@ namespace BizHawk.Emulation.Cores if (coreattr.Length != 1) throw new InvalidOperationException($"{nameof(IEmulator)} {typ} without {nameof(CoreAttribute)}s!"); var cons = typ.GetConstructors(BindingFlags.Public | BindingFlags.Instance) - .Where(c => c.GetCustomAttributes(typeof(CoreConstructorAttribute), false).Length > 0).ToList(); + .Where(c => c.GetCustomAttributes(typeof(CoreConstructorAttribute), false).Length > 0); foreach(var con in cons) { foreach (string system in ((CoreConstructorAttribute)con.GetCustomAttributes(typeof(CoreConstructorAttribute), false)[0]).Systems) diff --git a/BizHawk.Emulation.Cores/Waterbox/ElfRunner.cs b/BizHawk.Emulation.Cores/Waterbox/ElfRunner.cs index 2cc89ec24f..3428e5b508 100644 --- a/BizHawk.Emulation.Cores/Waterbox/ElfRunner.cs +++ b/BizHawk.Emulation.Cores/Waterbox/ElfRunner.cs @@ -253,17 +253,15 @@ namespace BizHawk.Emulation.Cores.Waterbox private void RegisterSymbols() { - var symbols = ((ISymbolTable)_elf.GetSection(".symtab")) - .Entries - .Cast>(); + _symlist = ((ISymbolTable) _elf.GetSection(".symtab")).Entries + .Cast>() + .ToList(); // when there are duplicate names, don't register either in the dictionary - _symdict = symbols - .GroupBy(e => e.Name) - .Where(g => g.Count() == 1) - .ToDictionary(g => g.Key, g => g.First()); - - _symlist = symbols.ToList(); + _symdict = _symlist + .GroupBy(e => e.Name) + .Where(g => g.Count() == 1) + .ToDictionary(g => g.Key, g => g.First()); } public void Seal() diff --git a/BizHawk.Emulation.DiscSystem/CDFS/ISOFile.cs b/BizHawk.Emulation.DiscSystem/CDFS/ISOFile.cs index f07ab2394a..14cb54fe02 100644 --- a/BizHawk.Emulation.DiscSystem/CDFS/ISOFile.cs +++ b/BizHawk.Emulation.DiscSystem/CDFS/ISOFile.cs @@ -182,9 +182,7 @@ namespace BizHawk.Emulation.DiscSystem return fileNodes; // get all folders - List> dirs = (from a in Root.Children - where a.Value.GetType() == typeof(ISODirectoryNode) - select a).ToList(); + var dirs = (from a in Root.Children where a.Value.GetType() == typeof(ISODirectoryNode) select a); // iterate through each folder foreach (var d in dirs) { From eed94c11cc1d017f60475df072c7ea62e3a8a107 Mon Sep 17 00:00:00 2001 From: "J.D. Purcell" Date: Sun, 13 Oct 2019 13:04:06 -0400 Subject: [PATCH 021/166] TAStudio: Improve control alignment and fix branches/markers not showing due to DPI scaling. Fixes #1151. --- .../TAStudio/BookmarksBranchesBox.Designer.cs | 62 ++++++------- .../tools/TAStudio/MarkerControl.Designer.cs | 91 +++++++++++-------- .../tools/TAStudio/PlaybackBox.Designer.cs | 10 +- .../tools/TAStudio/TAStudio.Designer.cs | 48 +++------- 4 files changed, 102 insertions(+), 109 deletions(-) diff --git a/BizHawk.Client.EmuHawk/tools/TAStudio/BookmarksBranchesBox.Designer.cs b/BizHawk.Client.EmuHawk/tools/TAStudio/BookmarksBranchesBox.Designer.cs index bacdef1f33..3e91765166 100644 --- a/BizHawk.Client.EmuHawk/tools/TAStudio/BookmarksBranchesBox.Designer.cs +++ b/BizHawk.Client.EmuHawk/tools/TAStudio/BookmarksBranchesBox.Designer.cs @@ -54,9 +54,6 @@ // // BookmarksBranchesGroupBox // - this.BookmarksBranchesGroupBox.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom) - | System.Windows.Forms.AnchorStyles.Left) - | System.Windows.Forms.AnchorStyles.Right))); this.BookmarksBranchesGroupBox.Controls.Add(this.UndoBranchButton); this.BookmarksBranchesGroupBox.Controls.Add(this.JumpToBranchButton); this.BookmarksBranchesGroupBox.Controls.Add(this.UpdateBranchButton); @@ -64,7 +61,8 @@ this.BookmarksBranchesGroupBox.Controls.Add(this.AddBranchButton); this.BookmarksBranchesGroupBox.Controls.Add(this.LoadBranchButton); this.BookmarksBranchesGroupBox.Controls.Add(this.BranchView); - this.BookmarksBranchesGroupBox.Location = new System.Drawing.Point(3, 0); + this.BookmarksBranchesGroupBox.Dock = System.Windows.Forms.DockStyle.Fill; + this.BookmarksBranchesGroupBox.Location = new System.Drawing.Point(0, 0); this.BookmarksBranchesGroupBox.Name = "BookmarksBranchesGroupBox"; this.BookmarksBranchesGroupBox.Size = new System.Drawing.Size(198, 278); this.BookmarksBranchesGroupBox.TabIndex = 0; @@ -76,10 +74,10 @@ this.UndoBranchButton.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left))); this.UndoBranchButton.Enabled = false; this.UndoBranchButton.Image = global::BizHawk.Client.EmuHawk.Properties.Resources.undo; - this.UndoBranchButton.Location = new System.Drawing.Point(159, 249); + this.UndoBranchButton.Location = new System.Drawing.Point(156, 247); this.UndoBranchButton.Name = "UndoBranchButton"; - this.UndoBranchButton.Size = new System.Drawing.Size(23, 23); - this.UndoBranchButton.TabIndex = 10; + this.UndoBranchButton.Size = new System.Drawing.Size(24, 24); + this.UndoBranchButton.TabIndex = 6; this.UndoBranchButton.UseVisualStyleBackColor = true; this.UndoBranchButton.Click += new System.EventHandler(this.UndoBranchToolStripMenuItem_Click); // @@ -88,10 +86,10 @@ this.JumpToBranchButton.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left))); this.JumpToBranchButton.Enabled = false; this.JumpToBranchButton.Image = global::BizHawk.Client.EmuHawk.Properties.Resources.JumpTo; - this.JumpToBranchButton.Location = new System.Drawing.Point(130, 249); + this.JumpToBranchButton.Location = new System.Drawing.Point(126, 247); this.JumpToBranchButton.Name = "JumpToBranchButton"; - this.JumpToBranchButton.Size = new System.Drawing.Size(23, 23); - this.JumpToBranchButton.TabIndex = 9; + this.JumpToBranchButton.Size = new System.Drawing.Size(24, 24); + this.JumpToBranchButton.TabIndex = 5; this.toolTip1.SetToolTip(this.JumpToBranchButton, "Jump To Branch Frame"); this.JumpToBranchButton.UseVisualStyleBackColor = true; this.JumpToBranchButton.Click += new System.EventHandler(this.JumpToBranchToolStripMenuItem_Click); @@ -101,9 +99,9 @@ this.UpdateBranchButton.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left))); this.UpdateBranchButton.Enabled = false; this.UpdateBranchButton.Image = global::BizHawk.Client.EmuHawk.Properties.Resources.reboot; - this.UpdateBranchButton.Location = new System.Drawing.Point(99, 249); + this.UpdateBranchButton.Location = new System.Drawing.Point(96, 247); this.UpdateBranchButton.Name = "UpdateBranchButton"; - this.UpdateBranchButton.Size = new System.Drawing.Size(25, 23); + this.UpdateBranchButton.Size = new System.Drawing.Size(24, 24); this.UpdateBranchButton.TabIndex = 4; this.toolTip1.SetToolTip(this.UpdateBranchButton, "Update Branch"); this.UpdateBranchButton.UseVisualStyleBackColor = true; @@ -113,10 +111,10 @@ // this.AddWithTextBranchButton.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left))); this.AddWithTextBranchButton.Image = global::BizHawk.Client.EmuHawk.Properties.Resources.AddEdit; - this.AddWithTextBranchButton.Location = new System.Drawing.Point(37, 249); + this.AddWithTextBranchButton.Location = new System.Drawing.Point(36, 247); this.AddWithTextBranchButton.Name = "AddWithTextBranchButton"; - this.AddWithTextBranchButton.Size = new System.Drawing.Size(25, 23); - this.AddWithTextBranchButton.TabIndex = 3; + this.AddWithTextBranchButton.Size = new System.Drawing.Size(24, 24); + this.AddWithTextBranchButton.TabIndex = 2; this.toolTip1.SetToolTip(this.AddWithTextBranchButton, "Add Branch with Text"); this.AddWithTextBranchButton.UseVisualStyleBackColor = true; this.AddWithTextBranchButton.Click += new System.EventHandler(this.AddBranchWithTexToolStripMenuItem_Click); @@ -125,10 +123,10 @@ // this.AddBranchButton.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left))); this.AddBranchButton.Image = global::BizHawk.Client.EmuHawk.Properties.Resources.add; - this.AddBranchButton.Location = new System.Drawing.Point(6, 249); + this.AddBranchButton.Location = new System.Drawing.Point(6, 247); this.AddBranchButton.Name = "AddBranchButton"; - this.AddBranchButton.Size = new System.Drawing.Size(25, 23); - this.AddBranchButton.TabIndex = 2; + this.AddBranchButton.Size = new System.Drawing.Size(24, 24); + this.AddBranchButton.TabIndex = 1; this.toolTip1.SetToolTip(this.AddBranchButton, "Add Branch"); this.AddBranchButton.UseVisualStyleBackColor = true; this.AddBranchButton.Click += new System.EventHandler(this.AddBranchToolStripMenuItem_Click); @@ -138,10 +136,10 @@ this.LoadBranchButton.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left))); this.LoadBranchButton.Enabled = false; this.LoadBranchButton.Image = global::BizHawk.Client.EmuHawk.Properties.Resources.Debugger; - this.LoadBranchButton.Location = new System.Drawing.Point(68, 249); + this.LoadBranchButton.Location = new System.Drawing.Point(66, 247); this.LoadBranchButton.Name = "LoadBranchButton"; - this.LoadBranchButton.Size = new System.Drawing.Size(25, 23); - this.LoadBranchButton.TabIndex = 1; + this.LoadBranchButton.Size = new System.Drawing.Size(24, 24); + this.LoadBranchButton.TabIndex = 3; this.toolTip1.SetToolTip(this.LoadBranchButton, "Load Branch"); this.LoadBranchButton.UseVisualStyleBackColor = true; this.LoadBranchButton.Click += new System.EventHandler(this.LoadBranchToolStripMenuItem_Click); @@ -193,14 +191,14 @@ this.toolStripSeparator2, this.RemoveBranchContextMenuItem}); this.BranchesContextMenu.Name = "BranchesContextMenu"; - this.BranchesContextMenu.Size = new System.Drawing.Size(153, 208); + this.BranchesContextMenu.Size = new System.Drawing.Size(147, 186); this.BranchesContextMenu.Opening += new System.ComponentModel.CancelEventHandler(this.BranchesContextMenu_Opening); // // AddBranchContextMenu // this.AddBranchContextMenu.Image = global::BizHawk.Client.EmuHawk.Properties.Resources.add; this.AddBranchContextMenu.Name = "AddBranchContextMenu"; - this.AddBranchContextMenu.Size = new System.Drawing.Size(152, 22); + this.AddBranchContextMenu.Size = new System.Drawing.Size(146, 22); this.AddBranchContextMenu.Text = "Add"; this.AddBranchContextMenu.Click += new System.EventHandler(this.AddBranchToolStripMenuItem_Click); // @@ -208,7 +206,7 @@ // this.AddBranchWithTextContextMenuItem.Image = global::BizHawk.Client.EmuHawk.Properties.Resources.AddEdit; this.AddBranchWithTextContextMenuItem.Name = "AddBranchWithTextContextMenuItem"; - this.AddBranchWithTextContextMenuItem.Size = new System.Drawing.Size(152, 22); + this.AddBranchWithTextContextMenuItem.Size = new System.Drawing.Size(146, 22); this.AddBranchWithTextContextMenuItem.Text = "Add with Text"; this.AddBranchWithTextContextMenuItem.Click += new System.EventHandler(this.AddBranchWithTexToolStripMenuItem_Click); // @@ -216,7 +214,7 @@ // this.LoadBranchContextMenuItem.Image = global::BizHawk.Client.EmuHawk.Properties.Resources.Debugger; this.LoadBranchContextMenuItem.Name = "LoadBranchContextMenuItem"; - this.LoadBranchContextMenuItem.Size = new System.Drawing.Size(152, 22); + this.LoadBranchContextMenuItem.Size = new System.Drawing.Size(146, 22); this.LoadBranchContextMenuItem.Text = "Load"; this.LoadBranchContextMenuItem.Click += new System.EventHandler(this.LoadBranchToolStripMenuItem_Click); // @@ -224,7 +222,7 @@ // this.UpdateBranchContextMenuItem.Image = global::BizHawk.Client.EmuHawk.Properties.Resources.reboot; this.UpdateBranchContextMenuItem.Name = "UpdateBranchContextMenuItem"; - this.UpdateBranchContextMenuItem.Size = new System.Drawing.Size(152, 22); + this.UpdateBranchContextMenuItem.Size = new System.Drawing.Size(146, 22); this.UpdateBranchContextMenuItem.Text = "&Update"; this.UpdateBranchContextMenuItem.Click += new System.EventHandler(this.UpdateBranchToolStripMenuItem_Click); // @@ -232,7 +230,7 @@ // this.EditBranchTextContextMenuItem.Image = global::BizHawk.Client.EmuHawk.Properties.Resources.pencil; this.EditBranchTextContextMenuItem.Name = "EditBranchTextContextMenuItem"; - this.EditBranchTextContextMenuItem.Size = new System.Drawing.Size(152, 22); + this.EditBranchTextContextMenuItem.Size = new System.Drawing.Size(146, 22); this.EditBranchTextContextMenuItem.Text = "Edit Text"; this.EditBranchTextContextMenuItem.Click += new System.EventHandler(this.EditBranchTextToolStripMenuItem_Click); // @@ -240,7 +238,7 @@ // this.JumpToBranchContextMenuItem.Image = global::BizHawk.Client.EmuHawk.Properties.Resources.JumpTo; this.JumpToBranchContextMenuItem.Name = "JumpToBranchContextMenuItem"; - this.JumpToBranchContextMenuItem.Size = new System.Drawing.Size(152, 22); + this.JumpToBranchContextMenuItem.Size = new System.Drawing.Size(146, 22); this.JumpToBranchContextMenuItem.Text = "Jump To"; this.JumpToBranchContextMenuItem.Click += new System.EventHandler(this.JumpToBranchToolStripMenuItem_Click); // @@ -249,20 +247,20 @@ this.UndoBranchToolStripMenuItem.Enabled = false; this.UndoBranchToolStripMenuItem.Image = global::BizHawk.Client.EmuHawk.Properties.Resources.undo; this.UndoBranchToolStripMenuItem.Name = "UndoBranchToolStripMenuItem"; - this.UndoBranchToolStripMenuItem.Size = new System.Drawing.Size(152, 22); + this.UndoBranchToolStripMenuItem.Size = new System.Drawing.Size(146, 22); this.UndoBranchToolStripMenuItem.Text = "Undo"; this.UndoBranchToolStripMenuItem.Click += new System.EventHandler(this.UndoBranchToolStripMenuItem_Click); // // toolStripSeparator2 // this.toolStripSeparator2.Name = "toolStripSeparator2"; - this.toolStripSeparator2.Size = new System.Drawing.Size(149, 6); + this.toolStripSeparator2.Size = new System.Drawing.Size(143, 6); // // RemoveBranchContextMenuItem // this.RemoveBranchContextMenuItem.Image = global::BizHawk.Client.EmuHawk.Properties.Resources.Delete; this.RemoveBranchContextMenuItem.Name = "RemoveBranchContextMenuItem"; - this.RemoveBranchContextMenuItem.Size = new System.Drawing.Size(152, 22); + this.RemoveBranchContextMenuItem.Size = new System.Drawing.Size(146, 22); this.RemoveBranchContextMenuItem.Text = "Remove"; this.RemoveBranchContextMenuItem.Click += new System.EventHandler(this.RemoveBranchToolStripMenuItem_Click); // @@ -271,7 +269,7 @@ this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Inherit; this.Controls.Add(this.BookmarksBranchesGroupBox); this.Name = "BookmarksBranchesBox"; - this.Size = new System.Drawing.Size(204, 281); + this.Size = new System.Drawing.Size(198, 278); this.BookmarksBranchesGroupBox.ResumeLayout(false); this.BranchesContextMenu.ResumeLayout(false); this.ResumeLayout(false); diff --git a/BizHawk.Client.EmuHawk/tools/TAStudio/MarkerControl.Designer.cs b/BizHawk.Client.EmuHawk/tools/TAStudio/MarkerControl.Designer.cs index fef9164076..a3726d0fe4 100644 --- a/BizHawk.Client.EmuHawk/tools/TAStudio/MarkerControl.Designer.cs +++ b/BizHawk.Client.EmuHawk/tools/TAStudio/MarkerControl.Designer.cs @@ -44,7 +44,9 @@ this.ScrollToMarkerButton = new System.Windows.Forms.Button(); this.AddMarkerWithTextButton = new System.Windows.Forms.Button(); this.MarkerView = new BizHawk.Client.EmuHawk.InputRoll(); + this.MarkersGroupBox = new System.Windows.Forms.GroupBox(); this.MarkerContextMenu.SuspendLayout(); + this.MarkersGroupBox.SuspendLayout(); this.SuspendLayout(); // // MarkerContextMenu @@ -57,14 +59,14 @@ this.toolStripSeparator1, this.RemoveMarkerToolStripMenuItem}); this.MarkerContextMenu.Name = "MarkerContextMenu"; - this.MarkerContextMenu.Size = new System.Drawing.Size(126, 120); + this.MarkerContextMenu.Size = new System.Drawing.Size(119, 120); this.MarkerContextMenu.Opening += new System.ComponentModel.CancelEventHandler(this.MarkerContextMenu_Opening); // // JumpToMarkerToolStripMenuItem // this.JumpToMarkerToolStripMenuItem.Image = global::BizHawk.Client.EmuHawk.Properties.Resources.JumpTo; this.JumpToMarkerToolStripMenuItem.Name = "JumpToMarkerToolStripMenuItem"; - this.JumpToMarkerToolStripMenuItem.Size = new System.Drawing.Size(125, 22); + this.JumpToMarkerToolStripMenuItem.Size = new System.Drawing.Size(118, 22); this.JumpToMarkerToolStripMenuItem.Text = "Jump To"; this.JumpToMarkerToolStripMenuItem.Click += new System.EventHandler(this.JumpToMarkerToolStripMenuItem_Click); // @@ -72,7 +74,7 @@ // this.ScrollToMarkerToolStripMenuItem.Image = global::BizHawk.Client.EmuHawk.Properties.Resources.ScrollTo; this.ScrollToMarkerToolStripMenuItem.Name = "ScrollToMarkerToolStripMenuItem"; - this.ScrollToMarkerToolStripMenuItem.Size = new System.Drawing.Size(125, 22); + this.ScrollToMarkerToolStripMenuItem.Size = new System.Drawing.Size(118, 22); this.ScrollToMarkerToolStripMenuItem.Text = "Scroll To"; this.ScrollToMarkerToolStripMenuItem.Click += new System.EventHandler(this.ScrollToMarkerToolStripMenuItem_Click); // @@ -80,7 +82,7 @@ // this.EditMarkerToolStripMenuItem.Image = global::BizHawk.Client.EmuHawk.Properties.Resources.pencil; this.EditMarkerToolStripMenuItem.Name = "EditMarkerToolStripMenuItem"; - this.EditMarkerToolStripMenuItem.Size = new System.Drawing.Size(125, 22); + this.EditMarkerToolStripMenuItem.Size = new System.Drawing.Size(118, 22); this.EditMarkerToolStripMenuItem.Text = "Edit"; this.EditMarkerToolStripMenuItem.Click += new System.EventHandler(this.EditMarkerToolStripMenuItem_Click); // @@ -88,20 +90,20 @@ // this.AddMarkerToolStripMenuItem.Image = global::BizHawk.Client.EmuHawk.Properties.Resources.add; this.AddMarkerToolStripMenuItem.Name = "AddMarkerToolStripMenuItem"; - this.AddMarkerToolStripMenuItem.Size = new System.Drawing.Size(125, 22); + this.AddMarkerToolStripMenuItem.Size = new System.Drawing.Size(118, 22); this.AddMarkerToolStripMenuItem.Text = "Add"; this.AddMarkerToolStripMenuItem.Click += new System.EventHandler(this.AddMarkerToolStripMenuItem_Click); // // toolStripSeparator1 // this.toolStripSeparator1.Name = "toolStripSeparator1"; - this.toolStripSeparator1.Size = new System.Drawing.Size(122, 6); + this.toolStripSeparator1.Size = new System.Drawing.Size(115, 6); // // RemoveMarkerToolStripMenuItem // this.RemoveMarkerToolStripMenuItem.Image = global::BizHawk.Client.EmuHawk.Properties.Resources.Delete; this.RemoveMarkerToolStripMenuItem.Name = "RemoveMarkerToolStripMenuItem"; - this.RemoveMarkerToolStripMenuItem.Size = new System.Drawing.Size(125, 22); + this.RemoveMarkerToolStripMenuItem.Size = new System.Drawing.Size(118, 22); this.RemoveMarkerToolStripMenuItem.Text = "Remove"; this.RemoveMarkerToolStripMenuItem.Click += new System.EventHandler(this.RemoveMarkerToolStripMenuItem_Click); // @@ -110,10 +112,10 @@ this.JumpToMarkerButton.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left))); this.JumpToMarkerButton.Enabled = false; this.JumpToMarkerButton.Image = global::BizHawk.Client.EmuHawk.Properties.Resources.JumpTo; - this.JumpToMarkerButton.Location = new System.Drawing.Point(61, 174); + this.JumpToMarkerButton.Location = new System.Drawing.Point(66, 247); this.JumpToMarkerButton.Name = "JumpToMarkerButton"; - this.JumpToMarkerButton.Size = new System.Drawing.Size(23, 23); - this.JumpToMarkerButton.TabIndex = 8; + this.JumpToMarkerButton.Size = new System.Drawing.Size(24, 24); + this.JumpToMarkerButton.TabIndex = 3; this.toolTip1.SetToolTip(this.JumpToMarkerButton, "Jump To Marker Frame"); this.JumpToMarkerButton.UseVisualStyleBackColor = true; this.JumpToMarkerButton.Click += new System.EventHandler(this.JumpToMarkerToolStripMenuItem_Click); @@ -123,10 +125,10 @@ this.EditMarkerButton.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left))); this.EditMarkerButton.Enabled = false; this.EditMarkerButton.Image = global::BizHawk.Client.EmuHawk.Properties.Resources.pencil; - this.EditMarkerButton.Location = new System.Drawing.Point(119, 174); + this.EditMarkerButton.Location = new System.Drawing.Point(126, 247); this.EditMarkerButton.Name = "EditMarkerButton"; - this.EditMarkerButton.Size = new System.Drawing.Size(23, 23); - this.EditMarkerButton.TabIndex = 9; + this.EditMarkerButton.Size = new System.Drawing.Size(24, 24); + this.EditMarkerButton.TabIndex = 5; this.toolTip1.SetToolTip(this.EditMarkerButton, "Edit Marker Text"); this.EditMarkerButton.UseVisualStyleBackColor = true; this.EditMarkerButton.Click += new System.EventHandler(this.EditMarkerToolStripMenuItem_Click); @@ -135,10 +137,10 @@ // this.AddMarkerButton.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left))); this.AddMarkerButton.Image = global::BizHawk.Client.EmuHawk.Properties.Resources.add; - this.AddMarkerButton.Location = new System.Drawing.Point(3, 174); + this.AddMarkerButton.Location = new System.Drawing.Point(6, 247); this.AddMarkerButton.Name = "AddMarkerButton"; - this.AddMarkerButton.Size = new System.Drawing.Size(23, 23); - this.AddMarkerButton.TabIndex = 6; + this.AddMarkerButton.Size = new System.Drawing.Size(24, 24); + this.AddMarkerButton.TabIndex = 1; this.toolTip1.SetToolTip(this.AddMarkerButton, "Add Marker to Emulated Frame"); this.AddMarkerButton.UseVisualStyleBackColor = true; this.AddMarkerButton.Click += new System.EventHandler(this.AddMarkerToolStripMenuItem_Click); @@ -148,10 +150,10 @@ this.RemoveMarkerButton.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left))); this.RemoveMarkerButton.Enabled = false; this.RemoveMarkerButton.Image = global::BizHawk.Client.EmuHawk.Properties.Resources.Delete; - this.RemoveMarkerButton.Location = new System.Drawing.Point(148, 174); + this.RemoveMarkerButton.Location = new System.Drawing.Point(156, 247); this.RemoveMarkerButton.Name = "RemoveMarkerButton"; - this.RemoveMarkerButton.Size = new System.Drawing.Size(23, 23); - this.RemoveMarkerButton.TabIndex = 7; + this.RemoveMarkerButton.Size = new System.Drawing.Size(24, 24); + this.RemoveMarkerButton.TabIndex = 6; this.toolTip1.SetToolTip(this.RemoveMarkerButton, "Remove Marker"); this.RemoveMarkerButton.UseVisualStyleBackColor = true; this.RemoveMarkerButton.Click += new System.EventHandler(this.RemoveMarkerToolStripMenuItem_Click); @@ -161,10 +163,10 @@ this.ScrollToMarkerButton.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left))); this.ScrollToMarkerButton.Enabled = false; this.ScrollToMarkerButton.Image = global::BizHawk.Client.EmuHawk.Properties.Resources.ScrollTo; - this.ScrollToMarkerButton.Location = new System.Drawing.Point(90, 174); + this.ScrollToMarkerButton.Location = new System.Drawing.Point(96, 247); this.ScrollToMarkerButton.Name = "ScrollToMarkerButton"; - this.ScrollToMarkerButton.Size = new System.Drawing.Size(23, 23); - this.ScrollToMarkerButton.TabIndex = 10; + this.ScrollToMarkerButton.Size = new System.Drawing.Size(24, 24); + this.ScrollToMarkerButton.TabIndex = 4; this.toolTip1.SetToolTip(this.ScrollToMarkerButton, "Scroll View To Marker Frame"); this.ScrollToMarkerButton.UseVisualStyleBackColor = true; this.ScrollToMarkerButton.Click += new System.EventHandler(this.ScrollToMarkerToolStripMenuItem_Click); @@ -173,10 +175,10 @@ // this.AddMarkerWithTextButton.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left))); this.AddMarkerWithTextButton.Image = global::BizHawk.Client.EmuHawk.Properties.Resources.AddEdit; - this.AddMarkerWithTextButton.Location = new System.Drawing.Point(32, 174); + this.AddMarkerWithTextButton.Location = new System.Drawing.Point(36, 247); this.AddMarkerWithTextButton.Name = "AddMarkerWithTextButton"; - this.AddMarkerWithTextButton.Size = new System.Drawing.Size(23, 23); - this.AddMarkerWithTextButton.TabIndex = 11; + this.AddMarkerWithTextButton.Size = new System.Drawing.Size(24, 24); + this.AddMarkerWithTextButton.TabIndex = 2; this.toolTip1.SetToolTip(this.AddMarkerWithTextButton, "Add Marker with Text to Emulated Frame"); this.AddMarkerWithTextButton.UseVisualStyleBackColor = true; this.AddMarkerWithTextButton.Click += new System.EventHandler(this.AddMarkerWithTextToolStripMenuItem_Click); @@ -197,33 +199,48 @@ this.MarkerView.HideWasLagFrames = false; this.MarkerView.HorizontalOrientation = false; this.MarkerView.LagFramesToHide = 0; - this.MarkerView.Location = new System.Drawing.Point(3, 3); + this.MarkerView.LetKeysModifySelection = false; + this.MarkerView.Location = new System.Drawing.Point(6, 19); this.MarkerView.MaxCharactersInHorizontal = 1; this.MarkerView.MultiSelect = false; this.MarkerView.Name = "MarkerView"; this.MarkerView.RowCount = 0; this.MarkerView.ScrollSpeed = 1; - this.MarkerView.Size = new System.Drawing.Size(195, 165); - this.MarkerView.TabIndex = 5; + this.MarkerView.SeekingCutoffInterval = 0; + this.MarkerView.Size = new System.Drawing.Size(186, 224); + this.MarkerView.SuspendHotkeys = false; + this.MarkerView.TabIndex = 0; this.MarkerView.TabStop = false; this.MarkerView.SelectedIndexChanged += new System.EventHandler(this.MarkerView_SelectedIndexChanged); this.MarkerView.MouseClick += new System.Windows.Forms.MouseEventHandler(this.MarkerView_MouseClick); this.MarkerView.MouseDoubleClick += new System.Windows.Forms.MouseEventHandler(this.MarkerView_MouseDoubleClick); // + // MarkersGroupBox + // + this.MarkersGroupBox.Controls.Add(this.MarkerView); + this.MarkersGroupBox.Controls.Add(this.AddMarkerButton); + this.MarkersGroupBox.Controls.Add(this.AddMarkerWithTextButton); + this.MarkersGroupBox.Controls.Add(this.RemoveMarkerButton); + this.MarkersGroupBox.Controls.Add(this.ScrollToMarkerButton); + this.MarkersGroupBox.Controls.Add(this.EditMarkerButton); + this.MarkersGroupBox.Controls.Add(this.JumpToMarkerButton); + this.MarkersGroupBox.Dock = System.Windows.Forms.DockStyle.Fill; + this.MarkersGroupBox.Location = new System.Drawing.Point(0, 0); + this.MarkersGroupBox.Name = "MarkersGroupBox"; + this.MarkersGroupBox.Size = new System.Drawing.Size(198, 278); + this.MarkersGroupBox.TabIndex = 0; + this.MarkersGroupBox.TabStop = false; + this.MarkersGroupBox.Text = "Markers"; + // // MarkerControl // this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Inherit; - this.Controls.Add(this.AddMarkerWithTextButton); - this.Controls.Add(this.MarkerView); - this.Controls.Add(this.EditMarkerButton); - this.Controls.Add(this.JumpToMarkerButton); - this.Controls.Add(this.ScrollToMarkerButton); - this.Controls.Add(this.RemoveMarkerButton); - this.Controls.Add(this.AddMarkerButton); + this.Controls.Add(this.MarkersGroupBox); this.Name = "MarkerControl"; - this.Size = new System.Drawing.Size(201, 200); + this.Size = new System.Drawing.Size(198, 278); this.Load += new System.EventHandler(this.MarkerControl_Load); this.MarkerContextMenu.ResumeLayout(false); + this.MarkersGroupBox.ResumeLayout(false); this.ResumeLayout(false); } @@ -245,6 +262,6 @@ private System.Windows.Forms.ToolStripMenuItem JumpToMarkerToolStripMenuItem; private System.Windows.Forms.ToolStripSeparator toolStripSeparator1; private System.Windows.Forms.Button AddMarkerWithTextButton; - + private System.Windows.Forms.GroupBox MarkersGroupBox; } } diff --git a/BizHawk.Client.EmuHawk/tools/TAStudio/PlaybackBox.Designer.cs b/BizHawk.Client.EmuHawk/tools/TAStudio/PlaybackBox.Designer.cs index 2319cf7923..8b2042936e 100644 --- a/BizHawk.Client.EmuHawk/tools/TAStudio/PlaybackBox.Designer.cs +++ b/BizHawk.Client.EmuHawk/tools/TAStudio/PlaybackBox.Designer.cs @@ -45,9 +45,6 @@ // // PlaybackGroupBox // - this.PlaybackGroupBox.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom) - | System.Windows.Forms.AnchorStyles.Left) - | System.Windows.Forms.AnchorStyles.Right))); this.PlaybackGroupBox.Controls.Add(this.RecordingModeCheckbox); this.PlaybackGroupBox.Controls.Add(this.AutoRestoreCheckbox); this.PlaybackGroupBox.Controls.Add(this.TurboSeekCheckbox); @@ -57,9 +54,10 @@ this.PlaybackGroupBox.Controls.Add(this.PauseButton); this.PlaybackGroupBox.Controls.Add(this.RewindButton); this.PlaybackGroupBox.Controls.Add(this.PreviousMarkerButton); - this.PlaybackGroupBox.Location = new System.Drawing.Point(3, 3); + this.PlaybackGroupBox.Dock = System.Windows.Forms.DockStyle.Fill; + this.PlaybackGroupBox.Location = new System.Drawing.Point(0, 0); this.PlaybackGroupBox.Name = "PlaybackGroupBox"; - this.PlaybackGroupBox.Size = new System.Drawing.Size(252, 104); + this.PlaybackGroupBox.Size = new System.Drawing.Size(198, 104); this.PlaybackGroupBox.TabIndex = 0; this.PlaybackGroupBox.TabStop = false; this.PlaybackGroupBox.Text = "Playback"; @@ -174,7 +172,7 @@ this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Inherit; this.Controls.Add(this.PlaybackGroupBox); this.Name = "PlaybackBox"; - this.Size = new System.Drawing.Size(258, 110); + this.Size = new System.Drawing.Size(198, 104); this.PlaybackGroupBox.ResumeLayout(false); this.PlaybackGroupBox.PerformLayout(); this.ResumeLayout(false); diff --git a/BizHawk.Client.EmuHawk/tools/TAStudio/TAStudio.Designer.cs b/BizHawk.Client.EmuHawk/tools/TAStudio/TAStudio.Designer.cs index aec14166a2..8972f50607 100644 --- a/BizHawk.Client.EmuHawk/tools/TAStudio/TAStudio.Designer.cs +++ b/BizHawk.Client.EmuHawk/tools/TAStudio/TAStudio.Designer.cs @@ -190,14 +190,12 @@ namespace BizHawk.Client.EmuHawk this.StartFromNowSeparator = new System.Windows.Forms.ToolStripSeparator(); this.StartNewProjectFromNowMenuItem = new System.Windows.Forms.ToolStripMenuItem(); this.StartANewProjectFromSaveRamMenuItem = new System.Windows.Forms.ToolStripMenuItem(); - this.groupBox1 = new System.Windows.Forms.GroupBox(); this.BookMarkControl = new BizHawk.Client.EmuHawk.BookmarksBranchesBox(); this.BranchesMarkersSplit = new System.Windows.Forms.SplitContainer(); this.MainVertialSplit = new System.Windows.Forms.SplitContainer(); this.TASMenu.SuspendLayout(); this.TasStatusStrip.SuspendLayout(); this.RightClickMenu.SuspendLayout(); - this.groupBox1.SuspendLayout(); ((System.ComponentModel.ISupportInitialize)(this.BranchesMarkersSplit)).BeginInit(); this.BranchesMarkersSplit.Panel1.SuspendLayout(); this.BranchesMarkersSplit.Panel2.SuspendLayout(); @@ -1309,20 +1307,18 @@ namespace BizHawk.Client.EmuHawk // this.TasPlaybackBox.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left) | System.Windows.Forms.AnchorStyles.Right))); - this.TasPlaybackBox.Location = new System.Drawing.Point(3, 4); + this.TasPlaybackBox.Location = new System.Drawing.Point(4, 4); this.TasPlaybackBox.Name = "TasPlaybackBox"; - this.TasPlaybackBox.Size = new System.Drawing.Size(204, 111); + this.TasPlaybackBox.Size = new System.Drawing.Size(200, 108); this.TasPlaybackBox.TabIndex = 5; this.TasPlaybackBox.Tastudio = null; // // MarkerControl // - this.MarkerControl.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom) - | System.Windows.Forms.AnchorStyles.Left) - | System.Windows.Forms.AnchorStyles.Right))); - this.MarkerControl.Location = new System.Drawing.Point(2, 16); + this.MarkerControl.Dock = System.Windows.Forms.DockStyle.Fill; + this.MarkerControl.Location = new System.Drawing.Point(0, 0); this.MarkerControl.Name = "MarkerControl"; - this.MarkerControl.Size = new System.Drawing.Size(194, 193); + this.MarkerControl.Size = new System.Drawing.Size(200, 224); this.MarkerControl.TabIndex = 6; this.MarkerControl.Tastudio = null; // @@ -1540,31 +1536,16 @@ namespace BizHawk.Client.EmuHawk this.StartANewProjectFromSaveRamMenuItem.Text = "Start a new project from SaveRam"; this.StartANewProjectFromSaveRamMenuItem.Click += new System.EventHandler(this.StartANewProjectFromSaveRamMenuItem_Click); // - // groupBox1 - // - this.groupBox1.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom) - | System.Windows.Forms.AnchorStyles.Left) - | System.Windows.Forms.AnchorStyles.Right))); - this.groupBox1.Controls.Add(this.MarkerControl); - this.groupBox1.Location = new System.Drawing.Point(-2, 3); - this.groupBox1.Name = "groupBox1"; - this.groupBox1.Size = new System.Drawing.Size(204, 215); - this.groupBox1.TabIndex = 7; - this.groupBox1.TabStop = false; - this.groupBox1.Text = "Markers"; - // // BookMarkControl // - this.BookMarkControl.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom) - | System.Windows.Forms.AnchorStyles.Left) - | System.Windows.Forms.AnchorStyles.Right))); + this.BookMarkControl.Dock = System.Windows.Forms.DockStyle.Fill; this.BookMarkControl.HoverInterval = 1; this.BookMarkControl.LoadedCallback = null; - this.BookMarkControl.Location = new System.Drawing.Point(-2, 5); + this.BookMarkControl.Location = new System.Drawing.Point(0, 0); this.BookMarkControl.Name = "BookMarkControl"; this.BookMarkControl.RemovedCallback = null; this.BookMarkControl.SavedCallback = null; - this.BookMarkControl.Size = new System.Drawing.Size(204, 173); + this.BookMarkControl.Size = new System.Drawing.Size(200, 184); this.BookMarkControl.TabIndex = 8; this.BookMarkControl.Tastudio = null; // @@ -1573,7 +1554,7 @@ namespace BizHawk.Client.EmuHawk this.BranchesMarkersSplit.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom) | System.Windows.Forms.AnchorStyles.Left) | System.Windows.Forms.AnchorStyles.Right))); - this.BranchesMarkersSplit.Location = new System.Drawing.Point(3, 121); + this.BranchesMarkersSplit.Location = new System.Drawing.Point(4, 116); this.BranchesMarkersSplit.Name = "BranchesMarkersSplit"; this.BranchesMarkersSplit.Orientation = System.Windows.Forms.Orientation.Horizontal; // @@ -1583,9 +1564,9 @@ namespace BizHawk.Client.EmuHawk // // BranchesMarkersSplit.Panel2 // - this.BranchesMarkersSplit.Panel2.Controls.Add(this.groupBox1); - this.BranchesMarkersSplit.Size = new System.Drawing.Size(204, 404); - this.BranchesMarkersSplit.SplitterDistance = 179; + this.BranchesMarkersSplit.Panel2.Controls.Add(this.MarkerControl); + this.BranchesMarkersSplit.Size = new System.Drawing.Size(200, 412); + this.BranchesMarkersSplit.SplitterDistance = 184; this.BranchesMarkersSplit.TabIndex = 9; this.BranchesMarkersSplit.SplitterMoved += new System.Windows.Forms.SplitterEventHandler(this.BranchesMarkersSplit_SplitterMoved); // @@ -1614,7 +1595,8 @@ namespace BizHawk.Client.EmuHawk // TAStudio // this.AllowDrop = true; - this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.None; + this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); + this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; this.ClientSize = new System.Drawing.Size(509, 576); this.Controls.Add(this.MainVertialSplit); this.Controls.Add(this.TasStatusStrip); @@ -1637,7 +1619,6 @@ namespace BizHawk.Client.EmuHawk this.TasStatusStrip.ResumeLayout(false); this.TasStatusStrip.PerformLayout(); this.RightClickMenu.ResumeLayout(false); - this.groupBox1.ResumeLayout(false); this.BranchesMarkersSplit.Panel1.ResumeLayout(false); this.BranchesMarkersSplit.Panel2.ResumeLayout(false); ((System.ComponentModel.ISupportInitialize)(this.BranchesMarkersSplit)).EndInit(); @@ -1739,7 +1720,6 @@ namespace BizHawk.Client.EmuHawk private System.Windows.Forms.ToolStripSeparator toolStripSeparator19; private System.Windows.Forms.ToolStripSeparator toolStripSeparator21; private System.Windows.Forms.ToolStripMenuItem DefaultStateSettingsMenuItem; - private System.Windows.Forms.GroupBox groupBox1; private System.Windows.Forms.ToolStripMenuItem CancelSeekContextMenuItem; private System.Windows.Forms.ToolStripSeparator StartFromNowSeparator; private System.Windows.Forms.ToolStripMenuItem StartNewProjectFromNowMenuItem; From 1ebdfa149a27768d6ead01dfed7feae1cdd1ca94 Mon Sep 17 00:00:00 2001 From: "J.D. Purcell" Date: Sun, 13 Oct 2019 14:21:15 -0400 Subject: [PATCH 022/166] Fix NullReferenceException in ToolManager.IsAvailable and remove unnecessary try/catch. --- BizHawk.Client.EmuHawk/ToolAttribute.cs | 11 ++++++----- BizHawk.Client.EmuHawk/tools/ToolManager.cs | 8 ++------ 2 files changed, 8 insertions(+), 11 deletions(-) diff --git a/BizHawk.Client.EmuHawk/ToolAttribute.cs b/BizHawk.Client.EmuHawk/ToolAttribute.cs index 721fa0cf48..53a2f837da 100644 --- a/BizHawk.Client.EmuHawk/ToolAttribute.cs +++ b/BizHawk.Client.EmuHawk/ToolAttribute.cs @@ -1,5 +1,6 @@ using System; using System.Collections.Generic; +using System.Linq; namespace BizHawk.Client.EmuHawk { @@ -9,14 +10,14 @@ namespace BizHawk.Client.EmuHawk public ToolAttribute(bool released, string[] supportedSystems, string[] unsupportedCores = null) { Released = released; - SupportedSystems = supportedSystems; - UnsupportedCores = unsupportedCores; + SupportedSystems = supportedSystems ?? Enumerable.Empty(); + UnsupportedCores = unsupportedCores ?? Enumerable.Empty(); } - public bool Released { get; private set; } + public bool Released { get; } - public IEnumerable SupportedSystems { get; private set; } + public IEnumerable SupportedSystems { get; } - public IEnumerable UnsupportedCores { get; private set; } + public IEnumerable UnsupportedCores { get; } } } diff --git a/BizHawk.Client.EmuHawk/tools/ToolManager.cs b/BizHawk.Client.EmuHawk/tools/ToolManager.cs index fef10a6b4b..e8bc2338ae 100644 --- a/BizHawk.Client.EmuHawk/tools/ToolManager.cs +++ b/BizHawk.Client.EmuHawk/tools/ToolManager.cs @@ -752,12 +752,8 @@ namespace BizHawk.Client.EmuHawk return false; } - ToolAttribute attr; - try - { - attr = tool.GetCustomAttributes(false).OfType().Single(); - } - catch (InvalidOperationException e) + ToolAttribute attr = tool.GetCustomAttributes(false).OfType().SingleOrDefault(); + if (attr == null) { return true; // no ToolAttribute on given type -> assumed all supported } From d3b62009e639f03294cced582d4679b700d00ab2 Mon Sep 17 00:00:00 2001 From: "J.D. Purcell" Date: Sun, 13 Oct 2019 14:49:25 -0400 Subject: [PATCH 023/166] BasicBot: Fix DPI scaling issues. --- BizHawk.Client.EmuHawk/UIHelper.cs | 2 ++ BizHawk.Client.EmuHawk/tools/BasicBot/BasicBot.cs | 10 ++++++---- .../tools/BasicBot/BotControlsRow.Designer.cs | 3 +-- 3 files changed, 9 insertions(+), 6 deletions(-) diff --git a/BizHawk.Client.EmuHawk/UIHelper.cs b/BizHawk.Client.EmuHawk/UIHelper.cs index f6e01d6f16..cc74296676 100644 --- a/BizHawk.Client.EmuHawk/UIHelper.cs +++ b/BizHawk.Client.EmuHawk/UIHelper.cs @@ -16,6 +16,8 @@ namespace BizHawk.Client.EmuHawk public static float AutoScaleFactorY { get; } = AutoScaleCurrentSize.Height / AutoScaleBaseSize.Height; + public static SizeF AutoScaleFactor { get; } = new SizeF(AutoScaleFactorX, AutoScaleFactorY); + public static int ScaleX(int size) { return (int)Math.Round(size * AutoScaleFactorX); diff --git a/BizHawk.Client.EmuHawk/tools/BasicBot/BasicBot.cs b/BizHawk.Client.EmuHawk/tools/BasicBot/BasicBot.cs index 9c3361cdaa..e4a1d99ca2 100644 --- a/BizHawk.Client.EmuHawk/tools/BasicBot/BasicBot.cs +++ b/BizHawk.Client.EmuHawk/tools/BasicBot/BasicBot.cs @@ -845,14 +845,14 @@ namespace BizHawk.Client.EmuHawk StartFromSlotBox.SelectedIndex = 0; - int starty = 0; + const int starty = 0; + const int lineHeight = 30; + const int marginLeft = 15; int accumulatedy = 0; - int lineHeight = 30; - int marginLeft = 15; int count = 0; + ControlProbabilityPanel.SuspendLayout(); ControlProbabilityPanel.Controls.Clear(); - foreach (var button in Emulator.ControllerDefinition.BoolButtons) { var control = new BotControlsRow @@ -863,11 +863,13 @@ namespace BizHawk.Client.EmuHawk TabIndex = count + 1, ProbabilityChangedCallback = AssessRunButtonStatus }; + control.Scale(UIHelper.AutoScaleFactor); ControlProbabilityPanel.Controls.Add(control); accumulatedy += lineHeight; count++; } + ControlProbabilityPanel.ResumeLayout(); if (Settings.RecentBotFiles.AutoLoad) { diff --git a/BizHawk.Client.EmuHawk/tools/BasicBot/BotControlsRow.Designer.cs b/BizHawk.Client.EmuHawk/tools/BasicBot/BotControlsRow.Designer.cs index 0ddb924cff..9ee550ffe8 100644 --- a/BizHawk.Client.EmuHawk/tools/BasicBot/BotControlsRow.Designer.cs +++ b/BizHawk.Client.EmuHawk/tools/BasicBot/BotControlsRow.Designer.cs @@ -72,8 +72,7 @@ // // BotControlsRow // - this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); - this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; + this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Inherit; this.Controls.Add(this.ProbabilitySlider); this.Controls.Add(this.ProbabilityUpDown); this.Controls.Add(this.ButtonNameLabel); From d95340182e7d12984a32e3264b86beca96d9e220 Mon Sep 17 00:00:00 2001 From: "J.D. Purcell" Date: Sun, 13 Oct 2019 15:42:38 -0400 Subject: [PATCH 024/166] Fix unescaped ampersands in the Recent ROM menu. --- BizHawk.Client.EmuHawk/Extensions/ToolExtensions.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/BizHawk.Client.EmuHawk/Extensions/ToolExtensions.cs b/BizHawk.Client.EmuHawk/Extensions/ToolExtensions.cs index c125b2286d..3e71f5ff11 100644 --- a/BizHawk.Client.EmuHawk/Extensions/ToolExtensions.cs +++ b/BizHawk.Client.EmuHawk/Extensions/ToolExtensions.cs @@ -50,7 +50,7 @@ namespace BizHawk.Client.EmuHawk.ToolExtensions } //TODO - do TSMI and TSDD need disposing? yuck - var item = new ToolStripMenuItem { Text = caption }; + var item = new ToolStripMenuItem { Text = caption.Replace("&", "&&") }; items.Add(item); item.Click += (o, ev) => From da49f85b81dae384eb84ccc43332dfac7b9bd1e4 Mon Sep 17 00:00:00 2001 From: "J.D. Purcell" Date: Sun, 13 Oct 2019 16:34:55 -0400 Subject: [PATCH 025/166] HotkeyConfig: Code cleanup. --- BizHawk.Client.EmuHawk/config/HotkeyConfig.cs | 60 ++++++++----------- 1 file changed, 24 insertions(+), 36 deletions(-) diff --git a/BizHawk.Client.EmuHawk/config/HotkeyConfig.cs b/BizHawk.Client.EmuHawk/config/HotkeyConfig.cs index 4713321dc8..79ba49db1d 100644 --- a/BizHawk.Client.EmuHawk/config/HotkeyConfig.cs +++ b/BizHawk.Client.EmuHawk/config/HotkeyConfig.cs @@ -72,32 +72,17 @@ namespace BizHawk.Client.EmuHawk foreach (var w in InputWidgets) { - var b = Global.Config.HotkeyBindings.FirstOrDefault(x => x.DisplayName == w.WidgetName); + var b = Global.Config.HotkeyBindings.First(x => x.DisplayName == w.WidgetName); b.Bindings = w.Bindings; } } - private IEnumerable InputWidgets - { - get - { - var widgets = new List(); - for (var x = 0; x < HotkeyTabControl.TabPages.Count; x++) - { - for (var y = 0; y < HotkeyTabControl.TabPages[x].Controls.Count; y++) - { - if (HotkeyTabControl.TabPages[x].Controls[y] is InputCompositeWidget) - { - widgets.Add(HotkeyTabControl.TabPages[x].Controls[y] as InputCompositeWidget); - } - } - } - return widgets; - } - } + private IEnumerable InputWidgets => + HotkeyTabControl.TabPages.Cast().SelectMany(tp => tp.Controls.OfType()); private void DoTabs() { + HotkeyTabControl.SuspendLayout(); HotkeyTabControl.TabPages.Clear(); // Buckets @@ -105,31 +90,31 @@ namespace BizHawk.Client.EmuHawk foreach (var tab in tabs) { - var _y = UIHelper.ScaleY(14); - var _x = UIHelper.ScaleX(6); - - var tb = new TabPage {Name = tab, Text = tab}; - - var bindings = Global.Config.HotkeyBindings.Where(x => x.TabGroup == tab).OrderBy(x => x.Ordinal).ThenBy(x => x.DisplayName); - + var tb = new TabPage { Name = tab, Text = tab }; + var bindings = Global.Config.HotkeyBindings.Where(n => n.TabGroup == tab).OrderBy(n => n.Ordinal).ThenBy(n => n.DisplayName); + int x = UIHelper.ScaleX(6); + int y = UIHelper.ScaleY(14); int iwOffsetX = UIHelper.ScaleX(110); int iwOffsetY = UIHelper.ScaleY(-4); int iwWidth = UIHelper.ScaleX(120); + + tb.SuspendLayout(); + foreach (var b in bindings) { var l = new Label { Text = b.DisplayName, - Location = new Point(_x, _y), - Size = new Size(iwOffsetX - UIHelper.ScaleX(2), UIHelper.ScaleY(15)), + Location = new Point(x, y), + Size = new Size(iwOffsetX - UIHelper.ScaleX(2), UIHelper.ScaleY(15)) }; var w = new InputCompositeWidget { - Location = new Point(_x + iwOffsetX, _y + iwOffsetY), + Location = new Point(x + iwOffsetX, y + iwOffsetY), AutoTab = AutoTabCheckBox.Checked, Width = iwWidth, - WidgetName = b.DisplayName, + WidgetName = b.DisplayName }; w.SetupTooltip(toolTip1, b.ToolTip); @@ -140,11 +125,11 @@ namespace BizHawk.Client.EmuHawk tb.Controls.Add(l); tb.Controls.Add(w); - _y += UIHelper.ScaleY(24); - if (_y > HotkeyTabControl.Height - UIHelper.ScaleY(35)) + y += UIHelper.ScaleY(24); + if (y > HotkeyTabControl.Height - UIHelper.ScaleY(35)) { - _x += iwOffsetX + iwWidth + UIHelper.ScaleX(10); - _y = UIHelper.ScaleY(14); + x += iwOffsetX + iwWidth + UIHelper.ScaleX(10); + y = UIHelper.ScaleY(14); } } @@ -153,13 +138,16 @@ namespace BizHawk.Client.EmuHawk tb.Controls.Add(new Label { Text = "Save States hotkeys operate with branches when TAStudio is engaged.", - Location = new Point(_x, _y), - Size = new Size(iwWidth + iwOffsetX, HotkeyTabControl.Height - _y), + Location = new Point(x, y), + Size = new Size(iwWidth + iwOffsetX, HotkeyTabControl.Height - y) }); } HotkeyTabControl.TabPages.Add(tb); + tb.ResumeLayout(); } + + HotkeyTabControl.ResumeLayout(); } private void Defaults() From 2e31d3856833d0580af22ef0310a050f2c097d2f Mon Sep 17 00:00:00 2001 From: alyosha-tas Date: Sun, 13 Oct 2019 19:27:14 -0400 Subject: [PATCH 026/166] GBHawk: fix a register --- .../Consoles/Nintendo/GBHawk/HW_Registers.cs | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/BizHawk.Emulation.Cores/Consoles/Nintendo/GBHawk/HW_Registers.cs b/BizHawk.Emulation.Cores/Consoles/Nintendo/GBHawk/HW_Registers.cs index 326a61cf3c..84cc406cae 100644 --- a/BizHawk.Emulation.Cores/Consoles/Nintendo/GBHawk/HW_Registers.cs +++ b/BizHawk.Emulation.Cores/Consoles/Nintendo/GBHawk/HW_Registers.cs @@ -1,7 +1,5 @@ using System; -using BizHawk.Emulation.Common; using BizHawk.Common.NumberExtensions; -using BizHawk.Common; namespace BizHawk.Emulation.Cores.Nintendo.GBHawk { @@ -144,7 +142,7 @@ namespace BizHawk.Emulation.Cores.Nintendo.GBHawk break; case 0xFF56: - if (is_GBC) + if (GBC_compat) { // can receive data if ((IR_reg & 0xC0) == 0xC0) From 65043873020d8e0e128f40f4adfe474735fad039 Mon Sep 17 00:00:00 2001 From: "J.D. Purcell" Date: Sun, 13 Oct 2019 19:49:17 -0400 Subject: [PATCH 027/166] Option to accept background input only from controller. Closes #1396. --- BizHawk.Client.Common/config/Config.cs | 1 + BizHawk.Client.EmuHawk/Input/Input.cs | 47 +++++++++++++------ BizHawk.Client.EmuHawk/MainForm.cs | 19 +++----- .../config/GuiOptions.Designer.cs | 15 ++++++ BizHawk.Client.EmuHawk/config/GuiOptions.cs | 7 +++ 5 files changed, 62 insertions(+), 27 deletions(-) diff --git a/BizHawk.Client.Common/config/Config.cs b/BizHawk.Client.Common/config/Config.cs index 057ec89c0b..b48b85a0dc 100644 --- a/BizHawk.Client.Common/config/Config.cs +++ b/BizHawk.Client.Common/config/Config.cs @@ -104,6 +104,7 @@ namespace BizHawk.Client.Common public int MainHeight = -1; public bool RunInBackground = true; public bool AcceptBackgroundInput = false; + public bool AcceptBackgroundInputControllerOnly = false; public bool SingleInstanceMode = false; public bool AllowUD_LR = false; public bool ForbidUD_LR = false; diff --git a/BizHawk.Client.EmuHawk/Input/Input.cs b/BizHawk.Client.EmuHawk/Input/Input.cs index a890029682..d187149c59 100644 --- a/BizHawk.Client.EmuHawk/Input/Input.cs +++ b/BizHawk.Client.EmuHawk/Input/Input.cs @@ -70,6 +70,13 @@ namespace BizHawk.Client.EmuHawk Pad = 4 } + public enum AllowInput + { + None = 0, + All = 1, + OnlyController = 2 + } + /// /// If your form needs this kind of input focus, be sure to say so. /// Really, this only makes sense for mouse, but I've started building it out for other things @@ -196,6 +203,7 @@ namespace BizHawk.Client.EmuHawk { public LogicalButton LogicalButton; public InputEventType EventType; + public InputFocus Source; public override string ToString() { return $"{EventType.ToString()}:{LogicalButton.ToString()}"; @@ -210,7 +218,7 @@ namespace BizHawk.Client.EmuHawk private readonly WorkingDictionary FloatDeltas = new WorkingDictionary(); private bool trackdeltas = false; - void HandleButton(string button, bool newState) + void HandleButton(string button, bool newState, InputFocus source) { bool isModifier = IgnoreKeys.Contains(button); if (EnableIgnoreModifiers && isModifier) return; @@ -253,7 +261,8 @@ namespace BizHawk.Client.EmuHawk var ie = new InputEvent { EventType = newState ? InputEventType.Press : InputEventType.Release, - LogicalButton = new LogicalButton(button, mods) + LogicalButton = new LogicalButton(button, mods), + Source = source }; LastState[button] = newState; @@ -276,7 +285,8 @@ namespace BizHawk.Client.EmuHawk var ieModified = new InputEvent { LogicalButton = (LogicalButton)ModifierState[button], - EventType = InputEventType.Release + EventType = InputEventType.Release, + Source = source }; if (ieModified.LogicalButton != alreadyReleased) _NewEvents.Add(ieModified); @@ -351,7 +361,7 @@ namespace BizHawk.Client.EmuHawk //analyze keys foreach (var ke in keyEvents) - HandleButton(ke.Key.ToString(), ke.Pressed); + HandleButton(ke.Key.ToString(), ke.Pressed, InputFocus.Keyboard); lock (FloatValues) { @@ -362,7 +372,7 @@ namespace BizHawk.Client.EmuHawk { string xname = $"X{pad.PlayerNumber} "; for (int b = 0; b < pad.NumButtons; b++) - HandleButton(xname + pad.ButtonName(b), pad.Pressed(b)); + HandleButton(xname + pad.ButtonName(b), pad.Pressed(b), InputFocus.Pad); foreach (var sv in pad.GetFloats()) { string n = xname + sv.Item1; @@ -378,7 +388,7 @@ namespace BizHawk.Client.EmuHawk { string jname = $"J{pad.PlayerNumber} "; for (int b = 0; b < pad.NumButtons; b++) - HandleButton(jname + pad.ButtonName(b), pad.Pressed(b)); + HandleButton(jname + pad.ButtonName(b), pad.Pressed(b), InputFocus.Pad); foreach (var sv in pad.GetFloats()) { string n = jname + sv.Item1; @@ -407,11 +417,11 @@ namespace BizHawk.Client.EmuHawk FloatValues["WMouse Y"] = P.Y; var B = System.Windows.Forms.Control.MouseButtons; - HandleButton("WMouse L", (B & System.Windows.Forms.MouseButtons.Left) != 0); - HandleButton("WMouse C", (B & System.Windows.Forms.MouseButtons.Middle) != 0); - HandleButton("WMouse R", (B & System.Windows.Forms.MouseButtons.Right) != 0); - HandleButton("WMouse 1", (B & System.Windows.Forms.MouseButtons.XButton1) != 0); - HandleButton("WMouse 2", (B & System.Windows.Forms.MouseButtons.XButton2) != 0); + HandleButton("WMouse L", (B & System.Windows.Forms.MouseButtons.Left) != 0, InputFocus.Mouse); + HandleButton("WMouse C", (B & System.Windows.Forms.MouseButtons.Middle) != 0, InputFocus.Mouse); + HandleButton("WMouse R", (B & System.Windows.Forms.MouseButtons.Right) != 0, InputFocus.Mouse); + HandleButton("WMouse 1", (B & System.Windows.Forms.MouseButtons.XButton1) != 0, InputFocus.Mouse); + HandleButton("WMouse 2", (B & System.Windows.Forms.MouseButtons.XButton2) != 0, InputFocus.Mouse); } else { @@ -427,14 +437,14 @@ namespace BizHawk.Client.EmuHawk } //WHAT!? WE SHOULD NOT BE SO NAIVELY TOUCHING MAINFORM FROM THE INPUTTHREAD. ITS BUSY RUNNING. - bool swallow = !GlobalWin.MainForm.AllowInput(false); + AllowInput allowInput = GlobalWin.MainForm.AllowInput(false); foreach (var ie in _NewEvents) { //events are swallowed in some cases: - if (ie.LogicalButton.Alt && !GlobalWin.MainForm.AllowInput(true)) + if (ie.LogicalButton.Alt && ShouldSwallow(GlobalWin.MainForm.AllowInput(true), ie)) { } - else if (ie.EventType == InputEventType.Press && swallow) + else if (ie.EventType == InputEventType.Press && ShouldSwallow(allowInput, ie)) { } else EnqueueEvent(ie); @@ -446,6 +456,11 @@ namespace BizHawk.Client.EmuHawk } } + private static bool ShouldSwallow(AllowInput allowInput, InputEvent inputEvent) + { + return allowInput == AllowInput.None || (allowInput == AllowInput.OnlyController && inputEvent.Source != InputFocus.Pad); + } + public void StartListeningForFloatEvents() { lock (FloatValues) @@ -490,7 +505,7 @@ namespace BizHawk.Client.EmuHawk lock (this) { if (InputEvents.Count == 0) return null; - if (!GlobalWin.MainForm.AllowInput(false)) return null; + AllowInput allowInput = GlobalWin.MainForm.AllowInput(false); //we only listen to releases for input binding, because we need to distinguish releases of pure modifierkeys from modified keys //if you just pressed ctrl, wanting to bind ctrl, we'd see: pressed:ctrl, unpressed:ctrl @@ -501,6 +516,8 @@ namespace BizHawk.Client.EmuHawk { var ie = DequeueEvent(); + if (ShouldSwallow(allowInput, ie)) continue; + //as a special perk, we'll accept escape immediately if (ie.EventType == InputEventType.Press && ie.LogicalButton.Button == "Escape") goto ACCEPT; diff --git a/BizHawk.Client.EmuHawk/MainForm.cs b/BizHawk.Client.EmuHawk/MainForm.cs index 444e73cc3d..0d32cd12f9 100644 --- a/BizHawk.Client.EmuHawk/MainForm.cs +++ b/BizHawk.Client.EmuHawk/MainForm.cs @@ -650,12 +650,12 @@ namespace BizHawk.Client.EmuHawk /// /// Controls whether the app generates input events. should be turned off for most modal dialogs /// - public bool AllowInput(bool yieldAlt) + public Input.AllowInput AllowInput(bool yieldAlt) { // the main form gets input if (ActiveForm == this) { - return true; + return Input.AllowInput.All; } // even more special logic for TAStudio: @@ -663,14 +663,9 @@ namespace BizHawk.Client.EmuHawk var maybeTAStudio = ActiveForm as TAStudio; if (maybeTAStudio != null) { - if (yieldAlt) + if (yieldAlt || maybeTAStudio.IsInMenuLoop) { - return false; - } - - if (maybeTAStudio.IsInMenuLoop) - { - return false; + return Input.AllowInput.None; } } @@ -680,16 +675,16 @@ namespace BizHawk.Client.EmuHawk || ActiveForm is TAStudio || ActiveForm is VirtualpadTool) { - return true; + return Input.AllowInput.All; } // if no form is active on this process, then the background input setting applies if (ActiveForm == null && Global.Config.AcceptBackgroundInput) { - return true; + return Global.Config.AcceptBackgroundInputControllerOnly ? Input.AllowInput.OnlyController : Input.AllowInput.All; } - return false; + return Input.AllowInput.None; } // TODO: make this an actual property, set it when loading a Rom, and pass it dialogs, etc diff --git a/BizHawk.Client.EmuHawk/config/GuiOptions.Designer.cs b/BizHawk.Client.EmuHawk/config/GuiOptions.Designer.cs index 70e35459eb..1daf1356b7 100644 --- a/BizHawk.Client.EmuHawk/config/GuiOptions.Designer.cs +++ b/BizHawk.Client.EmuHawk/config/GuiOptions.Designer.cs @@ -42,6 +42,7 @@ this.NeverAskSaveCheckbox = new System.Windows.Forms.CheckBox(); this.label2 = new System.Windows.Forms.Label(); this.AcceptBackgroundInputCheckbox = new System.Windows.Forms.CheckBox(); + this.AcceptBackgroundInputControllerOnlyCheckBox = new System.Windows.Forms.CheckBox(); this.label1 = new System.Windows.Forms.Label(); this.RunInBackgroundCheckbox = new System.Windows.Forms.CheckBox(); this.SaveWindowPositionCheckbox = new System.Windows.Forms.CheckBox(); @@ -124,6 +125,7 @@ this.tabPage1.Controls.Add(this.NeverAskSaveCheckbox); this.tabPage1.Controls.Add(this.label2); this.tabPage1.Controls.Add(this.AcceptBackgroundInputCheckbox); + this.tabPage1.Controls.Add(this.AcceptBackgroundInputControllerOnlyCheckBox); this.tabPage1.Controls.Add(this.label1); this.tabPage1.Controls.Add(this.RunInBackgroundCheckbox); this.tabPage1.Controls.Add(this.SaveWindowPositionCheckbox); @@ -227,6 +229,18 @@ this.AcceptBackgroundInputCheckbox.TabIndex = 8; this.AcceptBackgroundInputCheckbox.Text = "Accept background input"; this.AcceptBackgroundInputCheckbox.UseVisualStyleBackColor = true; + this.AcceptBackgroundInputCheckbox.CheckedChanged += new System.EventHandler(this.AcceptBackgroundInputCheckbox_CheckedChanged); + // + // AcceptBackgroundInputControllerOnlyCheckBox + // + this.AcceptBackgroundInputControllerOnlyCheckBox.AutoSize = true; + this.AcceptBackgroundInputControllerOnlyCheckBox.Enabled = false; + this.AcceptBackgroundInputControllerOnlyCheckBox.Location = new System.Drawing.Point(156, 135); + this.AcceptBackgroundInputControllerOnlyCheckBox.Name = "AcceptBackgroundInputControllerOnlyCheckBox"; + this.AcceptBackgroundInputControllerOnlyCheckBox.Size = new System.Drawing.Size(117, 17); + this.AcceptBackgroundInputControllerOnlyCheckBox.TabIndex = 14; + this.AcceptBackgroundInputControllerOnlyCheckBox.Text = "From controller only"; + this.AcceptBackgroundInputControllerOnlyCheckBox.UseVisualStyleBackColor = true; // // label1 // @@ -593,6 +607,7 @@ private System.Windows.Forms.Label label1; private System.Windows.Forms.Label label2; private System.Windows.Forms.CheckBox AcceptBackgroundInputCheckbox; + private System.Windows.Forms.CheckBox AcceptBackgroundInputControllerOnlyCheckBox; private System.Windows.Forms.CheckBox NeverAskSaveCheckbox; private System.Windows.Forms.Label label3; private System.Windows.Forms.CheckBox SingleInstanceModeCheckbox; diff --git a/BizHawk.Client.EmuHawk/config/GuiOptions.cs b/BizHawk.Client.EmuHawk/config/GuiOptions.cs index d5106c9d24..76e29d2a03 100644 --- a/BizHawk.Client.EmuHawk/config/GuiOptions.cs +++ b/BizHawk.Client.EmuHawk/config/GuiOptions.cs @@ -49,6 +49,7 @@ namespace BizHawk.Client.EmuHawk SaveWindowPositionCheckbox.Checked = Global.Config.SaveWindowPosition; RunInBackgroundCheckbox.Checked = Global.Config.RunInBackground; AcceptBackgroundInputCheckbox.Checked = Global.Config.AcceptBackgroundInput; + AcceptBackgroundInputControllerOnlyCheckBox.Checked = Global.Config.AcceptBackgroundInputControllerOnly; NeverAskSaveCheckbox.Checked = Global.Config.SupressAskSave; SingleInstanceModeCheckbox.Checked = Global.Config.SingleInstanceMode; @@ -83,6 +84,7 @@ namespace BizHawk.Client.EmuHawk Global.Config.SaveWindowPosition = SaveWindowPositionCheckbox.Checked; Global.Config.RunInBackground = RunInBackgroundCheckbox.Checked; Global.Config.AcceptBackgroundInput = AcceptBackgroundInputCheckbox.Checked; + Global.Config.AcceptBackgroundInputControllerOnly = AcceptBackgroundInputControllerOnlyCheckBox.Checked; Global.Config.SupressAskSave = NeverAskSaveCheckbox.Checked; Global.Config.SingleInstanceMode = SingleInstanceModeCheckbox.Checked; @@ -113,6 +115,11 @@ namespace BizHawk.Client.EmuHawk GlobalWin.OSD.AddMessage("Customizing aborted."); } + private void AcceptBackgroundInputCheckbox_CheckedChanged(object sender, EventArgs e) + { + AcceptBackgroundInputControllerOnlyCheckBox.Enabled = AcceptBackgroundInputCheckbox.Checked; + } + private void AutosaveSRAMCheckbox_CheckedChanged(object sender, EventArgs e) { groupBox2.Enabled = AutosaveSRAMCheckbox.Checked; From c42bf37e86f3fc33af97f1470917c0503c5e6e5b Mon Sep 17 00:00:00 2001 From: "J.D. Purcell" Date: Sun, 13 Oct 2019 22:56:14 -0400 Subject: [PATCH 028/166] Sound: Improve audio throttle behavior with N64. GetSamplesSync sometimes returns > 100ms of audio from N64. --- .../Sound/Interfaces/ISoundOutput.cs | 2 +- .../Sound/Output/DirectSoundSoundOutput.cs | 6 +-- .../Sound/Output/DummySoundOutput.cs | 2 +- .../Sound/Output/OpenALSoundOutput.cs | 18 ++++++- .../Sound/Output/XAudio2SoundOutput.cs | 5 +- BizHawk.Client.EmuHawk/Sound/Sound.cs | 50 +++++++++++-------- 6 files changed, 53 insertions(+), 30 deletions(-) diff --git a/BizHawk.Client.EmuHawk/Sound/Interfaces/ISoundOutput.cs b/BizHawk.Client.EmuHawk/Sound/Interfaces/ISoundOutput.cs index f6dce3be8d..061c93d7ff 100644 --- a/BizHawk.Client.EmuHawk/Sound/Interfaces/ISoundOutput.cs +++ b/BizHawk.Client.EmuHawk/Sound/Interfaces/ISoundOutput.cs @@ -9,6 +9,6 @@ namespace BizHawk.Client.EmuHawk void ApplyVolumeSettings(double volume); int MaxSamplesDeficit { get; } int CalculateSamplesNeeded(); - void WriteSamples(short[] samples, int sampleCount); + void WriteSamples(short[] samples, int sampleOffset, int sampleCount); } } diff --git a/BizHawk.Client.EmuHawk/Sound/Output/DirectSoundSoundOutput.cs b/BizHawk.Client.EmuHawk/Sound/Output/DirectSoundSoundOutput.cs index ba3ae8ba90..20d0959cad 100644 --- a/BizHawk.Client.EmuHawk/Sound/Output/DirectSoundSoundOutput.cs +++ b/BizHawk.Client.EmuHawk/Sound/Output/DirectSoundSoundOutput.cs @@ -152,12 +152,10 @@ namespace BizHawk.Client.EmuHawk return (end - start + size) % size; } - public void WriteSamples(short[] samples, int sampleCount) + public void WriteSamples(short[] samples, int sampleOffset, int sampleCount) { if (sampleCount == 0) return; - int total = sampleCount * Sound.ChannelCount; - if (total > samples.Length) { total = samples.Length; } - _deviceBuffer.Write(samples, 0, total, _actualWriteOffsetBytes, LockFlags.None); + _deviceBuffer.Write(samples, sampleOffset * Sound.ChannelCount, sampleCount * Sound.ChannelCount, _actualWriteOffsetBytes, LockFlags.None); _actualWriteOffsetBytes = (_actualWriteOffsetBytes + (sampleCount * Sound.BlockAlign)) % BufferSizeBytes; _filledBufferSizeBytes += sampleCount * Sound.BlockAlign; } diff --git a/BizHawk.Client.EmuHawk/Sound/Output/DummySoundOutput.cs b/BizHawk.Client.EmuHawk/Sound/Output/DummySoundOutput.cs index d1632ced87..31aebb6fa1 100644 --- a/BizHawk.Client.EmuHawk/Sound/Output/DummySoundOutput.cs +++ b/BizHawk.Client.EmuHawk/Sound/Output/DummySoundOutput.cs @@ -73,7 +73,7 @@ namespace BizHawk.Client.EmuHawk return samplesNeeded; } - public void WriteSamples(short[] samples, int sampleCount) + public void WriteSamples(short[] samples, int sampleOffset, int sampleCount) { if (sampleCount == 0) return; _remainingSamples += sampleCount; diff --git a/BizHawk.Client.EmuHawk/Sound/Output/OpenALSoundOutput.cs b/BizHawk.Client.EmuHawk/Sound/Output/OpenALSoundOutput.cs index 263a18c5be..37d3d277ea 100644 --- a/BizHawk.Client.EmuHawk/Sound/Output/OpenALSoundOutput.cs +++ b/BizHawk.Client.EmuHawk/Sound/Output/OpenALSoundOutput.cs @@ -17,6 +17,7 @@ namespace BizHawk.Client.EmuHawk private int _sourceID; private BufferPool _bufferPool; private int _currentSamplesQueued; + private short[] _tempSampleBuffer; public OpenALSoundOutput(Sound sound) { @@ -94,11 +95,17 @@ namespace BizHawk.Client.EmuHawk return samplesNeeded; } - public void WriteSamples(short[] samples, int sampleCount) + public void WriteSamples(short[] samples, int sampleOffset, int sampleCount) { if (sampleCount == 0) return; UnqueueProcessedBuffers(); int byteCount = sampleCount * Sound.BlockAlign; + if (sampleOffset != 0) + { + AllocateTempSampleBuffer(sampleCount); + Buffer.BlockCopy(samples, sampleOffset * Sound.BlockAlign, _tempSampleBuffer, 0, byteCount); + samples = _tempSampleBuffer; + } var buffer = _bufferPool.Obtain(byteCount); AL.BufferData(buffer.BufferID, ALFormat.Stereo16, samples, byteCount, Sound.SampleRate); AL.SourceQueueBuffer(_sourceID, buffer.BufferID); @@ -127,6 +134,15 @@ namespace BizHawk.Client.EmuHawk return value; } + private void AllocateTempSampleBuffer(int sampleCount) + { + int length = sampleCount * Sound.ChannelCount; + if (_tempSampleBuffer == null || _tempSampleBuffer.Length < length) + { + _tempSampleBuffer = new short[length]; + } + } + private class BufferPool : IDisposable { private Stack _availableItems = new Stack(); diff --git a/BizHawk.Client.EmuHawk/Sound/Output/XAudio2SoundOutput.cs b/BizHawk.Client.EmuHawk/Sound/Output/XAudio2SoundOutput.cs index 5c37748096..80fb913f06 100644 --- a/BizHawk.Client.EmuHawk/Sound/Output/XAudio2SoundOutput.cs +++ b/BizHawk.Client.EmuHawk/Sound/Output/XAudio2SoundOutput.cs @@ -112,14 +112,13 @@ namespace BizHawk.Client.EmuHawk return samplesNeeded; } - public void WriteSamples(short[] samples, int sampleCount) + public void WriteSamples(short[] samples, int sampleOffset, int sampleCount) { if (sampleCount == 0) return; _bufferPool.Release(_sourceVoice.State.BuffersQueued); int byteCount = sampleCount * Sound.BlockAlign; var buffer = _bufferPool.Obtain(byteCount); - if (byteCount > (samples.Length * 2)) { byteCount = samples.Length * 2; } - Buffer.BlockCopy(samples, 0, buffer.Bytes, 0, byteCount); + Buffer.BlockCopy(samples, sampleOffset * Sound.BlockAlign, buffer.Bytes, 0, byteCount); _sourceVoice.SubmitSourceBuffer(new AudioBuffer { AudioBytes = byteCount, diff --git a/BizHawk.Client.EmuHawk/Sound/Sound.cs b/BizHawk.Client.EmuHawk/Sound/Sound.cs index 85aaa2502d..6156b3cfc4 100644 --- a/BizHawk.Client.EmuHawk/Sound/Sound.cs +++ b/BizHawk.Client.EmuHawk/Sound/Sound.cs @@ -16,8 +16,6 @@ namespace BizHawk.Client.EmuHawk public const int BlockAlign = BytesPerSample * ChannelCount; private bool _disposed; - private bool _unjamSoundThrottle; - private readonly ISoundOutput _outputDevice; private readonly SoundOutputProvider _outputProvider = new SoundOutputProvider(); // Buffer for Sync sources private readonly BufferedAsync _bufferedAsync = new BufferedAsync(); // Buffer for Async sources @@ -118,9 +116,8 @@ namespace BizHawk.Client.EmuHawk // Fill device buffer with silence but leave enough room for one frame int samplesPerFrame = (int)Math.Round(SampleRate / (double)Global.Emulator.VsyncRate()); int silenceSamples = Math.Max(samplesNeeded - samplesPerFrame, 0); - _outputDevice.WriteSamples(new short[silenceSamples * 2], silenceSamples); + _outputDevice.WriteSamples(new short[silenceSamples * 2], 0, silenceSamples); samplesNeeded -= silenceSamples; - _unjamSoundThrottle = isUnderrun; if (isUnderrun) { @@ -141,14 +138,16 @@ namespace BizHawk.Client.EmuHawk if (atten > 1) atten = 1; _outputDevice.ApplyVolumeSettings(atten); - short[] samples; int samplesNeeded = _outputDevice.CalculateSamplesNeeded(); - int samplesProvided; + short[] samples; + int sampleOffset; + int sampleCount; if (atten == 0) { samples = new short[samplesNeeded * ChannelCount]; - samplesProvided = samplesNeeded; + sampleOffset = 0; + sampleCount = samplesNeeded; _bufferedProvider.DiscardSamples(); } @@ -156,25 +155,34 @@ namespace BizHawk.Client.EmuHawk { if (Global.Config.SoundThrottle) { - _outputProvider.BaseSoundProvider.GetSamplesSync(out samples, out samplesProvided); + _outputProvider.BaseSoundProvider.GetSamplesSync(out samples, out sampleCount); + sampleOffset = 0; - if (Global.DisableSecondaryThrottling && samplesProvided > samplesNeeded) + if (Global.DisableSecondaryThrottling && sampleCount > samplesNeeded) { return; } - while (samplesProvided > samplesNeeded) + int samplesPerMs = SampleRate / 1000; + int outputThresholdMs = 20; + while (sampleCount > samplesNeeded) { - Thread.Sleep((samplesProvided - samplesNeeded) / (SampleRate / 1000)); // Let the audio clock control sleep time - samplesNeeded = _outputDevice.CalculateSamplesNeeded(); - if (_unjamSoundThrottle) + if (samplesNeeded >= outputThresholdMs * samplesPerMs) { - //may be garbage, but what can we do? - samplesProvided = samplesNeeded; - break; + // If we were given a large enough number of samples (e.g. larger than the device's + // buffer), the device will never need that many samples no matter how long we + // wait, so we have to start splitting up the output + _outputDevice.WriteSamples(samples, sampleOffset, samplesNeeded); + sampleOffset += samplesNeeded; + sampleCount -= samplesNeeded; } + else + { + // Let the audio clock control sleep time + Thread.Sleep(Math.Min((sampleCount - samplesNeeded) / samplesPerMs, outputThresholdMs)); + } + samplesNeeded = _outputDevice.CalculateSamplesNeeded(); } - _unjamSoundThrottle = false; } else { @@ -182,7 +190,8 @@ namespace BizHawk.Client.EmuHawk { _outputProvider.OnVolatility(); } - _outputProvider.GetSamples(samplesNeeded, out samples, out samplesProvided); + _outputProvider.GetSamples(samplesNeeded, out samples, out sampleCount); + sampleOffset = 0; } } else if (_bufferedProvider == _bufferedAsync) @@ -191,14 +200,15 @@ namespace BizHawk.Client.EmuHawk _bufferedAsync.GetSamplesAsync(samples); - samplesProvided = samplesNeeded; + sampleOffset = 0; + sampleCount = samplesNeeded; } else { return; } - _outputDevice.WriteSamples(samples, samplesProvided); + _outputDevice.WriteSamples(samples, sampleOffset, sampleCount); } public static int MillisecondsToSamples(int milliseconds) From 4324e1b309744a25a59e0cf39ace9051dde7ad6b Mon Sep 17 00:00:00 2001 From: alyosha-tas Date: Mon, 14 Oct 2019 08:58:54 -0400 Subject: [PATCH 029/166] GBHawk: sync settings fix --- .../Consoles/Nintendo/GBHawk/GBHawk.ISettable.cs | 1 + .../Nintendo/GBHawkLink/GBHawkLink.ISettable.cs | 4 ++++ .../Nintendo/GBHawkLink3x/GBHawkLink3x.ISettable.cs | 7 +++++++ .../Nintendo/GBHawkLink4x/GBHawkLink4x.ISettable.cs | 10 ++++++++++ 4 files changed, 22 insertions(+) diff --git a/BizHawk.Emulation.Cores/Consoles/Nintendo/GBHawk/GBHawk.ISettable.cs b/BizHawk.Emulation.Cores/Consoles/Nintendo/GBHawk/GBHawk.ISettable.cs index 2aa660953b..da4d606465 100644 --- a/BizHawk.Emulation.Cores/Consoles/Nintendo/GBHawk/GBHawk.ISettable.cs +++ b/BizHawk.Emulation.Cores/Consoles/Nintendo/GBHawk/GBHawk.ISettable.cs @@ -137,6 +137,7 @@ namespace BizHawk.Emulation.Cores.Nintendo.GBHawk [JsonIgnore] private int _RTCInitialTime; + [JsonIgnore] private int _RTCOffset; [JsonIgnore] public ushort _DivInitialTime = 8; diff --git a/BizHawk.Emulation.Cores/Consoles/Nintendo/GBHawkLink/GBHawkLink.ISettable.cs b/BizHawk.Emulation.Cores/Consoles/Nintendo/GBHawkLink/GBHawkLink.ISettable.cs index c609a28515..73046bdbac 100644 --- a/BizHawk.Emulation.Cores/Consoles/Nintendo/GBHawkLink/GBHawkLink.ISettable.cs +++ b/BizHawk.Emulation.Cores/Consoles/Nintendo/GBHawkLink/GBHawkLink.ISettable.cs @@ -145,11 +145,15 @@ namespace BizHawk.Emulation.Cores.Nintendo.GBHawkLink [JsonIgnore] private int _RTCInitialTime_L; + [JsonIgnore] private int _RTCInitialTime_R; + [JsonIgnore] private int _RTCOffset_L; + [JsonIgnore] private int _RTCOffset_R; [JsonIgnore] public ushort _DivInitialTime_L = 8; + [JsonIgnore] public ushort _DivInitialTime_R = 8; public GBLinkSyncSettings Clone() diff --git a/BizHawk.Emulation.Cores/Consoles/Nintendo/GBHawkLink3x/GBHawkLink3x.ISettable.cs b/BizHawk.Emulation.Cores/Consoles/Nintendo/GBHawkLink3x/GBHawkLink3x.ISettable.cs index 9c0adf8f7b..0e959567d2 100644 --- a/BizHawk.Emulation.Cores/Consoles/Nintendo/GBHawkLink3x/GBHawkLink3x.ISettable.cs +++ b/BizHawk.Emulation.Cores/Consoles/Nintendo/GBHawkLink3x/GBHawkLink3x.ISettable.cs @@ -183,14 +183,21 @@ namespace BizHawk.Emulation.Cores.Nintendo.GBHawkLink3x [JsonIgnore] private int _RTCInitialTime_L; + [JsonIgnore] private int _RTCInitialTime_C; + [JsonIgnore] private int _RTCInitialTime_R; + [JsonIgnore] private int _RTCOffset_L; + [JsonIgnore] private int _RTCOffset_C; + [JsonIgnore] private int _RTCOffset_R; [JsonIgnore] public ushort _DivInitialTime_L = 8; + [JsonIgnore] public ushort _DivInitialTime_C = 8; + [JsonIgnore] public ushort _DivInitialTime_R = 8; public GBLink3xSyncSettings Clone() diff --git a/BizHawk.Emulation.Cores/Consoles/Nintendo/GBHawkLink4x/GBHawkLink4x.ISettable.cs b/BizHawk.Emulation.Cores/Consoles/Nintendo/GBHawkLink4x/GBHawkLink4x.ISettable.cs index b509dd1d3c..0ada335d84 100644 --- a/BizHawk.Emulation.Cores/Consoles/Nintendo/GBHawkLink4x/GBHawkLink4x.ISettable.cs +++ b/BizHawk.Emulation.Cores/Consoles/Nintendo/GBHawkLink4x/GBHawkLink4x.ISettable.cs @@ -221,17 +221,27 @@ namespace BizHawk.Emulation.Cores.Nintendo.GBHawkLink4x [JsonIgnore] private int _RTCInitialTime_A; + [JsonIgnore] private int _RTCInitialTime_B; + [JsonIgnore] private int _RTCInitialTime_C; + [JsonIgnore] private int _RTCInitialTime_D; + [JsonIgnore] private int _RTCOffset_A; + [JsonIgnore] private int _RTCOffset_B; + [JsonIgnore] private int _RTCOffset_C; + [JsonIgnore] private int _RTCOffset_D; [JsonIgnore] public ushort _DivInitialTime_A = 8; + [JsonIgnore] public ushort _DivInitialTime_B = 8; + [JsonIgnore] public ushort _DivInitialTime_C = 8; + [JsonIgnore] public ushort _DivInitialTime_D = 8; public GBLink4xSyncSettings Clone() From 854315d96dac0a29b74f07ef4f589aa5cd5f97cf Mon Sep 17 00:00:00 2001 From: "J.D. Purcell" Date: Mon, 14 Oct 2019 11:39:49 -0400 Subject: [PATCH 030/166] TabIndex fixes. --- .../config/GuiOptions.Designer.cs | 30 ++++----- .../config/RewindConfig.Designer.cs | 62 +++++++++---------- .../config/SoundConfig.Designer.cs | 34 +++++----- 3 files changed, 63 insertions(+), 63 deletions(-) diff --git a/BizHawk.Client.EmuHawk/config/GuiOptions.Designer.cs b/BizHawk.Client.EmuHawk/config/GuiOptions.Designer.cs index 1daf1356b7..4b273ae153 100644 --- a/BizHawk.Client.EmuHawk/config/GuiOptions.Designer.cs +++ b/BizHawk.Client.EmuHawk/config/GuiOptions.Designer.cs @@ -217,7 +217,7 @@ this.label2.Location = new System.Drawing.Point(26, 155); this.label2.Name = "label2"; this.label2.Size = new System.Drawing.Size(349, 13); - this.label2.TabIndex = 9; + this.label2.TabIndex = 10; this.label2.Text = "When this is set, the client will receive user input even when focus is lost"; // // AcceptBackgroundInputCheckbox @@ -238,7 +238,7 @@ this.AcceptBackgroundInputControllerOnlyCheckBox.Location = new System.Drawing.Point(156, 135); this.AcceptBackgroundInputControllerOnlyCheckBox.Name = "AcceptBackgroundInputControllerOnlyCheckBox"; this.AcceptBackgroundInputControllerOnlyCheckBox.Size = new System.Drawing.Size(117, 17); - this.AcceptBackgroundInputControllerOnlyCheckBox.TabIndex = 14; + this.AcceptBackgroundInputControllerOnlyCheckBox.TabIndex = 9; this.AcceptBackgroundInputControllerOnlyCheckBox.Text = "From controller only"; this.AcceptBackgroundInputControllerOnlyCheckBox.UseVisualStyleBackColor = true; // @@ -327,7 +327,7 @@ this.groupBox2.Margin = new System.Windows.Forms.Padding(0); this.groupBox2.Name = "groupBox2"; this.groupBox2.Size = new System.Drawing.Size(265, 60); - this.groupBox2.TabIndex = 27; + this.groupBox2.TabIndex = 5; this.groupBox2.TabStop = false; this.groupBox2.Text = "AutoSaveRAM"; // @@ -341,7 +341,7 @@ 0}); this.AutosaveSRAMtextBox.Name = "AutosaveSRAMtextBox"; this.AutosaveSRAMtextBox.Size = new System.Drawing.Size(50, 20); - this.AutosaveSRAMtextBox.TabIndex = 27; + this.AutosaveSRAMtextBox.TabIndex = 5; // // AutosaveSRAMradioButton1 // @@ -349,7 +349,7 @@ this.AutosaveSRAMradioButton1.Location = new System.Drawing.Point(48, 33); this.AutosaveSRAMradioButton1.Name = "AutosaveSRAMradioButton1"; this.AutosaveSRAMradioButton1.Size = new System.Drawing.Size(36, 17); - this.AutosaveSRAMradioButton1.TabIndex = 22; + this.AutosaveSRAMradioButton1.TabIndex = 2; this.AutosaveSRAMradioButton1.TabStop = true; this.AutosaveSRAMradioButton1.Text = "5s"; this.AutosaveSRAMradioButton1.UseVisualStyleBackColor = true; @@ -360,7 +360,7 @@ this.label8.Location = new System.Drawing.Point(202, 35); this.label8.Name = "label8"; this.label8.Size = new System.Drawing.Size(12, 13); - this.label8.TabIndex = 26; + this.label8.TabIndex = 6; this.label8.Text = "s"; // // AutosaveSRAMradioButton2 @@ -369,7 +369,7 @@ this.AutosaveSRAMradioButton2.Location = new System.Drawing.Point(90, 34); this.AutosaveSRAMradioButton2.Name = "AutosaveSRAMradioButton2"; this.AutosaveSRAMradioButton2.Size = new System.Drawing.Size(39, 17); - this.AutosaveSRAMradioButton2.TabIndex = 23; + this.AutosaveSRAMradioButton2.TabIndex = 3; this.AutosaveSRAMradioButton2.TabStop = true; this.AutosaveSRAMradioButton2.Text = "5m"; this.AutosaveSRAMradioButton2.UseVisualStyleBackColor = true; @@ -380,7 +380,7 @@ this.AutosaveSRAMradioButton3.Location = new System.Drawing.Point(131, 35); this.AutosaveSRAMradioButton3.Name = "AutosaveSRAMradioButton3"; this.AutosaveSRAMradioButton3.Size = new System.Drawing.Size(14, 13); - this.AutosaveSRAMradioButton3.TabIndex = 24; + this.AutosaveSRAMradioButton3.TabIndex = 4; this.AutosaveSRAMradioButton3.TabStop = true; this.AutosaveSRAMradioButton3.UseVisualStyleBackColor = true; this.AutosaveSRAMradioButton3.CheckedChanged += new System.EventHandler(this.AutosaveSRAMradioButton3_CheckedChanged); @@ -391,7 +391,7 @@ this.AutosaveSRAMCheckbox.Location = new System.Drawing.Point(6, 62); this.AutosaveSRAMCheckbox.Name = "AutosaveSRAMCheckbox"; this.AutosaveSRAMCheckbox.Size = new System.Drawing.Size(15, 14); - this.AutosaveSRAMCheckbox.TabIndex = 21; + this.AutosaveSRAMCheckbox.TabIndex = 4; this.AutosaveSRAMCheckbox.UseVisualStyleBackColor = true; this.AutosaveSRAMCheckbox.CheckedChanged += new System.EventHandler(this.AutosaveSRAMCheckbox_CheckedChanged); // @@ -411,7 +411,7 @@ this.label7.Location = new System.Drawing.Point(3, 1); this.label7.Name = "label7"; this.label7.Size = new System.Drawing.Size(50, 13); - this.label7.TabIndex = 2; + this.label7.TabIndex = 0; this.label7.Text = "Lua Core"; // // LuaInterfaceRadio @@ -420,7 +420,7 @@ this.LuaInterfaceRadio.Location = new System.Drawing.Point(4, 36); this.LuaInterfaceRadio.Name = "LuaInterfaceRadio"; this.LuaInterfaceRadio.Size = new System.Drawing.Size(338, 17); - this.LuaInterfaceRadio.TabIndex = 1; + this.LuaInterfaceRadio.TabIndex = 2; this.LuaInterfaceRadio.TabStop = true; this.LuaInterfaceRadio.Text = "Lua+LuaInterface - Faster but memory leaks, use at your own risk!"; this.LuaInterfaceRadio.UseVisualStyleBackColor = true; @@ -431,7 +431,7 @@ this.NLuaRadio.Location = new System.Drawing.Point(4, 17); this.NLuaRadio.Name = "NLuaRadio"; this.NLuaRadio.Size = new System.Drawing.Size(194, 17); - this.NLuaRadio.TabIndex = 0; + this.NLuaRadio.TabIndex = 1; this.NLuaRadio.TabStop = true; this.NLuaRadio.Text = "NLua+KopiLua - Reliable but slower"; this.NLuaRadio.UseVisualStyleBackColor = true; @@ -521,7 +521,7 @@ this.BackupSRamCheckbox.Location = new System.Drawing.Point(6, 39); this.BackupSRamCheckbox.Name = "BackupSRamCheckbox"; this.BackupSRamCheckbox.Size = new System.Drawing.Size(203, 17); - this.BackupSRamCheckbox.TabIndex = 9; + this.BackupSRamCheckbox.TabIndex = 3; this.BackupSRamCheckbox.Text = "Backup SaveRAM to .SaveRAM.bak"; this.BackupSRamCheckbox.UseVisualStyleBackColor = true; // @@ -550,7 +550,7 @@ this.label9.Location = new System.Drawing.Point(6, 16); this.label9.Name = "label9"; this.label9.Size = new System.Drawing.Size(225, 13); - this.label9.TabIndex = 28; + this.label9.TabIndex = 0; this.label9.Text = "Save SaveRAM to .AutoSaveRAM.SaveRAM"; // // label10 @@ -559,7 +559,7 @@ this.label10.Location = new System.Drawing.Point(9, 34); this.label10.Name = "label10"; this.label10.Size = new System.Drawing.Size(33, 13); - this.label10.TabIndex = 29; + this.label10.TabIndex = 1; this.label10.Text = "every"; // // EmuHawkOptions diff --git a/BizHawk.Client.EmuHawk/config/RewindConfig.Designer.cs b/BizHawk.Client.EmuHawk/config/RewindConfig.Designer.cs index 144227ae21..0c2c1db224 100644 --- a/BizHawk.Client.EmuHawk/config/RewindConfig.Designer.cs +++ b/BizHawk.Client.EmuHawk/config/RewindConfig.Designer.cs @@ -186,7 +186,7 @@ this.label10.Location = new System.Drawing.Point(6, 20); this.label10.Name = "label10"; this.label10.Size = new System.Drawing.Size(40, 13); - this.label10.TabIndex = 17; + this.label10.TabIndex = 0; this.label10.Text = "Enable"; // // LargeStateEnabledBox @@ -195,7 +195,7 @@ this.LargeStateEnabledBox.Location = new System.Drawing.Point(9, 87); this.LargeStateEnabledBox.Name = "LargeStateEnabledBox"; this.LargeStateEnabledBox.Size = new System.Drawing.Size(15, 14); - this.LargeStateEnabledBox.TabIndex = 16; + this.LargeStateEnabledBox.TabIndex = 11; this.LargeStateEnabledBox.UseVisualStyleBackColor = true; this.LargeStateEnabledBox.CheckStateChanged += new System.EventHandler(this.LargeStateEnabledBox_CheckStateChanged); // @@ -205,7 +205,7 @@ this.MediumStateEnabledBox.Location = new System.Drawing.Point(9, 63); this.MediumStateEnabledBox.Name = "MediumStateEnabledBox"; this.MediumStateEnabledBox.Size = new System.Drawing.Size(15, 14); - this.MediumStateEnabledBox.TabIndex = 15; + this.MediumStateEnabledBox.TabIndex = 6; this.MediumStateEnabledBox.UseVisualStyleBackColor = true; this.MediumStateEnabledBox.CheckStateChanged += new System.EventHandler(this.MediumStateEnabledBox_CheckStateChanged); // @@ -215,7 +215,7 @@ this.SmallStateEnabledBox.Location = new System.Drawing.Point(9, 39); this.SmallStateEnabledBox.Name = "SmallStateEnabledBox"; this.SmallStateEnabledBox.Size = new System.Drawing.Size(15, 14); - this.SmallStateEnabledBox.TabIndex = 14; + this.SmallStateEnabledBox.TabIndex = 1; this.SmallStateEnabledBox.UseVisualStyleBackColor = true; this.SmallStateEnabledBox.CheckStateChanged += new System.EventHandler(this.SmallStateEnabledBox_CheckStateChanged); // @@ -234,7 +234,7 @@ this.LargeLabel3.Location = new System.Drawing.Point(307, 88); this.LargeLabel3.Name = "LargeLabel3"; this.LargeLabel3.Size = new System.Drawing.Size(38, 13); - this.LargeLabel3.TabIndex = 12; + this.LargeLabel3.TabIndex = 15; this.LargeLabel3.Text = "frames"; // // LargeSavestateNumeric @@ -252,7 +252,7 @@ 0}); this.LargeSavestateNumeric.Name = "LargeSavestateNumeric"; this.LargeSavestateNumeric.Size = new System.Drawing.Size(38, 20); - this.LargeSavestateNumeric.TabIndex = 11; + this.LargeSavestateNumeric.TabIndex = 14; this.LargeSavestateNumeric.Value = new decimal(new int[] { 1, 0, @@ -266,7 +266,7 @@ this.LargeLabel1.Location = new System.Drawing.Point(40, 88); this.LargeLabel1.Name = "LargeLabel1"; this.LargeLabel1.Size = new System.Drawing.Size(179, 13); - this.LargeLabel1.TabIndex = 10; + this.LargeLabel1.TabIndex = 12; this.LargeLabel1.Text = "Large savestates (more than 100KB)"; this.LargeLabel1.Click += new System.EventHandler(this.LargeLabel1_Click); // @@ -276,7 +276,7 @@ this.MediumLabel2.Location = new System.Drawing.Point(227, 64); this.MediumLabel2.Name = "MediumLabel2"; this.MediumLabel2.Size = new System.Drawing.Size(33, 13); - this.MediumLabel2.TabIndex = 9; + this.MediumLabel2.TabIndex = 8; this.MediumLabel2.Text = "every"; // // MediumLabel3 @@ -285,7 +285,7 @@ this.MediumLabel3.Location = new System.Drawing.Point(307, 64); this.MediumLabel3.Name = "MediumLabel3"; this.MediumLabel3.Size = new System.Drawing.Size(38, 13); - this.MediumLabel3.TabIndex = 8; + this.MediumLabel3.TabIndex = 10; this.MediumLabel3.Text = "frames"; // // MediumSavestateNumeric @@ -303,7 +303,7 @@ 0}); this.MediumSavestateNumeric.Name = "MediumSavestateNumeric"; this.MediumSavestateNumeric.Size = new System.Drawing.Size(38, 20); - this.MediumSavestateNumeric.TabIndex = 7; + this.MediumSavestateNumeric.TabIndex = 9; this.MediumSavestateNumeric.Value = new decimal(new int[] { 1, 0, @@ -317,7 +317,7 @@ this.MediumLabel1.Location = new System.Drawing.Point(40, 64); this.MediumLabel1.Name = "MediumLabel1"; this.MediumLabel1.Size = new System.Drawing.Size(160, 13); - this.MediumLabel1.TabIndex = 6; + this.MediumLabel1.TabIndex = 7; this.MediumLabel1.Text = "Medium savestates (32 - 100KB)"; this.MediumLabel1.Click += new System.EventHandler(this.MediumLabel1_Click); // @@ -327,7 +327,7 @@ this.SmallLabel2.Location = new System.Drawing.Point(227, 40); this.SmallLabel2.Name = "SmallLabel2"; this.SmallLabel2.Size = new System.Drawing.Size(33, 13); - this.SmallLabel2.TabIndex = 5; + this.SmallLabel2.TabIndex = 3; this.SmallLabel2.Text = "every"; // // SmallLabel3 @@ -336,7 +336,7 @@ this.SmallLabel3.Location = new System.Drawing.Point(307, 40); this.SmallLabel3.Name = "SmallLabel3"; this.SmallLabel3.Size = new System.Drawing.Size(38, 13); - this.SmallLabel3.TabIndex = 4; + this.SmallLabel3.TabIndex = 5; this.SmallLabel3.Text = "frames"; // // SmallSavestateNumeric @@ -354,7 +354,7 @@ 0}); this.SmallSavestateNumeric.Name = "SmallSavestateNumeric"; this.SmallSavestateNumeric.Size = new System.Drawing.Size(38, 20); - this.SmallSavestateNumeric.TabIndex = 3; + this.SmallSavestateNumeric.TabIndex = 4; this.SmallSavestateNumeric.Value = new decimal(new int[] { 1, 0, @@ -399,7 +399,7 @@ this.MediumStateTrackbar.Minimum = 1; this.MediumStateTrackbar.Name = "MediumStateTrackbar"; this.MediumStateTrackbar.Size = new System.Drawing.Size(186, 45); - this.MediumStateTrackbar.TabIndex = 7; + this.MediumStateTrackbar.TabIndex = 1; this.MediumStateTrackbar.TickFrequency = 256; this.MediumStateTrackbar.Value = 1; this.MediumStateTrackbar.ValueChanged += new System.EventHandler(this.MediumStateTrackbar_ValueChanged); @@ -417,7 +417,7 @@ this.groupBox2.Location = new System.Drawing.Point(12, 387); this.groupBox2.Name = "groupBox2"; this.groupBox2.Size = new System.Drawing.Size(371, 105); - this.groupBox2.TabIndex = 8; + this.groupBox2.TabIndex = 5; this.groupBox2.TabStop = false; this.groupBox2.Text = "State Size Definition"; // @@ -436,7 +436,7 @@ 0}); this.LargeStateUpDown.Name = "LargeStateUpDown"; this.LargeStateUpDown.Size = new System.Drawing.Size(52, 20); - this.LargeStateUpDown.TabIndex = 14; + this.LargeStateUpDown.TabIndex = 6; this.LargeStateUpDown.Value = new decimal(new int[] { 256, 0, @@ -459,7 +459,7 @@ 0}); this.MediumStateUpDown.Name = "MediumStateUpDown"; this.MediumStateUpDown.Size = new System.Drawing.Size(52, 20); - this.MediumStateUpDown.TabIndex = 13; + this.MediumStateUpDown.TabIndex = 2; this.MediumStateUpDown.Value = new decimal(new int[] { 1, 0, @@ -473,7 +473,7 @@ this.LargeStateSizeLabel.Location = new System.Drawing.Point(312, 71); this.LargeStateSizeLabel.Name = "LargeStateSizeLabel"; this.LargeStateSizeLabel.Size = new System.Drawing.Size(21, 13); - this.LargeStateSizeLabel.TabIndex = 12; + this.LargeStateSizeLabel.TabIndex = 7; this.LargeStateSizeLabel.Text = "KB"; // // label5 @@ -482,7 +482,7 @@ this.label5.Location = new System.Drawing.Point(27, 63); this.label5.Name = "label5"; this.label5.Size = new System.Drawing.Size(34, 13); - this.label5.TabIndex = 11; + this.label5.TabIndex = 4; this.label5.Text = "Large"; // // LargeStateTrackbar @@ -493,7 +493,7 @@ this.LargeStateTrackbar.Minimum = 256; this.LargeStateTrackbar.Name = "LargeStateTrackbar"; this.LargeStateTrackbar.Size = new System.Drawing.Size(186, 45); - this.LargeStateTrackbar.TabIndex = 10; + this.LargeStateTrackbar.TabIndex = 5; this.LargeStateTrackbar.TickFrequency = 1024; this.LargeStateTrackbar.Value = 256; this.LargeStateTrackbar.ValueChanged += new System.EventHandler(this.LargeStateTrackbar_ValueChanged); @@ -504,7 +504,7 @@ this.MediumStateSizeLabel.Location = new System.Drawing.Point(313, 35); this.MediumStateSizeLabel.Name = "MediumStateSizeLabel"; this.MediumStateSizeLabel.Size = new System.Drawing.Size(21, 13); - this.MediumStateSizeLabel.TabIndex = 9; + this.MediumStateSizeLabel.TabIndex = 3; this.MediumStateSizeLabel.Text = "KB"; // // label2 @@ -513,7 +513,7 @@ this.label2.Location = new System.Drawing.Point(18, 31); this.label2.Name = "label2"; this.label2.Size = new System.Drawing.Size(44, 13); - this.label2.TabIndex = 8; + this.label2.TabIndex = 0; this.label2.Text = "Medium"; // // groupBox3 @@ -531,7 +531,7 @@ this.groupBox3.Location = new System.Drawing.Point(12, 214); this.groupBox3.Name = "groupBox3"; this.groupBox3.Size = new System.Drawing.Size(371, 167); - this.groupBox3.TabIndex = 9; + this.groupBox3.TabIndex = 4; this.groupBox3.TabStop = false; this.groupBox3.Text = "Rewind Options"; // @@ -683,7 +683,7 @@ this.groupBox4.Location = new System.Drawing.Point(12, 12); this.groupBox4.Name = "groupBox4"; this.groupBox4.Size = new System.Drawing.Size(371, 72); - this.groupBox4.TabIndex = 12; + this.groupBox4.TabIndex = 2; this.groupBox4.TabStop = false; this.groupBox4.Text = "Current Statistics"; // @@ -767,7 +767,7 @@ this.groupBox6.Location = new System.Drawing.Point(22, 78); this.groupBox6.Name = "groupBox6"; this.groupBox6.Size = new System.Drawing.Size(215, 48); - this.groupBox6.TabIndex = 0; + this.groupBox6.TabIndex = 4; this.groupBox6.TabStop = false; this.groupBox6.Text = "Type"; // @@ -811,7 +811,7 @@ this.btnResetCompression.Location = new System.Drawing.Point(243, 34); this.btnResetCompression.Name = "btnResetCompression"; this.btnResetCompression.Size = new System.Drawing.Size(27, 27); - this.btnResetCompression.TabIndex = 23; + this.btnResetCompression.TabIndex = 3; this.toolTip1.SetToolTip(this.btnResetCompression, "Reset to default"); this.btnResetCompression.UseVisualStyleBackColor = true; this.btnResetCompression.Click += new System.EventHandler(this.BtnResetCompression_Click); @@ -823,7 +823,7 @@ this.trackBarCompression.Maximum = 9; this.trackBarCompression.Name = "trackBarCompression"; this.trackBarCompression.Size = new System.Drawing.Size(157, 45); - this.trackBarCompression.TabIndex = 20; + this.trackBarCompression.TabIndex = 1; this.toolTip1.SetToolTip(this.trackBarCompression, "0 = None; 9 = Maximum"); this.trackBarCompression.Value = 1; this.trackBarCompression.ValueChanged += new System.EventHandler(this.TrackBarCompression_ValueChanged); @@ -838,7 +838,7 @@ 0}); this.nudCompression.Name = "nudCompression"; this.nudCompression.Size = new System.Drawing.Size(52, 20); - this.nudCompression.TabIndex = 22; + this.nudCompression.TabIndex = 2; this.nudCompression.Value = new decimal(new int[] { 1, 0, @@ -866,7 +866,7 @@ this.groupBox7.Location = new System.Drawing.Point(389, 12); this.groupBox7.Name = "groupBox7"; this.groupBox7.Size = new System.Drawing.Size(342, 408); - this.groupBox7.TabIndex = 2; + this.groupBox7.TabIndex = 6; this.groupBox7.TabStop = false; this.groupBox7.Text = "Savestate Options"; // @@ -983,7 +983,7 @@ this.label12.Location = new System.Drawing.Point(19, 21); this.label12.Name = "label12"; this.label12.Size = new System.Drawing.Size(96, 13); - this.label12.TabIndex = 24; + this.label12.TabIndex = 0; this.label12.Text = "Compression Level"; // // RewindConfig diff --git a/BizHawk.Client.EmuHawk/config/SoundConfig.Designer.cs b/BizHawk.Client.EmuHawk/config/SoundConfig.Designer.cs index 29732a87ea..6c53cb8612 100644 --- a/BizHawk.Client.EmuHawk/config/SoundConfig.Designer.cs +++ b/BizHawk.Client.EmuHawk/config/SoundConfig.Designer.cs @@ -89,7 +89,7 @@ this.cbEnableNormal.Location = new System.Drawing.Point(6, 20); this.cbEnableNormal.Name = "cbEnableNormal"; this.cbEnableNormal.Size = new System.Drawing.Size(48, 17); - this.cbEnableNormal.TabIndex = 3; + this.cbEnableNormal.TabIndex = 0; this.cbEnableNormal.Text = "Ena."; this.cbEnableNormal.UseVisualStyleBackColor = true; this.cbEnableNormal.CheckedChanged += new System.EventHandler(this.UpdateSoundDialog); @@ -116,7 +116,7 @@ this.nudRWFF.Location = new System.Drawing.Point(58, 223); this.nudRWFF.Name = "nudRWFF"; this.nudRWFF.Size = new System.Drawing.Size(45, 20); - this.nudRWFF.TabIndex = 15; + this.nudRWFF.TabIndex = 7; this.nudRWFF.Value = new decimal(new int[] { 100, 0, @@ -129,7 +129,7 @@ this.cbEnableRWFF.Location = new System.Drawing.Point(58, 20); this.cbEnableRWFF.Name = "cbEnableRWFF"; this.cbEnableRWFF.Size = new System.Drawing.Size(48, 17); - this.cbEnableRWFF.TabIndex = 14; + this.cbEnableRWFF.TabIndex = 4; this.cbEnableRWFF.Text = "Ena."; this.cbEnableRWFF.UseVisualStyleBackColor = true; // @@ -141,7 +141,7 @@ this.tbRWFF.Name = "tbRWFF"; this.tbRWFF.Orientation = System.Windows.Forms.Orientation.Vertical; this.tbRWFF.Size = new System.Drawing.Size(42, 164); - this.tbRWFF.TabIndex = 13; + this.tbRWFF.TabIndex = 6; this.tbRWFF.TickFrequency = 10; this.tbRWFF.Scroll += new System.EventHandler(this.TbRwff_Scroll); // @@ -152,7 +152,7 @@ this.label2.Location = new System.Drawing.Point(56, 42); this.label2.Name = "label2"; this.label2.Size = new System.Drawing.Size(50, 13); - this.label2.TabIndex = 12; + this.label2.TabIndex = 5; this.label2.Text = "RW && FF"; // // label1 @@ -162,7 +162,7 @@ this.label1.Location = new System.Drawing.Point(6, 42); this.label1.Name = "label1"; this.label1.Size = new System.Drawing.Size(40, 13); - this.label1.TabIndex = 11; + this.label1.TabIndex = 1; this.label1.Text = "Normal"; // // tbNormal @@ -173,7 +173,7 @@ this.tbNormal.Name = "tbNormal"; this.tbNormal.Orientation = System.Windows.Forms.Orientation.Vertical; this.tbNormal.Size = new System.Drawing.Size(42, 164); - this.tbNormal.TabIndex = 0; + this.tbNormal.TabIndex = 2; this.tbNormal.TickFrequency = 10; this.tbNormal.Scroll += new System.EventHandler(this.TrackBar1_Scroll); // @@ -182,7 +182,7 @@ this.nudNormal.Location = new System.Drawing.Point(5, 223); this.nudNormal.Name = "nudNormal"; this.nudNormal.Size = new System.Drawing.Size(45, 20); - this.nudNormal.TabIndex = 1; + this.nudNormal.TabIndex = 3; this.nudNormal.Value = new decimal(new int[] { 100, 0, @@ -199,7 +199,7 @@ this.listBoxSoundDevices.Location = new System.Drawing.Point(138, 110); this.listBoxSoundDevices.Name = "listBoxSoundDevices"; this.listBoxSoundDevices.Size = new System.Drawing.Size(254, 95); - this.listBoxSoundDevices.TabIndex = 7; + this.listBoxSoundDevices.TabIndex = 8; // // SoundDeviceLabel // @@ -207,7 +207,7 @@ this.SoundDeviceLabel.Location = new System.Drawing.Point(135, 89); this.SoundDeviceLabel.Name = "SoundDeviceLabel"; this.SoundDeviceLabel.Size = new System.Drawing.Size(78, 13); - this.SoundDeviceLabel.TabIndex = 6; + this.SoundDeviceLabel.TabIndex = 7; this.SoundDeviceLabel.Text = "Sound Device:"; // // BufferSizeLabel @@ -217,7 +217,7 @@ this.BufferSizeLabel.Location = new System.Drawing.Point(135, 210); this.BufferSizeLabel.Name = "BufferSizeLabel"; this.BufferSizeLabel.Size = new System.Drawing.Size(61, 13); - this.BufferSizeLabel.TabIndex = 8; + this.BufferSizeLabel.TabIndex = 9; this.BufferSizeLabel.Text = "Buffer Size:"; // // BufferSizeNumeric @@ -236,7 +236,7 @@ 0}); this.BufferSizeNumeric.Name = "BufferSizeNumeric"; this.BufferSizeNumeric.Size = new System.Drawing.Size(59, 20); - this.BufferSizeNumeric.TabIndex = 9; + this.BufferSizeNumeric.TabIndex = 10; this.BufferSizeNumeric.Value = new decimal(new int[] { 100, 0, @@ -250,7 +250,7 @@ this.BufferSizeUnitsLabel.Location = new System.Drawing.Point(267, 210); this.BufferSizeUnitsLabel.Name = "BufferSizeUnitsLabel"; this.BufferSizeUnitsLabel.Size = new System.Drawing.Size(63, 13); - this.BufferSizeUnitsLabel.TabIndex = 10; + this.BufferSizeUnitsLabel.TabIndex = 11; this.BufferSizeUnitsLabel.Text = "milliseconds"; // // grpOutputMethod @@ -261,7 +261,7 @@ this.grpOutputMethod.Location = new System.Drawing.Point(292, 12); this.grpOutputMethod.Name = "grpOutputMethod"; this.grpOutputMethod.Size = new System.Drawing.Size(100, 90); - this.grpOutputMethod.TabIndex = 5; + this.grpOutputMethod.TabIndex = 12; this.grpOutputMethod.TabStop = false; this.grpOutputMethod.Text = "Output Method"; // @@ -307,7 +307,7 @@ this.cbMuteFrameAdvance.Location = new System.Drawing.Point(139, 68); this.cbMuteFrameAdvance.Name = "cbMuteFrameAdvance"; this.cbMuteFrameAdvance.Size = new System.Drawing.Size(128, 17); - this.cbMuteFrameAdvance.TabIndex = 17; + this.cbMuteFrameAdvance.TabIndex = 6; this.cbMuteFrameAdvance.Text = "Mute Frame Advance"; this.cbMuteFrameAdvance.UseVisualStyleBackColor = true; // @@ -317,7 +317,7 @@ this.cbEnableMaster.Location = new System.Drawing.Point(139, 16); this.cbEnableMaster.Name = "cbEnableMaster"; this.cbEnableMaster.Size = new System.Drawing.Size(128, 17); - this.cbEnableMaster.TabIndex = 18; + this.cbEnableMaster.TabIndex = 4; this.cbEnableMaster.Text = "Sound Master Enable"; this.cbEnableMaster.UseVisualStyleBackColor = true; this.cbEnableMaster.CheckedChanged += new System.EventHandler(this.UpdateSoundDialog); @@ -328,7 +328,7 @@ this.label3.Location = new System.Drawing.Point(161, 35); this.label3.Name = "label3"; this.label3.Size = new System.Drawing.Size(126, 26); - this.label3.TabIndex = 19; + this.label3.TabIndex = 5; this.label3.Text = "Controls whether cores even generate audio."; // // SoundConfig From d3353f6acf03c0a4a0feb6b6123c905bb7e8c013 Mon Sep 17 00:00:00 2001 From: adelikat Date: Sat, 5 Oct 2019 14:40:02 -0500 Subject: [PATCH 031/166] Convert Ramwatch to use InputRoll instead of VirtualListView, rough in, still lots of todos --- .../tools/Watch/RamWatch.Designer.cs | 95 +--------- .../tools/Watch/RamWatch.cs | 175 ++++++++++-------- 2 files changed, 104 insertions(+), 166 deletions(-) diff --git a/BizHawk.Client.EmuHawk/tools/Watch/RamWatch.Designer.cs b/BizHawk.Client.EmuHawk/tools/Watch/RamWatch.Designer.cs index cafc1c6a6d..cc36c945b3 100644 --- a/BizHawk.Client.EmuHawk/tools/Watch/RamWatch.Designer.cs +++ b/BizHawk.Client.EmuHawk/tools/Watch/RamWatch.Designer.cs @@ -112,15 +112,7 @@ this.FloatingWindowMenuItem = new System.Windows.Forms.ToolStripMenuItem(); this.toolStripSeparator7 = new System.Windows.Forms.ToolStripSeparator(); this.RestoreWindowSizeMenuItem = new System.Windows.Forms.ToolStripMenuItem(); - this.WatchListView = new BizHawk.Client.EmuHawk.VirtualListView(); - this.AddressColumn = ((System.Windows.Forms.ColumnHeader)(new System.Windows.Forms.ColumnHeader())); - this.ValueColumn = ((System.Windows.Forms.ColumnHeader)(new System.Windows.Forms.ColumnHeader())); - this.PrevColumn = ((System.Windows.Forms.ColumnHeader)(new System.Windows.Forms.ColumnHeader())); - this.ChangesColumn = ((System.Windows.Forms.ColumnHeader)(new System.Windows.Forms.ColumnHeader())); - this.DiffColumn = ((System.Windows.Forms.ColumnHeader)(new System.Windows.Forms.ColumnHeader())); - this.TypeColumn = ((System.Windows.Forms.ColumnHeader)(new System.Windows.Forms.ColumnHeader())); - this.DomainColumn = ((System.Windows.Forms.ColumnHeader)(new System.Windows.Forms.ColumnHeader())); - this.NotesColumn = ((System.Windows.Forms.ColumnHeader)(new System.Windows.Forms.ColumnHeader())); + this.WatchListView = new InputRoll(); this.ListViewContextMenu.SuspendLayout(); this.statusStrip1.SuspendLayout(); this.toolStrip1.SuspendLayout(); @@ -891,90 +883,25 @@ this.WatchListView.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom) | System.Windows.Forms.AnchorStyles.Left) | System.Windows.Forms.AnchorStyles.Right))); - this.WatchListView.AutoArrange = false; - this.WatchListView.BlazingFast = false; - this.WatchListView.Columns.AddRange(new System.Windows.Forms.ColumnHeader[] { - this.AddressColumn, - this.ValueColumn, - this.PrevColumn, - this.ChangesColumn, - this.DiffColumn, - this.TypeColumn, - this.DomainColumn, - this.NotesColumn}); this.WatchListView.ContextMenuStrip = this.ListViewContextMenu; this.WatchListView.FullRowSelect = true; this.WatchListView.GridLines = true; - this.WatchListView.HideSelection = false; - this.WatchListView.ItemCount = 0; this.WatchListView.Location = new System.Drawing.Point(16, 76); this.WatchListView.Name = "WatchListView"; - this.WatchListView.SelectAllInProgress = false; - this.WatchListView.selectedItem = -1; this.WatchListView.Size = new System.Drawing.Size(332, 281); this.WatchListView.TabIndex = 2; - this.WatchListView.UseCompatibleStateImageBehavior = false; this.WatchListView.UseCustomBackground = true; - this.WatchListView.View = System.Windows.Forms.View.Details; - this.WatchListView.ColumnClick += new System.Windows.Forms.ColumnClickEventHandler(this.WatchListView_ColumnClick); + // InputRoll TODO + //this.WatchListView.ColumnClick += new System.Windows.Forms.ColumnClickEventHandler(this.WatchListView_ColumnClick); this.WatchListView.SelectedIndexChanged += new System.EventHandler(this.WatchListView_SelectedIndexChanged); - this.WatchListView.VirtualItemsSelectionRangeChanged += new System.Windows.Forms.ListViewVirtualItemsSelectionRangeChangedEventHandler(this.WatchListView_VirtualItemsSelectionRangeChanged); + + // InputRoll TODO + //this.WatchListView.VirtualItemsSelectionRangeChanged += new System.Windows.Forms.ListViewVirtualItemsSelectionRangeChangedEventHandler(this.WatchListView_VirtualItemsSelectionRangeChanged); this.WatchListView.DragDrop += new System.Windows.Forms.DragEventHandler(this.NewRamWatch_DragDrop); this.WatchListView.DragEnter += new System.Windows.Forms.DragEventHandler(this.DragEnterWrapper); this.WatchListView.KeyDown += new System.Windows.Forms.KeyEventHandler(this.WatchListView_KeyDown); this.WatchListView.MouseDoubleClick += new System.Windows.Forms.MouseEventHandler(this.WatchListView_MouseDoubleClick); // - // AddressColumn - // - this.AddressColumn.Name = "AddressColumn"; - this.AddressColumn.Text = "Address"; - // - // ValueColumn - // - this.ValueColumn.Name = "ValueColumn"; - this.ValueColumn.Text = "Value"; - this.ValueColumn.TextAlign = System.Windows.Forms.HorizontalAlignment.Center; - this.ValueColumn.Width = 59; - // - // PrevColumn - // - this.PrevColumn.Name = "PrevColumn"; - this.PrevColumn.Text = "Prev"; - this.PrevColumn.TextAlign = System.Windows.Forms.HorizontalAlignment.Center; - this.PrevColumn.Width = 59; - // - // ChangesColumn - // - this.ChangesColumn.Name = "ChangesColumn"; - this.ChangesColumn.Text = "Changes"; - this.ChangesColumn.TextAlign = System.Windows.Forms.HorizontalAlignment.Center; - this.ChangesColumn.Width = 54; - // - // DiffColumn - // - this.DiffColumn.Name = "DiffColumn"; - this.DiffColumn.Text = "Diff"; - this.DiffColumn.TextAlign = System.Windows.Forms.HorizontalAlignment.Center; - this.DiffColumn.Width = 59; - // - // TypeColumn - // - this.TypeColumn.Name = "TypeColumn"; - this.TypeColumn.Text = "Type"; - this.TypeColumn.Width = 55; - // - // DomainColumn - // - this.DomainColumn.Name = "DomainColumn"; - this.DomainColumn.Text = "Domain"; - this.DomainColumn.Width = 55; - // - // NotesColumn - // - this.NotesColumn.Name = "NotesColumn"; - this.NotesColumn.Text = "Notes"; - this.NotesColumn.Width = 128; - // // RamWatch // this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); @@ -1009,15 +936,7 @@ #endregion - private VirtualListView WatchListView; - private System.Windows.Forms.ColumnHeader AddressColumn; - private System.Windows.Forms.ColumnHeader ValueColumn; - private System.Windows.Forms.ColumnHeader PrevColumn; - private System.Windows.Forms.ColumnHeader ChangesColumn; - private System.Windows.Forms.ColumnHeader DiffColumn; - private System.Windows.Forms.ColumnHeader TypeColumn; - private System.Windows.Forms.ColumnHeader DomainColumn; - private System.Windows.Forms.ColumnHeader NotesColumn; + private InputRoll WatchListView; private MenuStripEx RamWatchMenu; private System.Windows.Forms.ToolStripMenuItem FileSubMenu; private System.Windows.Forms.ToolStripMenuItem NewListMenuItem; diff --git a/BizHawk.Client.EmuHawk/tools/Watch/RamWatch.cs b/BizHawk.Client.EmuHawk/tools/Watch/RamWatch.cs index 969a9f25cb..32c70400d4 100644 --- a/BizHawk.Client.EmuHawk/tools/Watch/RamWatch.cs +++ b/BizHawk.Client.EmuHawk/tools/Watch/RamWatch.cs @@ -42,7 +42,7 @@ namespace BizHawk.Client.EmuHawk WatchListView.QueryItemText += WatchListView_QueryItemText; WatchListView.QueryItemBkColor += WatchListView_QueryItemBkColor; - WatchListView.VirtualMode = true; + Closing += (o, e) => { if (AskSaveChanges()) @@ -57,6 +57,31 @@ namespace BizHawk.Client.EmuHawk _sortedColumn = ""; _sortReverse = false; + + AddColumn(WatchList.ADDRESS, "Address", 100, InputRoll.RollColumn.InputType.Text); + AddColumn(WatchList.VALUE, "Value", 100, InputRoll.RollColumn.InputType.Text); + AddColumn(WatchList.PREV, "Prev", 59, InputRoll.RollColumn.InputType.Text); + AddColumn(WatchList.CHANGES, "Changes", 54, InputRoll.RollColumn.InputType.Text); + AddColumn(WatchList.DIFF, "Diff", 59, InputRoll.RollColumn.InputType.Text); + AddColumn(WatchList.TYPE, "Type", 55, InputRoll.RollColumn.InputType.Text); + AddColumn(WatchList.DOMAIN, "Domain", 55, InputRoll.RollColumn.InputType.Text); + AddColumn(WatchList.NOTES, "Notes", 128, InputRoll.RollColumn.InputType.Text); + } + + public void AddColumn(string columnName, string columnText, int columnWidth, InputRoll.RollColumn.InputType columnType = InputRoll.RollColumn.InputType.Boolean) + { + if (WatchListView.AllColumns[columnName] == null) + { + var column = new InputRoll.RollColumn + { + Name = columnName, + Text = columnText, + Width = columnWidth, + Type = columnType + }; + + WatchListView.AllColumns.Add(column); + } } [ConfigPersist] @@ -82,7 +107,7 @@ namespace BizHawk.Client.EmuHawk public ColumnList Columns { get; set; } } - private IEnumerable SelectedIndices => WatchListView.SelectedIndices.Cast(); + private IEnumerable SelectedIndices => WatchListView.SelectedRows; private IEnumerable SelectedItems { @@ -117,7 +142,7 @@ namespace BizHawk.Client.EmuHawk public void AddWatch(Watch watch) { _watches.Add(watch); - WatchListView.ItemCount = _watches.Count; + WatchListView.RowCount = _watches.Count; UpdateValues(); UpdateWatchCount(); Changes(); @@ -174,7 +199,7 @@ namespace BizHawk.Client.EmuHawk else { Global.Config.RecentWatches.Add(path); - WatchListView.ItemCount = _watches.Count; + WatchListView.RowCount = _watches.Count; UpdateWatchCount(); UpdateStatusBar(); _watches.Changes = false; @@ -195,7 +220,7 @@ namespace BizHawk.Client.EmuHawk if (result) { _watches.Load(file.FullName, append); - WatchListView.ItemCount = _watches.Count; + WatchListView.RowCount = _watches.Count; UpdateWatchCount(); Global.Config.RecentWatches.Add(_watches.CurrentFileName); UpdateStatusBar(); @@ -271,10 +296,8 @@ namespace BizHawk.Client.EmuHawk return; } - WatchListView.BlazingFast = true; WatchListView.UseCustomBackground = NeedsBackground; WatchListView.Invalidate(); - WatchListView.BlazingFast = false; } } @@ -387,7 +410,7 @@ namespace BizHawk.Client.EmuHawk private void FullyUpdateWatchList() { - WatchListView.ItemCount = _watches.Count; + WatchListView.RowCount = _watches.Count; UpdateWatchCount(); UpdateStatusBar(); UpdateValues(); @@ -422,7 +445,7 @@ namespace BizHawk.Client.EmuHawk if (duplicate) { _watches.AddRange(we.Watches); - WatchListView.ItemCount = _watches.Count; + WatchListView.RowCount = _watches.Count; UpdateWatchCount(); } else @@ -514,7 +537,8 @@ namespace BizHawk.Client.EmuHawk Size = Settings.WindowSize; } - LoadColumnInfo(WatchListView, Settings.Columns); + // InputRoll TODO + //LoadColumnInfo(WatchListView, Settings.Columns); } private void NewWatchList(bool suppressAsk) @@ -528,7 +552,7 @@ namespace BizHawk.Client.EmuHawk if (result || suppressAsk) { _watches.Clear(); - WatchListView.ItemCount = _watches.Count; + WatchListView.RowCount = _watches.Count; UpdateWatchCount(); UpdateStatusBar(); _sortReverse = false; @@ -543,17 +567,18 @@ namespace BizHawk.Client.EmuHawk private void OrderColumn(int index) { - var column = WatchListView.Columns[index]; - if (column.Name != _sortedColumn) - { - _sortReverse = false; - } + // InputRoll TODO + ////var column = WatchListView.Columns[index]; + ////if (column.Name != _sortedColumn) + ////{ + //// _sortReverse = false; + ////} - _watches.OrderWatches(column.Name, _sortReverse); + ////_watches.OrderWatches(column.Name, _sortReverse); - _sortedColumn = column.Name; - _sortReverse ^= true; - WatchListView.Refresh(); + ////_sortedColumn = column.Name; + ////_sortReverse ^= true; + ////WatchListView.Refresh(); } private void SaveAs() @@ -568,7 +593,10 @@ namespace BizHawk.Client.EmuHawk private void SaveConfigSettings() { - SaveColumnInfo(WatchListView, Settings.Columns); + // Inputroll TODO + ////WatchListView.UserSettingsSerialized() + + ////SaveColumnInfo(WatchListView, Settings.Columns); if (WindowState == FormWindowState.Normal) { @@ -610,42 +638,38 @@ namespace BizHawk.Client.EmuHawk WatchCountLabel.Text = _watches.WatchCount + (_watches.WatchCount == 1 ? " watch" : " watches"); } - private void WatchListView_QueryItemBkColor(int index, int column, ref Color color) + private void WatchListView_QueryItemBkColor(int index, InputRoll.RollColumn column, ref Color color) { if (index >= _watches.Count) { return; } - if (column == 0) - { - if (_watches[index].IsSeparator) - { - color = BackColor; - } - else if (_watches[index].Address >= _watches[index].Domain.Size) - { - color = Color.PeachPuff; - } - else if (Global.CheatList.IsActive(_watches[index].Domain, _watches[index].Address)) - { - color = Color.LightCyan; - } - } - } - - private void WatchListView_QueryItemText(int index, int column, out string text) - { - text = ""; - - if (index >= _watches.Count) - { - return; - } - if (_watches[index].IsSeparator) { - if (WatchListView.Columns[column].Name == WatchList.ADDRESS) + color = BackColor; + } + else if (_watches[index].Address >= _watches[index].Domain.Size) + { + color = Color.PeachPuff; + } + else if (Global.CheatList.IsActive(_watches[index].Domain, _watches[index].Address)) + { + color = Color.LightCyan; + } + } + + private void WatchListView_QueryItemText(int index, InputRoll.RollColumn column, out string text, ref int offsetX, ref int offsetY) + { + text = ""; + if (index >= _watches.Count) + { + return; + } + + if (_watches[index].IsSeparator) + { + if (column.Name == WatchList.ADDRESS) { text = _watches[index].Notes; } @@ -653,9 +677,7 @@ namespace BizHawk.Client.EmuHawk return; } - var columnName = WatchListView.Columns[column].Name; - - switch (columnName) + switch (column.Name) { case WatchList.ADDRESS: text = _watches[index].AddressString; @@ -796,7 +818,7 @@ namespace BizHawk.Client.EmuHawk _watches.Add(we.Watches[0]); Changes(); UpdateWatchCount(); - WatchListView.ItemCount = _watches.Count; + WatchListView.RowCount = _watches.Count; UpdateValues(); } } @@ -816,7 +838,7 @@ namespace BizHawk.Client.EmuHawk _watches.Remove(item); } - WatchListView.ItemCount = _watches.Count; + WatchListView.RowCount = _watches.Count; UpdateValues(); UpdateWatchCount(); } @@ -870,7 +892,7 @@ namespace BizHawk.Client.EmuHawk _watches.Add(SeparatorWatch.Instance); } - WatchListView.ItemCount = _watches.Count; + WatchListView.RowCount = _watches.Count; Changes(); UpdateWatchCount(); } @@ -900,13 +922,13 @@ namespace BizHawk.Client.EmuHawk var indices = indexes.Select(t => t - 1); - WatchListView.SelectedIndices.Clear(); + WatchListView.DeselectAll(); foreach (var t in indices) { - WatchListView.SelectItem(t, true); + WatchListView.SelectRow(t, true); } - WatchListView.ItemCount = _watches.Count; + WatchListView.RowCount = _watches.Count; } private void MoveDownMenuItem_Click(object sender, EventArgs e) @@ -926,14 +948,14 @@ namespace BizHawk.Client.EmuHawk var newIndices = indices.Select(t => t + 1); - WatchListView.SelectedIndices.Clear(); + WatchListView.DeselectAll(); foreach (var t in newIndices) { - WatchListView.SelectItem(t, true); + WatchListView.SelectRow(t, true); } Changes(); - WatchListView.ItemCount = _watches.Count; + WatchListView.RowCount = _watches.Count; } private void MoveTopMenuItem_Click(object sender, EventArgs e) @@ -954,13 +976,13 @@ namespace BizHawk.Client.EmuHawk Changes(); - WatchListView.SelectedIndices.Clear(); + WatchListView.DeselectAll(); foreach (var t in indexes) { - WatchListView.SelectItem(t, true); + WatchListView.SelectRow(t, true); } - WatchListView.ItemCount = _watches.Count; + WatchListView.RowCount = _watches.Count; } private void MoveBottomMenuItem_Click(object sender, EventArgs e) @@ -984,14 +1006,14 @@ namespace BizHawk.Client.EmuHawk newInd.Add(x); } - WatchListView.SelectedIndices.Clear(); + WatchListView.DeselectAll(); foreach (var t in newInd) { - WatchListView.SelectItem(t, true); + WatchListView.SelectRow(t, true); } Changes(); - WatchListView.ItemCount = _watches.Count; + WatchListView.RowCount = _watches.Count; } private void SelectAllMenuItem_Click(object sender, EventArgs e) @@ -1083,7 +1105,8 @@ namespace BizHawk.Client.EmuHawk Global.Config.DisplayRamWatch = false; RefreshFloatingWindowControl(Settings.FloatingWindow); - LoadColumnInfo(WatchListView, Settings.Columns); + // InputRoll TODO + //LoadColumnInfo(WatchListView, Settings.Columns); } #endregion @@ -1106,8 +1129,9 @@ namespace BizHawk.Client.EmuHawk private void ColumnToggleCallback() { - SaveColumnInfo(WatchListView, Settings.Columns); - LoadColumnInfo(WatchListView, Settings.Columns); + //Input Roll TODO + //SaveColumnInfo(WatchListView, Settings.Columns); + //LoadColumnInfo(WatchListView, Settings.Columns); } private void NewRamWatch_Activated(object sender, EventArgs e) @@ -1122,7 +1146,7 @@ namespace BizHawk.Client.EmuHawk { _watches.Load(filePaths[0], append: false); Global.Config.RecentWatches.Add(_watches.CurrentFileName); - WatchListView.ItemCount = _watches.Count; + WatchListView.RowCount = _watches.Count; } } @@ -1133,7 +1157,7 @@ namespace BizHawk.Client.EmuHawk private void ListViewContextMenu_Opening(object sender, CancelEventArgs e) { - var indexes = WatchListView.SelectedIndices; + var indexes = WatchListView.SelectedRows.ToList(); EditContextMenuItem.Visible = RemoveContextMenuItem.Visible = @@ -1259,11 +1283,6 @@ namespace BizHawk.Client.EmuHawk private void WatchListView_SelectedIndexChanged(object sender, EventArgs e) { - if (WatchListView.SelectAllInProgress) - { - return; - } - PokeAddressToolBarItem.Enabled = FreezeAddressToolBarItem.Enabled = SelectedIndices.Any() && @@ -1291,7 +1310,7 @@ namespace BizHawk.Client.EmuHawk _watches.Remove(item); } - WatchListView.ItemCount = _watches.Count; + WatchListView.RowCount = _watches.Count; UpdateValues(); UpdateWatchCount(); UpdateStatusBar(); From 5b83b9e019a12ff880c2c7b291f0b14cf1d97ce5 Mon Sep 17 00:00:00 2001 From: adelikat Date: Mon, 14 Oct 2019 19:11:07 -0500 Subject: [PATCH 032/166] Ram Watch - Wire up column hiding/showing --- .../Extensions/ControlExtensions.cs | 35 +++++++++++++++++++ .../tools/Watch/RamWatch.cs | 4 +-- 2 files changed, 37 insertions(+), 2 deletions(-) diff --git a/BizHawk.Client.EmuHawk/Extensions/ControlExtensions.cs b/BizHawk.Client.EmuHawk/Extensions/ControlExtensions.cs index 756dcfca33..71d192046c 100644 --- a/BizHawk.Client.EmuHawk/Extensions/ControlExtensions.cs +++ b/BizHawk.Client.EmuHawk/Extensions/ControlExtensions.cs @@ -80,6 +80,41 @@ namespace BizHawk.Client.EmuHawk.WinFormExtensions } } + public static ToolStripMenuItem ToColumnsMenu(this InputRoll inputRoll) + { + var menu = new ToolStripMenuItem + { + Name = "GeneratedColumnsSubMenu", + Text = "Columns" + }; + + var columns = inputRoll.AllColumns; + + foreach (var column in columns) + { + var menuItem = new ToolStripMenuItem + { + Text = $"{column.Text} ({column.Name})", + Checked = column.Visible, + CheckOnClick = true, + Tag = column.Name + }; + + menuItem.CheckedChanged += (o, ev) => + { + var sender = (ToolStripMenuItem)o; + columns.Find(c => c.Name == (string)sender.Tag).Visible = sender.Checked; + columns.ColumnsChanged(); + + inputRoll.Refresh(); + }; + + menu.DropDownItems.Add(menuItem); + } + + return menu; + } + public static ToolStripMenuItem GenerateColumnsMenu(this ToolDialogSettings.ColumnList list, Action changeCallback) { var menu = new ToolStripMenuItem diff --git a/BizHawk.Client.EmuHawk/tools/Watch/RamWatch.cs b/BizHawk.Client.EmuHawk/tools/Watch/RamWatch.cs index 32c70400d4..f0ce11fdc0 100644 --- a/BizHawk.Client.EmuHawk/tools/Watch/RamWatch.cs +++ b/BizHawk.Client.EmuHawk/tools/Watch/RamWatch.cs @@ -1100,7 +1100,7 @@ namespace BizHawk.Client.EmuHawk .OfType() .First(x => x.Name == "GeneratedColumnsSubMenu")); - RamWatchMenu.Items.Add(Settings.Columns.GenerateColumnsMenu(ColumnToggleCallback)); + RamWatchMenu.Items.Add(WatchListView.ToColumnsMenu()); Global.Config.DisplayRamWatch = false; @@ -1118,7 +1118,7 @@ namespace BizHawk.Client.EmuHawk TopMost = Settings.TopMost; _watches = new WatchList(MemoryDomains, Emu.SystemId); LoadConfigSettings(); - RamWatchMenu.Items.Add(Settings.Columns.GenerateColumnsMenu(ColumnToggleCallback)); + RamWatchMenu.Items.Add(WatchListView.ToColumnsMenu()); UpdateStatusBar(); PokeAddressToolBarItem.Enabled = From cfab768846c6a69cb2175d1dfc3aa5c23267d38d Mon Sep 17 00:00:00 2001 From: adelikat Date: Mon, 14 Oct 2019 19:56:35 -0500 Subject: [PATCH 033/166] Ram Watch - saving/loading column settings --- .../Extensions/ControlExtensions.cs | 4 +- .../tools/Watch/RamWatch.cs | 63 ++++++++++--------- 2 files changed, 34 insertions(+), 33 deletions(-) diff --git a/BizHawk.Client.EmuHawk/Extensions/ControlExtensions.cs b/BizHawk.Client.EmuHawk/Extensions/ControlExtensions.cs index 71d192046c..6e21c8a88d 100644 --- a/BizHawk.Client.EmuHawk/Extensions/ControlExtensions.cs +++ b/BizHawk.Client.EmuHawk/Extensions/ControlExtensions.cs @@ -80,7 +80,7 @@ namespace BizHawk.Client.EmuHawk.WinFormExtensions } } - public static ToolStripMenuItem ToColumnsMenu(this InputRoll inputRoll) + public static ToolStripMenuItem ToColumnsMenu(this InputRoll inputRoll, Action changeCallback) { var menu = new ToolStripMenuItem { @@ -105,7 +105,7 @@ namespace BizHawk.Client.EmuHawk.WinFormExtensions var sender = (ToolStripMenuItem)o; columns.Find(c => c.Name == (string)sender.Tag).Visible = sender.Checked; columns.ColumnsChanged(); - + changeCallback(); inputRoll.Refresh(); }; diff --git a/BizHawk.Client.EmuHawk/tools/Watch/RamWatch.cs b/BizHawk.Client.EmuHawk/tools/Watch/RamWatch.cs index f0ce11fdc0..0778645501 100644 --- a/BizHawk.Client.EmuHawk/tools/Watch/RamWatch.cs +++ b/BizHawk.Client.EmuHawk/tools/Watch/RamWatch.cs @@ -58,14 +58,19 @@ namespace BizHawk.Client.EmuHawk _sortedColumn = ""; _sortReverse = false; - AddColumn(WatchList.ADDRESS, "Address", 100, InputRoll.RollColumn.InputType.Text); - AddColumn(WatchList.VALUE, "Value", 100, InputRoll.RollColumn.InputType.Text); - AddColumn(WatchList.PREV, "Prev", 59, InputRoll.RollColumn.InputType.Text); - AddColumn(WatchList.CHANGES, "Changes", 54, InputRoll.RollColumn.InputType.Text); - AddColumn(WatchList.DIFF, "Diff", 59, InputRoll.RollColumn.InputType.Text); - AddColumn(WatchList.TYPE, "Type", 55, InputRoll.RollColumn.InputType.Text); - AddColumn(WatchList.DOMAIN, "Domain", 55, InputRoll.RollColumn.InputType.Text); - AddColumn(WatchList.NOTES, "Notes", 128, InputRoll.RollColumn.InputType.Text); + + SetColumns(); + } + + private void SetColumns() + { + foreach (var column in Settings.Columns) + { + if (WatchListView.AllColumns[column.Name] == null) + { + WatchListView.AllColumns.Add(column); + } + } } public void AddColumn(string columnName, string columnText, int columnWidth, InputRoll.RollColumn.InputType columnType = InputRoll.RollColumn.InputType.Boolean) @@ -91,20 +96,20 @@ namespace BizHawk.Client.EmuHawk { public RamWatchSettings() { - Columns = new ColumnList + Columns = new List { - new Column { Name = WatchList.ADDRESS, Visible = true, Index = 0, Width = 60 }, - new Column { Name = WatchList.VALUE, Visible = true, Index = 1, Width = 59 }, - new Column { Name = WatchList.PREV, Visible = false, Index = 2, Width = 59 }, - new Column { Name = WatchList.CHANGES, Visible = true, Index = 3, Width = 55 }, - new Column { Name = WatchList.DIFF, Visible = false, Index = 4, Width = 59 }, - new Column { Name = WatchList.TYPE, Visible = false, Index = 5, Width = 55 }, - new Column { Name = WatchList.DOMAIN, Visible = true, Index = 6, Width = 55 }, - new Column { Name = WatchList.NOTES, Visible = true, Index = 7, Width = 128 }, + new InputRoll.RollColumn { Text = "Address", Name = WatchList.ADDRESS, Visible = true, Width = 60 }, + new InputRoll.RollColumn { Text = "Value", Name = WatchList.VALUE, Visible = true, Width = 59 }, + new InputRoll.RollColumn { Text = "Prev", Name = WatchList.PREV, Visible = false, Width = 59 }, + new InputRoll.RollColumn { Text = "Changes", Name = WatchList.CHANGES, Visible = true, Width = 55 }, + new InputRoll.RollColumn { Text = "Diff", Name = WatchList.DIFF, Visible = false, Width = 59 }, + new InputRoll.RollColumn { Text = "Type", Name = WatchList.TYPE, Visible = false, Width = 55 }, + new InputRoll.RollColumn { Text = "Domain", Name = WatchList.DOMAIN, Visible = true, Width = 55 }, + new InputRoll.RollColumn { Text = "Notes", Name = WatchList.NOTES, Visible = true, Width = 128 }, }; } - public ColumnList Columns { get; set; } + public List Columns { get; set; } } private IEnumerable SelectedIndices => WatchListView.SelectedRows; @@ -537,8 +542,8 @@ namespace BizHawk.Client.EmuHawk Size = Settings.WindowSize; } - // InputRoll TODO - //LoadColumnInfo(WatchListView, Settings.Columns); + WatchListView.AllColumns.Clear(); + SetColumns(); } private void NewWatchList(bool suppressAsk) @@ -593,10 +598,7 @@ namespace BizHawk.Client.EmuHawk private void SaveConfigSettings() { - // Inputroll TODO - ////WatchListView.UserSettingsSerialized() - - ////SaveColumnInfo(WatchListView, Settings.Columns); + Settings.Columns = WatchListView.AllColumns; if (WindowState == FormWindowState.Normal) { @@ -1100,13 +1102,14 @@ namespace BizHawk.Client.EmuHawk .OfType() .First(x => x.Name == "GeneratedColumnsSubMenu")); - RamWatchMenu.Items.Add(WatchListView.ToColumnsMenu()); + RamWatchMenu.Items.Add(WatchListView.ToColumnsMenu(ColumnToggleCallback)); Global.Config.DisplayRamWatch = false; RefreshFloatingWindowControl(Settings.FloatingWindow); - // InputRoll TODO - //LoadColumnInfo(WatchListView, Settings.Columns); + + WatchListView.AllColumns.Clear(); + SetColumns(); } #endregion @@ -1118,7 +1121,7 @@ namespace BizHawk.Client.EmuHawk TopMost = Settings.TopMost; _watches = new WatchList(MemoryDomains, Emu.SystemId); LoadConfigSettings(); - RamWatchMenu.Items.Add(WatchListView.ToColumnsMenu()); + RamWatchMenu.Items.Add(WatchListView.ToColumnsMenu(ColumnToggleCallback)); UpdateStatusBar(); PokeAddressToolBarItem.Enabled = @@ -1129,9 +1132,7 @@ namespace BizHawk.Client.EmuHawk private void ColumnToggleCallback() { - //Input Roll TODO - //SaveColumnInfo(WatchListView, Settings.Columns); - //LoadColumnInfo(WatchListView, Settings.Columns); + Settings.Columns = WatchListView.AllColumns; } private void NewRamWatch_Activated(object sender, EventArgs e) From 9c574c2124f880fc3bdbfc0341ca2a07147547da Mon Sep 17 00:00:00 2001 From: adelikat Date: Mon, 14 Oct 2019 20:06:02 -0500 Subject: [PATCH 034/166] Ram Watch - cleanup --- .../tools/Watch/RamWatch.cs | 36 ++++++------------- 1 file changed, 10 insertions(+), 26 deletions(-) diff --git a/BizHawk.Client.EmuHawk/tools/Watch/RamWatch.cs b/BizHawk.Client.EmuHawk/tools/Watch/RamWatch.cs index 0778645501..efd4697047 100644 --- a/BizHawk.Client.EmuHawk/tools/Watch/RamWatch.cs +++ b/BizHawk.Client.EmuHawk/tools/Watch/RamWatch.cs @@ -73,22 +73,6 @@ namespace BizHawk.Client.EmuHawk } } - public void AddColumn(string columnName, string columnText, int columnWidth, InputRoll.RollColumn.InputType columnType = InputRoll.RollColumn.InputType.Boolean) - { - if (WatchListView.AllColumns[columnName] == null) - { - var column = new InputRoll.RollColumn - { - Name = columnName, - Text = columnText, - Width = columnWidth, - Type = columnType - }; - - WatchListView.AllColumns.Add(column); - } - } - [ConfigPersist] public RamWatchSettings Settings { get; set; } @@ -572,18 +556,17 @@ namespace BizHawk.Client.EmuHawk private void OrderColumn(int index) { - // InputRoll TODO - ////var column = WatchListView.Columns[index]; - ////if (column.Name != _sortedColumn) - ////{ - //// _sortReverse = false; - ////} + var column = WatchListView.AllColumns[index]; + if (column.Name != _sortedColumn) + { + _sortReverse = false; + } - ////_watches.OrderWatches(column.Name, _sortReverse); + _watches.OrderWatches(column.Name, _sortReverse); - ////_sortedColumn = column.Name; - ////_sortReverse ^= true; - ////WatchListView.Refresh(); + _sortedColumn = column.Name; + _sortReverse ^= true; + WatchListView.Refresh(); } private void SaveAs() @@ -1295,6 +1278,7 @@ namespace BizHawk.Client.EmuHawk EditWatch(); } + // InputRoll TODO private void WatchListView_ColumnClick(object sender, ColumnClickEventArgs e) { OrderColumn(e.Column); From 3e1f783c271eb8a1b2a9eda16c8a399b13b4cb29 Mon Sep 17 00:00:00 2001 From: adelikat Date: Mon, 14 Oct 2019 20:22:06 -0500 Subject: [PATCH 035/166] Ram watch - fix multi-select --- .../tools/Watch/RamWatch.Designer.cs | 2 ++ BizHawk.Client.EmuHawk/tools/Watch/RamWatch.cs | 17 ++++++++--------- 2 files changed, 10 insertions(+), 9 deletions(-) diff --git a/BizHawk.Client.EmuHawk/tools/Watch/RamWatch.Designer.cs b/BizHawk.Client.EmuHawk/tools/Watch/RamWatch.Designer.cs index cc36c945b3..58c94824bd 100644 --- a/BizHawk.Client.EmuHawk/tools/Watch/RamWatch.Designer.cs +++ b/BizHawk.Client.EmuHawk/tools/Watch/RamWatch.Designer.cs @@ -878,6 +878,8 @@ // // WatchListView // + this.WatchListView.FullRowSelect = true; + this.WatchListView.MultiSelect = true; this.WatchListView.AllowColumnReorder = true; this.WatchListView.AllowDrop = true; this.WatchListView.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom) diff --git a/BizHawk.Client.EmuHawk/tools/Watch/RamWatch.cs b/BizHawk.Client.EmuHawk/tools/Watch/RamWatch.cs index efd4697047..2f2b961cd1 100644 --- a/BizHawk.Client.EmuHawk/tools/Watch/RamWatch.cs +++ b/BizHawk.Client.EmuHawk/tools/Watch/RamWatch.cs @@ -42,7 +42,6 @@ namespace BizHawk.Client.EmuHawk WatchListView.QueryItemText += WatchListView_QueryItemText; WatchListView.QueryItemBkColor += WatchListView_QueryItemBkColor; - Closing += (o, e) => { if (AskSaveChanges()) @@ -82,14 +81,14 @@ namespace BizHawk.Client.EmuHawk { Columns = new List { - new InputRoll.RollColumn { Text = "Address", Name = WatchList.ADDRESS, Visible = true, Width = 60 }, - new InputRoll.RollColumn { Text = "Value", Name = WatchList.VALUE, Visible = true, Width = 59 }, - new InputRoll.RollColumn { Text = "Prev", Name = WatchList.PREV, Visible = false, Width = 59 }, - new InputRoll.RollColumn { Text = "Changes", Name = WatchList.CHANGES, Visible = true, Width = 55 }, - new InputRoll.RollColumn { Text = "Diff", Name = WatchList.DIFF, Visible = false, Width = 59 }, - new InputRoll.RollColumn { Text = "Type", Name = WatchList.TYPE, Visible = false, Width = 55 }, - new InputRoll.RollColumn { Text = "Domain", Name = WatchList.DOMAIN, Visible = true, Width = 55 }, - new InputRoll.RollColumn { Text = "Notes", Name = WatchList.NOTES, Visible = true, Width = 128 }, + new InputRoll.RollColumn { Text = "Address", Name = WatchList.ADDRESS, Visible = true, Width = 60, Type = InputRoll.RollColumn.InputType.Text }, + new InputRoll.RollColumn { Text = "Value", Name = WatchList.VALUE, Visible = true, Width = 59, Type = InputRoll.RollColumn.InputType.Text }, + new InputRoll.RollColumn { Text = "Prev", Name = WatchList.PREV, Visible = false, Width = 59, Type = InputRoll.RollColumn.InputType.Text }, + new InputRoll.RollColumn { Text = "Changes", Name = WatchList.CHANGES, Visible = true, Width = 55, Type = InputRoll.RollColumn.InputType.Text }, + new InputRoll.RollColumn { Text = "Diff", Name = WatchList.DIFF, Visible = false, Width = 59, Type = InputRoll.RollColumn.InputType.Text }, + new InputRoll.RollColumn { Text = "Type", Name = WatchList.TYPE, Visible = false, Width = 55, Type = InputRoll.RollColumn.InputType.Text }, + new InputRoll.RollColumn { Text = "Domain", Name = WatchList.DOMAIN, Visible = true, Width = 55, Type = InputRoll.RollColumn.InputType.Text }, + new InputRoll.RollColumn { Text = "Notes", Name = WatchList.NOTES, Visible = true, Width = 128, Type = InputRoll.RollColumn.InputType.Text } }; } From f875bf656d31351bfb685ef737942e6f49a6f49c Mon Sep 17 00:00:00 2001 From: adelikat Date: Mon, 14 Oct 2019 20:28:31 -0500 Subject: [PATCH 036/166] Ram Watch - more configuration settings --- BizHawk.Client.EmuHawk/tools/Watch/RamWatch.Designer.cs | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/BizHawk.Client.EmuHawk/tools/Watch/RamWatch.Designer.cs b/BizHawk.Client.EmuHawk/tools/Watch/RamWatch.Designer.cs index 58c94824bd..332ec7d199 100644 --- a/BizHawk.Client.EmuHawk/tools/Watch/RamWatch.Designer.cs +++ b/BizHawk.Client.EmuHawk/tools/Watch/RamWatch.Designer.cs @@ -878,8 +878,10 @@ // // WatchListView // - this.WatchListView.FullRowSelect = true; - this.WatchListView.MultiSelect = true; + this.WatchListView.AllowColumnResize = true; + this.WatchListView.AllowColumnReorder = true; + this.WatchListView.FullRowSelect = true; + this.WatchListView.MultiSelect = true; this.WatchListView.AllowColumnReorder = true; this.WatchListView.AllowDrop = true; this.WatchListView.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom) From 488b8457b0b3722ea67305514bf88a66b65cc1ba Mon Sep 17 00:00:00 2001 From: adelikat Date: Mon, 14 Oct 2019 20:31:25 -0500 Subject: [PATCH 037/166] Ram watch - this hack is no longer needed, inputroll doesn't have this issue --- BizHawk.Client.EmuHawk/tools/Watch/RamWatch.Designer.cs | 3 --- BizHawk.Client.EmuHawk/tools/Watch/RamWatch.cs | 8 -------- 2 files changed, 11 deletions(-) diff --git a/BizHawk.Client.EmuHawk/tools/Watch/RamWatch.Designer.cs b/BizHawk.Client.EmuHawk/tools/Watch/RamWatch.Designer.cs index 332ec7d199..da195243d7 100644 --- a/BizHawk.Client.EmuHawk/tools/Watch/RamWatch.Designer.cs +++ b/BizHawk.Client.EmuHawk/tools/Watch/RamWatch.Designer.cs @@ -898,9 +898,6 @@ // InputRoll TODO //this.WatchListView.ColumnClick += new System.Windows.Forms.ColumnClickEventHandler(this.WatchListView_ColumnClick); this.WatchListView.SelectedIndexChanged += new System.EventHandler(this.WatchListView_SelectedIndexChanged); - - // InputRoll TODO - //this.WatchListView.VirtualItemsSelectionRangeChanged += new System.Windows.Forms.ListViewVirtualItemsSelectionRangeChangedEventHandler(this.WatchListView_VirtualItemsSelectionRangeChanged); this.WatchListView.DragDrop += new System.Windows.Forms.DragEventHandler(this.NewRamWatch_DragDrop); this.WatchListView.DragEnter += new System.Windows.Forms.DragEventHandler(this.DragEnterWrapper); this.WatchListView.KeyDown += new System.Windows.Forms.KeyEventHandler(this.WatchListView_KeyDown); diff --git a/BizHawk.Client.EmuHawk/tools/Watch/RamWatch.cs b/BizHawk.Client.EmuHawk/tools/Watch/RamWatch.cs index 2f2b961cd1..dd4d5fe4cb 100644 --- a/BizHawk.Client.EmuHawk/tools/Watch/RamWatch.cs +++ b/BizHawk.Client.EmuHawk/tools/Watch/RamWatch.cs @@ -1303,14 +1303,6 @@ namespace BizHawk.Client.EmuHawk #endregion #endregion - private void WatchListView_VirtualItemsSelectionRangeChanged(object sender, ListViewVirtualItemsSelectionRangeChangedEventArgs e) - { - PokeAddressToolBarItem.Enabled = - FreezeAddressToolBarItem.Enabled = - SelectedIndices.Any() && - SelectedWatches.All(w => w.Domain.CanPoke()); - } - // Stupid designer protected void DragEnterWrapper(object sender, DragEventArgs e) { From b3e6d1b49f9a40ca4ddf7bbbe789f6020ca888c3 Mon Sep 17 00:00:00 2001 From: adelikat Date: Mon, 14 Oct 2019 20:39:10 -0500 Subject: [PATCH 038/166] Ram Watch - wire up column sorting --- BizHawk.Client.EmuHawk/tools/Watch/RamWatch.Designer.cs | 3 +-- BizHawk.Client.EmuHawk/tools/Watch/RamWatch.cs | 5 ++--- 2 files changed, 3 insertions(+), 5 deletions(-) diff --git a/BizHawk.Client.EmuHawk/tools/Watch/RamWatch.Designer.cs b/BizHawk.Client.EmuHawk/tools/Watch/RamWatch.Designer.cs index da195243d7..efda464bdd 100644 --- a/BizHawk.Client.EmuHawk/tools/Watch/RamWatch.Designer.cs +++ b/BizHawk.Client.EmuHawk/tools/Watch/RamWatch.Designer.cs @@ -895,8 +895,7 @@ this.WatchListView.Size = new System.Drawing.Size(332, 281); this.WatchListView.TabIndex = 2; this.WatchListView.UseCustomBackground = true; - // InputRoll TODO - //this.WatchListView.ColumnClick += new System.Windows.Forms.ColumnClickEventHandler(this.WatchListView_ColumnClick); + this.WatchListView.ColumnClick += new BizHawk.Client.EmuHawk.InputRoll.ColumnClickEventHandler(this.WatchListView_ColumnClick); this.WatchListView.SelectedIndexChanged += new System.EventHandler(this.WatchListView_SelectedIndexChanged); this.WatchListView.DragDrop += new System.Windows.Forms.DragEventHandler(this.NewRamWatch_DragDrop); this.WatchListView.DragEnter += new System.Windows.Forms.DragEventHandler(this.DragEnterWrapper); diff --git a/BizHawk.Client.EmuHawk/tools/Watch/RamWatch.cs b/BizHawk.Client.EmuHawk/tools/Watch/RamWatch.cs index dd4d5fe4cb..68e96c26df 100644 --- a/BizHawk.Client.EmuHawk/tools/Watch/RamWatch.cs +++ b/BizHawk.Client.EmuHawk/tools/Watch/RamWatch.cs @@ -553,9 +553,8 @@ namespace BizHawk.Client.EmuHawk } } - private void OrderColumn(int index) + private void OrderColumn(InputRoll.RollColumn column) { - var column = WatchListView.AllColumns[index]; if (column.Name != _sortedColumn) { _sortReverse = false; @@ -1278,7 +1277,7 @@ namespace BizHawk.Client.EmuHawk } // InputRoll TODO - private void WatchListView_ColumnClick(object sender, ColumnClickEventArgs e) + private void WatchListView_ColumnClick(object sender, InputRoll.ColumnClickEventArgs e) { OrderColumn(e.Column); } From d898c321f274cf37ef09b66741b5ab7f4a1b4af4 Mon Sep 17 00:00:00 2001 From: adelikat Date: Mon, 14 Oct 2019 21:10:34 -0500 Subject: [PATCH 039/166] make ram watch wider by default as input roll takes a bit more width for the text, fix changes default column width --- BizHawk.Client.EmuHawk/tools/Watch/RamWatch.Designer.cs | 4 ++-- BizHawk.Client.EmuHawk/tools/Watch/RamWatch.cs | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/BizHawk.Client.EmuHawk/tools/Watch/RamWatch.Designer.cs b/BizHawk.Client.EmuHawk/tools/Watch/RamWatch.Designer.cs index efda464bdd..a353a41066 100644 --- a/BizHawk.Client.EmuHawk/tools/Watch/RamWatch.Designer.cs +++ b/BizHawk.Client.EmuHawk/tools/Watch/RamWatch.Designer.cs @@ -892,7 +892,7 @@ this.WatchListView.GridLines = true; this.WatchListView.Location = new System.Drawing.Point(16, 76); this.WatchListView.Name = "WatchListView"; - this.WatchListView.Size = new System.Drawing.Size(332, 281); + this.WatchListView.Size = new System.Drawing.Size(363, 281); this.WatchListView.TabIndex = 2; this.WatchListView.UseCustomBackground = true; this.WatchListView.ColumnClick += new BizHawk.Client.EmuHawk.InputRoll.ColumnClickEventHandler(this.WatchListView_ColumnClick); @@ -906,7 +906,7 @@ // this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; - this.ClientSize = new System.Drawing.Size(364, 378); + this.ClientSize = new System.Drawing.Size(395, 378); this.Controls.Add(this.statusStrip1); this.Controls.Add(this.WatchCountLabel); this.Controls.Add(this.toolStrip1); diff --git a/BizHawk.Client.EmuHawk/tools/Watch/RamWatch.cs b/BizHawk.Client.EmuHawk/tools/Watch/RamWatch.cs index 68e96c26df..6c5f3f3a2c 100644 --- a/BizHawk.Client.EmuHawk/tools/Watch/RamWatch.cs +++ b/BizHawk.Client.EmuHawk/tools/Watch/RamWatch.cs @@ -84,7 +84,7 @@ namespace BizHawk.Client.EmuHawk new InputRoll.RollColumn { Text = "Address", Name = WatchList.ADDRESS, Visible = true, Width = 60, Type = InputRoll.RollColumn.InputType.Text }, new InputRoll.RollColumn { Text = "Value", Name = WatchList.VALUE, Visible = true, Width = 59, Type = InputRoll.RollColumn.InputType.Text }, new InputRoll.RollColumn { Text = "Prev", Name = WatchList.PREV, Visible = false, Width = 59, Type = InputRoll.RollColumn.InputType.Text }, - new InputRoll.RollColumn { Text = "Changes", Name = WatchList.CHANGES, Visible = true, Width = 55, Type = InputRoll.RollColumn.InputType.Text }, + new InputRoll.RollColumn { Text = "Changes", Name = WatchList.CHANGES, Visible = true, Width = 60, Type = InputRoll.RollColumn.InputType.Text }, new InputRoll.RollColumn { Text = "Diff", Name = WatchList.DIFF, Visible = false, Width = 59, Type = InputRoll.RollColumn.InputType.Text }, new InputRoll.RollColumn { Text = "Type", Name = WatchList.TYPE, Visible = false, Width = 55, Type = InputRoll.RollColumn.InputType.Text }, new InputRoll.RollColumn { Text = "Domain", Name = WatchList.DOMAIN, Visible = true, Width = 55, Type = InputRoll.RollColumn.InputType.Text }, From b60ed035437e7d30d59cabe2c5b84d7804f7f1d3 Mon Sep 17 00:00:00 2001 From: adelikat Date: Thu, 17 Oct 2019 15:20:58 -0500 Subject: [PATCH 040/166] inputroll - column resizing (not implemented for HorizontalOrientation yet) --- .../CustomControls/InputRoll.cs | 67 ++++++++++++++----- 1 file changed, 51 insertions(+), 16 deletions(-) diff --git a/BizHawk.Client.EmuHawk/CustomControls/InputRoll.cs b/BizHawk.Client.EmuHawk/CustomControls/InputRoll.cs index e9489b93bb..6add3349b6 100644 --- a/BizHawk.Client.EmuHawk/CustomControls/InputRoll.cs +++ b/BizHawk.Client.EmuHawk/CustomControls/InputRoll.cs @@ -38,6 +38,7 @@ namespace BizHawk.Client.EmuHawk private Size _charSize; private RollColumn _columnDown; + private RollColumn _columnResizing; private int? _currentX; private int? _currentY; @@ -971,18 +972,30 @@ namespace BizHawk.Client.EmuHawk #region Mouse and Key Events private bool _columnDownMoved; + private int _previousX = 0; // TODO: move me + protected override void OnMouseMove(MouseEventArgs e) { + _previousX = _currentX ?? 0; _currentX = e.X; _currentY = e.Y; - if (_columnDown != null) + if (_columnResizing != null) + { + if (_currentX != _previousX) + { + _columnResizing.Width += _currentX - _previousX; + _columns.ColumnsChanged(); + Refresh(); + } + } + else if (_columnDown != null) { _columnDownMoved = true; } Cell newCell = CalculatePointedCell(_currentX.Value, _currentY.Value); - + // SuuperW: Hide lag frames if (QueryFrameLag != null && newCell.RowIndex.HasValue) { @@ -1014,6 +1027,10 @@ namespace BizHawk.Client.EmuHawk Refresh(); } + Cursor = IsHoveringOnColumnEdge || _columnResizing != null + ? Cursors.VSplit + : Cursors.Default; + base.OnMouseMove(e); } @@ -1034,6 +1051,7 @@ namespace BizHawk.Client.EmuHawk _currentY = null; CurrentCell = null; IsPaintDown = false; + _columnResizing = null; _hoverTimer.Stop(); Refresh(); base.OnMouseLeave(e); @@ -1079,6 +1097,10 @@ namespace BizHawk.Client.EmuHawk if (e.Button == MouseButtons.Left) { + if (IsHoveringOnColumnEdge) + { + _columnResizing = CurrentCell.Column; + } if (IsHoveringOnColumnCell) { _columnDown = CurrentCell.Column; @@ -1209,7 +1231,7 @@ namespace BizHawk.Client.EmuHawk protected override void OnMouseUp(MouseEventArgs e) { - if (IsHoveringOnColumnCell) + if (_columnResizing == null && IsHoveringOnColumnCell) { if (_columnDown != null && _columnDownMoved) { @@ -1227,6 +1249,7 @@ namespace BizHawk.Client.EmuHawk } } + _columnResizing = null; _columnDown = null; _columnDownMoved = false; RightButtonHeld = false; @@ -1590,7 +1613,8 @@ namespace BizHawk.Client.EmuHawk } else { - NeedsVScrollbar = RowCount > 1; + //NeedsVScrollbar = RowCount > 1; + NeedsVScrollbar = false; NeedsHScrollbar = TotalColWidth.HasValue && TotalColWidth.Value - DrawWidth + 1 > 0; } @@ -1731,12 +1755,35 @@ namespace BizHawk.Client.EmuHawk private bool IsHoveringOnColumnCell => CurrentCell?.Column != null && !CurrentCell.RowIndex.HasValue; + private bool IsHoveringOnColumnEdge => AllowColumnResize && IsHoveringOnColumnCell && IsPointingOnCellEdge(_currentX); + private bool IsHoveringOnDataCell => CurrentCell?.Column != null && CurrentCell.RowIndex.HasValue; private bool WasHoveringOnColumnCell => LastCell?.Column != null && !LastCell.RowIndex.HasValue; private bool WasHoveringOnDataCell => LastCell?.Column != null && LastCell.RowIndex.HasValue; + private bool IsPointingOnCellEdge(int? x) + { + if (x.HasValue) + { + if (HorizontalOrientation) + { + return false; // TODO: support column resize in horizontal orientation + } + + foreach (RollColumn column in _columns.VisibleColumns) + { + if (column.Left - _hBar.Value + (column.Width - column.Width / 6) <= x.Value && column.Right - _hBar.Value >= x.Value) + { + return true; + } + } + } + + return false; + } + /// /// Finds the specific cell that contains the (x, y) coordinate. /// @@ -1783,18 +1830,6 @@ namespace BizHawk.Client.EmuHawk // A boolean that indicates if the InputRoll is too large horizontally and requires a horizontal scrollbar. private bool NeedsHScrollbar { get; set; } - /// - /// Updates the width of the supplied column. - /// Call when changing the ColumnCell text, CellPadding, or text font. - /// - /// The RollColumn object to update. - /// The new width of the RollColumn object. - private int UpdateWidth(RollColumn col) - { - col.Width = (col.Text.Length * _charSize.Width) + (CellWidthPadding * 4); - return col.Width.Value; - } - /// /// Gets the total width of all the columns by using the last column's Right property. /// From 9da739eaeb53fada6e6d538fc31b51ee88f5740a Mon Sep 17 00:00:00 2001 From: alyosha-tas Date: Fri, 18 Oct 2019 17:35:59 -0400 Subject: [PATCH 041/166] GBHawk: TAMA5 initial work --- .../Consoles/Nintendo/GBHawk/GBHawk.cs | 18 +- .../Nintendo/GBHawk/Mappers/Mapper_TAMA5.cs | 257 ++++++++++++++++-- 2 files changed, 248 insertions(+), 27 deletions(-) diff --git a/BizHawk.Emulation.Cores/Consoles/Nintendo/GBHawk/GBHawk.cs b/BizHawk.Emulation.Cores/Consoles/Nintendo/GBHawk/GBHawk.cs index 3cb80bf96f..57dafa2366 100644 --- a/BizHawk.Emulation.Cores/Consoles/Nintendo/GBHawk/GBHawk.cs +++ b/BizHawk.Emulation.Cores/Consoles/Nintendo/GBHawk/GBHawk.cs @@ -342,7 +342,7 @@ namespace BizHawk.Emulation.Cores.Nintendo.GBHawk case 0x20: mapper = new MapperMBC6(); mppr = "MBC6"; break; case 0x22: mapper = new MapperMBC7(); mppr = "MBC7"; has_bat = true; break; case 0xFC: mapper = new MapperCamera(); mppr = "CAM"; break; - case 0xFD: mapper = new MapperTAMA5(); mppr = "TAMA5"; break; + case 0xFD: mapper = new MapperTAMA5(); mppr = "TAMA5"; has_bat = true; break; case 0xFE: mapper = new MapperHuC3(); mppr = "HuC3"; break; case 0xFF: mapper = new MapperHuC1(); mppr = "HuC1"; break; @@ -453,6 +453,13 @@ namespace BizHawk.Emulation.Cores.Nintendo.GBHawk has_bat = true; } + // TAMA5 has 0x1000 bytes of RAM, regardless of any header info + if (mppr == "TAMA5") + { + cart_RAM = new byte[0x20]; + has_bat = true; + } + mapper.Core = this; mapper.Initialize(); @@ -466,7 +473,7 @@ namespace BizHawk.Emulation.Cores.Nintendo.GBHawk } } - // Extra RTC initialization for mbc3 + // Extra RTC initialization for mbc3, HuC3, and TAMA5 if (mppr == "MBC3") { Use_MT = true; @@ -521,6 +528,13 @@ namespace BizHawk.Emulation.Cores.Nintendo.GBHawk mapper.RTC_Get(minutes_upper, 8); mapper.RTC_Get(remaining & 0xFF, 0); } + + if (mppr == "TAMA5") + { + Use_MT = true; + + // currently no date / time input for TAMA5 + } } } } diff --git a/BizHawk.Emulation.Cores/Consoles/Nintendo/GBHawk/Mappers/Mapper_TAMA5.cs b/BizHawk.Emulation.Cores/Consoles/Nintendo/GBHawk/Mappers/Mapper_TAMA5.cs index 64239c64da..206ecdba9b 100644 --- a/BizHawk.Emulation.Cores/Consoles/Nintendo/GBHawk/Mappers/Mapper_TAMA5.cs +++ b/BizHawk.Emulation.Cores/Consoles/Nintendo/GBHawk/Mappers/Mapper_TAMA5.cs @@ -6,49 +6,95 @@ using BizHawk.Emulation.Common.Components.LR35902; namespace BizHawk.Emulation.Cores.Nintendo.GBHawk { - // Default mapper with no bank switching + // Tama 5 mapper used in tamagatchi 3 public class MapperTAMA5 : MapperBase { + public int ROM_bank; + public int RAM_bank; + public int ROM_mask; + public int RAM_mask; + public byte[] RTC_regs = new byte[10]; + public int RTC_timer; + public int RTC_low_clock; + public bool halt; + public int RTC_offset; + public int ctrl; + public int RAM_addr_low; + public int RAM_addr_high; + public int RAM_val_low; + public int RAM_val_high; + public byte Chip_return_low; + public byte Chip_return_high; + public override void Initialize() { - // nothing to initialize + ROM_bank = 0; + RAM_bank = 0; + ROM_mask = Core._rom.Length / 0x4000 - 1; + + // some games have sizes that result in a degenerate ROM, account for it here + if (ROM_mask > 4) { ROM_mask |= 3; } + + RAM_mask = 0; + if (Core.cart_RAM != null) + { + RAM_mask = Core.cart_RAM.Length / 0x2000 - 1; + if (Core.cart_RAM.Length == 0x800) { RAM_mask = 0; } + } + + RTC_regs[0] = 0; + RTC_regs[1] = 0; + RTC_regs[2] = 0; + RTC_regs[3] = 0; + RTC_regs[4] = 0; + + ctrl = 0; } public override byte ReadMemory(ushort addr) { - if (addr < 0x8000) + if (addr < 0x4000) { return Core._rom[addr]; } + else if (addr < 0x8000) + { + return Core._rom[(addr - 0x4000) + ROM_bank * 0x4000]; + } else { - if (Core.cart_RAM != null) + + switch (ctrl) { - return Core.cart_RAM[addr - 0xA000]; - } - else - { - return 0; + case 0xA: + // The game won't proceed unless this value (anded with 3) is 1 + // see bank 0: 0x1A7D to 0x1A89 + return 1; + case 0xC: + //Console.WriteLine("read low: " + Chip_return_low); + return Chip_return_low; + case 0xD: + //Console.WriteLine("read high: " + Chip_return_high); + return Chip_return_high; } + + return 0x0; } } public override void MapCDL(ushort addr, LR35902.eCDLogMemFlags flags) { - if (addr < 0x8000) + if (addr < 0x4000) { SetCDLROM(flags, addr); } + else if (addr < 0x8000) + { + SetCDLROM(flags, (addr - 0x4000) + ROM_bank * 0x4000); + } else { - if (Core.cart_RAM != null) - { - SetCDLRAM(flags, addr - 0xA000); - } - else - { - return; - } + } } @@ -59,22 +105,183 @@ namespace BizHawk.Emulation.Cores.Nintendo.GBHawk public override void WriteMemory(ushort addr, byte value) { - if (addr < 0x8000) + if (addr == 0xA000) { - // no mapping hardware available - } - else - { - if (Core.cart_RAM != null) + switch (ctrl) { - Core.cart_RAM[addr - 0xA000] = value; + case 0: + ROM_bank &= 0xF0; + ROM_bank |= (value & 0xF); + break; + case 1: + ROM_bank &= 0x0F; + ROM_bank |= ((value & 0x1) << 4); + break; + case 4: + RAM_val_low = (value & 0xF); + break; + case 5: + RAM_val_high = (value & 0xF); + //Core.cart_RAM[(RAM_addr_high << 4) | RAM_addr_low] = (byte)((RAM_val_high << 4) | RAM_val_low); + break; + case 6: + RAM_addr_high = (value & 1); + + switch ((value & 0xE) >> 1) + { + case 0: + // write to RAM + Core.cart_RAM[(RAM_addr_high << 4) | RAM_addr_low] = (byte)((RAM_val_high << 4) | RAM_val_low); + break; + case 1: + // read from RAM + Chip_return_high = (byte)(Core.cart_RAM[(RAM_addr_high << 4) | RAM_addr_low] >> 4); + Chip_return_low = (byte)(Core.cart_RAM[(RAM_addr_high << 4) | RAM_addr_low] & 0xF); + break; + case 2: + // read from RTC registers + if (RAM_addr_low == 3) + { + Chip_return_high = RTC_regs[2]; + Chip_return_low = RTC_regs[1]; + } + else if (RAM_addr_low == 6) + { + Chip_return_high = RTC_regs[4]; + Chip_return_low = RTC_regs[3]; + } + else + { + Chip_return_high = 1; + Chip_return_low = 1; + } + break; + case 3: + // write to RTC registers (probably wrong, not well tested) + if (RAM_addr_low == 3) + { + RTC_regs[2] = (byte)(RAM_val_high & 0xF); + RTC_regs[1] = (byte)(RAM_val_low & 0xF); + } + else if (RAM_addr_low == 6) + { + RTC_regs[4] = (byte)(RAM_val_high & 0xF); + RTC_regs[3] = (byte)(RAM_val_low & 0xF); + } + else + { + + } + break; + case 4: + // read from seconds register (time changes are checked when it rolls over) + Chip_return_low = (byte)(RTC_regs[0] & 0xF); + break; + } + + //Console.WriteLine("CTRL: " + (value >> 1) + " RAM_high:" + RAM_addr_high + " RAM_low: " + RAM_addr_low + " val: " + (byte)((RAM_val_high << 4) | RAM_val_low) + " Cpu: " + Core.cpu.TotalExecutedCycles); + break; + case 7: + RAM_addr_low = (value & 0xF); + + //Console.WriteLine(" RAM_low:" + RAM_addr_low + " Cpu: " + Core.cpu.TotalExecutedCycles); + break; } } + else if (addr == 0xA001) + { + ctrl = value; + } } public override void PokeMemory(ushort addr, byte value) { WriteMemory(addr, value); } + + public override void RTC_Get(int value, int index) + { + if (index < 10) + { + RTC_regs[index] = (byte)value; + } + else + { + RTC_offset = value; + } + } + + public override void Mapper_Tick() + { + if (!halt) + { + RTC_timer++; + + if (RTC_timer == 128) + { + RTC_timer = 0; + + RTC_low_clock++; + + if (RTC_low_clock == 32768) + { + RTC_low_clock = 0; + RTC_timer = RTC_offset; + + RTC_regs[0]++; + + if (RTC_regs[0] > 59) + { + RTC_regs[0] = 0; + RTC_regs[1]++; + // 1's digit of minutes + if (RTC_regs[1] > 9) + { + RTC_regs[1] = 0; + RTC_regs[2]++; + // 10's digit of minutes + if (RTC_regs[2] > 5) + { + RTC_regs[2] = 0; + RTC_regs[3]++; + // 1's digit of hours + if (RTC_regs[3] > 9) + { + RTC_regs[3] = 0; + RTC_regs[4]++; + // 10's digit of hours + if (RTC_regs[4] > 2) + { + RTC_regs[4] = 0; + RTC_regs[5]++; + } + } + } + } + } + } + } + } + } + + public override void SyncState(Serializer ser) + { + ser.Sync(nameof(ROM_bank), ref ROM_bank); + ser.Sync(nameof(ROM_mask), ref ROM_mask); + ser.Sync(nameof(RAM_bank), ref RAM_bank); + ser.Sync(nameof(RAM_mask), ref RAM_mask); + ser.Sync(nameof(halt), ref halt); + ser.Sync(nameof(RTC_regs), ref RTC_regs, false); + ser.Sync(nameof(RTC_timer), ref RTC_timer); + ser.Sync(nameof(RTC_low_clock), ref RTC_low_clock); + ser.Sync(nameof(RTC_offset), ref RTC_offset); + ser.Sync(nameof(ctrl), ref ctrl); + ser.Sync(nameof(RAM_addr_low), ref RAM_addr_low); + ser.Sync(nameof(RAM_addr_high), ref RAM_addr_high); + ser.Sync(nameof(RAM_val_low), ref RAM_val_low); + ser.Sync(nameof(RAM_val_high), ref RAM_val_high); + ser.Sync(nameof(Chip_return_low), ref Chip_return_low); + ser.Sync(nameof(Chip_return_high), ref Chip_return_high); + } } } From a51bca38f0ce6e797055299d0f708f7b5d3d5650 Mon Sep 17 00:00:00 2001 From: adelikat Date: Fri, 18 Oct 2019 18:56:21 -0500 Subject: [PATCH 042/166] convert RamSearch to use InputRoll --- .../Extensions/ControlExtensions.cs | 1 + .../tools/Watch/RamSearch.Designer.cs | 57 +------ .../tools/Watch/RamSearch.cs | 160 +++++++++++------- 3 files changed, 101 insertions(+), 117 deletions(-) diff --git a/BizHawk.Client.EmuHawk/Extensions/ControlExtensions.cs b/BizHawk.Client.EmuHawk/Extensions/ControlExtensions.cs index 6e21c8a88d..9518dde03e 100644 --- a/BizHawk.Client.EmuHawk/Extensions/ControlExtensions.cs +++ b/BizHawk.Client.EmuHawk/Extensions/ControlExtensions.cs @@ -94,6 +94,7 @@ namespace BizHawk.Client.EmuHawk.WinFormExtensions { var menuItem = new ToolStripMenuItem { + Name = column.Name, Text = $"{column.Text} ({column.Name})", Checked = column.Visible, CheckOnClick = true, diff --git a/BizHawk.Client.EmuHawk/tools/Watch/RamSearch.Designer.cs b/BizHawk.Client.EmuHawk/tools/Watch/RamSearch.Designer.cs index b126c12fe1..ba24ec8b2f 100644 --- a/BizHawk.Client.EmuHawk/tools/Watch/RamSearch.Designer.cs +++ b/BizHawk.Client.EmuHawk/tools/Watch/RamSearch.Designer.cs @@ -32,12 +32,7 @@ System.Windows.Forms.ToolStripMenuItem SearchMenuItem; System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(RamSearch)); this.TotalSearchLabel = new System.Windows.Forms.Label(); - this.WatchListView = new BizHawk.Client.EmuHawk.VirtualListView(); - this.AddressColumn = ((System.Windows.Forms.ColumnHeader)(new System.Windows.Forms.ColumnHeader())); - this.ValueColumn = ((System.Windows.Forms.ColumnHeader)(new System.Windows.Forms.ColumnHeader())); - this.PreviousColumn = ((System.Windows.Forms.ColumnHeader)(new System.Windows.Forms.ColumnHeader())); - this.ChangesColumn = ((System.Windows.Forms.ColumnHeader)(new System.Windows.Forms.ColumnHeader())); - this.DiffColumn = ((System.Windows.Forms.ColumnHeader)(new System.Windows.Forms.ColumnHeader())); + this.WatchListView = new InputRoll(); this.ListViewContextMenu = new System.Windows.Forms.ContextMenuStrip(this.components); this.DoSearchContextMenuItem = new System.Windows.Forms.ToolStripMenuItem(); this.NewSearchContextMenuItem = new System.Windows.Forms.ToolStripMenuItem(); @@ -189,61 +184,24 @@ this.WatchListView.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom) | System.Windows.Forms.AnchorStyles.Left) | System.Windows.Forms.AnchorStyles.Right))); - this.WatchListView.BlazingFast = false; - this.WatchListView.Columns.AddRange(new System.Windows.Forms.ColumnHeader[] { - this.AddressColumn, - this.ValueColumn, - this.PreviousColumn, - this.ChangesColumn, - this.DiffColumn}); this.WatchListView.ContextMenuStrip = this.ListViewContextMenu; this.WatchListView.FullRowSelect = true; this.WatchListView.GridLines = true; - this.WatchListView.HideSelection = false; - this.WatchListView.ItemCount = 0; + this.WatchListView.RowCount = 0; this.WatchListView.Location = new System.Drawing.Point(9, 65); this.WatchListView.Name = "WatchListView"; - this.WatchListView.SelectAllInProgress = false; - this.WatchListView.selectedItem = -1; this.WatchListView.Size = new System.Drawing.Size(230, 366); this.WatchListView.TabIndex = 1; - this.WatchListView.UseCompatibleStateImageBehavior = false; this.WatchListView.UseCustomBackground = true; - this.WatchListView.View = System.Windows.Forms.View.Details; - this.WatchListView.VirtualMode = true; - this.WatchListView.ColumnClick += new System.Windows.Forms.ColumnClickEventHandler(this.WatchListView_ColumnClick); + + this.WatchListView.ColumnClick += new BizHawk.Client.EmuHawk.InputRoll.ColumnClickEventHandler(this.WatchListView_ColumnClick); this.WatchListView.SelectedIndexChanged += new System.EventHandler(this.WatchListView_SelectedIndexChanged); - this.WatchListView.VirtualItemsSelectionRangeChanged += new System.Windows.Forms.ListViewVirtualItemsSelectionRangeChangedEventHandler(this.WatchListView_VirtualItemsSelectionRangeChanged); this.WatchListView.DragDrop += new System.Windows.Forms.DragEventHandler(this.NewRamSearch_DragDrop); this.WatchListView.DragEnter += new System.Windows.Forms.DragEventHandler(this.DragEnterWrapper); this.WatchListView.Enter += new System.EventHandler(this.WatchListView_Enter); this.WatchListView.KeyDown += new System.Windows.Forms.KeyEventHandler(this.WatchListView_KeyDown); this.WatchListView.MouseDoubleClick += new System.Windows.Forms.MouseEventHandler(this.WatchListView_MouseDoubleClick); // - // AddressColumn - // - this.AddressColumn.Text = "Address"; - this.AddressColumn.Width = 61; - // - // ValueColumn - // - this.ValueColumn.Text = "Value"; - this.ValueColumn.Width = 48; - // - // PreviousColumn - // - this.PreviousColumn.Text = "Prev"; - this.PreviousColumn.Width = 48; - // - // ChangesColumn - // - this.ChangesColumn.Text = "Changes"; - this.ChangesColumn.Width = 55; - // - // DiffColumn - // - this.DiffColumn.Text = "Diff"; - // // ListViewContextMenu // this.ListViewContextMenu.Items.AddRange(new System.Windows.Forms.ToolStripItem[] { @@ -1422,11 +1380,7 @@ #endregion private System.Windows.Forms.Label TotalSearchLabel; - VirtualListView WatchListView; - private System.Windows.Forms.ColumnHeader AddressColumn; - private System.Windows.Forms.ColumnHeader ValueColumn; - private System.Windows.Forms.ColumnHeader PreviousColumn; - private System.Windows.Forms.ColumnHeader ChangesColumn; + InputRoll WatchListView; private System.Windows.Forms.ToolStripMenuItem fileToolStripMenuItem; private System.Windows.Forms.ToolStripMenuItem OpenMenuItem; private System.Windows.Forms.ToolStripMenuItem SaveAsMenuItem; @@ -1530,7 +1484,6 @@ private WatchValueBox DifferenceBox; private System.Windows.Forms.ToolStripMenuItem AutoSearchMenuItem; private System.Windows.Forms.ToolStripSeparator toolStripSeparator9; - private System.Windows.Forms.ColumnHeader DiffColumn; private System.Windows.Forms.ToolStripSeparator toolStripSeparator12; private System.Windows.Forms.ToolStripButton UndoToolBarButton; private System.Windows.Forms.ToolStripButton RedoToolBarItem; diff --git a/BizHawk.Client.EmuHawk/tools/Watch/RamSearch.cs b/BizHawk.Client.EmuHawk/tools/Watch/RamSearch.cs index 91605466a5..4d82362c12 100644 --- a/BizHawk.Client.EmuHawk/tools/Watch/RamSearch.cs +++ b/BizHawk.Client.EmuHawk/tools/Watch/RamSearch.cs @@ -53,13 +53,13 @@ namespace BizHawk.Client.EmuHawk InitializeComponent(); WatchListView.QueryItemText += ListView_QueryItemText; WatchListView.QueryItemBkColor += ListView_QueryItemBkColor; - WatchListView.VirtualMode = true; Closing += (o, e) => SaveConfigSettings(); _sortedColumn = ""; _sortReverse = false; Settings = new RamSearchSettings(); + SetColumns(); } [RequiredService] @@ -110,15 +110,20 @@ namespace BizHawk.Client.EmuHawk private void ColumnToggleCallback() { - SaveColumnInfo(WatchListView, Settings.Columns); - LoadColumnInfo(WatchListView, Settings.Columns); + Settings.Columns = WatchListView.AllColumns; } private void RamSearch_Load(object sender, EventArgs e) { + // Hack for previous config settings + if (Settings.Columns.Any(c => string.IsNullOrWhiteSpace(c.Text))) + { + Settings = new RamSearchSettings(); + } + TopMost = Settings.TopMost; - RamSearchMenu.Items.Add(Settings.Columns.GenerateColumnsMenu(ColumnToggleCallback)); + RamSearchMenu.Items.Add(WatchListView.ToColumnsMenu(ColumnToggleCallback)); _settings = new RamSearchEngine.Settings(MemoryDomains); _searches = new RamSearchEngine(_settings, MemoryDomains); @@ -161,39 +166,36 @@ namespace BizHawk.Client.EmuHawk ErrorIconButton.Visible = _searches.OutOfRangeAddress.Any(); } - private void ListView_QueryItemBkColor(int index, int column, ref Color color) + private void ListView_QueryItemBkColor(int index, InputRoll.RollColumn column, ref Color color) { - if (column == 0) + if (_searches.Count > 0) { - if (_searches.Count > 0 && column == 0) + var nextColor = Color.White; + + var isCheat = Global.CheatList.IsActive(_settings.Domain, _searches[index].Address); + var isWeeded = Settings.PreviewMode && !_forcePreviewClear && _searches.Preview(_searches[index].Address); + + if (_searches[index].Address >= _searches[index].Domain.Size) { - var nextColor = Color.White; - - var isCheat = Global.CheatList.IsActive(_settings.Domain, _searches[index].Address); - var isWeeded = Settings.PreviewMode && !_forcePreviewClear && _searches.Preview(_searches[index].Address); - - if (_searches[index].Address >= _searches[index].Domain.Size) - { - nextColor = Color.PeachPuff; - } - else if (isCheat) - { - nextColor = isWeeded ? Color.Lavender : Color.LightCyan; - } - else - { - if (isWeeded) - { - nextColor = Color.Pink; - } - } - - color = nextColor; + nextColor = Color.PeachPuff; } + else if (isCheat) + { + nextColor = isWeeded ? Color.Lavender : Color.LightCyan; + } + else + { + if (isWeeded) + { + nextColor = Color.Pink; + } + } + + color = nextColor; } } - private void ListView_QueryItemText(int index, int column, out string text) + private void ListView_QueryItemText(int index, InputRoll.RollColumn column, out string text, ref int offsetX, ref int offsetY) { text = ""; @@ -202,7 +204,7 @@ namespace BizHawk.Client.EmuHawk return; } - var columnName = WatchListView.Columns[column].Name; + var columnName = column.Name; switch (columnName) { case WatchList.ADDRESS: @@ -240,7 +242,19 @@ namespace BizHawk.Client.EmuHawk TopMost = Settings.TopMost; - LoadColumnInfo(WatchListView, Settings.Columns); + WatchListView.AllColumns.Clear(); + SetColumns(); + } + + private void SetColumns() + { + foreach (var column in Settings.Columns) + { + if (WatchListView.AllColumns[column.Name] == null) + { + WatchListView.AllColumns.Add(column); + } + } } #endregion @@ -252,7 +266,7 @@ namespace BizHawk.Client.EmuHawk /// private void UpdateList() { - WatchListView.ItemCount = _searches.Count; + WatchListView.RowCount = _searches.Count; SetTotal(); } @@ -282,9 +296,7 @@ namespace BizHawk.Client.EmuHawk } _forcePreviewClear = false; - WatchListView.BlazingFast = true; WatchListView.Invalidate(); - WatchListView.BlazingFast = false; } } @@ -314,7 +326,7 @@ namespace BizHawk.Client.EmuHawk private void SaveConfigSettings() { - SaveColumnInfo(WatchListView, Settings.Columns); + Settings.Columns = WatchListView.AllColumns; if (WindowState == FormWindowState.Normal) { @@ -551,7 +563,7 @@ namespace BizHawk.Client.EmuHawk _forcePreviewClear = true; } - private IEnumerable SelectedIndices => WatchListView.SelectedIndices.Cast(); + private IEnumerable SelectedIndices => WatchListView.SelectedRows; private IEnumerable SelectedItems { @@ -771,10 +783,27 @@ namespace BizHawk.Client.EmuHawk DifferenceRadio.Enabled = true; DifferentByBox.Enabled = true; ClearChangeCountsToolBarItem.Enabled = true; - WatchListView.Columns[WatchList.CHANGES].Width = Settings.Columns[WatchList.CHANGES].Width; + + WatchListView.AllColumns[WatchList.CHANGES].Visible = true; + ChangesMenuItem.Checked = true; + + ColumnToggleCallback(); SetReboot(true); } + private ToolStripMenuItem ChangesMenuItem + { + get + { + var subMenu = (ToolStripMenuItem)RamSearchMenu.Items + .Cast() + .Single(t => t.Name == "GeneratedColumnsSubMenu"); // InputRoll TODO - make name a constant + return subMenu.DropDownItems + .Cast() + .Single(t => t.Name == WatchList.CHANGES); + } + } + private void SetToFastMode() { _settings.Mode = RamSearchEngine.Settings.SearchMode.Fast; @@ -794,8 +823,10 @@ namespace BizHawk.Client.EmuHawk PreviousValueRadio.Checked = true; } - Settings.Columns[WatchList.CHANGES].Width = WatchListView.Columns[WatchList.CHANGES].Width; - WatchListView.Columns[WatchList.CHANGES].Width = 0; + WatchListView.AllColumns[WatchList.CHANGES].Visible = false; + ChangesMenuItem.Checked = false; + + ColumnToggleCallback(); SetReboot(true); } @@ -808,7 +839,7 @@ namespace BizHawk.Client.EmuHawk _searches.RemoveRange(indices); UpdateList(); - WatchListView.SelectedIndices.Clear(); + WatchListView.DeselectAll(); ToggleSearchDependentToolBarItems(); } } @@ -899,7 +930,7 @@ namespace BizHawk.Client.EmuHawk private void GoToSpecifiedAddress() { - WatchListView.SelectedIndices.Clear(); + WatchListView.DeselectAll(); var prompt = new InputPrompt { Text = "Go to Address", @@ -916,8 +947,9 @@ namespace BizHawk.Client.EmuHawk { if (_searches[index].Address == addr) { - WatchListView.SelectItem(index, true); - WatchListView.ensureVisible(); + WatchListView.SelectRow(index, true); + // InputRoll TODO: + //WatchListView.ensureVisible(); return; // Don't re-show dialog on success } } @@ -943,13 +975,13 @@ namespace BizHawk.Client.EmuHawk { public RamSearchSettings() { - Columns = new ColumnList + Columns = new List { - new Column { Name = WatchList.ADDRESS, Visible = true, Index = 0, Width = 60 }, - new Column { Name = WatchList.VALUE, Visible = true, Index = 1, Width = 59 }, - new Column { Name = WatchList.PREV, Visible = true, Index = 2, Width = 59 }, - new Column { Name = WatchList.CHANGES, Visible = true, Index = 3, Width = 55 }, - new Column { Name = WatchList.DIFF, Visible = false, Index = 4, Width = 59 }, + new InputRoll.RollColumn { Text = "Address", Name = WatchList.ADDRESS, Visible = true, Width = 60, Type = InputRoll.RollColumn.InputType.Text }, + new InputRoll.RollColumn { Text = "Value", Name = WatchList.VALUE, Visible = true, Width = 59, Type = InputRoll.RollColumn.InputType.Text }, + new InputRoll.RollColumn { Text = "Prev", Name = WatchList.PREV, Visible = false, Width = 59, Type = InputRoll.RollColumn.InputType.Text }, + new InputRoll.RollColumn { Text = "Changes", Name = WatchList.CHANGES, Visible = true, Width = 60, Type = InputRoll.RollColumn.InputType.Text }, + new InputRoll.RollColumn { Text = "Diff", Name = WatchList.DIFF, Visible = false, Width = 59, Type = InputRoll.RollColumn.InputType.Text }, }; PreviewMode = true; @@ -957,7 +989,7 @@ namespace BizHawk.Client.EmuHawk AutoSearchTakeLagFramesIntoAccount = true; } - public ColumnList Columns { get; } + public List Columns { get; set; } public bool PreviewMode { get; set; } public bool AlwaysExcludeRamWatch { get; set; } public bool AutoSearchTakeLagFramesIntoAccount { get; set; } @@ -1387,7 +1419,7 @@ namespace BizHawk.Client.EmuHawk .OfType() .First(x => x.Name == "GeneratedColumnsSubMenu")); - RamSearchMenu.Items.Add(Settings.Columns.GenerateColumnsMenu(ColumnToggleCallback)); + RamSearchMenu.Items.Add(WatchListView.ToColumnsMenu(ColumnToggleCallback)); _settings = new RamSearchEngine.Settings(MemoryDomains); if (_settings.Mode == RamSearchEngine.Settings.SearchMode.Fast) @@ -1396,7 +1428,9 @@ namespace BizHawk.Client.EmuHawk } RefreshFloatingWindowControl(Settings.FloatingWindow); - LoadColumnInfo(WatchListView, Settings.Columns); + + WatchListView.AllColumns.Clear(); + SetColumns(); } #endregion @@ -1708,16 +1742,17 @@ namespace BizHawk.Client.EmuHawk } else if (e.KeyCode == Keys.Escape && !e.Control && !e.Alt && !e.Shift) { - WatchListView.SelectedIndices.Clear(); + WatchListView.DeselectAll(); } } private void WatchListView_SelectedIndexChanged(object sender, EventArgs e) { - if (WatchListView.SelectAllInProgress) - { - return; - } + // InputRoll todo - do we need this? + //if (WatchListView.SelectAllInProgress) + //{ + // return; + //} RemoveToolBarItem.Enabled = AddToRamWatchToolBarItem.Enabled = @@ -1729,19 +1764,14 @@ namespace BizHawk.Client.EmuHawk _searches.Domain.CanPoke(); } - private void WatchListView_VirtualItemsSelectionRangeChanged(object sender, ListViewVirtualItemsSelectionRangeChangedEventArgs e) - { - WatchListView_SelectedIndexChanged(sender, e); - } - private void WatchListView_Enter(object sender, EventArgs e) { WatchListView.Refresh(); } - private void WatchListView_ColumnClick(object sender, ColumnClickEventArgs e) + private void WatchListView_ColumnClick(object sender, InputRoll.ColumnClickEventArgs e) { - var column = WatchListView.Columns[e.Column]; + var column = e.Column; if (column.Name != _sortedColumn) { _sortReverse = false; From 427f51f407c345d347fff1fa6488b2e9ef328b34 Mon Sep 17 00:00:00 2001 From: adelikat Date: Fri, 18 Oct 2019 20:02:58 -0500 Subject: [PATCH 043/166] fix inputroll vertical scrollbar logic --- BizHawk.Client.EmuHawk/CustomControls/InputRoll.cs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/BizHawk.Client.EmuHawk/CustomControls/InputRoll.cs b/BizHawk.Client.EmuHawk/CustomControls/InputRoll.cs index 6add3349b6..01704912c0 100644 --- a/BizHawk.Client.EmuHawk/CustomControls/InputRoll.cs +++ b/BizHawk.Client.EmuHawk/CustomControls/InputRoll.cs @@ -1613,8 +1613,7 @@ namespace BizHawk.Client.EmuHawk } else { - //NeedsVScrollbar = RowCount > 1; - NeedsVScrollbar = false; + NeedsVScrollbar = RowCount > 1; NeedsHScrollbar = TotalColWidth.HasValue && TotalColWidth.Value - DrawWidth + 1 > 0; } From 3d33c3fa21be449f88f891a842ff3e3911a36189 Mon Sep 17 00:00:00 2001 From: adelikat Date: Fri, 18 Oct 2019 20:04:15 -0500 Subject: [PATCH 044/166] Ram Search - fix GoTo Address --- BizHawk.Client.EmuHawk/tools/Watch/RamSearch.cs | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/BizHawk.Client.EmuHawk/tools/Watch/RamSearch.cs b/BizHawk.Client.EmuHawk/tools/Watch/RamSearch.cs index 4d82362c12..5e520273f9 100644 --- a/BizHawk.Client.EmuHawk/tools/Watch/RamSearch.cs +++ b/BizHawk.Client.EmuHawk/tools/Watch/RamSearch.cs @@ -797,7 +797,7 @@ namespace BizHawk.Client.EmuHawk { var subMenu = (ToolStripMenuItem)RamSearchMenu.Items .Cast() - .Single(t => t.Name == "GeneratedColumnsSubMenu"); // InputRoll TODO - make name a constant + .Single(t => t.Name == "GeneratedColumnsSubMenu"); // TODO - make name a constant return subMenu.DropDownItems .Cast() .Single(t => t.Name == WatchList.CHANGES); @@ -948,8 +948,7 @@ namespace BizHawk.Client.EmuHawk if (_searches[index].Address == addr) { WatchListView.SelectRow(index, true); - // InputRoll TODO: - //WatchListView.ensureVisible(); + WatchListView.ScrollToIndex(index); return; // Don't re-show dialog on success } } From d76531064edd33048e92989a71c81e10b68c19b7 Mon Sep 17 00:00:00 2001 From: adelikat Date: Fri, 18 Oct 2019 20:07:16 -0500 Subject: [PATCH 045/166] Ram Search - show Prev column by default --- BizHawk.Client.EmuHawk/tools/Watch/RamSearch.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/BizHawk.Client.EmuHawk/tools/Watch/RamSearch.cs b/BizHawk.Client.EmuHawk/tools/Watch/RamSearch.cs index 5e520273f9..aa0eba2cb2 100644 --- a/BizHawk.Client.EmuHawk/tools/Watch/RamSearch.cs +++ b/BizHawk.Client.EmuHawk/tools/Watch/RamSearch.cs @@ -978,7 +978,7 @@ namespace BizHawk.Client.EmuHawk { new InputRoll.RollColumn { Text = "Address", Name = WatchList.ADDRESS, Visible = true, Width = 60, Type = InputRoll.RollColumn.InputType.Text }, new InputRoll.RollColumn { Text = "Value", Name = WatchList.VALUE, Visible = true, Width = 59, Type = InputRoll.RollColumn.InputType.Text }, - new InputRoll.RollColumn { Text = "Prev", Name = WatchList.PREV, Visible = false, Width = 59, Type = InputRoll.RollColumn.InputType.Text }, + new InputRoll.RollColumn { Text = "Prev", Name = WatchList.PREV, Visible = true, Width = 59, Type = InputRoll.RollColumn.InputType.Text }, new InputRoll.RollColumn { Text = "Changes", Name = WatchList.CHANGES, Visible = true, Width = 60, Type = InputRoll.RollColumn.InputType.Text }, new InputRoll.RollColumn { Text = "Diff", Name = WatchList.DIFF, Visible = false, Width = 59, Type = InputRoll.RollColumn.InputType.Text }, }; @@ -1416,7 +1416,7 @@ namespace BizHawk.Client.EmuHawk RamSearchMenu.Items.Remove( RamSearchMenu.Items .OfType() - .First(x => x.Name == "GeneratedColumnsSubMenu")); + .Single(x => x.Name == "GeneratedColumnsSubMenu")); RamSearchMenu.Items.Add(WatchListView.ToColumnsMenu(ColumnToggleCallback)); From 109b0fd8fe9ade9f4266145efcec38475fdaabf0 Mon Sep 17 00:00:00 2001 From: adelikat Date: Fri, 18 Oct 2019 21:20:50 -0500 Subject: [PATCH 046/166] Ram Search - allow multi-select --- BizHawk.Client.EmuHawk/tools/Watch/RamSearch.Designer.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/BizHawk.Client.EmuHawk/tools/Watch/RamSearch.Designer.cs b/BizHawk.Client.EmuHawk/tools/Watch/RamSearch.Designer.cs index ba24ec8b2f..718148439e 100644 --- a/BizHawk.Client.EmuHawk/tools/Watch/RamSearch.Designer.cs +++ b/BizHawk.Client.EmuHawk/tools/Watch/RamSearch.Designer.cs @@ -193,7 +193,7 @@ this.WatchListView.Size = new System.Drawing.Size(230, 366); this.WatchListView.TabIndex = 1; this.WatchListView.UseCustomBackground = true; - + this.WatchListView.MultiSelect = true; this.WatchListView.ColumnClick += new BizHawk.Client.EmuHawk.InputRoll.ColumnClickEventHandler(this.WatchListView_ColumnClick); this.WatchListView.SelectedIndexChanged += new System.EventHandler(this.WatchListView_SelectedIndexChanged); this.WatchListView.DragDrop += new System.Windows.Forms.DragEventHandler(this.NewRamSearch_DragDrop); From 6977ac20a1b8c8a80ba7f3b2f66f3c1cc881424b Mon Sep 17 00:00:00 2001 From: adelikat Date: Fri, 18 Oct 2019 21:21:44 -0500 Subject: [PATCH 047/166] Ram Search - remove some code that i don't think is necessary with inputroll --- BizHawk.Client.EmuHawk/tools/Watch/RamSearch.cs | 6 ------ 1 file changed, 6 deletions(-) diff --git a/BizHawk.Client.EmuHawk/tools/Watch/RamSearch.cs b/BizHawk.Client.EmuHawk/tools/Watch/RamSearch.cs index aa0eba2cb2..a7be2ebb0e 100644 --- a/BizHawk.Client.EmuHawk/tools/Watch/RamSearch.cs +++ b/BizHawk.Client.EmuHawk/tools/Watch/RamSearch.cs @@ -1747,12 +1747,6 @@ namespace BizHawk.Client.EmuHawk private void WatchListView_SelectedIndexChanged(object sender, EventArgs e) { - // InputRoll todo - do we need this? - //if (WatchListView.SelectAllInProgress) - //{ - // return; - //} - RemoveToolBarItem.Enabled = AddToRamWatchToolBarItem.Enabled = SelectedIndices.Any(); From 5b5a238590a1c16c92e37b448afaaa452c54226c Mon Sep 17 00:00:00 2001 From: adelikat Date: Fri, 18 Oct 2019 21:41:50 -0500 Subject: [PATCH 048/166] Ram Search - allow column resize --- BizHawk.Client.EmuHawk/tools/Watch/RamSearch.Designer.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/BizHawk.Client.EmuHawk/tools/Watch/RamSearch.Designer.cs b/BizHawk.Client.EmuHawk/tools/Watch/RamSearch.Designer.cs index 718148439e..e5322fd38a 100644 --- a/BizHawk.Client.EmuHawk/tools/Watch/RamSearch.Designer.cs +++ b/BizHawk.Client.EmuHawk/tools/Watch/RamSearch.Designer.cs @@ -180,6 +180,7 @@ // WatchListView // this.WatchListView.AllowColumnReorder = true; + this.WatchListView.AllowColumnResize = true; this.WatchListView.AllowDrop = true; this.WatchListView.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom) | System.Windows.Forms.AnchorStyles.Left) From 5826d584cc04a2d6472581703cef97f03a0f64c7 Mon Sep 17 00:00:00 2001 From: adelikat Date: Fri, 18 Oct 2019 21:43:34 -0500 Subject: [PATCH 049/166] convert cheats dialog to use InputRoll --- .../tools/Cheats/Cheats.Designer.cs | 74 +----------- BizHawk.Client.EmuHawk/tools/Cheats/Cheats.cs | 108 ++++++++++-------- 2 files changed, 66 insertions(+), 116 deletions(-) diff --git a/BizHawk.Client.EmuHawk/tools/Cheats/Cheats.Designer.cs b/BizHawk.Client.EmuHawk/tools/Cheats/Cheats.Designer.cs index 63fce6be5a..f5d56cbd24 100644 --- a/BizHawk.Client.EmuHawk/tools/Cheats/Cheats.Designer.cs +++ b/BizHawk.Client.EmuHawk/tools/Cheats/Cheats.Designer.cs @@ -30,14 +30,7 @@ { this.components = new System.ComponentModel.Container(); System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(Cheats)); - this.CheatListView = new BizHawk.Client.EmuHawk.VirtualListView(); - this.CheatName = ((System.Windows.Forms.ColumnHeader)(new System.Windows.Forms.ColumnHeader())); - this.Address = ((System.Windows.Forms.ColumnHeader)(new System.Windows.Forms.ColumnHeader())); - this.Value = ((System.Windows.Forms.ColumnHeader)(new System.Windows.Forms.ColumnHeader())); - this.Compare = ((System.Windows.Forms.ColumnHeader)(new System.Windows.Forms.ColumnHeader())); - this.ComparisonType = ((System.Windows.Forms.ColumnHeader)(new System.Windows.Forms.ColumnHeader())); - this.On = ((System.Windows.Forms.ColumnHeader)(new System.Windows.Forms.ColumnHeader())); - this.Domain = ((System.Windows.Forms.ColumnHeader)(new System.Windows.Forms.ColumnHeader())); + this.CheatListView = new InputRoll(); this.CheatsContextMenu = new System.Windows.Forms.ContextMenuStrip(this.components); this.ToggleContextMenuItem = new System.Windows.Forms.ToolStripMenuItem(); this.RemoveContextMenuItem = new System.Windows.Forms.ToolStripMenuItem(); @@ -102,35 +95,22 @@ // CheatListView // this.CheatListView.AllowColumnReorder = true; + this.CheatListView.AllowColumnResize = true; + this.CheatListView.MultiSelect = true; this.CheatListView.AllowDrop = true; this.CheatListView.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom) | System.Windows.Forms.AnchorStyles.Left) | System.Windows.Forms.AnchorStyles.Right))); - this.CheatListView.AutoArrange = false; - this.CheatListView.BlazingFast = false; - this.CheatListView.Columns.AddRange(new System.Windows.Forms.ColumnHeader[] { - this.CheatName, - this.Address, - this.Value, - this.Compare, - this.ComparisonType, - this.On, - this.Domain}); this.CheatListView.ContextMenuStrip = this.CheatsContextMenu; this.CheatListView.FullRowSelect = true; this.CheatListView.GridLines = true; - this.CheatListView.HideSelection = false; - this.CheatListView.ItemCount = 0; + this.CheatListView.RowCount = 0; this.CheatListView.Location = new System.Drawing.Point(12, 72); this.CheatListView.Name = "CheatListView"; - this.CheatListView.SelectAllInProgress = false; - this.CheatListView.selectedItem = -1; this.CheatListView.Size = new System.Drawing.Size(414, 321); this.CheatListView.TabIndex = 1; - this.CheatListView.UseCompatibleStateImageBehavior = false; this.CheatListView.UseCustomBackground = true; - this.CheatListView.View = System.Windows.Forms.View.Details; - this.CheatListView.ColumnClick += new System.Windows.Forms.ColumnClickEventHandler(this.CheatListView_ColumnClick); + this.CheatListView.ColumnClick += new BizHawk.Client.EmuHawk.InputRoll.ColumnClickEventHandler(this.CheatListView_ColumnClick); this.CheatListView.SelectedIndexChanged += new System.EventHandler(this.CheatListView_SelectedIndexChanged); this.CheatListView.Click += new System.EventHandler(this.CheatListView_Click); this.CheatListView.DragDrop += new System.Windows.Forms.DragEventHandler(this.NewCheatForm_DragDrop); @@ -138,41 +118,6 @@ this.CheatListView.DoubleClick += new System.EventHandler(this.CheatListView_DoubleClick); this.CheatListView.KeyDown += new System.Windows.Forms.KeyEventHandler(this.CheatListView_KeyDown); // - // CheatName - // - this.CheatName.Text = "Name"; - this.CheatName.Width = 104; - // - // Address - // - this.Address.Text = "Address"; - this.Address.Width = 52; - // - // Value - // - this.Value.Text = "Value"; - this.Value.Width = 40; - // - // Compare - // - this.Compare.Text = "Compare"; - // - // ComparisonType - // - this.ComparisonType.Text = "Comparison Type"; - this.ComparisonType.Width = 194; - // - // On - // - this.On.Text = "On"; - this.On.TextAlign = System.Windows.Forms.HorizontalAlignment.Center; - this.On.Width = 40; - // - // Domain - // - this.Domain.Text = "Domain"; - this.Domain.Width = 75; - // // CheatsContextMenu // this.CheatsContextMenu.Items.AddRange(new System.Windows.Forms.ToolStripItem[] { @@ -693,14 +638,7 @@ #endregion - private VirtualListView CheatListView; - private System.Windows.Forms.ColumnHeader CheatName; - private System.Windows.Forms.ColumnHeader Address; - private System.Windows.Forms.ColumnHeader Value; - private System.Windows.Forms.ColumnHeader ComparisonType; - private System.Windows.Forms.ColumnHeader Compare; - private System.Windows.Forms.ColumnHeader On; - private System.Windows.Forms.ColumnHeader Domain; + private InputRoll CheatListView; private MenuStripEx CheatsMenu; private System.Windows.Forms.ToolStripMenuItem FileSubMenu; private System.Windows.Forms.ToolStripMenuItem NewMenuItem; diff --git a/BizHawk.Client.EmuHawk/tools/Cheats/Cheats.cs b/BizHawk.Client.EmuHawk/tools/Cheats/Cheats.cs index ef614a8e74..afb412e6f0 100644 --- a/BizHawk.Client.EmuHawk/tools/Cheats/Cheats.cs +++ b/BizHawk.Client.EmuHawk/tools/Cheats/Cheats.cs @@ -43,7 +43,6 @@ namespace BizHawk.Client.EmuHawk CheatListView.QueryItemText += CheatListView_QueryItemText; CheatListView.QueryItemBkColor += CheatListView_QueryItemBkColor; - CheatListView.VirtualMode = true; _sortedColumn = ""; _sortReverse = false; @@ -80,7 +79,7 @@ namespace BizHawk.Client.EmuHawk /// public void UpdateDialog() { - CheatListView.ItemCount = Global.CheatList.Count; + CheatListView.RowCount = Global.CheatList.Count; TotalLabel.Text = $"{Global.CheatList.CheatCount} {(Global.CheatList.CheatCount == 1 ? "cheat" : "cheats")} {Global.CheatList.ActiveCount} active"; } @@ -150,21 +149,36 @@ namespace BizHawk.Client.EmuHawk private void Cheats_Load(object sender, EventArgs e) { + // Hack for previous config settings + if (Settings.Columns.Any(c => string.IsNullOrWhiteSpace(c.Text))) + { + Settings = new CheatsSettings(); + } + TopMost = Settings.TopMost; CheatEditor.MemoryDomains = Core; LoadConfigSettings(); + CheatsMenu.Items.Add(CheatListView.ToColumnsMenu(ColumnToggleCallback)); ToggleGameGenieButton(); CheatEditor.SetAddEvent(AddCheat); CheatEditor.SetEditEvent(EditCheat); UpdateDialog(); + } - CheatsMenu.Items.Add(Settings.Columns.GenerateColumnsMenu(ColumnToggleCallback)); + private void SetColumns() + { + foreach (var column in Settings.Columns) + { + if (CheatListView.AllColumns[column.Name] == null) + { + CheatListView.AllColumns.Add(column); + } + } } private void ColumnToggleCallback() { - SaveColumnInfo(CheatListView, Settings.Columns); - LoadColumnInfo(CheatListView, Settings.Columns); + Settings.Columns = CheatListView.AllColumns; } private void ToggleGameGenieButton() @@ -195,7 +209,7 @@ namespace BizHawk.Client.EmuHawk private void SaveConfigSettings() { - SaveColumnInfo(CheatListView, Settings.Columns); + Settings.Columns =CheatListView.AllColumns; if (WindowState == FormWindowState.Normal) { @@ -221,10 +235,11 @@ namespace BizHawk.Client.EmuHawk Size = Settings.WindowSize; } - LoadColumnInfo(CheatListView, Settings.Columns); + CheatListView.AllColumns.Clear(); + SetColumns(); } - private void CheatListView_QueryItemText(int index, int column, out string text) + private void CheatListView_QueryItemText(int index, InputRoll.RollColumn column, out string text, ref int offsetX, ref int offsetY) { text = ""; if (index >= Global.CheatList.Count || Global.CheatList[index].IsSeparator) @@ -232,7 +247,7 @@ namespace BizHawk.Client.EmuHawk return; } - var columnName = CheatListView.Columns[column].Name; + var columnName = column.Name; switch (columnName) { @@ -296,7 +311,7 @@ namespace BizHawk.Client.EmuHawk } } - private void CheatListView_QueryItemBkColor(int index, int column, ref Color color) + private void CheatListView_QueryItemBkColor(int index, InputRoll.RollColumn column, ref Color color) { if (index < Global.CheatList.Count) { @@ -311,7 +326,7 @@ namespace BizHawk.Client.EmuHawk } } - private IEnumerable SelectedIndices => CheatListView.SelectedIndices.Cast(); + private IEnumerable SelectedIndices => CheatListView.SelectedRows; private IEnumerable SelectedItems { @@ -325,19 +340,16 @@ namespace BizHawk.Client.EmuHawk private void DoSelectedIndexChange() { - if (!CheatListView.SelectAllInProgress) + if (SelectedCheats.Any()) { - if (SelectedCheats.Any()) - { - var cheat = SelectedCheats.First(); - CheatEditor.SetCheat(cheat); - CheatGroupBox.Text = $"Editing Cheat {cheat.Name} - {cheat.AddressStr}"; - } - else - { - CheatEditor.ClearForm(); - CheatGroupBox.Text = "New Cheat"; - } + var cheat = SelectedCheats.First(); + CheatEditor.SetCheat(cheat); + CheatGroupBox.Text = $"Editing Cheat {cheat.Name} - {cheat.AddressStr}"; + } + else + { + CheatEditor.ClearForm(); + CheatGroupBox.Text = "New Cheat"; } } @@ -451,7 +463,7 @@ namespace BizHawk.Client.EmuHawk Global.CheatList.Remove(item); } - CheatListView.SelectedIndices.Clear(); + CheatListView.DeselectAll(); UpdateDialog(); } } @@ -486,12 +498,12 @@ namespace BizHawk.Client.EmuHawk Global.CheatList.Insert(index - 1, cheat); } - var newindices = indices.Select(t => t - 1); + var newIndices = indices.Select(t => t - 1); - CheatListView.SelectedIndices.Clear(); - foreach (var newi in newindices) + CheatListView.DeselectAll(); + foreach (var index in newIndices) { - CheatListView.SelectItem(newi, true); + CheatListView.SelectRow(index, true); } UpdateMessageLabel(); @@ -515,12 +527,12 @@ namespace BizHawk.Client.EmuHawk UpdateMessageLabel(); - var newindices = indices.Select(t => t + 1); + var newIndices = indices.Select(t => t + 1); - CheatListView.SelectedIndices.Clear(); - foreach (var newi in newindices) + CheatListView.DeselectAll(); + foreach (var index in newIndices) { - CheatListView.SelectItem(newi, true); + CheatListView.SelectRow(index, true); } UpdateDialog(); @@ -611,14 +623,15 @@ namespace BizHawk.Client.EmuHawk .OfType() .First(x => x.Name == "GeneratedColumnsSubMenu")); - CheatsMenu.Items.Add(Settings.Columns.GenerateColumnsMenu(ColumnToggleCallback)); + CheatsMenu.Items.Add(CheatListView.ToColumnsMenu(ColumnToggleCallback)); Global.Config.DisableCheatsOnLoad = false; Global.Config.LoadCheatFileByGame = true; Global.Config.CheatsAutoSaveOnClose = true; RefreshFloatingWindowControl(Settings.FloatingWindow); - LoadColumnInfo(CheatListView, Settings.Columns); + CheatListView.AllColumns.Clear(); + SetColumns(); } #endregion @@ -651,9 +664,9 @@ namespace BizHawk.Client.EmuHawk DoSelectedIndexChange(); } - private void CheatListView_ColumnClick(object sender, ColumnClickEventArgs e) + private void CheatListView_ColumnClick(object sender, InputRoll.ColumnClickEventArgs e) { - var column = CheatListView.Columns[e.Column]; + var column = e.Column; if (column.Name != _sortedColumn) { _sortReverse = false; @@ -723,22 +736,21 @@ namespace BizHawk.Client.EmuHawk { public CheatsSettings() { - Columns = new ColumnList + Columns = new List { - new Column { Name = NameColumn, Visible = true, Index = 0, Width = 128 }, - new Column { Name = AddressColumn, Visible = true, Index = 1, Width = 60 }, - new Column { Name = ValueColumn, Visible = true, Index = 2, Width = 59 }, - new Column { Name = CompareColumn, Visible = true, Index = 3, Width = 59 }, - new Column { Name = ComparisonTypeColumn, Visible = true, Index = 4, Width = 60 }, - new Column { Name = OnColumn, Visible = false, Index = 5, Width = 28 }, - new Column { Name = DomainColumn, Visible = true, Index = 6, Width = 55 }, - new Column { Name = SizeColumn, Visible = true, Index = 7, Width = 55 }, - new Column { Name = EndianColumn, Visible = false, Index = 8, Width = 55 }, - new Column { Name = TypeColumn, Visible = false, Index = 9, Width = 55 } + new InputRoll.RollColumn { Text = "Names", Name = NameColumn, Visible = true, Width = 128, Type = InputRoll.RollColumn.InputType.Text }, + new InputRoll.RollColumn { Text = "Address", Name = AddressColumn, Visible = true, Width = 60, Type = InputRoll.RollColumn.InputType.Text }, + new InputRoll.RollColumn { Text = "Value", Name = ValueColumn, Visible = true, Width = 59, Type = InputRoll.RollColumn.InputType.Text }, + new InputRoll.RollColumn { Text = "Compare", Name = CompareColumn, Visible = true, Width = 63, Type = InputRoll.RollColumn.InputType.Text }, + new InputRoll.RollColumn { Text = "Compare Type", Name = ComparisonTypeColumn, Visible = true, Width = 98, Type = InputRoll.RollColumn.InputType.Text }, + new InputRoll.RollColumn { Text = "On", Name = OnColumn, Visible = false, Width = 28, Type = InputRoll.RollColumn.InputType.Text }, + new InputRoll.RollColumn { Text = "Size", Name = SizeColumn, Visible = true, Width = 55, Type = InputRoll.RollColumn.InputType.Text }, + new InputRoll.RollColumn { Text = "Endian", Name = EndianColumn, Visible = false, Width = 55, Type = InputRoll.RollColumn.InputType.Text }, + new InputRoll.RollColumn { Text = "Display Type", Name = TypeColumn, Visible = false, Width = 88, Type = InputRoll.RollColumn.InputType.Text } }; } - public ColumnList Columns { get; set; } + public List Columns { get; set; } } } } From 83032a363bde2cd88e189bd3ceff06290177f0ce Mon Sep 17 00:00:00 2001 From: adelikat Date: Sat, 19 Oct 2019 09:16:45 -0500 Subject: [PATCH 050/166] Ram Watch - hack for backwards config compatibility --- BizHawk.Client.EmuHawk/tools/Watch/RamWatch.cs | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/BizHawk.Client.EmuHawk/tools/Watch/RamWatch.cs b/BizHawk.Client.EmuHawk/tools/Watch/RamWatch.cs index 6c5f3f3a2c..7377d33b4c 100644 --- a/BizHawk.Client.EmuHawk/tools/Watch/RamWatch.cs +++ b/BizHawk.Client.EmuHawk/tools/Watch/RamWatch.cs @@ -1099,6 +1099,12 @@ namespace BizHawk.Client.EmuHawk private void NewRamWatch_Load(object sender, EventArgs e) { + // Hack for previous config settings + if (Settings.Columns.Any(c => string.IsNullOrWhiteSpace(c.Text))) + { + Settings = new RamWatchSettings(); + } + TopMost = Settings.TopMost; _watches = new WatchList(MemoryDomains, Emu.SystemId); LoadConfigSettings(); From d6972d125290f569798918ac1c9f621ce6c87453 Mon Sep 17 00:00:00 2001 From: adelikat Date: Sat, 19 Oct 2019 09:50:21 -0500 Subject: [PATCH 051/166] Lua Console - use InputRolle, fix all kinds of bugs with using Separators --- BizHawk.Client.Common/lua/LuaFile.cs | 5 + BizHawk.Client.Common/lua/LuaFileList.cs | 18 ++- .../BizHawk.Client.EmuHawk.csproj | 1 + .../Properties/Resources.Designer.cs | 12 +- .../Properties/Resources.resx | 3 + .../tools/Lua/LuaConsole.Designer.cs | 45 +----- .../tools/Lua/LuaConsole.cs | 145 ++++++++++-------- 7 files changed, 119 insertions(+), 110 deletions(-) diff --git a/BizHawk.Client.Common/lua/LuaFile.cs b/BizHawk.Client.Common/lua/LuaFile.cs index 63ae59c75e..dddb59a85d 100644 --- a/BizHawk.Client.Common/lua/LuaFile.cs +++ b/BizHawk.Client.Common/lua/LuaFile.cs @@ -48,6 +48,11 @@ public void Stop() { + if (Thread == null) + { + return; + } + State = RunState.Disabled; //if(NLua.Lua.WhichLua == "NLua") Thread.GetTable("keepalives")[Thread] = null; diff --git a/BizHawk.Client.Common/lua/LuaFileList.cs b/BizHawk.Client.Common/lua/LuaFileList.cs index 678a4c7809..a8148df357 100644 --- a/BizHawk.Client.Common/lua/LuaFileList.cs +++ b/BizHawk.Client.Common/lua/LuaFileList.cs @@ -140,11 +140,19 @@ namespace BizHawk.Client.Common var sb = new StringBuilder(); foreach (var file in this) { - sb - .Append(file.Enabled ? "1" : "0") - .Append(' ') - .Append(PathManager.MakeRelativeTo(PathManager.MakeAbsolutePath(file.Path, ""), Path.GetDirectoryName(path))) - .AppendLine(); + if (file.IsSeparator) + { + sb.AppendLine("---"); + } + else + { + sb + .Append(file.Enabled ? "1" : "0") + .Append(' ') + .Append(PathManager.MakeRelativeTo(PathManager.MakeAbsolutePath(file.Path, "") + , Path.GetDirectoryName(path))) + .AppendLine(); + } } sw.Write(sb.ToString()); diff --git a/BizHawk.Client.EmuHawk/BizHawk.Client.EmuHawk.csproj b/BizHawk.Client.EmuHawk/BizHawk.Client.EmuHawk.csproj index 4e5ecd01d7..004021caf8 100644 --- a/BizHawk.Client.EmuHawk/BizHawk.Client.EmuHawk.csproj +++ b/BizHawk.Client.EmuHawk/BizHawk.Client.EmuHawk.csproj @@ -1892,6 +1892,7 @@ + diff --git a/BizHawk.Client.EmuHawk/Properties/Resources.Designer.cs b/BizHawk.Client.EmuHawk/Properties/Resources.Designer.cs index d9e97b6eff..022c725cc6 100644 --- a/BizHawk.Client.EmuHawk/Properties/Resources.Designer.cs +++ b/BizHawk.Client.EmuHawk/Properties/Resources.Designer.cs @@ -19,7 +19,7 @@ namespace BizHawk.Client.EmuHawk.Properties { // class via a tool like ResGen or Visual Studio. // To add or remove a member, edit your .ResX file then rerun ResGen // with the /str option, or rebuild your VS project. - [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "15.0.0.0")] + [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "16.0.0.0")] [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] internal class Resources { @@ -1479,6 +1479,16 @@ namespace BizHawk.Client.EmuHawk.Properties { } } + /// + /// Looks up a localized resource of type System.Drawing.Bitmap. + /// + internal static System.Drawing.Bitmap StopButton { + get { + object obj = ResourceManager.GetObject("StopButton", resourceCulture); + return ((System.Drawing.Bitmap)(obj)); + } + } + /// /// Looks up a localized resource of type System.Drawing.Bitmap. /// diff --git a/BizHawk.Client.EmuHawk/Properties/Resources.resx b/BizHawk.Client.EmuHawk/Properties/Resources.resx index 1876bfb3b7..610b6c155b 100644 --- a/BizHawk.Client.EmuHawk/Properties/Resources.resx +++ b/BizHawk.Client.EmuHawk/Properties/Resources.resx @@ -1563,4 +1563,7 @@ ..\Resources\MoveTop.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + ..\images\StopButton.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + \ No newline at end of file diff --git a/BizHawk.Client.EmuHawk/tools/Lua/LuaConsole.Designer.cs b/BizHawk.Client.EmuHawk/tools/Lua/LuaConsole.Designer.cs index 01816fd1c6..f5388aabd7 100644 --- a/BizHawk.Client.EmuHawk/tools/Lua/LuaConsole.Designer.cs +++ b/BizHawk.Client.EmuHawk/tools/Lua/LuaConsole.Designer.cs @@ -104,10 +104,7 @@ this.InsertSeparatorToolbarItem = new System.Windows.Forms.ToolStripButton(); this.toolStripSeparator10 = new System.Windows.Forms.ToolStripSeparator(); this.EraseToolbarItem = new System.Windows.Forms.ToolStripButton(); - this.LuaListView = new BizHawk.Client.EmuHawk.VirtualListView(); - this.Script = ((System.Windows.Forms.ColumnHeader)(new System.Windows.Forms.ColumnHeader())); - this.PathName = ((System.Windows.Forms.ColumnHeader)(new System.Windows.Forms.ColumnHeader())); - this.imageList1 = new System.Windows.Forms.ImageList(this.components); + this.LuaListView = new InputRoll(); this.splitContainer1 = new System.Windows.Forms.SplitContainer(); this.CopyContextItem = new System.Windows.Forms.ToolStripMenuItem(); this.ScriptListContextMenu.SuspendLayout(); @@ -805,47 +802,20 @@ this.LuaListView.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom) | System.Windows.Forms.AnchorStyles.Left) | System.Windows.Forms.AnchorStyles.Right))); - this.LuaListView.BlazingFast = false; - this.LuaListView.Columns.AddRange(new System.Windows.Forms.ColumnHeader[] { - this.Script, - this.PathName}); + this.LuaListView.AllowColumnResize = true; + this.LuaListView.AllowColumnReorder = false; this.LuaListView.ContextMenuStrip = this.ScriptListContextMenu; this.LuaListView.FullRowSelect = true; this.LuaListView.GridLines = true; - this.LuaListView.HideSelection = false; - this.LuaListView.ItemCount = 0; + this.LuaListView.RowCount = 0; this.LuaListView.Location = new System.Drawing.Point(4, 21); this.LuaListView.Name = "LuaListView"; - this.LuaListView.SelectAllInProgress = false; - this.LuaListView.selectedItem = -1; this.LuaListView.Size = new System.Drawing.Size(273, 271); - this.LuaListView.SmallImageList = this.imageList1; this.LuaListView.TabIndex = 0; - this.LuaListView.UseCompatibleStateImageBehavior = false; this.LuaListView.UseCustomBackground = true; - this.LuaListView.View = System.Windows.Forms.View.Details; - this.LuaListView.ColumnClick += new System.Windows.Forms.ColumnClickEventHandler(this.LuaListView_ColumnClick); - this.LuaListView.ItemActivate += new System.EventHandler(this.LuaListView_ItemActivate); + this.LuaListView.ColumnClick += new BizHawk.Client.EmuHawk.InputRoll.ColumnClickEventHandler(this.LuaListView_ColumnClick); this.LuaListView.KeyDown += new System.Windows.Forms.KeyEventHandler(this.LuaListView_KeyDown); // - // Script - // - this.Script.Text = "Script"; - this.Script.Width = 92; - // - // PathName - // - this.PathName.Text = "Path"; - this.PathName.Width = 195; - // - // imageList1 - // - this.imageList1.ImageStream = ((System.Windows.Forms.ImageListStreamer)(resources.GetObject("imageList1.ImageStream"))); - this.imageList1.TransparentColor = System.Drawing.Color.Transparent; - this.imageList1.Images.SetKeyName(0, "StopButton.png"); - this.imageList1.Images.SetKeyName(1, "PlayButton.png"); - this.imageList1.Images.SetKeyName(2, "Pause.png"); - // // splitContainer1 // this.splitContainer1.Dock = System.Windows.Forms.DockStyle.Fill; @@ -910,8 +880,7 @@ #endregion - private VirtualListView LuaListView; - private System.Windows.Forms.ColumnHeader PathName; + private InputRoll LuaListView; private MenuStripEx menuStrip1; private System.Windows.Forms.ToolStripMenuItem FileSubMenu; private System.Windows.Forms.ToolStripMenuItem SaveSessionMenuItem; @@ -921,7 +890,6 @@ private System.Windows.Forms.ToolStripMenuItem ScriptSubMenu; private System.Windows.Forms.ToolStripMenuItem EditScriptMenuItem; private System.Windows.Forms.ToolStripMenuItem ToggleScriptMenuItem; - public System.Windows.Forms.ColumnHeader Script; private System.Windows.Forms.GroupBox groupBox1; private System.Windows.Forms.ToolStripMenuItem NewSessionMenuItem; private System.Windows.Forms.ToolStripMenuItem SettingsSubMenu; @@ -980,7 +948,6 @@ private System.Windows.Forms.ToolStripMenuItem DuplicateScriptMenuItem; private System.Windows.Forms.TextBox InputBox; private System.Windows.Forms.SplitContainer splitContainer1; - private System.Windows.Forms.ImageList imageList1; private System.Windows.Forms.ToolStripMenuItem ReturnAllIfNoneSelectedMenuItem; private System.Windows.Forms.ToolStripMenuItem RemoveRegisteredFunctionsOnToggleMenuItem; private System.Windows.Forms.ToolStripMenuItem ReloadWhenScriptFileChangesMenuItem; diff --git a/BizHawk.Client.EmuHawk/tools/Lua/LuaConsole.cs b/BizHawk.Client.EmuHawk/tools/Lua/LuaConsole.cs index 63ff408725..4478babacc 100644 --- a/BizHawk.Client.EmuHawk/tools/Lua/LuaConsole.cs +++ b/BizHawk.Client.EmuHawk/tools/Lua/LuaConsole.cs @@ -18,6 +18,10 @@ namespace BizHawk.Client.EmuHawk { public partial class LuaConsole : ToolFormBase, IToolFormAutoConfig { + private const string IconColumnName = "Icon"; + private const string ScriptColumnName = "Script"; + private const string PathColumnName = "PathName"; + [RequiredService] private IEmulator Emulator { get; set; } @@ -33,14 +37,15 @@ namespace BizHawk.Client.EmuHawk { public LuaConsoleSettings() { - Columns = new ToolDialogSettings.ColumnList + Columns = new List { - new ToolDialogSettings.Column { Name = "Script", Visible = true, Index = 0, Width = 92 }, - new ToolDialogSettings.Column { Name = "PathName", Visible = true, Index = 0, Width = 195 } + new InputRoll.RollColumn { Name = IconColumnName, Text = " ", Visible = true, Width = 22, Type = InputRoll.RollColumn.InputType.Image }, + new InputRoll.RollColumn { Name = ScriptColumnName, Text = "Script", Visible = true, Width = 92, Type = InputRoll.RollColumn.InputType.Text }, + new InputRoll.RollColumn { Name = PathColumnName, Text = "Path", Visible = true, Width = 300, Type = InputRoll.RollColumn.InputType.Text } }; } - public ToolDialogSettings.ColumnList Columns { get; set; } + public List Columns { get; set; } } [ConfigPersist] @@ -58,7 +63,7 @@ namespace BizHawk.Client.EmuHawk { if (AskSaveChanges()) { - SaveColumnInfo(LuaListView, Settings.Columns); + Settings.Columns = LuaListView.AllColumns; GlobalWin.DisplayManager.ClearLuaSurfaces(); @@ -85,9 +90,7 @@ namespace BizHawk.Client.EmuHawk LuaListView.QueryItemText += LuaListView_QueryItemText; LuaListView.QueryItemBkColor += LuaListView_QueryItemBkColor; - LuaListView.QueryItemImage += LuaListView_QueryItemImage; - LuaListView.QueryItemIndent += LuaListView_QueryItemIndent; - LuaListView.VirtualMode = true; + LuaListView.QueryItemIcon += LuaListView_QueryItemImage; // this is bad, in case we ever have more than one gui part running lua.. not sure how much other badness there is like that LuaSandbox.DefaultLogger = ConsoleLog; @@ -99,7 +102,7 @@ namespace BizHawk.Client.EmuHawk private IEnumerable SelectedItems { - get { return LuaListView.SelectedIndices().Select(index => LuaImp.ScriptList[index]); } + get { return LuaListView.SelectedRows.Select(index => LuaImp.ScriptList[index]); } } private IEnumerable SelectedFiles @@ -129,6 +132,12 @@ namespace BizHawk.Client.EmuHawk private void LuaConsole_Load(object sender, EventArgs e) { + // Hack for previous config settings + if (Settings.Columns.Any(c => string.IsNullOrWhiteSpace(c.Text))) + { + Settings = new LuaConsoleSettings(); + } + LuaImp.ScriptList.ChangedCallback = SessionChangedCallback; LuaImp.ScriptList.LoadCallback = ClearOutputWindow; @@ -144,7 +153,7 @@ namespace BizHawk.Client.EmuHawk } } - LoadColumnInfo(LuaListView, Settings.Columns); + SetColumns(); } public void Restart() @@ -217,10 +226,21 @@ namespace BizHawk.Client.EmuHawk private readonly List _watches = new List(); + private void SetColumns() + { + foreach (var column in Settings.Columns) + { + if (LuaListView.AllColumns[column.Name] == null) + { + LuaListView.AllColumns.Add(column); + } + } + } + private void AddFileWatches() { _watches.Clear(); - foreach (var item in LuaImp.ScriptList) + foreach (var item in LuaImp.ScriptList.Where(s => !s.IsSeparator)) { var processedPath = PathManager.TryMakeRelative(item.Path); string pathToLoad = ProcessPath(processedPath); @@ -263,7 +283,7 @@ namespace BizHawk.Client.EmuHawk var luaFile = new LuaFile("", processedPath); LuaImp.ScriptList.Add(luaFile); - LuaListView.ItemCount = LuaImp.ScriptList.Count; + LuaListView.RowCount = LuaImp.ScriptList.Count; Global.Config.RecentLua.Add(processedPath); if (!Global.Config.DisableLuaScriptsOnLoad) @@ -297,7 +317,7 @@ namespace BizHawk.Client.EmuHawk private void UpdateDialog() { - LuaListView.ItemCount = LuaImp.ScriptList.Count; + LuaListView.RowCount = LuaImp.ScriptList.Count; LuaListView.Refresh(); UpdateNumberOfScripts(); UpdateRegisteredFunctionsDialog(); @@ -305,7 +325,7 @@ namespace BizHawk.Client.EmuHawk private void RunLuaScripts() { - foreach (var file in LuaImp.ScriptList) + foreach (var file in LuaImp.ScriptList.Where(s => !s.IsSeparator)) { if (!file.Enabled && file.Thread == null) { @@ -340,62 +360,62 @@ namespace BizHawk.Client.EmuHawk Path.GetFileName(LuaImp.ScriptList.Filename); } - private void LuaListView_QueryItemImage(int item, int subItem, out int imageIndex) + private void LuaListView_QueryItemImage(int index, InputRoll.RollColumn column, ref Bitmap bitmap, ref int offsetX, ref int offsetY) { - imageIndex = -1; - if (subItem != 0) + if (column.Name != IconColumnName) { return; } - if (LuaImp.ScriptList[item].Paused) + if (LuaImp.ScriptList[index].IsSeparator) { - imageIndex = 2; + return; } - else if (LuaImp.ScriptList[item].Enabled) + + if (LuaImp.ScriptList[index].Paused) { - imageIndex = 1; + bitmap = Properties.Resources.Pause; + } + else if (LuaImp.ScriptList[index].Enabled) + { + bitmap = Properties.Resources.ts_h_arrow_green; } else { - imageIndex = 0; + bitmap = Properties.Resources.StopButton; } } - private void LuaListView_QueryItemIndent(int item, out int itemIndent) + private void LuaListView_QueryItemBkColor(int index, InputRoll.RollColumn column, ref Color color) { - itemIndent = 0; - } - - private void LuaListView_QueryItemBkColor(int index, int column, ref Color color) - { - if (column == 0) + if (LuaImp.ScriptList[index].IsSeparator) { - if (LuaImp.ScriptList[index].IsSeparator) - { - color = BackColor; - } - else if (LuaImp.ScriptList[index].Enabled && !LuaImp.ScriptList[index].Paused) - { - color = Color.LightCyan; - } - else if (LuaImp.ScriptList[index].Enabled && LuaImp.ScriptList[index].Paused) - { - color = Color.LightPink; - } + color = BackColor; + } + else if (LuaImp.ScriptList[index].Enabled && !LuaImp.ScriptList[index].Paused) + { + color = Color.LightCyan; + } + else if (LuaImp.ScriptList[index].Enabled && LuaImp.ScriptList[index].Paused) + { + color = Color.LightPink; } - - UpdateNumberOfScripts(); } - private void LuaListView_QueryItemText(int index, int column, out string text) + private void LuaListView_QueryItemText(int index, InputRoll.RollColumn column, out string text, ref int offsetX, ref int offsetY) { text = ""; - if (column == 0) + + if (LuaImp.ScriptList[index].IsSeparator) + { + return; + } + + if (column.Name == ScriptColumnName) { text = Path.GetFileNameWithoutExtension(LuaImp.ScriptList[index].Path); // TODO: how about allow the user to name scripts? } - else if (column == 1) + else if (column.Name == PathColumnName) { text = DressUpRelative(LuaImp.ScriptList[index].Path); } @@ -437,9 +457,9 @@ namespace BizHawk.Client.EmuHawk private void UpdateNumberOfScripts() { var message = ""; - var total = SelectedFiles.Count(); - var active = LuaImp.ScriptList.Count(file => file.Enabled); - var paused = LuaImp.ScriptList.Count(file => file.Enabled && file.Paused); + var total = LuaImp.ScriptList.Count(file => !file.IsSeparator); + var active = LuaImp.ScriptList.Count(file => !file.IsSeparator && file.Enabled); + var paused = LuaImp.ScriptList.Count(file => !file.IsSeparator && file.Enabled && file.Paused); if (total == 1) { @@ -780,7 +800,7 @@ namespace BizHawk.Client.EmuHawk DuplicateScriptMenuItem.Enabled = MoveUpMenuItem.Enabled = MoveDownMenuItem.Enabled = - LuaListView.SelectedIndices().Any(); + LuaListView.SelectedRows.Any(); SelectAllMenuItem.Enabled = LuaImp.ScriptList.Any(); StopAllScriptsMenuItem.Enabled = LuaImp.ScriptList.Any(script => script.Enabled); @@ -946,7 +966,7 @@ namespace BizHawk.Client.EmuHawk private void DuplicateScriptMenuItem_Click(object sender, EventArgs e) { - if (LuaListView.SelectedIndices().Any()) + if (LuaListView.SelectedRows.Any()) { var script = SelectedFiles.First(); @@ -976,7 +996,7 @@ namespace BizHawk.Client.EmuHawk private void InsertSeparatorMenuItem_Click(object sender, EventArgs e) { - var indices = LuaListView.SelectedIndices().ToList(); + var indices = LuaListView.SelectedRows.ToList(); if (indices.Any() && indices.Last() < LuaImp.ScriptList.Count) { LuaImp.ScriptList.Insert(indices.Last(), LuaFile.SeparatorInstance); @@ -991,7 +1011,7 @@ namespace BizHawk.Client.EmuHawk private void MoveUpMenuItem_Click(object sender, EventArgs e) { - var indices = LuaListView.SelectedIndices().ToList(); + var indices = LuaListView.SelectedRows.ToList(); if (indices.Count == 0 || indices[0] == 0) { return; @@ -1006,10 +1026,10 @@ namespace BizHawk.Client.EmuHawk var newIndices = indices.Select(t => t - 1); - LuaListView.SelectedIndices.Clear(); + LuaListView.DeselectAll(); foreach (var i in newIndices) { - LuaListView.SelectItem(i, true); + LuaListView.SelectRow(i, true); } UpdateDialog(); @@ -1017,7 +1037,7 @@ namespace BizHawk.Client.EmuHawk private void MoveDownMenuItem_Click(object sender, EventArgs e) { - var indices = LuaListView.SelectedIndices().ToList(); + var indices = LuaListView.SelectedRows.ToList(); if (indices.Count == 0 || indices.Last() == LuaImp.ScriptList.Count - 1) { return; @@ -1032,10 +1052,10 @@ namespace BizHawk.Client.EmuHawk var newIndices = indices.Select(t => t + 1); - LuaListView.SelectedIndices.Clear(); + LuaListView.DeselectAll(); foreach (var i in newIndices) { - LuaListView.SelectItem(i, true); + LuaListView.SelectRow(i, true); } UpdateDialog(); @@ -1280,11 +1300,6 @@ namespace BizHawk.Client.EmuHawk } } - private void LuaListView_ItemActivate(object sender, EventArgs e) - { - ToggleScriptMenuItem_Click(sender, e); - } - private void OutputBox_KeyDown(object sender, KeyEventArgs e) { if (e.KeyCode == Keys.F12 && !e.Control && !e.Alt && !e.Shift) // F12 @@ -1296,9 +1311,9 @@ namespace BizHawk.Client.EmuHawk /// /// Sorts the column Ascending on the first click and Descending on the second click. /// - private void LuaListView_ColumnClick(object sender, ColumnClickEventArgs e) + private void LuaListView_ColumnClick(object sender, InputRoll.ColumnClickEventArgs e) { - var columnToSort = LuaListView.Columns[e.Column].Text; + var columnToSort = e.Column.Name; var luaListTemp = new List(); if (columnToSort != _lastColumnSorted) { From 571c172bd4d0d40b5f31fab094def456c3893913 Mon Sep 17 00:00:00 2001 From: adelikat Date: Sat, 19 Oct 2019 09:54:38 -0500 Subject: [PATCH 052/166] remove image stuff from lua console .resx --- .../tools/Lua/LuaConsole.resx | 72 ------------------- 1 file changed, 72 deletions(-) diff --git a/BizHawk.Client.EmuHawk/tools/Lua/LuaConsole.resx b/BizHawk.Client.EmuHawk/tools/Lua/LuaConsole.resx index 7d82bb08eb..4b0fdcdf07 100644 --- a/BizHawk.Client.EmuHawk/tools/Lua/LuaConsole.resx +++ b/BizHawk.Client.EmuHawk/tools/Lua/LuaConsole.resx @@ -144,78 +144,6 @@ S+GOLQu6U6BFjPvqKOP1AYw88WOoZif9DgmfLVtxaj1RSLdwNvrkPCA3M54KqxrnvRia9MKcGrUrqFOt 5H7qKsqT1mGO9+Lqhc2ELdw+U/r0i+gVZ8hMiCDx3DHORwZyKnQ/hw/uYt9uCTskPvh6e7Fp41rWr/Fg g6eHO+A/lyD8ARfG3mk9fv1YAAAAAElFTkSuQmCC - - - - 489, 17 - - - - AAEAAAD/////AQAAAAAAAAAMAgAAAFdTeXN0ZW0uV2luZG93cy5Gb3JtcywgVmVyc2lvbj00LjAuMC4w - LCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODkFAQAAACZTeXN0 - ZW0uV2luZG93cy5Gb3Jtcy5JbWFnZUxpc3RTdHJlYW1lcgEAAAAERGF0YQcCAgAAAAkDAAAADwMAAABi - DgAAAk1TRnQBSQFMAgEBAwEAAVgBAAFYAQABEAEAARABAAT/ASEBAAj/AUIBTQE2BwABNgMAASgDAAFA - AwABEAMAAQEBAAEgBgABECoAAWUBWwFdAeUBsgG0AdIB/wG7Ab4B1wH/AWYCXAHnMAABZQFdAVsB5QGy - AdIBtgH/AbsB1wG+Af8BZgJcAecwAAFnAlsB5QHSAb4BsgH/AdcBxQG7Af8BaQJcAedoAAFoAVkBbQH1 - ATUBPAGXAf8BAQEMAYcB/wECAQwBhwH/AQABCwGHAf8BBwERAYgB/wEKARQBiQH/AWkBXgGEAfkgAAFo - AW0BWQH1ATUBlwFBAf8BAQGHARAB/wECAYcBEQH/AQABhwEOAf8BBwGIARUB/wEKAYkBGAH/AWkBhAFe - AfkgAAF+AWABWQH1AZcBVwE1Af8BhwEvAQEB/wGHATABAgH/AYcBLgEAAf8BiAEzAQcB/wGJATYBCgH/ - AYsBaAFaAflcAAEwATgBmAH/AS0BNQGYAf8BsAGyAcsB/wHaAdsB2gH/AtEB1QH/AcsBzAHSAf8BxAHH - Ac4B/wFUAVoBpQH/AUcBRQFqAfkBJQEuAY8B/xgAASIBkgEuAf8BLQGYATkB/wGwAcsBswH/AdsC2gH/ - AdEB1QHSAf8BywHSAcsB/wHFAc4BxAH/AVQBpQFdAf8BRwFqAUYB+QElAY8BMAH/GAABkgFIASIB/wGY - AVIBLQH/AcsBugGwAf8C2gHbAf8B1QHTAdEB/wHSAc0BywH/Ac4BxgHEAf8BpQFvAVQB/wGEAVwBQQH5 - AY8BSAElAf9UAAJAAY0B/QFiAlgB4wL+Af0B/wH+Af0B9QH/AvcB8wH/Ae8C7gH/Au0B6wH/AdkC2wH/ - AeMB5AHiAf8CwAHMAf8BZgFYAV0B7QFMAUkBeQH7EAABQAGNAUAB/QFiAlgB4wH/Af4C/wH+AfUB/QH/ - AfcB8wH2Af8C7gHvAf8B7QHrAe0B/wLbAdkB/wHkAeIB4wH/AcABzAHCAf8BZgFdAVgB7QFMAXkBSwH7 - EAABkwFGAUAB/QFkAlgB4wH+A/8B9QH7Af4B/wHzAfUB9wH/Ae4B7wHuAf8B6wHsAe0B/wHbAdkB2gH/ - AuIB5AH/AcwBxQHAAf8BagFZAVcB7QGGAVkBQwH7TAABagFdAWwB8wFqAVkBYAHrBf8B/gH9F/8B/gH/ - AfAB7wHwAf8BzwHQAdYB/wFjAVQBXQHtAWQBWAFiAe8IAAFqAWwBXQHzAWoBYAFZAesF/wH9Bv8B4wHw - AeMB/wGcAc0BnAr/Af4C/wHvAvAB/wHPAdYBzwH/AWMBXQFUAe0BZAFiAVgB7wgAAXsBXwFdAfMBbgFg - AVkB6wT/Af0X/wH+A/8C4wHgAf8BzwHJAccB/wFpAVgBUwHtAWwCWAHvSAABagFeAYkB+QP+Jf8B8AHy - AfAB/wLGAc0B/wFHAUEBagH5CAABagGJAV4B+RD/AdwB7QHcAf8BDQF1AQ0B/wGDAcEBgw3/AfIB8QHw - Af8BxwHOAcgB/wFHAWoBQQH5CAABjAFqAV4B+Qz/AeEBzQG+Af8BvgGSAY0B/wH3AfEB7wH/AfsB+AH3 - Af8BwQGYAY8B/wHqAdoB0QX/AeUB4gHmAf8BzgHKAccB/wGAAVcBQQH5RAABbwFfAXAB8wFqAV0BYwHt - CP8C9QH7Af8BaQFlAdQB/wGhAZ8B5wH/AaMBoQHmAf8BogGhAeUB/wGUAZEB4QH/AZ4BnAHmBf8B+QH4 - AfcB/wHnAeQB3gH/AVkBVwFqAfUBXQFZAYkB+wFvAXABXwHzAWoBYwFdAe0Q/wHkAfEB5AH/AQABcQEA - Af8BDQF3AQ0B/wGcAc4BnAn/AfkB9wH5Af8B5gHeAecB/wFZAWoBWQH1AV0BiQFZAfsBgAFoAV8B8wFx - Al0B7Qz/Aa4BcgFQAf8BVQIAAf8B+AH1AfIB/wH6AfcB9QH/AVUCAAH/AbMBdwFWBf8B8QH0AfUB/wHe - AeYB5wH/AXQBWQFUAfUBkQFfAVQB+0AAAYIBiAHKAf8B0AHSAe0J/wL1AfoB/wE3ATQBuwH/AWMBYAHe - Af8BYAFcAdgB/wFbAVcB0wH/AU8BSgHRAf8BogGhAekF/wL5AfgB/wH8AfsB6gH/AaMBpgG+Af8BPwFG - AaAB/wGCAcoBigH/AdAB7QHUEf8B4gHwAeIB/wEAAXIBAAH/AQABcgEAAf8BDQGEAQ0B/wGYAcwBmAX/ - AfkB+AH5Af8B/AHqAfoB/wGjAb4BpQH/AT8BoAFKAf8BygGcAYIB/wHtAdsB0A3/AboBjAFmAf8BjQEe - AQAC/wL+Af8D/gH/AY0BHQEAAf8BuwGJAWQF/wHyAfQB9QH/AeoB9QH8Af8BvgGsAaMB/wGgAWABPwH/ - QAABcAF2AcIB/wHlAeYB9An/AvcB+wH/AUYBQwHDAf8BcQFvAeMB/wFsAWkB3QH/AWcBZAHYAf8BWwFW - AdMB/wGrAakB6gX/A/kB/wH+AfsB7wH/AbQBtgHFAf8BPQFFAZ8B/wFwAcIBgQH/AeUB9AHnEf8B4gHw - AeIB/wEAAXQBAAH/AQABdgEAAf8BAAFuAQAB/wENAYQBDQH/AfoB/AH6Af8D+QH/Af4B7wH+Af8BtAHF - AbYB/wE9AZ8BSAH/AcIBkwFwAf8B9AHrAeUN/wG5AYwBZwH/AacBNAEHAf8B+wH5AfgB/wH7AfoB+QH/ - AacBNAEHAf8BvQGMAWcF/wP0Af8B7wH6Af4B/wHFAboBtAH/AZ8BXgE9Af9AAAFsAXMBvQH/AtoB7wn/ - AvcB+wH/AUoBRwHHAf8BdwF1AeoB/wFyAXEB4wH/AW8BbQHfAf8BYgFfAdoB/wGtAasB6wX/AvoB+AH/ - Af0B/AHuAf8BnQGgAbsB/wFFAU0BowH/AWwBvQF0Af8B2gHvAd4R/wHiAfAB4gH/AQABdAEAAf8BAAFs - AQAB/wEoAY4BKAH/AeIB8AHiBf8B+gH4AfoB/wH9Ae4B+wH/AZ0BuwGhAf8BRQGjAU4B/wG9AY4BbAH/ - Ae8B4wHaDf8BtwGIAWIB/wHEAUMBIAH/Av0B/AH/AfwB+gH5Af8BxgFGASIB/wHCAY8BbAX/AfIB9QH3 - Af8B7gH3Af0B/wG7AagBnQH/AaMBZAFFAf9AAAFoAVgBYwHvAXMBZAFuAfEI/wL2AfsB/wFHAUMBxQH/ - AXYBdQHrAf8BcgFxAeQB/wFwAW0B4QH/AWABXQHbAf8BqQGnAesF/wL7AfkB/wH7AfwB7gH/AU0BSgGB - AfsBZQFYAWIB7wFoAWMBWAHvAXMBbgFkAfEQ/wHiAfAB4gH/AQABagEAAf8BJAGHASQB/wHnAfMB5wn/ - AfsB+QH7Af8B/AHuAfkB/wFNAYEBTAH7AWUBYgFYAe8BcgFiAVgB7wGAAWUBZAHxDP8BwQGXAXYB/wGk - AToBEgH/Af0B+wH6Af8B/AH6AfkB/wGTATUBCwH/AcwBqQGUBf8B9AH3AfkB/wHuAfUB/AH/AYoBWQFF - AfsBcAJYAe9EAAF3AYEBzwn/AvMB+QH/AUUBQgG5Af8BhwGGAdYB/wGHAYUB1QH/AYcBhQHVAf8BYQFe - AcgB/wFpAWgBzAb/Af4B/AH/As4B1wH/ATUBPQGYAf8IAAF3Ac8BjRH/AdMB6AHTAf8BIAGHASAB/wHi - AfAB4g3/Af4B/AL/Ac4B1wHQAf8BNQGYAT8B/wgAAc8BoQF3Kf8B+wP/AdcB0gHOAf8BmAFWATUB/0gA - AYIBagGQAfkBewFlAXQB8ST/AfwB+wH2Af8BMwE7AZYB/wFlAVgBWwHpCAABggGQAWoB+QF7AXQBbQHx - DP8B+gH8AfoB/wHvAfYB7xH/AfwB9gH8Af8BMwGWAT0B/wFlAVsBWAHpCAABngGBAWoB+QGCAW0BZQHx - JP8B9QH6AfwB/wGWAVQBMwH/AWoCWAHpTAACgwG4Af0BagFdAWIB6Rz/AfIB9QH4Af8CWQFqAfUBaQFZ - AW4B9RAAAYMBuAGIAf0BagFiAV0B6Rz/AfQB+AHyAf8BWQFqAVkB9QFpAW4BWQH1EAABugGdAXEB/QFs - AV8BXQHpHP8B+ALyAf8BdwFZAUsB9QGAAWABWQH1VAABdgFtAZsB+wGJAXcBmQH5AtMB9wH/AfEB8AH7 - Af8B9gH3Av8B9wH4Af0B/wHkAecB8wH/AWUBWAFiAe8BbAFfAWwB8wFrAVkBYAHrGAABdgGbAXkB+wGJ - AZkBhAH5AdMB9wHaAf8B8AH7AfMB/wH2Af8B9wH/AfcB/QH4Af8B5AHzAeQB/wFlAWIBWAHvAmwBXwHz - AWsBYAFZAesYAAGjAYgBZgH7AaUBiwF0AfkB9wHjAdMB/wH7AfYB8AL/AfkB9gH/Af0B+QH3Af8B8wHo - AeQB/wFwAlgB7wF8Al8B8wFxAWABWQHrXAABbgFgAWIB6wGNAZMB1wH/AY4BlAHdAf8BjwGVAeAB/wGN - AZQB2wH/AZoBnwHaAf8BZgJcAeckAAFuAWIBYAHrAY0B1wGWAf8BjgHdAZgB/wGPAeABmQH/AY0B2wGW - Af8BmgHaAaIB/wFmAlwB5yQAAXMCYAHrAdcBqAGNAf8B3QGsAY4B/wHgAa0BjwH/AdsBqQGNAf8B2gGy - AZoB/wFpAlwB51QAAUIBTQE+BwABPgMAASgDAAFAAwABEAMAAQEBAAEBBQABgBcAA/8BAAH8AT8B/AE/ - AfwBPwIAAfABDwHwAQ8B8AEPAgAB4AEHAeABBwHgAQcCAAHAAQMBwAEDAcABAwIAAYABAQGAAQEBgAEB - AgABgAEBAYABAQGAAQEqAAGAAQEBgAEBAYABAQIAAYABAQGAAQEBgAEBAgABwAEDAcABAwHAAQMCAAHg - AQcB4AEHAeABBwIAAfABHwHwAR8B8AEfAgAL From f802f4875449e429b3e2aecb699afaab333388b2 Mon Sep 17 00:00:00 2001 From: adelikat Date: Sat, 19 Oct 2019 10:11:04 -0500 Subject: [PATCH 053/166] Lua console - implement double click toggle --- .../tools/Lua/LuaConsole.Designer.cs | 1 + BizHawk.Client.EmuHawk/tools/Lua/LuaConsole.cs | 15 +++++++++++++++ 2 files changed, 16 insertions(+) diff --git a/BizHawk.Client.EmuHawk/tools/Lua/LuaConsole.Designer.cs b/BizHawk.Client.EmuHawk/tools/Lua/LuaConsole.Designer.cs index f5388aabd7..fb7bfd1ac9 100644 --- a/BizHawk.Client.EmuHawk/tools/Lua/LuaConsole.Designer.cs +++ b/BizHawk.Client.EmuHawk/tools/Lua/LuaConsole.Designer.cs @@ -815,6 +815,7 @@ this.LuaListView.UseCustomBackground = true; this.LuaListView.ColumnClick += new BizHawk.Client.EmuHawk.InputRoll.ColumnClickEventHandler(this.LuaListView_ColumnClick); this.LuaListView.KeyDown += new System.Windows.Forms.KeyEventHandler(this.LuaListView_KeyDown); + this.LuaListView.DoubleClick += new System.EventHandler(this.LuaListView_DoubleClick); // // splitContainer1 // diff --git a/BizHawk.Client.EmuHawk/tools/Lua/LuaConsole.cs b/BizHawk.Client.EmuHawk/tools/Lua/LuaConsole.cs index 4478babacc..a018c28797 100644 --- a/BizHawk.Client.EmuHawk/tools/Lua/LuaConsole.cs +++ b/BizHawk.Client.EmuHawk/tools/Lua/LuaConsole.cs @@ -13,6 +13,7 @@ using BizHawk.Client.EmuHawk.ToolExtensions; using BizHawk.Client.EmuHawk.WinFormExtensions; using BizHawk.Common; using BizHawk.Emulation.Common; +using NLua; namespace BizHawk.Client.EmuHawk { @@ -1453,5 +1454,19 @@ namespace BizHawk.Client.EmuHawk } #endregion + + private void LuaListView_DoubleClick(object sender, EventArgs e) + { + var index = LuaListView.CurrentCell?.RowIndex; + if (index < LuaImp.ScriptList.Count) + { + var file = LuaImp.ScriptList[index.Value]; + if (!file.IsSeparator) + { + file.Toggle(); + UpdateDialog(); + } + } + } } } From 6c22e1c4c6b5b4b20b78d0a1f612be72b4de10d8 Mon Sep 17 00:00:00 2001 From: adelikat Date: Sat, 19 Oct 2019 10:45:42 -0500 Subject: [PATCH 054/166] Lua console - implement saving/loading of column info --- BizHawk.Client.Common/BizHawk.Client.Common.csproj | 1 + .../config/RestoreDefaultsAttribute.cs | 12 ++++++++++++ BizHawk.Client.EmuHawk/tools/Lua/LuaConsole.cs | 12 +++++++++++- BizHawk.Client.EmuHawk/tools/ToolManager.cs | 5 +++++ BizHawk.Common/Extensions/ReflectionExtensions.cs | 6 ++++++ 5 files changed, 35 insertions(+), 1 deletion(-) create mode 100644 BizHawk.Client.Common/config/RestoreDefaultsAttribute.cs diff --git a/BizHawk.Client.Common/BizHawk.Client.Common.csproj b/BizHawk.Client.Common/BizHawk.Client.Common.csproj index c866a9a85c..de8ff5983c 100644 --- a/BizHawk.Client.Common/BizHawk.Client.Common.csproj +++ b/BizHawk.Client.Common/BizHawk.Client.Common.csproj @@ -123,6 +123,7 @@ + diff --git a/BizHawk.Client.Common/config/RestoreDefaultsAttribute.cs b/BizHawk.Client.Common/config/RestoreDefaultsAttribute.cs new file mode 100644 index 0000000000..eb8584cd6e --- /dev/null +++ b/BizHawk.Client.Common/config/RestoreDefaultsAttribute.cs @@ -0,0 +1,12 @@ +using System; + +namespace BizHawk.Client.Common +{ + /// + /// Defines a method to be called when a tool dialog's Restore Defaults method is called + /// + [AttributeUsage(AttributeTargets.Method)] + public class RestoreDefaultsAttribute : Attribute + { + } +} diff --git a/BizHawk.Client.EmuHawk/tools/Lua/LuaConsole.cs b/BizHawk.Client.EmuHawk/tools/Lua/LuaConsole.cs index a018c28797..fed33dd0b8 100644 --- a/BizHawk.Client.EmuHawk/tools/Lua/LuaConsole.cs +++ b/BizHawk.Client.EmuHawk/tools/Lua/LuaConsole.cs @@ -134,7 +134,7 @@ namespace BizHawk.Client.EmuHawk private void LuaConsole_Load(object sender, EventArgs e) { // Hack for previous config settings - if (Settings.Columns.Any(c => string.IsNullOrWhiteSpace(c.Text))) + if (Settings.Columns.Any(c => c.Text == null)) { Settings = new LuaConsoleSettings(); } @@ -154,6 +154,7 @@ namespace BizHawk.Client.EmuHawk } } + LuaListView.AllColumns.Clear(); SetColumns(); } @@ -1468,5 +1469,14 @@ namespace BizHawk.Client.EmuHawk } } } + + [RestoreDefaults] + private void RestoreDefaults() + { + Settings = new LuaConsoleSettings(); + LuaListView.AllColumns.Clear(); + SetColumns(); + UpdateDialog(); + } } } diff --git a/BizHawk.Client.EmuHawk/tools/ToolManager.cs b/BizHawk.Client.EmuHawk/tools/ToolManager.cs index e8bc2338ae..2adc46a38f 100644 --- a/BizHawk.Client.EmuHawk/tools/ToolManager.cs +++ b/BizHawk.Client.EmuHawk/tools/ToolManager.cs @@ -323,6 +323,11 @@ namespace BizHawk.Client.EmuHawk settings.RestoreDefaults(); RefreshSettings(form, dest, settings, idx); form.Size = oldsize; + + form.GetType() + .GetMethodsWithAttrib(typeof(RestoreDefaultsAttribute)) + .FirstOrDefault() + ?.Invoke(form, new object[0]); }; } diff --git a/BizHawk.Common/Extensions/ReflectionExtensions.cs b/BizHawk.Common/Extensions/ReflectionExtensions.cs index 505939d717..ec997a25c9 100644 --- a/BizHawk.Common/Extensions/ReflectionExtensions.cs +++ b/BizHawk.Common/Extensions/ReflectionExtensions.cs @@ -19,6 +19,12 @@ namespace BizHawk.Common.ReflectionExtensions .Where(p => p.GetCustomAttributes(attributeType, false).Length > 0); } + public static IEnumerable GetMethodsWithAttrib(this Type type, Type attributeType) + { + return type.GetMethods(BindingFlags.Public | BindingFlags.Instance | BindingFlags.NonPublic) + .Where(p => p.GetCustomAttributes(attributeType, false).Length > 0); + } + /// /// Gets the description attribute from an object /// From 9a4de3b70daae1b1035f006dbc3476dc177b46cb Mon Sep 17 00:00:00 2001 From: adelikat Date: Sat, 19 Oct 2019 10:55:37 -0500 Subject: [PATCH 055/166] remove some now unused methods --- BizHawk.Client.EmuHawk/tools/ToolHelpers.cs | 27 +-------------------- 1 file changed, 1 insertion(+), 26 deletions(-) diff --git a/BizHawk.Client.EmuHawk/tools/ToolHelpers.cs b/BizHawk.Client.EmuHawk/tools/ToolHelpers.cs index 870c8da835..05f3c4e27e 100644 --- a/BizHawk.Client.EmuHawk/tools/ToolHelpers.cs +++ b/BizHawk.Client.EmuHawk/tools/ToolHelpers.cs @@ -1,7 +1,5 @@ -using System; -using System.Collections.Generic; +using System.Collections.Generic; using System.IO; -using System.Linq; using System.Windows.Forms; using BizHawk.Emulation.Common; @@ -105,29 +103,6 @@ namespace BizHawk.Client.EmuHawk e.Effect = e.Data.GetDataPresent(DataFormats.FileDrop) ? DragDropEffects.Copy : DragDropEffects.None; } - protected void LoadColumnInfo(VirtualListView listView, ToolDialogSettings.ColumnList columns) - { - listView.Columns.Clear(); - - var cl = columns - .Where(c => c.Visible) - .OrderBy(c => c.Index); - - foreach (var column in cl) - { - listView.AddColumn(column); - } - } - - protected void SaveColumnInfo(VirtualListView listview, ToolDialogSettings.ColumnList columns) - { - foreach (ColumnHeader column in listview.Columns) - { - columns[column.Name].Index = column.DisplayIndex; - columns[column.Name].Width = column.Width; - } - } - protected void RefreshFloatingWindowControl(bool floatingWindow) { Owner = floatingWindow ? null : GlobalWin.MainForm; From fb2048075cf657155a9b1e4d703062a5f2c78620 Mon Sep 17 00:00:00 2001 From: adelikat Date: Sat, 19 Oct 2019 11:21:34 -0500 Subject: [PATCH 056/166] InputRoll - cutoff text if it overflows the cell --- .../CustomControls/InputRoll.Drawing.cs | 50 ++++++++++++++----- 1 file changed, 38 insertions(+), 12 deletions(-) diff --git a/BizHawk.Client.EmuHawk/CustomControls/InputRoll.Drawing.cs b/BizHawk.Client.EmuHawk/CustomControls/InputRoll.Drawing.cs index b5a2556f7b..068908729e 100644 --- a/BizHawk.Client.EmuHawk/CustomControls/InputRoll.Drawing.cs +++ b/BizHawk.Client.EmuHawk/CustomControls/InputRoll.Drawing.cs @@ -44,6 +44,38 @@ namespace BizHawk.Client.EmuHawk } } + private string Cap(string text, int? width) + { + if (string.IsNullOrEmpty(text) || width == null) + { + return text; + } + + var max = width.Value / (_charSize.Width - CellWidthPadding); + return text.Length < max + ? text + : text.Substring(0, max); + } + + private void DrawString(string text, int? width, Point point) + { + if (string.IsNullOrWhiteSpace(text)) + { + return; + } + + if (width.HasValue) + { + var max = (width.Value - CellWidthPadding) / _charSize.Width; + if (text.Length >= max) + { + text = text.Substring(0, max); + } + } + + _gdi.DrawString(text, point); + } + protected override void OnPaintBackground(PaintEventArgs pevent) { // Do nothing, and this should never be called @@ -105,12 +137,12 @@ namespace BizHawk.Client.EmuHawk if (IsHoveringOnColumnCell && column == CurrentCell.Column) { _gdi.PrepDrawString(_normalFont, SystemColors.HighlightText); - _gdi.DrawString(column.Text, point); + DrawString(column.Text, column.Width, point); _gdi.PrepDrawString(_normalFont, _foreColor); } else { - _gdi.DrawString(column.Text, point); + DrawString(column.Text, column.Width, point); } start += CellHeight; @@ -127,12 +159,12 @@ namespace BizHawk.Client.EmuHawk if (IsHoveringOnColumnCell && column == CurrentCell.Column) { _gdi.PrepDrawString(_normalFont, SystemColors.HighlightText); - _gdi.DrawString(column.Text, point); + DrawString(column.Text, column.Width, point); _gdi.PrepDrawString(_normalFont, _foreColor); } else { - _gdi.DrawString(column.Text, point); + DrawString(column.Text, column.Width, point); } } } @@ -198,10 +230,7 @@ namespace BizHawk.Client.EmuHawk _gdi.PrepDrawString(_rotatedFont, _foreColor); } - if (!string.IsNullOrWhiteSpace(text)) - { - _gdi.DrawString(text, point); - } + DrawString(text, ColumnWidth, point); if (rePrep) { @@ -250,10 +279,7 @@ namespace BizHawk.Client.EmuHawk rePrep = true; } - if (!string.IsNullOrWhiteSpace(text)) - { - _gdi.DrawString(text, new Point(point.X + strOffsetX, point.Y + strOffsetY)); - } + DrawString(text, col.Width, new Point(point.X + strOffsetX, point.Y + strOffsetY)); if (rePrep) { From 7428a5d2443ba19594c4330ad6c987645ee5f693 Mon Sep 17 00:00:00 2001 From: adelikat Date: Sat, 19 Oct 2019 11:45:18 -0500 Subject: [PATCH 057/166] InputRoll - if column resize is enabled, double clicking a column edge resizes it to fit the text --- .../CustomControls/InputRoll.cs | 35 +++++++++++++++++++ 1 file changed, 35 insertions(+) diff --git a/BizHawk.Client.EmuHawk/CustomControls/InputRoll.cs b/BizHawk.Client.EmuHawk/CustomControls/InputRoll.cs index 01704912c0..af975a8622 100644 --- a/BizHawk.Client.EmuHawk/CustomControls/InputRoll.cs +++ b/BizHawk.Client.EmuHawk/CustomControls/InputRoll.cs @@ -135,6 +135,41 @@ namespace BizHawk.Client.EmuHawk base.Dispose(disposing); } + protected override void OnDoubleClick(EventArgs e) + { + if (IsHoveringOnColumnEdge) + { + if (HorizontalOrientation) + { + // TODO + } + else + { + var maxLength = CurrentCell.Column.Text?.Length ?? 0; + + + for (int i = 0; i < RowCount; i++) + { + string text = ""; + int offSetX = 0, offSetY = 0; + QueryItemText?.Invoke(i, CurrentCell.Column, out text, ref offSetX, ref offSetY); + if (text.Length > maxLength) + { + maxLength = text.Length; + } + } + + var newWidth = (maxLength * _charSize.Width) + (CellWidthPadding * 2); + CurrentCell.Column.Width = newWidth; + _columns.ColumnsChanged(); + Refresh(); + } + + } + + base.OnDoubleClick(e); + } + #region Properties /// From f96e778c35e0cce1174ce54e8aeabff10a80123a Mon Sep 17 00:00:00 2001 From: adelikat Date: Sat, 19 Oct 2019 11:46:56 -0500 Subject: [PATCH 058/166] remove unused method --- .../CustomControls/InputRoll.Drawing.cs | 13 ------------- 1 file changed, 13 deletions(-) diff --git a/BizHawk.Client.EmuHawk/CustomControls/InputRoll.Drawing.cs b/BizHawk.Client.EmuHawk/CustomControls/InputRoll.Drawing.cs index 068908729e..f26d76fe3a 100644 --- a/BizHawk.Client.EmuHawk/CustomControls/InputRoll.Drawing.cs +++ b/BizHawk.Client.EmuHawk/CustomControls/InputRoll.Drawing.cs @@ -44,19 +44,6 @@ namespace BizHawk.Client.EmuHawk } } - private string Cap(string text, int? width) - { - if (string.IsNullOrEmpty(text) || width == null) - { - return text; - } - - var max = width.Value / (_charSize.Width - CellWidthPadding); - return text.Length < max - ? text - : text.Substring(0, max); - } - private void DrawString(string text, int? width, Point point) { if (string.IsNullOrWhiteSpace(text)) From b5d05e0f0c58de84fb00f3e673afd92ee22d631b Mon Sep 17 00:00:00 2001 From: adelikat Date: Sat, 19 Oct 2019 13:01:53 -0500 Subject: [PATCH 059/166] InputRoll - properly calculate if a vertical scrollbar is needed --- BizHawk.Client.EmuHawk/CustomControls/InputRoll.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/BizHawk.Client.EmuHawk/CustomControls/InputRoll.cs b/BizHawk.Client.EmuHawk/CustomControls/InputRoll.cs index af975a8622..ae12c73001 100644 --- a/BizHawk.Client.EmuHawk/CustomControls/InputRoll.cs +++ b/BizHawk.Client.EmuHawk/CustomControls/InputRoll.cs @@ -1648,7 +1648,7 @@ namespace BizHawk.Client.EmuHawk } else { - NeedsVScrollbar = RowCount > 1; + NeedsVScrollbar = ColumnHeight + (RowCount * RowHeight) > Height; NeedsHScrollbar = TotalColWidth.HasValue && TotalColWidth.Value - DrawWidth + 1 > 0; } From de015966176d751791d599c9674dd3863113f2ab Mon Sep 17 00:00:00 2001 From: adelikat Date: Sat, 19 Oct 2019 13:07:36 -0500 Subject: [PATCH 060/166] delete unused TasListView, not sure what this was trying to be --- .../BizHawk.Client.EmuHawk.csproj | 6 - .../CustomControls/TasListView.cs | 181 ------------------ .../CustomControls/TasListView.resx | 126 ------------ 3 files changed, 313 deletions(-) delete mode 100644 BizHawk.Client.EmuHawk/CustomControls/TasListView.cs delete mode 100644 BizHawk.Client.EmuHawk/CustomControls/TasListView.resx diff --git a/BizHawk.Client.EmuHawk/BizHawk.Client.EmuHawk.csproj b/BizHawk.Client.EmuHawk/BizHawk.Client.EmuHawk.csproj index 004021caf8..d1c2c3b684 100644 --- a/BizHawk.Client.EmuHawk/BizHawk.Client.EmuHawk.csproj +++ b/BizHawk.Client.EmuHawk/BizHawk.Client.EmuHawk.csproj @@ -628,9 +628,6 @@ Component - - Component - Component @@ -1518,9 +1515,6 @@ QuickProgressPopup.cs - - TasListView.cs - MainForm.cs Designer diff --git a/BizHawk.Client.EmuHawk/CustomControls/TasListView.cs b/BizHawk.Client.EmuHawk/CustomControls/TasListView.cs deleted file mode 100644 index 2fd17e6f68..0000000000 --- a/BizHawk.Client.EmuHawk/CustomControls/TasListView.cs +++ /dev/null @@ -1,181 +0,0 @@ -using System; -using System.Linq; -using System.Windows.Forms; - -namespace BizHawk.Client.EmuHawk -{ - public class TasListView : VirtualListView - { - public class Cell - { - public int? RowIndex; - public string Column; - - // Convenience hack - public override string ToString() - { - return string.IsNullOrEmpty(Column) ? "?" : $"{Column} - {(RowIndex.HasValue ? RowIndex.ToString() : "?")}"; - } - } - - public bool RightButtonHeld { get; set; } - - public int? LastSelectedIndex - { - get - { - if (SelectedIndices.Count > 0) - { - return SelectedIndices - .OfType() - .OrderBy(x => x) - .Last(); - } - - return null; - } - } - - private Cell _currentPointedCell = new Cell(); - public Cell CurrentCell - { - get { return _currentPointedCell; } - } - - private Cell _lastPointedCell = new Cell(); - public Cell LastCell - { - get { return _lastPointedCell; } - } - - public bool InputPaintingMode { get; set; } - public bool IsPaintDown { get; private set; } - - /// - /// Calculates the column name and row number that the point (x, y) lies in. - /// - /// X coordinate - /// Y coordinate - private void CalculatePointedCell(int x, int y) - { - int? newRow; - string newColumn = ""; - - var accumulator = 0; - foreach (ColumnHeader column in Columns) - { - accumulator += column.Width; - if (accumulator < x) - { - continue; - } - - newColumn = column.Name; - break; - } - - var rowHeight = this.LineHeight;// 5 (in VirtualListView) and 6 work here for me, but are they always dependable, how can I get the padding? - var headerHeight = rowHeight + 6; - - newRow = ((y - headerHeight) / rowHeight) + this.VScrollPos; - if (newRow >= ItemCount) - { - newRow = null; - } - - if (newColumn != CurrentCell.Column || newRow != CurrentCell.RowIndex) - { - LastCell.Column = CurrentCell.Column; - LastCell.RowIndex = CurrentCell.RowIndex; - - CurrentCell.Column = newColumn; - CurrentCell.RowIndex = newRow; - - CellChanged(LastCell, CurrentCell); - } - } - - public class CellEventArgs - { - public CellEventArgs(Cell oldCell, Cell newCell) - { - OldCell = oldCell; - NewCell = newCell; - } - - public Cell OldCell { get; private set; } - public Cell NewCell { get; private set; } - } - - public delegate void CellChangeEventHandler(object sender, CellEventArgs e); - public event CellChangeEventHandler PointedCellChanged; - - private void CellChanged(Cell oldCell, Cell newCell) - { - if (PointedCellChanged != null) - { - PointedCellChanged(this, new CellEventArgs(oldCell, newCell)); - } - } - - protected override void OnMouseLeave(EventArgs e) - { - _currentPointedCell.Column = ""; - _currentPointedCell.RowIndex = null; - IsPaintDown = false; - base.OnMouseLeave(e); - } - - protected override void OnMouseMove(MouseEventArgs e) - { - CalculatePointedCell(e.X, e.Y); - base.OnMouseMove(e); - } - - protected override void OnMouseDown(MouseEventArgs e) - { - if (e.Button == MouseButtons.Left && InputPaintingMode) - { - IsPaintDown = true; - } - - if (e.Button == MouseButtons.Right) - { - RightButtonHeld = true; - } - - base.OnMouseDown(e); - } - - protected override void OnMouseUp(MouseEventArgs e) - { - IsPaintDown = false; - RightButtonHeld = false; - - base.OnMouseUp(e); - } - - protected override void OnMouseWheel(MouseEventArgs e) - { - if (RightButtonHeld) - { - DoRightMouseScroll(this, e); - } - else - { - base.OnMouseWheel(e); - } - } - - public delegate void RightMouseScrollEventHandler(object sender, MouseEventArgs e); - public event RightMouseScrollEventHandler RightMouseScrolled; - - private void DoRightMouseScroll(object sender, MouseEventArgs e) - { - if (RightMouseScrolled != null) - { - RightMouseScrolled(sender, e); - } - } - } -} diff --git a/BizHawk.Client.EmuHawk/CustomControls/TasListView.resx b/BizHawk.Client.EmuHawk/CustomControls/TasListView.resx deleted file mode 100644 index 43b04417e2..0000000000 --- a/BizHawk.Client.EmuHawk/CustomControls/TasListView.resx +++ /dev/null @@ -1,126 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - text/microsoft-resx - - - 2.0 - - - System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - - System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - - 17, 17 - - - False - - \ No newline at end of file From 975c9f9f0d1d154424d36ed457c06d45ad645d83 Mon Sep 17 00:00:00 2001 From: adelikat Date: Sat, 19 Oct 2019 13:55:26 -0500 Subject: [PATCH 061/166] LogWindow - use ListView in virtual mode instead of VirtualListView --- BizHawk.Client.EmuHawk/LogWindow.Designer.cs | 15 +++++++-------- BizHawk.Client.EmuHawk/LogWindow.cs | 11 +++++------ 2 files changed, 12 insertions(+), 14 deletions(-) diff --git a/BizHawk.Client.EmuHawk/LogWindow.Designer.cs b/BizHawk.Client.EmuHawk/LogWindow.Designer.cs index fe03b76c7a..1b681d0bf9 100644 --- a/BizHawk.Client.EmuHawk/LogWindow.Designer.cs +++ b/BizHawk.Client.EmuHawk/LogWindow.Designer.cs @@ -1,4 +1,6 @@ -namespace BizHawk.Client.EmuHawk +using System.Windows.Forms; + +namespace BizHawk.Client.EmuHawk { partial class LogWindow { @@ -34,7 +36,7 @@ this.buttonCopy = new System.Windows.Forms.Button(); this.buttonCopyAll = new System.Windows.Forms.Button(); this.AddToGameDbBtn = new System.Windows.Forms.Button(); - this.virtualListView1 = new BizHawk.Client.EmuHawk.VirtualListView(); + this.virtualListView1 = new System.Windows.Forms.ListView(); this.columnHeader1 = ((System.Windows.Forms.ColumnHeader)(new System.Windows.Forms.ColumnHeader())); this.tableLayoutPanel1.SuspendLayout(); this.SuspendLayout(); @@ -118,23 +120,20 @@ // // virtualListView1 // - this.virtualListView1.BlazingFast = false; this.virtualListView1.Columns.AddRange(new System.Windows.Forms.ColumnHeader[] { this.columnHeader1}); this.virtualListView1.Dock = System.Windows.Forms.DockStyle.Fill; this.virtualListView1.Font = new System.Drawing.Font("Courier New", 8.25F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0))); this.virtualListView1.HeaderStyle = System.Windows.Forms.ColumnHeaderStyle.None; - this.virtualListView1.ItemCount = 0; + this.virtualListView1.VirtualListSize = 0; this.virtualListView1.Location = new System.Drawing.Point(0, 0); this.virtualListView1.Name = "virtualListView1"; - this.virtualListView1.SelectAllInProgress = false; - this.virtualListView1.selectedItem = -1; this.virtualListView1.Size = new System.Drawing.Size(675, 367); this.virtualListView1.TabIndex = 8; this.virtualListView1.UseCompatibleStateImageBehavior = false; this.virtualListView1.View = System.Windows.Forms.View.Details; this.virtualListView1.VirtualMode = true; - this.virtualListView1.QueryItemText += new BizHawk.Client.EmuHawk.QueryItemTextHandler(this.virtualListView1_QueryItemText); + this.virtualListView1.RetrieveVirtualItem += new RetrieveVirtualItemEventHandler(this.virtualListView1_QueryItemText); this.virtualListView1.ClientSizeChanged += new System.EventHandler(this.virtualListView1_ClientSizeChanged); this.virtualListView1.KeyDown += new System.Windows.Forms.KeyEventHandler(this.virtualListView1_KeyDown); // @@ -163,7 +162,7 @@ private System.Windows.Forms.Button btnClose; private System.Windows.Forms.Button btnClear; private System.Windows.Forms.TableLayoutPanel tableLayoutPanel1; - private VirtualListView virtualListView1; + private System.Windows.Forms.ListView virtualListView1; private System.Windows.Forms.ColumnHeader columnHeader1; private System.Windows.Forms.Button buttonCopy; private System.Windows.Forms.Button buttonCopyAll; diff --git a/BizHawk.Client.EmuHawk/LogWindow.cs b/BizHawk.Client.EmuHawk/LogWindow.cs index af5d0d8968..212ec849d2 100644 --- a/BizHawk.Client.EmuHawk/LogWindow.cs +++ b/BizHawk.Client.EmuHawk/LogWindow.cs @@ -5,7 +5,6 @@ using System.IO; using System.Text; using System.Windows.Forms; -using BizHawk.Common.ReflectionExtensions; using BizHawk.Emulation.Common; using BizHawk.Emulation.Common.IEmulatorExtensions; using BizHawk.Client.Common; @@ -40,7 +39,7 @@ namespace BizHawk.Client.EmuHawk var ss = report.Split('\n'); foreach (var s in ss) dlg.Lines.Add(s.TrimEnd('\r')); - dlg.virtualListView1.ItemCount = ss.Length; + dlg.virtualListView1.VirtualListSize = ss.Length; dlg.Text = title; dlg.btnClear.Visible = false; dlg.ShowDialog(parent); @@ -55,7 +54,7 @@ namespace BizHawk.Client.EmuHawk if (!string.IsNullOrWhiteSpace(s)) { Lines.Add(s.TrimEnd('\r')); - virtualListView1.ItemCount++; + virtualListView1.VirtualListSize++; } } } @@ -63,7 +62,7 @@ namespace BizHawk.Client.EmuHawk private void btnClear_Click(object sender, EventArgs e) { Lines.Clear(); - virtualListView1.ItemCount = 0; + virtualListView1.VirtualListSize = 0; virtualListView1.SelectedIndices.Clear(); } @@ -99,9 +98,9 @@ namespace BizHawk.Client.EmuHawk } } - private void virtualListView1_QueryItemText(int item, int subItem, out string text) + private void virtualListView1_QueryItemText(object sender, RetrieveVirtualItemEventArgs e) { - text = Lines[item]; + e.Item = new ListViewItem(Lines[e.ItemIndex]); } private void virtualListView1_ClientSizeChanged(object sender, EventArgs e) From 2a6225940b77f0ab102e4fd082f46511971234ce Mon Sep 17 00:00:00 2001 From: adelikat Date: Sat, 19 Oct 2019 14:18:43 -0500 Subject: [PATCH 062/166] PlayMovie - use listview in virtual mode instead of VirtualListView --- .../movie/PlayMovie.Designer.cs | 10 ++--- BizHawk.Client.EmuHawk/movie/PlayMovie.cs | 41 ++++++------------- 2 files changed, 15 insertions(+), 36 deletions(-) diff --git a/BizHawk.Client.EmuHawk/movie/PlayMovie.Designer.cs b/BizHawk.Client.EmuHawk/movie/PlayMovie.Designer.cs index 8afcc7d618..3ccf267f64 100644 --- a/BizHawk.Client.EmuHawk/movie/PlayMovie.Designer.cs +++ b/BizHawk.Client.EmuHawk/movie/PlayMovie.Designer.cs @@ -49,7 +49,7 @@ this.editToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); this.StopOnFrameCheckbox = new System.Windows.Forms.CheckBox(); this.StopOnFrameTextBox = new BizHawk.Client.EmuHawk.WatchValueBox(); - this.MovieView = new BizHawk.Client.EmuHawk.VirtualListView(); + this.MovieView = new System.Windows.Forms.ListView(); this.columnHeader1 = ((System.Windows.Forms.ColumnHeader)(new System.Windows.Forms.ColumnHeader())); this.columnHeader2 = ((System.Windows.Forms.ColumnHeader)(new System.Windows.Forms.ColumnHeader())); this.columnHeader3 = ((System.Windows.Forms.ColumnHeader)(new System.Windows.Forms.ColumnHeader())); @@ -269,7 +269,6 @@ this.MovieView.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom) | System.Windows.Forms.AnchorStyles.Left) | System.Windows.Forms.AnchorStyles.Right))); - this.MovieView.BlazingFast = false; this.MovieView.Columns.AddRange(new System.Windows.Forms.ColumnHeader[] { this.columnHeader1, this.columnHeader2, @@ -279,16 +278,13 @@ this.MovieView.FullRowSelect = true; this.MovieView.GridLines = true; this.MovieView.HideSelection = false; - this.MovieView.ItemCount = 0; + this.MovieView.VirtualListSize = 0; this.MovieView.Location = new System.Drawing.Point(12, 28); this.MovieView.MultiSelect = false; this.MovieView.Name = "MovieView"; - this.MovieView.SelectAllInProgress = false; - this.MovieView.selectedItem = -1; this.MovieView.Size = new System.Drawing.Size(480, 322); this.MovieView.TabIndex = 5; this.MovieView.UseCompatibleStateImageBehavior = false; - this.MovieView.UseCustomBackground = true; this.MovieView.View = System.Windows.Forms.View.Details; this.MovieView.ColumnClick += new System.Windows.Forms.ColumnClickEventHandler(this.MovieView_ColumnClick); this.MovieView.SelectedIndexChanged += new System.EventHandler(this.MovieView_SelectedIndexChanged); @@ -381,7 +377,7 @@ private System.Windows.Forms.Button Cancel; private System.Windows.Forms.Button OK; private System.Windows.Forms.Button BrowseMovies; - private VirtualListView MovieView; + private System.Windows.Forms.ListView MovieView; private System.Windows.Forms.ColumnHeader columnHeader1; private System.Windows.Forms.ColumnHeader columnHeader2; private System.Windows.Forms.ColumnHeader columnHeader3; diff --git a/BizHawk.Client.EmuHawk/movie/PlayMovie.cs b/BizHawk.Client.EmuHawk/movie/PlayMovie.cs index b99913aeab..7a3169b96f 100644 --- a/BizHawk.Client.EmuHawk/movie/PlayMovie.cs +++ b/BizHawk.Client.EmuHawk/movie/PlayMovie.cs @@ -27,7 +27,7 @@ namespace BizHawk.Client.EmuHawk public PlayMovie() { InitializeComponent(); - MovieView.QueryItemText += MovieView_QueryItemText; + MovieView.RetrieveVirtualItem += MovieView_QueryItemText; MovieView.VirtualMode = true; _sortReverse = false; _sortedCol = ""; @@ -45,28 +45,13 @@ namespace BizHawk.Client.EmuHawk TurboCheckbox.Checked = Global.Config.TurboSeek; } - private void MovieView_QueryItemText(int index, int column, out string text) + private void MovieView_QueryItemText(object sender, RetrieveVirtualItemEventArgs e) { - text = ""; - if (column == 0) // File - { - text = Path.GetFileName(_movieList[index].Filename); - } - - if (column == 1) // System - { - text = _movieList[index].SystemID; - } - - if (column == 2) // Game - { - text = _movieList[index].GameName; - } - - if (column == 3) // Time - { - text = PlatformFrameRates.MovieTime(_movieList[index]).ToString(@"hh\:mm\:ss\.fff"); - } + var entry = _movieList[e.ItemIndex]; + e.Item = new ListViewItem(entry.Filename); + e.Item.SubItems.Add(entry.SystemID); + e.Item.SubItems.Add(entry.GameName); + e.Item.SubItems.Add(PlatformFrameRates.MovieTime(entry).ToString(@"hh\:mm\:ss\.fff")); } private void Run() @@ -230,14 +215,13 @@ namespace BizHawk.Client.EmuHawk private void HighlightMovie(int index) { MovieView.SelectedIndices.Clear(); - MovieView.setSelection(index); - MovieView.SelectItem(index, true); + MovieView.Items[index].Selected = true; } private void ScanFiles() { _movieList.Clear(); - MovieView.ItemCount = 0; + MovieView.VirtualListSize = 0; MovieView.Update(); var directory = PathManager.MakeAbsolutePath(Global.Config.PathEntries.MoviesPathFragment, null); @@ -293,7 +277,7 @@ namespace BizHawk.Client.EmuHawk void RefreshMovieList() { - MovieView.ItemCount = _movieList.Count; + MovieView.VirtualListSize = _movieList.Count; UpdateList(); } @@ -403,7 +387,7 @@ namespace BizHawk.Client.EmuHawk OK.Enabled = true; var firstIndex = MovieView.SelectedIndices[0]; - MovieView.ensureVisible(firstIndex); + MovieView.EnsureVisible(firstIndex); foreach (var kvp in _movieList[firstIndex].HeaderEntries) { @@ -593,8 +577,7 @@ namespace BizHawk.Client.EmuHawk if (index.HasValue) { MovieView.SelectedIndices.Clear(); - MovieView.setSelection(index.Value); - MovieView.SelectItem(index.Value, true); + MovieView.Items[index.Value].Selected = true; } } } From b84413b94785e0f719007ba779d51b5a8da6e156 Mon Sep 17 00:00:00 2001 From: adelikat Date: Sat, 19 Oct 2019 14:26:45 -0500 Subject: [PATCH 063/166] LuaFunctions dialog - use listview in virtualmode instead of virtuallistview --- .../tools/Lua/LuaFunctionsForm.Designer.cs | 9 +-- .../tools/Lua/LuaFunctionsForm.cs | 56 +++++-------------- 2 files changed, 18 insertions(+), 47 deletions(-) diff --git a/BizHawk.Client.EmuHawk/tools/Lua/LuaFunctionsForm.Designer.cs b/BizHawk.Client.EmuHawk/tools/Lua/LuaFunctionsForm.Designer.cs index 4805891afc..9c559ab2a4 100644 --- a/BizHawk.Client.EmuHawk/tools/Lua/LuaFunctionsForm.Designer.cs +++ b/BizHawk.Client.EmuHawk/tools/Lua/LuaFunctionsForm.Designer.cs @@ -34,7 +34,7 @@ this.FilterBox = new System.Windows.Forms.TextBox(); this.label1 = new System.Windows.Forms.Label(); this.ToWikiMarkupButton = new System.Windows.Forms.Button(); - this.FunctionView = new BizHawk.Client.EmuHawk.VirtualListView(); + this.FunctionView = new System.Windows.Forms.ListView(); this.LibraryReturn = ((System.Windows.Forms.ColumnHeader)(new System.Windows.Forms.ColumnHeader())); this.LibraryHead = ((System.Windows.Forms.ColumnHeader)(new System.Windows.Forms.ColumnHeader())); this.LibraryName = ((System.Windows.Forms.ColumnHeader)(new System.Windows.Forms.ColumnHeader())); @@ -96,7 +96,6 @@ this.FunctionView.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom) | System.Windows.Forms.AnchorStyles.Left) | System.Windows.Forms.AnchorStyles.Right))); - this.FunctionView.BlazingFast = false; this.FunctionView.Columns.AddRange(new System.Windows.Forms.ColumnHeader[] { this.LibraryReturn, this.LibraryHead, @@ -105,11 +104,9 @@ this.LibraryDescription}); this.FunctionView.FullRowSelect = true; this.FunctionView.GridLines = true; - this.FunctionView.ItemCount = 0; + this.FunctionView.VirtualListSize = 0; this.FunctionView.Location = new System.Drawing.Point(12, 12); this.FunctionView.Name = "FunctionView"; - this.FunctionView.SelectAllInProgress = false; - this.FunctionView.selectedItem = -1; this.FunctionView.Size = new System.Drawing.Size(710, 291); this.FunctionView.TabIndex = 1; this.FunctionView.UseCompatibleStateImageBehavior = false; @@ -170,7 +167,7 @@ private System.Windows.Forms.Button OK; private System.DirectoryServices.DirectoryEntry directoryEntry1; - private VirtualListView FunctionView; + private System.Windows.Forms.ListView FunctionView; private System.Windows.Forms.ColumnHeader LibraryHead; private System.Windows.Forms.ColumnHeader LibraryReturn; private System.Windows.Forms.ColumnHeader LibraryName; diff --git a/BizHawk.Client.EmuHawk/tools/Lua/LuaFunctionsForm.cs b/BizHawk.Client.EmuHawk/tools/Lua/LuaFunctionsForm.cs index 8a0aceb800..0f5772db3b 100644 --- a/BizHawk.Client.EmuHawk/tools/Lua/LuaFunctionsForm.cs +++ b/BizHawk.Client.EmuHawk/tools/Lua/LuaFunctionsForm.cs @@ -1,12 +1,10 @@ using System; using System.Collections.Generic; -using System.Drawing; using System.Linq; using System.Text; using System.Windows.Forms; using BizHawk.Client.Common; -using BizHawk.Common; namespace BizHawk.Client.EmuHawk { @@ -35,8 +33,7 @@ namespace BizHawk.Client.EmuHawk public LuaFunctionsForm() { InitializeComponent(); - FunctionView.QueryItemText += FunctionView_QueryItemText; - FunctionView.QueryItemBkColor += FunctionView_QueryItemBkColor; + FunctionView.RetrieveVirtualItem += FunctionView_QueryItemText; } private void LuaFunctionList_Load(object sender, EventArgs e) @@ -51,42 +48,14 @@ namespace BizHawk.Client.EmuHawk ToWikiMarkupButton.Visible = VersionInfo.DeveloperBuild; } - private void FunctionView_QueryItemBkColor(int index, int column, ref Color color) + private void FunctionView_QueryItemText(object sender, RetrieveVirtualItemEventArgs e) { - } - - private void FunctionView_QueryItemText(int index, int column, out string text) - { - text = ""; - - try - { - if (_filteredList.Any() && index < _filteredList.Count) - { - switch (column) - { - case 0: - text = _filteredList[index].ReturnType; - break; - case 1: - text = _filteredList[index].Library; - break; - case 2: - text = _filteredList[index].Name; - break; - case 3: - text = _filteredList[index].ParameterList; - break; - case 4: - text = _filteredList[index].Description; - break; - } - } - } - catch - { - /* Eat it*/ - } + var entry = _filteredList[e.ItemIndex]; + e.Item = new ListViewItem(entry.ReturnType); + e.Item.SubItems.Add(entry.Library); + e.Item.SubItems.Add(entry.Name); + e.Item.SubItems.Add(entry.ParameterList); + e.Item.SubItems.Add(entry.Description); } private void OrderColumn(int column) @@ -206,7 +175,12 @@ namespace BizHawk.Client.EmuHawk //FREVBHFYL? private void FunctionView_Copy(object sender, EventArgs e) { - var itm = _filteredList[FunctionView.selectedItem]; + if (FunctionView.SelectedIndices.Count == 0) + { + return; + } + + var itm = _filteredList[FunctionView.SelectedIndices[0]]; var sb = new StringBuilder($"//{itm.Library}.{itm.Name}{itm.ParameterList}"); //comment style not an accident: the 'declaration' is not legal lua, so use of -- to comment it shouldn't suggest it. right? if (itm.Example != null) { @@ -221,7 +195,7 @@ namespace BizHawk.Client.EmuHawk private void UpdateList() { GenerateFilteredList(); - FunctionView.ItemCount = _filteredList.Count; + FunctionView.VirtualListSize = _filteredList.Count; } private void FilterBox_KeyUp(object sender, KeyEventArgs e) From da0e59c10fa512c9d1cbfcaf06e9858155e3ff82 Mon Sep 17 00:00:00 2001 From: adelikat Date: Sat, 19 Oct 2019 14:38:58 -0500 Subject: [PATCH 064/166] Multihawk begone! --- BizHawk.Client.MultiHawk/App.config | 6 - .../BizHawk.Client.MultiHawk.csproj | 250 --- ...izHawk.Client.MultiHawk.csproj.DotSettings | 2 - .../DisplayManager/DisplayManager.cs | 724 -------- .../EmulatorWindow.Designer.cs | 48 - BizHawk.Client.MultiHawk/EmulatorWindow.cs | 411 ----- BizHawk.Client.MultiHawk/EmulatorWindow.resx | 120 -- .../EmulatorWindowList.cs | 66 - .../Extensions/ToolExtensions.cs | 228 --- BizHawk.Client.MultiHawk/GlobalWin.cs | 25 - BizHawk.Client.MultiHawk/Input/GamePad.cs | 235 --- BizHawk.Client.MultiHawk/Input/Input.cs | 511 ------ BizHawk.Client.MultiHawk/Input/Keyboard.cs | 132 -- BizHawk.Client.MultiHawk/InputManager.cs | 121 -- BizHawk.Client.MultiHawk/Mainform.Designer.cs | 548 ------ BizHawk.Client.MultiHawk/Mainform.cs | 1560 ----------------- BizHawk.Client.MultiHawk/Mainform.resx | 132 -- BizHawk.Client.MultiHawk/PresentationPanel.cs | 64 - BizHawk.Client.MultiHawk/Program.cs | 171 -- .../Properties/AssemblyInfo.cs | 36 - .../Properties/Resources.Designer.cs | 293 ---- .../Properties/Resources.resx | 190 -- .../Properties/Settings.Designer.cs | 26 - .../Properties/Settings.settings | 7 - .../Resources/courier16px.bmfc | 55 - .../Resources/courier16px.fnt | 208 --- .../Resources/courier16px_0.png | Bin 2268 -> 0 bytes BizHawk.Client.MultiHawk/images/Blank.png | Bin 154 -> 0 bytes BizHawk.Client.MultiHawk/images/CutHS.png | Bin 578 -> 0 bytes .../images/ExclamationRed.png | Bin 676 -> 0 bytes .../images/GameController.png | Bin 806 -> 0 bytes .../images/GreenCheck.png | Bin 576 -> 0 bytes BizHawk.Client.MultiHawk/images/Help.png | Bin 646 -> 0 bytes BizHawk.Client.MultiHawk/images/HotKeys.png | Bin 751 -> 0 bytes BizHawk.Client.MultiHawk/images/OpenFile.png | Bin 743 -> 0 bytes BizHawk.Client.MultiHawk/images/Pause.png | Bin 886 -> 0 bytes BizHawk.Client.MultiHawk/images/Play.png | Bin 382 -> 0 bytes BizHawk.Client.MultiHawk/images/ReadOnly.png | Bin 698 -> 0 bytes BizHawk.Client.MultiHawk/images/Recent.png | Bin 907 -> 0 bytes BizHawk.Client.MultiHawk/images/RecordHS.png | Bin 358 -> 0 bytes BizHawk.Client.MultiHawk/images/Save.png | Bin 857 -> 0 bytes BizHawk.Client.MultiHawk/images/SaveAllHS.png | Bin 623 -> 0 bytes BizHawk.Client.MultiHawk/images/SaveAs.png | Bin 595 -> 0 bytes BizHawk.Client.MultiHawk/images/Scan.png | Bin 544 -> 0 bytes BizHawk.Client.MultiHawk/images/Stop.png | Bin 441 -> 0 bytes BizHawk.Client.MultiHawk/images/reboot.png | Bin 1013 -> 0 bytes BizHawk.Client.MultiHawk/images/restart.png | Bin 473 -> 0 bytes .../movie/PlayMovie.Designer.cs | 406 ----- BizHawk.Client.MultiHawk/movie/PlayMovie.cs | 673 ------- BizHawk.Client.MultiHawk/movie/PlayMovie.resx | 155 -- .../movie/RecordMovie.Designer.cs | 210 --- BizHawk.Client.MultiHawk/movie/RecordMovie.cs | 179 -- .../movie/RecordMovie.resx | 149 -- BizHawk.sln | 7 - 54 files changed, 7948 deletions(-) delete mode 100644 BizHawk.Client.MultiHawk/App.config delete mode 100644 BizHawk.Client.MultiHawk/BizHawk.Client.MultiHawk.csproj delete mode 100644 BizHawk.Client.MultiHawk/BizHawk.Client.MultiHawk.csproj.DotSettings delete mode 100644 BizHawk.Client.MultiHawk/DisplayManager/DisplayManager.cs delete mode 100644 BizHawk.Client.MultiHawk/EmulatorWindow.Designer.cs delete mode 100644 BizHawk.Client.MultiHawk/EmulatorWindow.cs delete mode 100644 BizHawk.Client.MultiHawk/EmulatorWindow.resx delete mode 100644 BizHawk.Client.MultiHawk/EmulatorWindowList.cs delete mode 100644 BizHawk.Client.MultiHawk/Extensions/ToolExtensions.cs delete mode 100644 BizHawk.Client.MultiHawk/GlobalWin.cs delete mode 100644 BizHawk.Client.MultiHawk/Input/GamePad.cs delete mode 100644 BizHawk.Client.MultiHawk/Input/Input.cs delete mode 100644 BizHawk.Client.MultiHawk/Input/Keyboard.cs delete mode 100644 BizHawk.Client.MultiHawk/InputManager.cs delete mode 100644 BizHawk.Client.MultiHawk/Mainform.Designer.cs delete mode 100644 BizHawk.Client.MultiHawk/Mainform.cs delete mode 100644 BizHawk.Client.MultiHawk/Mainform.resx delete mode 100644 BizHawk.Client.MultiHawk/PresentationPanel.cs delete mode 100644 BizHawk.Client.MultiHawk/Program.cs delete mode 100644 BizHawk.Client.MultiHawk/Properties/AssemblyInfo.cs delete mode 100644 BizHawk.Client.MultiHawk/Properties/Resources.Designer.cs delete mode 100644 BizHawk.Client.MultiHawk/Properties/Resources.resx delete mode 100644 BizHawk.Client.MultiHawk/Properties/Settings.Designer.cs delete mode 100644 BizHawk.Client.MultiHawk/Properties/Settings.settings delete mode 100644 BizHawk.Client.MultiHawk/Resources/courier16px.bmfc delete mode 100644 BizHawk.Client.MultiHawk/Resources/courier16px.fnt delete mode 100644 BizHawk.Client.MultiHawk/Resources/courier16px_0.png delete mode 100644 BizHawk.Client.MultiHawk/images/Blank.png delete mode 100644 BizHawk.Client.MultiHawk/images/CutHS.png delete mode 100644 BizHawk.Client.MultiHawk/images/ExclamationRed.png delete mode 100644 BizHawk.Client.MultiHawk/images/GameController.png delete mode 100644 BizHawk.Client.MultiHawk/images/GreenCheck.png delete mode 100644 BizHawk.Client.MultiHawk/images/Help.png delete mode 100644 BizHawk.Client.MultiHawk/images/HotKeys.png delete mode 100644 BizHawk.Client.MultiHawk/images/OpenFile.png delete mode 100644 BizHawk.Client.MultiHawk/images/Pause.png delete mode 100644 BizHawk.Client.MultiHawk/images/Play.png delete mode 100644 BizHawk.Client.MultiHawk/images/ReadOnly.png delete mode 100644 BizHawk.Client.MultiHawk/images/Recent.png delete mode 100644 BizHawk.Client.MultiHawk/images/RecordHS.png delete mode 100644 BizHawk.Client.MultiHawk/images/Save.png delete mode 100644 BizHawk.Client.MultiHawk/images/SaveAllHS.png delete mode 100644 BizHawk.Client.MultiHawk/images/SaveAs.png delete mode 100644 BizHawk.Client.MultiHawk/images/Scan.png delete mode 100644 BizHawk.Client.MultiHawk/images/Stop.png delete mode 100644 BizHawk.Client.MultiHawk/images/reboot.png delete mode 100644 BizHawk.Client.MultiHawk/images/restart.png delete mode 100644 BizHawk.Client.MultiHawk/movie/PlayMovie.Designer.cs delete mode 100644 BizHawk.Client.MultiHawk/movie/PlayMovie.cs delete mode 100644 BizHawk.Client.MultiHawk/movie/PlayMovie.resx delete mode 100644 BizHawk.Client.MultiHawk/movie/RecordMovie.Designer.cs delete mode 100644 BizHawk.Client.MultiHawk/movie/RecordMovie.cs delete mode 100644 BizHawk.Client.MultiHawk/movie/RecordMovie.resx diff --git a/BizHawk.Client.MultiHawk/App.config b/BizHawk.Client.MultiHawk/App.config deleted file mode 100644 index 45437954e0..0000000000 --- a/BizHawk.Client.MultiHawk/App.config +++ /dev/null @@ -1,6 +0,0 @@ - - - - - - diff --git a/BizHawk.Client.MultiHawk/BizHawk.Client.MultiHawk.csproj b/BizHawk.Client.MultiHawk/BizHawk.Client.MultiHawk.csproj deleted file mode 100644 index daf4e4ecc3..0000000000 --- a/BizHawk.Client.MultiHawk/BizHawk.Client.MultiHawk.csproj +++ /dev/null @@ -1,250 +0,0 @@ - - - - true - ..\output\ - TRACE;DEBUG;WINDOWS - true - full - AnyCPU - prompt - - MinimumRecommendedRules.ruleset - - - ..\output\ - TRACE;WINDOWS - true - true - pdbonly - AnyCPU - prompt - - MinimumRecommendedRules.ruleset - - - - Debug - x86 - {B95649F5-A0AE-41EB-B62B-578A2AFF5E18} - WinExe - Properties - BizHawk.Client.MultiHawk - MultiHawk - v4.6.1 - 512 - - None - true - - - - - False - ..\References\Newtonsoft.Json.dll - - - ..\References\OpenTK.dll - - - False - ..\References\x64\SlimDX.dll - - - - - - - - - - - - - - - Form - - - PlayMovie.cs - - - Form - - - RecordMovie.cs - - - - Form - - - EmulatorWindow.cs - - - - - - - - Form - - - Mainform.cs - - - - - - - - PlayMovie.cs - - - RecordMovie.cs - - - EmulatorWindow.cs - - - Mainform.cs - - - ResXFileCodeGenerator - Resources.Designer.cs - Designer - - - True - Resources.resx - True - - - SettingsSingleFileGenerator - Settings.Designer.cs - - - True - Settings.settings - True - - - - - - - - - - {24a0aa3c-b25f-4197-b23d-476d6462dba0} - BizHawk.Client.Common - - - {dd448b37-ba3f-4544-9754-5406e8094723} - BizHawk.Client.EmuHawk - - - {866f8d13-0678-4ff9-80a4-a3993fd4d8a3} - BizHawk.Common - - - {e1a23168-b571-411c-b360-2229e7225e0e} - BizHawk.Emulation.Common - - - {197d4314-8a9f-49ba-977d-54acefaeb6ba} - BizHawk.Emulation.Cores - - - {f51946ea-827f-4d82-b841-1f2f6d060312} - BizHawk.Emulation.DiscSystem - - - {337ca23e-65e7-44e1-9411-97ee08bb8116} - BizHawk.Bizware.BizwareGL.GdiPlus - - - {5160cfb1-5389-47c1-b7f6-8a0dc97641ee} - BizHawk.Bizware.BizwareGL.OpenTK - - - {e6b436b1-a3cd-4c9a-8f76-5d7154726884} - BizHawk.Bizware.BizwareGL.SlimDX - - - {9f84a0b2-861e-4ef4-b89b-5e2a3f38a465} - BizHawk.Bizware.BizwareGL - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/BizHawk.Client.MultiHawk/BizHawk.Client.MultiHawk.csproj.DotSettings b/BizHawk.Client.MultiHawk/BizHawk.Client.MultiHawk.csproj.DotSettings deleted file mode 100644 index 73e96563f9..0000000000 --- a/BizHawk.Client.MultiHawk/BizHawk.Client.MultiHawk.csproj.DotSettings +++ /dev/null @@ -1,2 +0,0 @@ - - CSharp60 \ No newline at end of file diff --git a/BizHawk.Client.MultiHawk/DisplayManager/DisplayManager.cs b/BizHawk.Client.MultiHawk/DisplayManager/DisplayManager.cs deleted file mode 100644 index ceb67d81e7..0000000000 --- a/BizHawk.Client.MultiHawk/DisplayManager/DisplayManager.cs +++ /dev/null @@ -1,724 +0,0 @@ -//TODO -//we could flag textures as 'actually' render targets (keep a reference to the render target?) which could allow us to convert between them more quickly in some cases - -using System; -using System.IO; -using System.Collections.Generic; -using System.Diagnostics; -using System.Drawing; - -using BizHawk.Emulation.Common; -using BizHawk.Client.Common; -using BizHawk.Client.EmuHawk; -using BizHawk.Client.EmuHawk.FilterManager; -using BizHawk.Bizware.BizwareGL; - -using OpenTK; -using BizHawk.Bizware.BizwareGL.Drivers.SlimDX; -using BizHawk.Bizware.BizwareGL.Drivers.GdiPlus; - -namespace BizHawk.Client.MultiHawk -{ - /// - /// A DisplayManager is destined forevermore to drive the PresentationPanel it gets initialized with. - /// Its job is to receive OSD and emulator outputs, and produce one single buffer (BitampBuffer? Texture2d?) for display by the PresentationPanel. - /// Details TBD - /// - public class DisplayManager : IDisposable - { - class DisplayManagerRenderTargetProvider : IRenderTargetProvider - { - public DisplayManagerRenderTargetProvider(Func callback) { Callback = callback; } - Func Callback; - RenderTarget IRenderTargetProvider.Get(Size size) - { - return Callback(size); - } - } - - public DisplayManager(PresentationPanel presentationPanel, IGL gl, GLManager glManager) - { - GL = gl; - GLManager = glManager; - this.presentationPanel = presentationPanel; - GraphicsControl = this.presentationPanel.GraphicsControl; - CR_GraphicsControl = GLManager.GetContextForGraphicsControl(GraphicsControl); - - //it's sort of important for these to be initialized to something nonzero - currEmuWidth = currEmuHeight = 1; - - Renderer = GL.CreateRenderer(); - - VideoTextureFrugalizer = new TextureFrugalizer(GL); - - ShaderChainFrugalizers = new RenderTargetFrugalizer[16]; //hacky hardcoded limit.. need some other way to manage these - for (int i = 0; i < 16; i++) - { - ShaderChainFrugalizers[i] = new RenderTargetFrugalizer(GL); - } - - RefreshUserShader(); - } - - public bool Disposed { get; private set; } - - public void Dispose() - { - if (Disposed) return; - Disposed = true; - VideoTextureFrugalizer.Dispose(); - foreach (var f in LuaSurfaceFrugalizers.Values) - f.Dispose(); - foreach (var f in ShaderChainFrugalizers) - if (f != null) - f.Dispose(); - Renderer.Dispose(); - } - - //rendering resources: - IGL GL; - GLManager GLManager; - IGuiRenderer Renderer; - - //layer resources - PresentationPanel presentationPanel; //well, its the final layer's target, at least - GraphicsControl GraphicsControl; //well, its the final layer's target, at least - GLManager.ContextRef CR_GraphicsControl; - FilterProgram CurrentFilterProgram; - - /// - /// these variables will track the dimensions of the last frame's (or the next frame? this is confusing) emulator native output size - /// THIS IS OLD JUNK. I should get rid of it, I think. complex results from the last filter ingestion should be saved instead. - /// - int currEmuWidth, currEmuHeight; - - /// - /// additional pixels added at the unscaled level for the use of lua drawing. essentially increases the input video provider dimensions - /// - public System.Windows.Forms.Padding GameExtraPadding; - - /// - /// additional pixels added at the native level for the use of lua drawing. essentially just gets tacked onto the final calculated window sizes. - /// - public System.Windows.Forms.Padding ClientExtraPadding; - - /// - /// custom fonts that don't need to be installed on the user side - /// - public System.Drawing.Text.PrivateFontCollection CustomFonts = new System.Drawing.Text.PrivateFontCollection(); - - TextureFrugalizer VideoTextureFrugalizer; - Dictionary LuaSurfaceFrugalizers = new Dictionary(); - RenderTargetFrugalizer[] ShaderChainFrugalizers; - EmuHawk.Filters.RetroShaderChain ShaderChain_user; - - public void RefreshUserShader() - { - if (ShaderChain_user != null) - ShaderChain_user.Dispose(); - if (File.Exists(Global.Config.DispUserFilterPath)) - { - var fi = new FileInfo(Global.Config.DispUserFilterPath); - using (var stream = fi.OpenRead()) - ShaderChain_user = new EmuHawk.Filters.RetroShaderChain(GL, new EmuHawk.Filters.RetroShaderPreset(stream), Path.GetDirectoryName(Global.Config.DispUserFilterPath)); - } - } - - System.Windows.Forms.Padding CalculateCompleteContentPadding(bool user, bool source) - { - var padding = new System.Windows.Forms.Padding(); - - if(user) - padding += GameExtraPadding; - - //an experimental feature - if(source) - if (Global.Emulator is BizHawk.Emulation.Cores.Sony.PSX.Octoshock) - { - var psx = Global.Emulator as BizHawk.Emulation.Cores.Sony.PSX.Octoshock; - var core_padding = psx.VideoProvider_Padding; - padding.Left += core_padding.Width / 2; - padding.Right += core_padding.Width - core_padding.Width / 2; - padding.Top += core_padding.Height / 2; - padding.Bottom += core_padding.Height - core_padding.Height / 2; - } - - return padding; - } - - FilterProgram BuildDefaultChain(Size chain_insize, Size chain_outsize, bool includeOSD) - { - //select user special FX shader chain - Dictionary selectedChainProperties = new Dictionary(); - EmuHawk.Filters.RetroShaderChain selectedChain = null; - if (Global.Config.TargetDisplayFilter == 3 && ShaderChain_user != null && ShaderChain_user.Available) - selectedChain = ShaderChain_user; - - EmuHawk.Filters.FinalPresentation fPresent = new EmuHawk.Filters.FinalPresentation(chain_outsize); - EmuHawk.Filters.SourceImage fInput = new EmuHawk.Filters.SourceImage(chain_insize); - EmuHawk.Filters.OSD fOSD = new EmuHawk.Filters.OSD(); - fOSD.RenderCallback = () => - { - if (!includeOSD) - return; - var size = fOSD.FindInput().SurfaceFormat.Size; - Renderer.Begin(size.Width, size.Height); - Renderer.SetBlendState(GL.BlendNormal); - Renderer.End(); - }; - - var chain = new FilterProgram(); - - //add the first filter, encompassing output from the emulator core - chain.AddFilter(fInput, "input"); - - //if a non-zero padding is required, add a filter to allow for that - //note, we have two sources of padding right now.. one can come from the videoprovider and one from the user. - //we're combining these now and just using black, for sake of being lean, despite the discussion below: - //keep in mind, the videoprovider design in principle might call for another color. - //we havent really been using this very hard, but users will probably want black there (they could fill it to another color if needed tho) - var padding = CalculateCompleteContentPadding(true,true); - if (padding.Vertical != 0 || padding.Horizontal != 0) - { - //TODO - add another filter just for this, its cumbersome to use final presentation... I think. but maybe theres enough similarities to justify it. - Size size = chain_insize; - size.Width += padding.Horizontal; - size.Height += padding.Vertical; - EmuHawk.Filters.FinalPresentation fPadding = new EmuHawk.Filters.FinalPresentation(size); - chain.AddFilter(fPadding, "padding"); - fPadding.GuiRenderer = Renderer; - fPadding.GL = GL; - fPadding.Config_PadOnly = true; - fPadding.Padding = padding; - } - - if (Global.Config.DispPrescale != 1) - { - EmuHawk.Filters.PrescaleFilter fPrescale = new EmuHawk.Filters.PrescaleFilter() { Scale = Global.Config.DispPrescale }; - chain.AddFilter(fPrescale, "user_prescale"); - } - - //AutoPrescale makes no sense for a None final filter - if (Global.Config.DispAutoPrescale && Global.Config.DispFinalFilter != (int)EmuHawk.Filters.FinalPresentation.eFilterOption.None) - { - var apf = new EmuHawk.Filters.AutoPrescaleFilter(); - chain.AddFilter(apf, "auto_prescale"); - } - - //choose final filter - EmuHawk.Filters.FinalPresentation.eFilterOption finalFilter = EmuHawk.Filters.FinalPresentation.eFilterOption.None; - fPresent.FilterOption = finalFilter; - - //add final presentation - chain.AddFilter(fPresent, "presentation"); - - return chain; - } - - /// - /// This will receive an emulated output frame from an IVideoProvider and run it through the complete frame processing pipeline - /// Then it will stuff it into the bound PresentationPanel. - /// --- - /// If the int[] is size=1, then it contains an openGL texture ID (and the size should be as specified from videoProvider) - /// Don't worry about the case where the frontend isnt using opengl; DisplayManager deals with it - /// - public void UpdateSource(IVideoProvider videoProvider) - { - bool displayNothing = Global.Config.DispSpeedupFeatures == 0; - var job = new JobInfo - { - videoProvider = videoProvider, - simulate = displayNothing, - chain_outsize = GraphicsControl.Size, - includeOSD = true, - }; - UpdateSourceInternal(job); - } - - public BitmapBuffer RenderVideoProvider(IVideoProvider videoProvider) - { - //TODO - we might need to gather more Global.Config.DispXXX properties here, so they can be overridden - var targetSize = new Size(videoProvider.BufferWidth, videoProvider.BufferHeight); - var padding = CalculateCompleteContentPadding(true,true); - targetSize.Width += padding.Horizontal; - targetSize.Height += padding.Vertical; - - var job = new JobInfo - { - videoProvider = videoProvider, - simulate = false, - chain_outsize = targetSize, - offscreen = true, - includeOSD = false - }; - UpdateSourceInternal(job); - return job.offscreenBB; - } - - /// - /// Does the entire display process to an offscreen buffer, suitable for a 'client' screenshot. - /// - public BitmapBuffer RenderOffscreen(IVideoProvider videoProvider, bool includeOSD) - { - var job = new JobInfo - { - videoProvider = videoProvider, - simulate = false, - chain_outsize = GraphicsControl.Size, - offscreen = true, - includeOSD = includeOSD - }; - UpdateSourceInternal(job); - return job.offscreenBB; - } - - class FakeVideoProvider : IVideoProvider - { - public int[] GetVideoBuffer() { return new int[] {}; } - - public int VirtualWidth { get; set; } - public int VirtualHeight { get; set; } - - public int BufferWidth { get; set; } - public int BufferHeight { get; set; } - public int BackgroundColor { get; set; } - - public int VsyncNumerator - { - get { throw new InvalidOperationException(); } - } - - public int VsyncDenominator - { - get { throw new InvalidOperationException(); } - } - } - - void FixRatio(float x, float y, int inw, int inh, out int outw, out int outh) - { - float ratio = x / y; - if (ratio <= 1) - { - //taller. weird. expand height. - outw = inw; - outh = (int)((float)inw / ratio); - } - else - { - //wider. normal. expand width. - outw = (int)((float)inh * ratio); - outh = inh; - } - } - - /// - /// Attempts to calculate a good client size with the given zoom factor, considering the user's DisplayManager preferences - /// TODO - this needs to be redone with a concept different from zoom factor. - /// basically, each increment of a 'zoomlike' factor should definitely increase the viewable area somehow, even if it isnt strictly by an entire zoom level. - /// - public Size CalculateClientSize(IVideoProvider videoProvider, int zoom) - { - bool ar_active = Global.Config.DispFixAspectRatio; - bool ar_system = Global.Config.DispManagerAR == Config.EDispManagerAR.System; - bool ar_custom = Global.Config.DispManagerAR == Config.EDispManagerAR.Custom; - bool ar_customRatio = Global.Config.DispManagerAR == Config.EDispManagerAR.CustomRatio; - bool ar_correct = ar_system || ar_custom || ar_customRatio; - bool ar_unity = !ar_correct; - bool ar_integer = Global.Config.DispFixScaleInteger; - - int bufferWidth = videoProvider.BufferWidth; - int bufferHeight = videoProvider.BufferHeight; - int virtualWidth = videoProvider.VirtualWidth; - int virtualHeight = videoProvider.VirtualHeight; - - if (ar_custom) - { - virtualWidth = Global.Config.DispCustomUserARWidth; - virtualHeight = Global.Config.DispCustomUserARHeight; - } - - if (ar_customRatio) - { - FixRatio(Global.Config.DispCustomUserARX, Global.Config.DispCustomUserARY, videoProvider.BufferWidth, videoProvider.BufferHeight, out virtualWidth, out virtualHeight); - } - - var padding = CalculateCompleteContentPadding(true, false); - virtualWidth += padding.Horizontal; - virtualHeight += padding.Vertical; - - padding = CalculateCompleteContentPadding(true, true); - bufferWidth += padding.Horizontal; - bufferHeight += padding.Vertical; - - //Console.WriteLine("DISPZOOM " + zoom); //test - - //old stuff - var fvp = new FakeVideoProvider(); - fvp.BufferWidth = bufferWidth; - fvp.BufferHeight = bufferHeight; - fvp.VirtualWidth = virtualWidth; - fvp.VirtualHeight = virtualHeight; - - Size chain_outsize = new Size(fvp.BufferWidth * zoom, fvp.BufferHeight * zoom); - - if (ar_active) - { - if (ar_correct) - { - if (ar_integer) - { - //ALERT COPYPASTE LAUNDROMAT - Vector2 VS = new Vector2(virtualWidth, virtualHeight); - Vector2 BS = new Vector2(bufferWidth, bufferHeight); - Vector2 AR = Vector2.Divide(VS, BS); - float target_par = (AR.X / AR.Y); - - //this would malfunction for AR <= 0.5 or AR >= 2.0 - //EDIT - in fact, we have AR like that coming from PSX, sometimes, so maybe we should solve this better - Vector2 PS = new Vector2(1, 1); - - //here's how we define zooming, in this case: - //make sure each step is an increment of zoom for at least one of the dimensions (or maybe both of them) - //look for the increment which helps the AR the best - //TODO - this cant possibly support scale factors like 1.5x - //TODO - also, this might be messing up zooms and stuff, we might need to run this on the output size of the filter chain - for (int i = 1; i < zoom;i++) - { - //would not be good to run this per frame, but it seems to only run when the resolution changes, etc. - Vector2[] trials = new[] { - PS + new Vector2(1, 0), - PS + new Vector2(0, 1), - PS + new Vector2(1, 1) - }; - int bestIndex = -1; - float bestValue = 1000.0f; - for (int t = 0; t < trials.Length; t++) - { - //I. - float test_ar = trials[t].X / trials[t].Y; - - //II. - //Vector2 calc = Vector2.Multiply(trials[t], VS); - //float test_ar = calc.X / calc.Y; - - //not clear which approach is superior - float deviation_linear = Math.Abs(test_ar - target_par); - float deviation_geom = test_ar / target_par; - if (deviation_geom < 1) deviation_geom = 1.0f / deviation_geom; - - float value = deviation_linear; - if (value < bestValue) - { - bestIndex = t; - bestValue = value; - } - } - //is it possible to get here without selecting one? doubtful. - //EDIT: YES IT IS. it happened with an 0,0 buffer size. of course, that was a mistake, but we shouldnt crash - if(bestIndex != -1) //so, what now? well, this will result in 0,0 getting picked, so thats probably all we can do - PS = trials[bestIndex]; - } - - chain_outsize = new Size((int)(bufferWidth * PS.X), (int)(bufferHeight * PS.Y)); - } - else - { - //obey the AR, but allow free scaling: just zoom the virtual size - chain_outsize = new Size(virtualWidth * zoom, virtualHeight * zoom); - } - } - else - { - //ar_unity: - //just choose to zoom the buffer (make no effort to incorporate AR) - chain_outsize = new Size(bufferWidth * zoom, bufferHeight * zoom); - } - } - else - { - //!ar_active: - //just choose to zoom the buffer (make no effort to incorporate AR) - chain_outsize = new Size(bufferWidth * zoom, bufferHeight * zoom); - } - - chain_outsize.Width += ClientExtraPadding.Horizontal; - chain_outsize.Height += ClientExtraPadding.Vertical; - - var job = new JobInfo - { - videoProvider = fvp, - simulate = true, - chain_outsize = chain_outsize, - }; - var filterProgram = UpdateSourceInternal(job); - - var size = filterProgram.Filters[filterProgram.Filters.Count - 1].FindOutput().SurfaceFormat.Size; - - return size; - } - - class JobInfo - { - public IVideoProvider videoProvider; - public bool simulate; - public Size chain_outsize; - public bool offscreen; - public BitmapBuffer offscreenBB; - public bool includeOSD; - } - - FilterProgram UpdateSourceInternal(JobInfo job) - { - if (job.chain_outsize.Width == 0 || job.chain_outsize.Height == 0) - { - //this has to be a NOP, because lots of stuff will malfunction on a 0-sized viewport - return null; - } - - //no drawing actually happens. it's important not to begin drawing on a control - if (!job.simulate && !job.offscreen) - { - GLManager.Activate(CR_GraphicsControl); - } - - IVideoProvider videoProvider = job.videoProvider; - bool simulate = job.simulate; - Size chain_outsize = job.chain_outsize; - - //simulate = true; - - int vw = videoProvider.BufferWidth; - int vh = videoProvider.BufferHeight; - - if (Global.Config.DispFixAspectRatio) - { - if (Global.Config.DispManagerAR == Config.EDispManagerAR.System) - { - vw = videoProvider.VirtualWidth; - vh = videoProvider.VirtualHeight; - } - if (Global.Config.DispManagerAR == Config.EDispManagerAR.Custom) - { - vw = Global.Config.DispCustomUserARWidth; - vh = Global.Config.DispCustomUserARHeight; - } - if (Global.Config.DispManagerAR == Config.EDispManagerAR.CustomRatio) - { - FixRatio(Global.Config.DispCustomUserARX, Global.Config.DispCustomUserARY, videoProvider.BufferWidth, videoProvider.BufferHeight, out vw, out vh); - } - } - - var padding = CalculateCompleteContentPadding(true,false); - vw += padding.Horizontal; - vh += padding.Vertical; - - int[] videoBuffer = videoProvider.GetVideoBuffer(); - - int bufferWidth = videoProvider.BufferWidth; - int bufferHeight = videoProvider.BufferHeight; - bool isGlTextureId = videoBuffer.Length == 1; - - BitmapBuffer bb = null; - Texture2d videoTexture = null; - if (!simulate) - { - if (isGlTextureId) - { - //FYI: this is a million years from happening on n64, since it's all geriatric non-FBO code - //is it workable for saturn? - videoTexture = GL.WrapGLTexture2d(new IntPtr(videoBuffer[0]), bufferWidth, bufferHeight); - } - else - { - //wrap the videoprovider data in a BitmapBuffer (no point to refactoring that many IVideoProviders) - bb = new BitmapBuffer(bufferWidth, bufferHeight, videoBuffer); - bb.DiscardAlpha(); - - //now, acquire the data sent from the videoProvider into a texture - videoTexture = VideoTextureFrugalizer.Get(bb); - - //lets not use this. lets define BizwareGL to make clamp by default (TBD: check opengl) - //GL.SetTextureWrapMode(videoTexture, true); - } - } - - //record the size of what we received, since lua and stuff is gonna want to draw onto it - currEmuWidth = bufferWidth; - currEmuHeight = bufferHeight; - - //build the default filter chain and set it up with services filters will need - Size chain_insize = new Size(bufferWidth, bufferHeight); - - var filterProgram = BuildDefaultChain(chain_insize, chain_outsize, job.includeOSD); - filterProgram.GuiRenderer = Renderer; - filterProgram.GL = GL; - - //setup the source image filter - EmuHawk.Filters.SourceImage fInput = filterProgram["input"] as EmuHawk.Filters.SourceImage; - fInput.Texture = videoTexture; - - //setup the final presentation filter - EmuHawk.Filters.FinalPresentation fPresent = filterProgram["presentation"] as EmuHawk.Filters.FinalPresentation; - fPresent.VirtualTextureSize = new Size(vw, vh); - fPresent.TextureSize = new Size(bufferWidth, bufferHeight); - fPresent.BackgroundColor = videoProvider.BackgroundColor; - fPresent.GuiRenderer = Renderer; - fPresent.Flip = isGlTextureId; - fPresent.Config_FixAspectRatio = Global.Config.DispFixAspectRatio; - fPresent.Config_FixScaleInteger = Global.Config.DispFixScaleInteger; - fPresent.Padding = ClientExtraPadding; - fPresent.AutoPrescale = Global.Config.DispAutoPrescale; - - fPresent.GL = GL; - - filterProgram.Compile("default", chain_insize, chain_outsize, !job.offscreen); - - if (simulate) - { - } - else - { - CurrentFilterProgram = filterProgram; - UpdateSourceDrawingWork(job); - } - - //cleanup: - if (bb != null) bb.Dispose(); - - return filterProgram; - } - - void UpdateSourceDrawingWork(JobInfo job) - { - bool vsync = false; - bool alternateVsync = false; - //only used by alternate vsync - IGL_SlimDX9 dx9 = null; - - if (!job.offscreen) - { - //apply the vsync setting (should probably try to avoid repeating this) - vsync = Global.Config.VSyncThrottle || Global.Config.VSync; - - //ok, now this is a bit undesireable. - //maybe the user wants vsync, but not vsync throttle. - //this makes sense... but we dont have the infrastructure to support it now (we'd have to enable triple buffering or something like that) - //so what we're gonna do is disable vsync no matter what if throttling is off, and maybe nobody will notice. - //update 26-mar-2016: this upsets me. When fastforwarding and skipping frames, vsync should still work. But I'm not changing it yet - if (Global.DisableSecondaryThrottling) - vsync = false; - - //for now, it's assumed that the presentation panel is the main window, but that may not always be true - if (vsync && Global.Config.DispAlternateVsync && Global.Config.VSyncThrottle) - { - dx9 = GL as IGL_SlimDX9; - if (dx9 != null) - { - alternateVsync = true; - //unset normal vsync if we've chosen the alternate vsync - vsync = false; - } - } - - //TODO - whats so hard about triple buffering anyway? just enable it always, and change api to SetVsync(enable,throttle) - //maybe even SetVsync(enable,throttlemethod) or just SetVsync(enable,throttle,advanced) - - if (LastVsyncSetting != vsync || LastVsyncSettingGraphicsControl != presentationPanel.GraphicsControl) - { - if (LastVsyncSetting == null && vsync) - { - // Workaround for vsync not taking effect at startup (Intel graphics related?) - presentationPanel.GraphicsControl.SetVsync(false); - } - presentationPanel.GraphicsControl.SetVsync(vsync); - LastVsyncSettingGraphicsControl = presentationPanel.GraphicsControl; - LastVsyncSetting = vsync; - } - } - - //begin rendering on this context - //should this have been done earlier? - //do i need to check this on an intel video card to see if running excessively is a problem? (it used to be in the FinalTarget command below, shouldnt be a problem) - //GraphicsControl.Begin(); //CRITICAL POINT for yabause+GL - - //TODO - auto-create and age these (and dispose when old) - int rtCounter = 0; - - CurrentFilterProgram.RenderTargetProvider = new DisplayManagerRenderTargetProvider((size) => ShaderChainFrugalizers[rtCounter++].Get(size)); - - GL.BeginScene(); - - //run filter chain - Texture2d texCurr = null; - RenderTarget rtCurr = null; - bool inFinalTarget = false; - foreach (var step in CurrentFilterProgram.Program) - { - switch (step.Type) - { - case FilterProgram.ProgramStepType.Run: - { - int fi = (int)step.Args; - var f = CurrentFilterProgram.Filters[fi]; - f.SetInput(texCurr); - f.Run(); - var orec = f.FindOutput(); - if (orec != null) - { - if (orec.SurfaceDisposition == SurfaceDisposition.Texture) - { - texCurr = f.GetOutput(); - rtCurr = null; - } - } - break; - } - case FilterProgram.ProgramStepType.NewTarget: - { - var size = (Size)step.Args; - rtCurr = ShaderChainFrugalizers[rtCounter++].Get(size); - rtCurr.Bind(); - CurrentFilterProgram.CurrRenderTarget = rtCurr; - break; - } - case FilterProgram.ProgramStepType.FinalTarget: - { - var size = (Size)step.Args; - inFinalTarget = true; - rtCurr = null; - CurrentFilterProgram.CurrRenderTarget = null; - GL.BindRenderTarget(null); - break; - } - } - } - - GL.EndScene(); - - if (job.offscreen) - { - job.offscreenBB = rtCurr.Texture2d.Resolve(); - job.offscreenBB.DiscardAlpha(); - } - else - { - Debug.Assert(inFinalTarget); - - //wait for vsync to begin - if (alternateVsync) dx9.AlternateVsyncPass(0); - - //present and conclude drawing - presentationPanel.GraphicsControl.SwapBuffers(); - - //wait for vsync to end - if (alternateVsync) dx9.AlternateVsyncPass(1); - - //nope. dont do this. workaround for slow context switching on intel GPUs. just switch to another context when necessary before doing anything - //presentationPanel.GraphicsControl.End(); - } - } - - bool? LastVsyncSetting; - GraphicsControl LastVsyncSettingGraphicsControl; - } -} \ No newline at end of file diff --git a/BizHawk.Client.MultiHawk/EmulatorWindow.Designer.cs b/BizHawk.Client.MultiHawk/EmulatorWindow.Designer.cs deleted file mode 100644 index 5fbddd196c..0000000000 --- a/BizHawk.Client.MultiHawk/EmulatorWindow.Designer.cs +++ /dev/null @@ -1,48 +0,0 @@ -namespace BizHawk.Client.MultiHawk -{ - partial class EmulatorWindow - { - /// - /// Required designer variable. - /// - private System.ComponentModel.IContainer components = null; - - /// - /// Clean up any resources being used. - /// - /// true if managed resources should be disposed; otherwise, false. - protected override void Dispose(bool disposing) - { - if (disposing && (components != null)) - { - components.Dispose(); - } - base.Dispose(disposing); - } - - #region Windows Form Designer generated code - - /// - /// Required method for Designer support - do not modify - /// the contents of this method with the code editor. - /// - private void InitializeComponent() - { - this.SuspendLayout(); - // - // EmulatorWindow - // - this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); - this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; - this.ClientSize = new System.Drawing.Size(284, 262); - this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedToolWindow; - this.Name = "EmulatorWindow"; - this.ShowIcon = false; - this.Load += new System.EventHandler(this.EmulatorWindow_Load); - this.ResumeLayout(false); - - } - - #endregion - } -} \ No newline at end of file diff --git a/BizHawk.Client.MultiHawk/EmulatorWindow.cs b/BizHawk.Client.MultiHawk/EmulatorWindow.cs deleted file mode 100644 index 0ea193c46c..0000000000 --- a/BizHawk.Client.MultiHawk/EmulatorWindow.cs +++ /dev/null @@ -1,411 +0,0 @@ -using System; -using System.Collections.Generic; -using System.ComponentModel; -using System.Data; -using System.Drawing; -using System.Linq; -using System.Text; -using System.Windows.Forms; - -using BizHawk.Common; -using BizHawk.Common.BufferExtensions; -using BizHawk.Client.EmuHawk; -using BizHawk.Bizware.BizwareGL; -using BizHawk.Client.Common; -using BizHawk.Emulation.Common; -using BizHawk.Emulation.Common.IEmulatorExtensions; -using System.IO; - - -namespace BizHawk.Client.MultiHawk -{ - // TODO: we can safely assume videoprovider cores are a requirement of multihawk, - // but fail sooner and with a clear message instead of making misc calls to AsVideoProvider that will fail - public partial class EmulatorWindow : Form - { - public EmulatorWindow(Mainform parent) - { - InitializeComponent(); - Closing += (o, e) => - { - ShutDown(); - }; - - MainForm = parent; - } - - private void EmulatorWindow_Load(object sender, EventArgs e) - { - if (Game != null) - { - Text = Game.Name; - } - } - - public Mainform MainForm { get; private set; } - public IEmulator Emulator { get; set; } - public CoreComm CoreComm { get; set; } - public GameInfo Game { get; set; } - public string CurrentRomPath { get; set; } - - public IGL GL { get; set; } - public GLManager.ContextRef CR_GL { get; set; } - public GLManager GLManager { get; set; } - - public PresentationPanel PresentationPanel { get; set; } - - //public Sound Sound; // TODO - public DisplayManager DisplayManager; - - - public void Init() - { - PresentationPanel = new PresentationPanel(this, GL); - CR_GL = GLManager.GetContextForIGL(GL); - DisplayManager = new DisplayManager(PresentationPanel, GL ,GLManager); - - Controls.Add(PresentationPanel); - Controls.SetChildIndex(PresentationPanel, 0); - } - - public void ShutDown() - { - SaveRam(); - MainForm.EmulatorWindowClosed(this); - Emulator.Dispose(); - GL.Dispose(); - } - - public void LoadQuickSave(string quickSlotName) - { - if (!Emulator.HasSavestates()) - { - return; - } - - var path = PathManager.SaveStatePrefix(Game) + "." + quickSlotName + ".State"; - - if (LoadStateFile(path, quickSlotName)) - { - // SetMainformMovieInfo(); // TODO - MainForm.AddMessage("Loaded state: " + quickSlotName); - } - else - { - MainForm.AddMessage("Loadstate error!"); - } - } - - public bool LoadStateFile(string path, string name) - { - var core = Emulator.AsStatable(); - - // try to detect binary first - var bl = BinaryStateLoader.LoadAndDetect(path); - if (bl != null) - { - try - { - var succeed = false; - - // TODO - if (IAmMaster) - { - if (Global.MovieSession.Movie.IsActive) - { - bl.GetLump(BinaryStateLump.Input, true, tr => succeed = Global.MovieSession.HandleMovieLoadState_HackyStep1(tr)); - if (!succeed) - { - return false; - } - - bl.GetLump(BinaryStateLump.Input, true, tr => succeed = Global.MovieSession.HandleMovieLoadState_HackyStep2(tr)); - if (!succeed) - { - return false; - } - } - } - - using (new SimpleTime("Load Core")) - bl.GetCoreState(br => core.LoadStateBinary(br), tr => core.LoadStateText(tr)); - - bl.GetLump(BinaryStateLump.Framebuffer, false, PopulateFramebuffer); - } - catch - { - return false; - } - finally - { - bl.Dispose(); - } - - return true; - } - else // text mode - { - if (Global.MovieSession.HandleMovieLoadState(path)) - { - using (var reader = new StreamReader(path)) - { - core.LoadStateText(reader); - - while (true) - { - var str = reader.ReadLine(); - if (str == null) - { - break; - } - - if (str.Trim() == "") - { - continue; - } - - var args = str.Split(' '); - if (args[0] == "Framebuffer") - { - Emulator.AsVideoProvider().GetVideoBuffer().ReadFromHex(args[1]); - } - } - } - - return true; - } - else - { - return false; - } - } - } - - public void PopulateFramebuffer(BinaryReader br) - { - try - { - using (new SimpleTime("Load Framebuffer")) - QuickBmpFile.Load(Emulator.AsVideoProvider(), br.BaseStream); - } - catch - { - var buff = Emulator.AsVideoProvider().GetVideoBuffer(); - try - { - for (int i = 0; i < buff.Length; i++) - { - int j = br.ReadInt32(); - buff[i] = j; - } - } - catch (EndOfStreamException) { } - } - } - - public void SaveQuickSave(string quickSlotName) - { - if (!Emulator.HasSavestates()) - { - return; - } - - var path = PathManager.SaveStatePrefix(Game) + "." + quickSlotName + ".State"; - - var file = new FileInfo(path); - if (file.Directory != null && file.Directory.Exists == false) - { - file.Directory.Create(); - } - - // TODO - // Make backup first - //if (Global.Config.BackupSavestates && file.Exists) - //{ - // var backup = path + ".bak"; - // var backupFile = new FileInfo(backup); - // if (backupFile.Exists) - // { - // backupFile.Delete(); - // } - - // File.Move(path, backup); - //} - - try - { - SaveStateFile(path, quickSlotName); - - MainForm.AddMessage("Saved state: " + quickSlotName); - } - catch (IOException) - { - MainForm.AddMessage("Unable to save state " + path); - } - - // TODO - } - - private void SaveStateFile(string filename, string name) - { - var core = Emulator.AsStatable(); - - using (var bs = new BinaryStateSaver(filename)) - { - if (Global.Config.SaveStateType == Config.SaveStateTypeE.Text || - (Global.Config.SaveStateType == Config.SaveStateTypeE.Default && !core.BinarySaveStatesPreferred)) - { - // text savestate format - using (new SimpleTime("Save Core")) - bs.PutLump(BinaryStateLump.CorestateText, (tw) => core.SaveStateText(tw)); - } - else - { - // binary core lump format - using (new SimpleTime("Save Core")) - bs.PutLump(BinaryStateLump.Corestate, bw => core.SaveStateBinary(bw)); - } - - if (true) //TODO: Global.Config.SaveScreenshotWithStates) - { - var vp = Emulator.AsVideoProvider(); - var buff = vp.GetVideoBuffer(); - - int out_w = vp.BufferWidth; - int out_h = vp.BufferHeight; - - // if buffer is too big, scale down screenshot - if (true /* !Global.Config.NoLowResLargeScreenshotWithStates*/ && buff.Length >= Global.Config.BigScreenshotSize) - { - out_w /= 2; - out_h /= 2; - } - using (new SimpleTime("Save Framebuffer")) - bs.PutLump(BinaryStateLump.Framebuffer, (s) => QuickBmpFile.Save(Emulator.AsVideoProvider(), s, out_w, out_h)); - } - - if (IAmMaster) - { - if (Global.MovieSession.Movie.IsActive) - { - bs.PutLump(BinaryStateLump.Input, - delegate(TextWriter tw) - { - // this never should have been a core's responsibility - tw.WriteLine("Frame {0}", Emulator.Frame); - Global.MovieSession.HandleMovieSaveState(tw); - }); - } - } - } - } - - public bool IAmMaster - { - get - { - return MainForm.EmulatorWindows.First() == this; - } - } - - public void FrameBufferResized() - { - // run this entire thing exactly twice, since the first resize may adjust the menu stacking - for (int i = 0; i < 2; i++) - { - var video = Emulator.AsVideoProvider(); - int zoom = Global.Config.TargetZoomFactors[Global.Emulator.SystemId]; - var area = Screen.FromControl(this).WorkingArea; - - int borderWidth = Size.Width - PresentationPanel.Control.Size.Width; - int borderHeight = Size.Height - PresentationPanel.Control.Size.Height; - - // start at target zoom and work way down until we find acceptable zoom - Size lastComputedSize = new Size(1, 1); - for (; zoom >= 1; zoom--) - { - lastComputedSize = DisplayManager.CalculateClientSize(video, zoom); - if ((((lastComputedSize.Width) + borderWidth) < area.Width) - && (((lastComputedSize.Height) + borderHeight) < area.Height)) - { - break; - } - } - Console.WriteLine("Selecting display size " + lastComputedSize.ToString()); - - // Change size - Size = new Size((lastComputedSize.Width) + borderWidth, ((lastComputedSize.Height) + borderHeight)); - PerformLayout(); - PresentationPanel.Resized = true; - - // Is window off the screen at this size? - if (area.Contains(Bounds) == false) - { - if (Bounds.Right > area.Right) // Window is off the right edge - { - Location = new Point(area.Right - Size.Width, Location.Y); - } - - if (Bounds.Bottom > area.Bottom) // Window is off the bottom edge - { - Location = new Point(Location.X, area.Bottom - Size.Height); - } - } - } - } - - private Size _lastVideoSize = new Size(-1, -1), _lastVirtualSize = new Size(-1, -1); - public void Render() - { - var video = Emulator.AsVideoProvider(); - - Size currVideoSize = new Size(video.BufferWidth, video.BufferHeight); - Size currVirtualSize = new Size(video.VirtualWidth, video.VirtualWidth); - if (currVideoSize != _lastVideoSize || currVirtualSize != _lastVirtualSize) - { - _lastVideoSize = currVideoSize; - _lastVirtualSize = currVirtualSize; - FrameBufferResized(); - } - - DisplayManager.UpdateSource(video); - } - - public void FrameAdvance() - { - Emulator.FrameAdvance(Global.ControllerOutput, true); - } - - public void SaveRam() - { - if (Emulator.HasSaveRam() && Emulator.AsSaveRam().SaveRamModified) - { - var path = PathManager.SaveRamPath(Global.Game); - var f = new FileInfo(path); - if (f.Directory != null && f.Directory.Exists == false) - { - f.Directory.Create(); - } - - // Make backup first - if (Global.Config.BackupSaveram && f.Exists) - { - var backup = path + ".bak"; - var backupFile = new FileInfo(backup); - if (backupFile.Exists) - { - backupFile.Delete(); - } - - f.CopyTo(backup); - } - - var writer = new BinaryWriter(new FileStream(path, FileMode.Create, FileAccess.Write)); - var saveram = Emulator.AsSaveRam().CloneSaveRam(); - - writer.Write(saveram, 0, saveram.Length); - writer.Close(); - } - } - } -} diff --git a/BizHawk.Client.MultiHawk/EmulatorWindow.resx b/BizHawk.Client.MultiHawk/EmulatorWindow.resx deleted file mode 100644 index 29dcb1b3a3..0000000000 --- a/BizHawk.Client.MultiHawk/EmulatorWindow.resx +++ /dev/null @@ -1,120 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - text/microsoft-resx - - - 2.0 - - - System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - - System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - \ No newline at end of file diff --git a/BizHawk.Client.MultiHawk/EmulatorWindowList.cs b/BizHawk.Client.MultiHawk/EmulatorWindowList.cs deleted file mode 100644 index 1da78079a1..0000000000 --- a/BizHawk.Client.MultiHawk/EmulatorWindowList.cs +++ /dev/null @@ -1,66 +0,0 @@ -using System; -using System.Collections.Generic; -using System.IO; -using System.Linq; -using System.Text; -using Newtonsoft.Json; - -namespace BizHawk.Client.MultiHawk -{ - public class EmulatorWindowList : List - { - public string SessionName { get; set; } - - public EmulatorWindow Master - { - get - { - if (this.Any()) - { - return this.First(); - } - - return null; - } - } - - public IEnumerable Session - { - get - { - return this.Select(ew => new RomSessionEntry - { - RomName = ew.CurrentRomPath, - Wndx = ew.Location.X, - Wndy = ew.Location.Y - }); - } - } - - public string SessionJson - { - get - { - return JsonConvert.SerializeObject(Session); - } - } - - public static IEnumerable FromJson(string json) - { - return JsonConvert.DeserializeObject>(json); - } - - public new void Clear() - { - SessionName = ""; - base.Clear(); - } - - public class RomSessionEntry - { - public string RomName { get; set; } - public int Wndx { get; set; } - public int Wndy { get; set; } - } - } -} diff --git a/BizHawk.Client.MultiHawk/Extensions/ToolExtensions.cs b/BizHawk.Client.MultiHawk/Extensions/ToolExtensions.cs deleted file mode 100644 index 5648ebc66f..0000000000 --- a/BizHawk.Client.MultiHawk/Extensions/ToolExtensions.cs +++ /dev/null @@ -1,228 +0,0 @@ -using System; -using System.IO; -using System.Collections.Generic; -using System.Windows.Forms; -using System.Linq; - -using BizHawk.Common; - -using BizHawk.Emulation.Common; -using BizHawk.Client.Common; - -namespace BizHawk.Client.MultiHawk.ToolExtensions -{ - public static class ToolExtensions - { - public static ToolStripItem[] RecentMenu(this RecentFiles recent, Action loadFileCallback, bool autoload = false) - { - var items = new List(); - - if (recent.Empty) - { - var none = new ToolStripMenuItem { Enabled = false, Text = "None" }; - items.Add(none); - } - else - { - foreach (var filename in recent) - { - //TODO - do TSMI and TSDD need disposing? yuck - var temp = filename; - var item = new ToolStripMenuItem { Text = temp }; - items.Add(item); - - item.Click += (o, ev) => - { - loadFileCallback(temp); - }; - - //TODO - use standard methods to split filename (hawkfile acquire?) - var hf = new HawkFile(); - hf.Parse(temp); - bool canExplore = true; - if (!File.Exists(hf.FullPathWithoutMember)) - canExplore = false; - - var tsdd = new ToolStripDropDownMenu(); - - // TODO - if (canExplore) - { - //make a menuitem to show the last modified timestamp - // var timestamp = File.GetLastWriteTime(hf.FullPathWithoutMember); - // var tsmiTimestamp = new ToolStripLabel { Text = timestamp.ToString() }; - - // tsdd.Items.Add(tsmiTimestamp); - // tsdd.Items.Add(new ToolStripSeparator()); - - - - // if (hf.IsArchive) - // { - // //make a menuitem to let you copy the path - // var tsmiCopyCanonicalPath = new ToolStripMenuItem { Text = "&Copy Canonical Path" }; - // tsmiCopyCanonicalPath.Click += (o, ev) => { System.Windows.Forms.Clipboard.SetText(temp); }; - // tsdd.Items.Add(tsmiCopyCanonicalPath); - - // var tsmiCopyArchivePath = new ToolStripMenuItem { Text = "Copy Archive Path" }; - // tsmiCopyArchivePath.Click += (o, ev) => { System.Windows.Forms.Clipboard.SetText(hf.FullPathWithoutMember); }; - // tsdd.Items.Add(tsmiCopyArchivePath); - - // var tsmiOpenArchive = new ToolStripMenuItem { Text = "Open &Archive" }; - // tsmiOpenArchive.Click += (o, ev) => { System.Diagnostics.Process.Start(hf.FullPathWithoutMember); }; - // tsdd.Items.Add(tsmiOpenArchive); - // } - // else - // { - // //make a menuitem to let you copy the path - // var tsmiCopyPath = new ToolStripMenuItem { Text = "&Copy Path" }; - // tsmiCopyPath.Click += (o, ev) => { System.Windows.Forms.Clipboard.SetText(temp); }; - // tsdd.Items.Add(tsmiCopyPath); - // } - - // tsdd.Items.Add(new ToolStripSeparator()); - - // //make a menuitem to let you explore to it - // var tsmiExplore = new ToolStripMenuItem { Text = "&Explore" }; - // string explorePath = "\"" + hf.FullPathWithoutMember + "\""; - // tsmiExplore.Click += (o, ev) => { System.Diagnostics.Process.Start("explorer.exe", "/select, " + explorePath); }; - // tsdd.Items.Add(tsmiExplore); - - // var tsmiCopyFile = new ToolStripMenuItem { Text = "Copy &File" }; - // var lame = new System.Collections.Specialized.StringCollection(); - // lame.Add(hf.FullPathWithoutMember); - // tsmiCopyFile.Click += (o, ev) => { System.Windows.Forms.Clipboard.SetFileDropList(lame); }; - // tsdd.Items.Add(tsmiCopyFile); - - // var tsmiTest = new ToolStripMenuItem { Text = "&Shell Context Menu" }; - // tsmiTest.Click += (o, ev) => { - // var si = new GongSolutions.Shell.ShellItem(hf.FullPathWithoutMember); - // var scm = new GongSolutions.Shell.ShellContextMenu(si); - // var tsddi = o as ToolStripDropDownItem; - // tsddi.Owner.Update(); - // scm.ShowContextMenu(tsddi.Owner, new System.Drawing.Point(0, 0)); - // }; - // tsdd.Items.Add(tsmiTest); - - // tsdd.Items.Add(new ToolStripSeparator()); - //} - //else - //{ - // //make a menuitem to show the last modified timestamp - // var tsmiMissingFile = new ToolStripLabel { Text = "-Missing-" }; - // tsdd.Items.Add(tsmiMissingFile); - // tsdd.Items.Add(new ToolStripSeparator()); - //} - - ////in either case, make a menuitem to let you remove the path - //var tsmiRemovePath = new ToolStripMenuItem { Text = "&Remove" }; - //tsmiRemovePath.Click += (o, ev) => { recent.Remove(temp); }; - - //tsdd.Items.Add(tsmiRemovePath); - - //////experiment of popping open a submenu. doesnt work well. - ////item.MouseDown += (o, mev) => - ////{ - //// if (mev.Button != MouseButtons.Right) return; - //// //location of the menu containing this item that was just rightclicked - //// var pos = item.Owner.Bounds.Location; - //// //the offset within that menu of this item - //// var tsddi = item as ToolStripDropDownItem; - //// pos.Offset(tsddi.Bounds.Location); - //// //the offset of the click - //// pos.Offset(mev.Location); - //// //tsdd.OwnerItem = item; //has interesting promise, but breaks things otherwise - //// tsdd.Show(pos); - ////}; - - ////just add it to the submenu for now - //item.MouseDown += (o, mev) => - //{ - // if (mev.Button != MouseButtons.Right) return; - // if (item.DropDown != null) - // item.DropDown = tsdd; - // item.ShowDropDown(); - }; - } - } - - items.Add(new ToolStripSeparator()); - - var clearitem = new ToolStripMenuItem { Text = "&Clear", Enabled = !recent.Frozen }; - clearitem.Click += (o, ev) => recent.Clear(); - items.Add(clearitem); - - var freezeitem = new ToolStripMenuItem { Text = recent.Frozen ? "&Unfreeze" : "&Freeze" }; - freezeitem.Click += (o, ev) => recent.Frozen ^= true; - items.Add(freezeitem); - - if (autoload) - { - var auto = new ToolStripMenuItem { Text = "&Autoload", Checked = recent.AutoLoad }; - auto.Click += (o, ev) => recent.ToggleAutoLoad(); - items.Add(auto); - } - - // TODO - //var settingsitem = new ToolStripMenuItem { Text = "&Recent Settings..." }; - //settingsitem.Click += (o, ev) => - //{ - // using (var prompt = new InputPrompt - // { - // TextInputType = InputPrompt.InputType.Unsigned, - // Message = "Number of recent files to track", - // InitialValue = recent.MAX_RECENT_FILES.ToString() - // }) - // { - // var result = prompt.ShowDialog(); - // if (result == DialogResult.OK) - // { - // int val = int.Parse(prompt.PromptText); - // if (val > 0) - // recent.MAX_RECENT_FILES = val; - // } - // } - //}; - //items.Add(settingsitem); - - return items.ToArray(); - } - - public static void HandleLoadError(this RecentFiles recent, string path) - { - // TODO - //GlobalWin.Sound.StopSound(); - if (recent.Frozen) - { - var result = MessageBox.Show("Could not open " + path, "File not found", MessageBoxButtons.OK, MessageBoxIcon.Error); - } - else - { - var result = MessageBox.Show("Could not open " + path + "\nRemove from list?", "File not found", MessageBoxButtons.YesNo, MessageBoxIcon.Error); - if (result == DialogResult.Yes) - { - recent.Remove(path); - } - } - - //GlobalWin.Sound.StartSound(); - } - - public static IEnumerable MenuItems(this IMemoryDomains domains, Action setCallback, string selected = "", int? maxSize = null) - { - foreach (var domain in domains) - { - var name = domain.Name; - var item = new ToolStripMenuItem - { - Text = name, - Enabled = !(maxSize.HasValue && domain.Size > maxSize.Value), - Checked = name == selected - }; - item.Click += (o, ev) => setCallback(name); - - yield return item; - } - } - } -} diff --git a/BizHawk.Client.MultiHawk/GlobalWin.cs b/BizHawk.Client.MultiHawk/GlobalWin.cs deleted file mode 100644 index 45794b7700..0000000000 --- a/BizHawk.Client.MultiHawk/GlobalWin.cs +++ /dev/null @@ -1,25 +0,0 @@ -using BizHawk.Client.Common; -using BizHawk.Bizware.BizwareGL; -using SlimDX.DirectSound; - -namespace BizHawk.Client.MultiHawk -{ - public static class GlobalWin - { - public static Mainform MainForm; - //public static ToolManager Tools; - public static IGL GL; - public static Bizware.BizwareGL.Drivers.OpenTK.IGL_TK IGL_GL; - public static BizHawk.Client.EmuHawk.GLManager.ContextRef CR_GL; - //public static Sound Sound; - //public static PresentationPanel PresentationPanel; - //public static OSDManager OSD = new OSDManager(); - //public static DisplayManager DisplayManager; - public static BizHawk.Client.EmuHawk.GLManager GLManager; - - //input state which has been destined for game controller inputs are coalesced here - //public static ControllerInputCoalescer ControllerInputCoalescer = new ControllerInputCoalescer(); - //input state which has been destined for client hotkey consumption are colesced here - public static InputCoalescer HotkeyCoalescer = new InputCoalescer(); - } -} diff --git a/BizHawk.Client.MultiHawk/Input/GamePad.cs b/BizHawk.Client.MultiHawk/Input/GamePad.cs deleted file mode 100644 index 75e03c44a2..0000000000 --- a/BizHawk.Client.MultiHawk/Input/GamePad.cs +++ /dev/null @@ -1,235 +0,0 @@ -using System; -using System.Collections.Generic; -using SlimDX; -using SlimDX.DirectInput; - -namespace BizHawk.Client.MultiHawk -{ - public class GamePad - { - // ********************************** Static interface ********************************** - - static DirectInput dinput; - public static List Devices; - - public static void Initialize(IntPtr parent) - { - if (dinput == null) - dinput = new DirectInput(); - - Devices = new List(); - - foreach (DeviceInstance device in dinput.GetDevices(DeviceClass.GameController, DeviceEnumerationFlags.AttachedOnly)) - { - Console.WriteLine("joydevice: {0} `{1}`", device.InstanceGuid, device.ProductName); - - if (device.ProductName.Contains("XBOX 360")) - continue; // Don't input XBOX 360 controllers into here; we'll process them via XInput (there are limitations in some trigger axes when xbox pads go over xinput) - - var joystick = new Joystick(dinput, device.InstanceGuid); - joystick.SetCooperativeLevel(parent, CooperativeLevel.Background | CooperativeLevel.Nonexclusive); - foreach (DeviceObjectInstance deviceObject in joystick.GetObjects()) - { - if ((deviceObject.ObjectType & ObjectDeviceType.Axis) != 0) - joystick.GetObjectPropertiesById((int)deviceObject.ObjectType).SetRange(-1000, 1000); - } - joystick.Acquire(); - - GamePad p = new GamePad(device.InstanceName, device.InstanceGuid, joystick); - Devices.Add(p); - } - } - - public static void UpdateAll() - { - foreach (var device in Devices) - device.Update(); - } - - public static void CloseAll() - { - if (Devices != null) - { - foreach (var device in Devices) - device.joystick.Dispose(); - Devices.Clear(); - } - } - - // ********************************** Instance Members ********************************** - - readonly string name; - readonly Guid guid; - readonly Joystick joystick; - JoystickState state = new JoystickState(); - - GamePad(string name, Guid guid, Joystick joystick) - { - this.name = name; - this.guid = guid; - this.joystick = joystick; - Update(); - InitializeCallbacks(); - } - - public void Update() - { - try - { - if (joystick.Acquire().IsFailure) - return; - } - catch - { - return; - } - if (joystick.Poll().IsFailure) - return; - - state = joystick.GetCurrentState(); - if (Result.Last.IsFailure) - // do something? - return; - } - - public IEnumerable> GetFloats() - { - var pis = typeof(JoystickState).GetProperties(); - foreach (var pi in pis) - yield return new Tuple(pi.Name, 10.0f * (float)(int)pi.GetValue(state, null)); - } - - /// FOR DEBUGGING ONLY - public JoystickState GetInternalState() - { - return state; - } - - public string Name { get { return name; } } - public Guid Guid { get { return guid; } } - - - public string ButtonName(int index) - { - return names[index]; - } - public bool Pressed(int index) - { - return actions[index](); - } - public int NumButtons { get; private set; } - - private readonly List names = new List(); - private readonly List> actions = new List>(); - - void AddItem(string _name, Func callback) - { - names.Add(_name); - actions.Add(callback); - NumButtons++; - } - - void InitializeCallbacks() - { - const int dzp = 400; - const int dzn = -400; - - names.Clear(); - actions.Clear(); - NumButtons = 0; - - AddItem("AccelerationX+", () => state.AccelerationX >= dzp); - AddItem("AccelerationX-", () => state.AccelerationX <= dzn); - AddItem("AccelerationY+", () => state.AccelerationY >= dzp); - AddItem("AccelerationY-", () => state.AccelerationY <= dzn); - AddItem("AccelerationZ+", () => state.AccelerationZ >= dzp); - AddItem("AccelerationZ-", () => state.AccelerationZ <= dzn); - AddItem("AngularAccelerationX+", () => state.AngularAccelerationX >= dzp); - AddItem("AngularAccelerationX-", () => state.AngularAccelerationX <= dzn); - AddItem("AngularAccelerationY+", () => state.AngularAccelerationY >= dzp); - AddItem("AngularAccelerationY-", () => state.AngularAccelerationY <= dzn); - AddItem("AngularAccelerationZ+", () => state.AngularAccelerationZ >= dzp); - AddItem("AngularAccelerationZ-", () => state.AngularAccelerationZ <= dzn); - AddItem("AngularVelocityX+", () => state.AngularVelocityX >= dzp); - AddItem("AngularVelocityX-", () => state.AngularVelocityX <= dzn); - AddItem("AngularVelocityY+", () => state.AngularVelocityY >= dzp); - AddItem("AngularVelocityY-", () => state.AngularVelocityY <= dzn); - AddItem("AngularVelocityZ+", () => state.AngularVelocityZ >= dzp); - AddItem("AngularVelocityZ-", () => state.AngularVelocityZ <= dzn); - AddItem("ForceX+", () => state.ForceX >= dzp); - AddItem("ForceX-", () => state.ForceX <= dzn); - AddItem("ForceY+", () => state.ForceY >= dzp); - AddItem("ForceY-", () => state.ForceY <= dzn); - AddItem("ForceZ+", () => state.ForceZ >= dzp); - AddItem("ForceZ-", () => state.ForceZ <= dzn); - AddItem("RotationX+", () => state.RotationX >= dzp); - AddItem("RotationX-", () => state.RotationX <= dzn); - AddItem("RotationY+", () => state.RotationY >= dzp); - AddItem("RotationY-", () => state.RotationY <= dzn); - AddItem("RotationZ+", () => state.RotationZ >= dzp); - AddItem("RotationZ-", () => state.RotationZ <= dzn); - AddItem("TorqueX+", () => state.TorqueX >= dzp); - AddItem("TorqueX-", () => state.TorqueX <= dzn); - AddItem("TorqueY+", () => state.TorqueY >= dzp); - AddItem("TorqueY-", () => state.TorqueY <= dzn); - AddItem("TorqueZ+", () => state.TorqueZ >= dzp); - AddItem("TorqueZ-", () => state.TorqueZ <= dzn); - AddItem("VelocityX+", () => state.VelocityX >= dzp); - AddItem("VelocityX-", () => state.VelocityX <= dzn); - AddItem("VelocityY+", () => state.VelocityY >= dzp); - AddItem("VelocityY-", () => state.VelocityY <= dzn); - AddItem("VelocityZ+", () => state.VelocityZ >= dzp); - AddItem("VelocityZ-", () => state.VelocityZ <= dzn); - AddItem("X+", () => state.X >= dzp); - AddItem("X-", () => state.X <= dzn); - AddItem("Y+", () => state.Y >= dzp); - AddItem("Y-", () => state.Y <= dzn); - AddItem("Z+", () => state.Z >= dzp); - AddItem("Z-", () => state.Z <= dzn); - - // i don't know what the "Slider"s do, so they're omitted for the moment - - for (int i = 0; i < state.GetButtons().Length; i++) - { - int j = i; - AddItem($"B{i + 1}", () => state.IsPressed(j)); - } - - for (int i = 0; i < state.GetPointOfViewControllers().Length; i++) - { - int j = i; - AddItem($"POV{i + 1}U", - () => { int t = state.GetPointOfViewControllers()[j]; return (t >= 0 && t <= 4500) || (t >= 31500 && t < 36000); }); - AddItem($"POV{i + 1}D", - () => { int t = state.GetPointOfViewControllers()[j]; return t >= 13500 && t <= 22500; }); - AddItem($"POV{i + 1}L", - () => { int t = state.GetPointOfViewControllers()[j]; return t >= 22500 && t <= 31500; }); - AddItem($"POV{i + 1}R", - () => { int t = state.GetPointOfViewControllers()[j]; return t >= 4500 && t <= 13500; }); - } - } - - // Note that this does not appear to work at this time. I probably need to have more infos. - public void SetVibration(int left, int right) - { - int[] temp1, temp2; - // my first clue that it doesnt work is that LEFT and RIGHT _ARENT USED_ - // I should just look for C++ examples instead of trying to look for SlimDX examples - - var parameters = new EffectParameters - { - Duration = 0x2710, - Gain = 0x2710, - SamplePeriod = 0, - TriggerButton = 0, - TriggerRepeatInterval = 0x2710, - Flags = EffectFlags.None - }; - parameters.GetAxes(out temp1, out temp2); - parameters.SetAxes(temp1, temp2); - var effect = new Effect(joystick, EffectGuid.ConstantForce); - effect.SetParameters(parameters); - effect.Start(1); - } - } -} \ No newline at end of file diff --git a/BizHawk.Client.MultiHawk/Input/Input.cs b/BizHawk.Client.MultiHawk/Input/Input.cs deleted file mode 100644 index 9c3abc76f0..0000000000 --- a/BizHawk.Client.MultiHawk/Input/Input.cs +++ /dev/null @@ -1,511 +0,0 @@ -using System; -using System.Linq; -using System.Collections.Generic; -using System.Threading; -#if WINDOWS -using SlimDX.DirectInput; -#endif - -using BizHawk.Common; -using BizHawk.Client.Common; - -namespace BizHawk.Client.MultiHawk -{ - //coalesces events back into instantaneous states - public class InputCoalescer : SimpleController - { - public void Receive(Input.InputEvent ie) - { - bool state = ie.EventType == Input.InputEventType.Press; - - string button = ie.LogicalButton.ToString(); - Buttons[button] = state; - - //when a button is released, all modified variants of it are released as well - if (!state) - { - var releases = Buttons.Where(kvp => kvp.Key.Contains("+") && kvp.Key.EndsWith(ie.LogicalButton.Button)).ToArray(); - foreach (var kvp in releases) - Buttons[kvp.Key] = false; - } - } - } - - public class ControllerInputCoalescer : SimpleController - { - public void Receive(Input.InputEvent ie) - { - bool state = ie.EventType == Input.InputEventType.Press; - - string button = ie.LogicalButton.ToString(); - Buttons[button] = state; - - //For controller input, we want Shift+X to register as both Shift and X (for Keyboard controllers) - string[] subgroups = button.Split('+'); - if (subgroups.Length > 0) - { - foreach (string s in subgroups) - { - Buttons[s] = state; - } - } - - //when a button is released, all modified variants of it are released as well - if (!state) - { - var releases = Buttons.Where((kvp) => kvp.Key.Contains("+") && kvp.Key.EndsWith(ie.LogicalButton.Button)).ToArray(); - foreach (var kvp in releases) - Buttons[kvp.Key] = false; - } - } - } - - public class Input - { - [Flags] - public enum InputFocus - { - None = 0, - Mouse = 1, - Keyboard = 2, - Pad = 4 - } - - /// - /// If your form needs this kind of input focus, be sure to say so. - /// Really, this only makes sense for mouse, but I've started building it out for other things - /// Why is this receiving a control, but actually using it as a Form (where the WantingMouseFocus is checked?) - /// Because later we might change it to work off the control, specifically, if a control is supplied (normally actually a Form will be supplied) - /// - public void ControlInputFocus(System.Windows.Forms.Control c, InputFocus types, bool wants) - { - if (types.HasFlag(InputFocus.Mouse) && wants) WantingMouseFocus.Add(c); - if (types.HasFlag(InputFocus.Mouse) && !wants) WantingMouseFocus.Remove(c); - } - - HashSet WantingMouseFocus = new HashSet(); - - [Flags] - public enum ModifierKey - { - // Summary: - // The bitmask to extract modifiers from a key value. - Modifiers = -65536, - // - // Summary: - // No key pressed. - None = 0, - // - // Summary: - // The SHIFT modifier key. - Shift = 65536, - // - // Summary: - // The CTRL modifier key. - Control = 131072, - // - // Summary: - // The ALT modifier key. - Alt = 262144, - } - - public static Input Instance { get; private set; } - readonly Thread UpdateThread; - - private Input() - { -#if WINDOWS - UpdateThread = new Thread(UpdateThreadProc) - { - IsBackground = true, - Priority = ThreadPriority.AboveNormal //why not? this thread shouldn't be very heavy duty, and we want it to be responsive - }; - UpdateThread.Start(); -#endif - } - - public static void Initialize(IntPtr parent) - { -#if WINDOWS - KeyInput.Initialize(parent); - GamePad.Initialize(parent); - BizHawk.Client.EmuHawk.GamePad360.Initialize(); -#endif - Instance = new Input(); - } - - public enum InputEventType - { - Press, Release - } - public struct LogicalButton - { - public LogicalButton(string button, ModifierKey modifiers) - { - Button = button; - Modifiers = modifiers; - } - public readonly string Button; - public readonly ModifierKey Modifiers; - - public bool Alt { get { return ((Modifiers & ModifierKey.Alt) != 0); } } - public bool Control { get { return ((Modifiers & ModifierKey.Control) != 0); } } - public bool Shift { get { return ((Modifiers & ModifierKey.Shift) != 0); } } - - public override string ToString() - { - string ret = ""; - if (Control) ret += "Ctrl+"; - if (Alt) ret += "Alt+"; - if (Shift) ret += "Shift+"; - ret += Button; - return ret; - } - public override bool Equals(object obj) - { - var other = (LogicalButton)obj; - return other == this; - } - public override int GetHashCode() - { - return Button.GetHashCode() ^ Modifiers.GetHashCode(); - } - public static bool operator ==(LogicalButton lhs, LogicalButton rhs) - { - return lhs.Button == rhs.Button && lhs.Modifiers == rhs.Modifiers; - } - public static bool operator !=(LogicalButton lhs, LogicalButton rhs) - { - return !(lhs == rhs); - } - } - public class InputEvent - { - public LogicalButton LogicalButton; - public InputEventType EventType; - public override string ToString() => $"{EventType.ToString()}:{LogicalButton.ToString()}"; - } - - private readonly WorkingDictionary ModifierState = new WorkingDictionary(); - private readonly WorkingDictionary LastState = new WorkingDictionary(); - private readonly WorkingDictionary UnpressState = new WorkingDictionary(); - private readonly HashSet IgnoreKeys = new HashSet(new[] { "LeftShift", "RightShift", "LeftControl", "RightControl", "LeftAlt", "RightAlt" }); - private readonly WorkingDictionary FloatValues = new WorkingDictionary(); - private readonly WorkingDictionary FloatDeltas = new WorkingDictionary(); - private bool trackdeltas = false; - - void HandleButton(string button, bool newState) - { - bool isModifier = IgnoreKeys.Contains(button); - if (EnableIgnoreModifiers && isModifier) return; - if (LastState[button] && newState) return; - if (!LastState[button] && !newState) return; - - //apply - //NOTE: this is not quite right. if someone held leftshift+rightshift it would be broken. seems unlikely, though. - if (button == "LeftShift") - { - _Modifiers &= ~ModifierKey.Shift; - if (newState) - _Modifiers |= ModifierKey.Shift; - } - if (button == "RightShift") { _Modifiers &= ~ModifierKey.Shift; if (newState) _Modifiers |= ModifierKey.Shift; } - if (button == "LeftControl") { _Modifiers &= ~ModifierKey.Control; if (newState) _Modifiers |= ModifierKey.Control; } - if (button == "RightControl") { _Modifiers &= ~ModifierKey.Control; if (newState) _Modifiers |= ModifierKey.Control; } - if (button == "LeftAlt") { _Modifiers &= ~ModifierKey.Alt; if (newState) _Modifiers |= ModifierKey.Alt; } - if (button == "RightAlt") { _Modifiers &= ~ModifierKey.Alt; if (newState) _Modifiers |= ModifierKey.Alt; } - - if (UnpressState.ContainsKey(button)) - { - if (newState) return; - Console.WriteLine($"Removing Unpress {button} with {nameof(newState)} {newState}"); - UnpressState.Remove(button); - LastState[button] = false; - return; - } - - - //dont generate events for things like Ctrl+LeftControl - ModifierKey mods = _Modifiers; - if (button == "LeftShift") mods &= ~ModifierKey.Shift; - if (button == "RightShift") mods &= ~ModifierKey.Shift; - if (button == "LeftControl") mods &= ~ModifierKey.Control; - if (button == "RightControl") mods &= ~ModifierKey.Control; - if (button == "LeftAlt") mods &= ~ModifierKey.Alt; - if (button == "RightAlt") mods &= ~ModifierKey.Alt; - - var ie = new InputEvent - { - EventType = newState ? InputEventType.Press : InputEventType.Release, - LogicalButton = new LogicalButton(button, mods) - }; - LastState[button] = newState; - - //track the pressed events with modifiers that we send so that we can send corresponding unpresses with modifiers - //this is an interesting idea, which we may need later, but not yet. - //for example, you may see this series of events: press:ctrl+c, release:ctrl, release:c - //but you might would rather have press:ctr+c, release:ctrl+c - //this code relates the releases to the original presses. - //UPDATE - this is necessary for the frame advance key, which has a special meaning when it gets stuck down - //so, i am adding it as of 11-sep-2011 - if (newState) - { - ModifierState[button] = ie.LogicalButton; - } - else - { - if (ModifierState[button] != null) - { - LogicalButton alreadyReleased = ie.LogicalButton; - var ieModified = new InputEvent - { - LogicalButton = (LogicalButton)ModifierState[button], - EventType = InputEventType.Release - }; - if (ieModified.LogicalButton != alreadyReleased) - _NewEvents.Add(ieModified); - } - ModifierState[button] = null; - } - - _NewEvents.Add(ie); - } - - ModifierKey _Modifiers; - private readonly List _NewEvents = new List(); - - //do we need this? - public void ClearEvents() - { - lock (this) - { - InputEvents.Clear(); - } - } - - private readonly Queue InputEvents = new Queue(); - public InputEvent DequeueEvent() - { - lock (this) - { - if (InputEvents.Count == 0) return null; - else return InputEvents.Dequeue(); - } - } - void EnqueueEvent(InputEvent ie) - { - lock (this) - { - InputEvents.Enqueue(ie); - } - } - - public List> GetFloats() - { - List> FloatValuesCopy = new List>(); - lock (FloatValues) - { - foreach (var kvp in FloatValues) - FloatValuesCopy.Add(new Tuple(kvp.Key, kvp.Value)); - } - return FloatValuesCopy; - } - -#if WINDOWS - void UpdateThreadProc() - { - for (; ; ) - { - var keyEvents = KeyInput.Update(); - GamePad.UpdateAll(); - BizHawk.Client.EmuHawk.GamePad360.UpdateAll(); - - //this block is going to massively modify data structures that the binding method uses, so we have to lock it all - lock (this) - { - _NewEvents.Clear(); - - //analyze keys - foreach (var ke in keyEvents) - HandleButton(ke.Key.ToString(), ke.Pressed); - - lock (FloatValues) - { - //FloatValues.Clear(); - - //analyze xinput - foreach (var pad in BizHawk.Client.EmuHawk.GamePad360.EnumerateDevices()) - { - string xname = "X" + pad.PlayerNumber + " "; - for (int b = 0; b < pad.NumButtons; b++) - HandleButton(xname + pad.ButtonName(b), pad.Pressed(b)); - foreach (var sv in pad.GetFloats()) - { - string n = xname + sv.Item1; - float f = sv.Item2; - if (trackdeltas) - FloatDeltas[n] += Math.Abs(f - FloatValues[n]); - FloatValues[n] = f; - } - } - - //analyze joysticks - for (int i = 0; i < GamePad.Devices.Count; i++) - { - var pad = GamePad.Devices[i]; - string jname = "J" + (i + 1) + " "; - - for (int b = 0; b < pad.NumButtons; b++) - HandleButton(jname + pad.ButtonName(b), pad.Pressed(b)); - foreach (var sv in pad.GetFloats()) - { - string n = jname + sv.Item1; - float f = sv.Item2; - //if (n == "J5 RotationZ") - // System.Diagnostics.Debugger.Break(); - if (trackdeltas) - FloatDeltas[n] += Math.Abs(f - FloatValues[n]); - FloatValues[n] = f; - } - } - - // analyse moose - // other sorts of mouse api (raw input) could easily be added as a separate listing under a different class - if (WantingMouseFocus.Contains(System.Windows.Forms.Form.ActiveForm)) - { - var P = System.Windows.Forms.Control.MousePosition; - if (trackdeltas) - { - // these are relative to screen coordinates, but that's not terribly important - FloatDeltas["WMouse X"] += Math.Abs(P.X - FloatValues["WMouse X"]) * 50; - FloatDeltas["WMouse Y"] += Math.Abs(P.Y - FloatValues["WMouse Y"]) * 50; - } - // coordinate translation happens later - FloatValues["WMouse X"] = P.X; - FloatValues["WMouse Y"] = P.Y; - - var B = System.Windows.Forms.Control.MouseButtons; - HandleButton("WMouse L", (B & System.Windows.Forms.MouseButtons.Left) != 0); - HandleButton("WMouse C", (B & System.Windows.Forms.MouseButtons.Middle) != 0); - HandleButton("WMouse R", (B & System.Windows.Forms.MouseButtons.Right) != 0); - HandleButton("WMouse 1", (B & System.Windows.Forms.MouseButtons.XButton1) != 0); - HandleButton("WMouse 2", (B & System.Windows.Forms.MouseButtons.XButton2) != 0); - } - else - { - //dont do this: for now, it will interfere with the virtualpad. dont do something similar for the mouse position either - //unpress all buttons - //HandleButton("WMouse L", false); - //HandleButton("WMouse C", false); - //HandleButton("WMouse R", false); - //HandleButton("WMouse 1", false); - //HandleButton("WMouse 2", false); - } - - } - - bool swallow = !GlobalWin.MainForm.AllowInput; - - foreach (var ie in _NewEvents) - { - //events are swallowed in some cases: - if (ie.EventType == InputEventType.Press && swallow) - { } - else - EnqueueEvent(ie); - } - } //lock(this) - - //arbitrary selection of polling frequency: - Thread.Sleep(10); - } - } -#endif - - public void StartListeningForFloatEvents() - { - lock (FloatValues) - { - FloatDeltas.Clear(); - trackdeltas = true; - } - } - - public string GetNextFloatEvent() - { - lock (FloatValues) - { - foreach (var kvp in FloatDeltas) - { - // need to wiggle the stick a bit - if (kvp.Value >= 20000.0f) - return kvp.Key; - } - } - return null; - } - - public void StopListeningForFloatEvents() - { - lock (FloatValues) - { - trackdeltas = false; - } - } - - public void Update() - { - //TODO - for some reason, we may want to control when the next event processing step happens - //so i will leave this method here for now.. - } - - //returns the next Press event, if available. should be useful - public string GetNextBindEvent() - { - //this whole process is intimately involved with the data structures, which can conflict with the input thread. - lock (this) - { - if (InputEvents.Count == 0) return null; - if (!GlobalWin.MainForm.AllowInput) return null; - - //we only listen to releases for input binding, because we need to distinguish releases of pure modifierkeys from modified keys - //if you just pressed ctrl, wanting to bind ctrl, we'd see: pressed:ctrl, unpressed:ctrl - //if you just pressed ctrl+c, wanting to bind ctrl+c, we'd see: pressed:ctrl, pressed:ctrl+c, unpressed:ctrl+c, unpressed:ctrl - //so its the first unpress we need to listen for - - while (InputEvents.Count != 0) - { - var ie = DequeueEvent(); - - //as a special perk, we'll accept escape immediately - if (ie.EventType == InputEventType.Press && ie.LogicalButton.Button == "Escape") - goto ACCEPT; - - if (ie.EventType == InputEventType.Press) continue; - - ACCEPT: - Console.WriteLine("Bind Event: {0} ", ie); - - foreach (var kvp in LastState) - if (kvp.Value) - { - Console.WriteLine("Unpressing " + kvp.Key); - UnpressState[kvp.Key] = true; - } - - InputEvents.Clear(); - - return ie.LogicalButton.ToString(); - } - - return null; - } - } - - //controls whether modifier keys will be ignored as key press events - //this should be used by hotkey binders, but we may want modifier key events - //to get triggered in the main form - public bool EnableIgnoreModifiers = false; - - } -} diff --git a/BizHawk.Client.MultiHawk/Input/Keyboard.cs b/BizHawk.Client.MultiHawk/Input/Keyboard.cs deleted file mode 100644 index 33f5ba938a..0000000000 --- a/BizHawk.Client.MultiHawk/Input/Keyboard.cs +++ /dev/null @@ -1,132 +0,0 @@ -using System.Collections.Generic; -using SlimDX; -using SlimDX.DirectInput; -using System; - -namespace BizHawk.Client.MultiHawk -{ - public static class KeyInput - { - private static DirectInput dinput; - private static Keyboard keyboard; - private static KeyboardState state = new KeyboardState(); - - public static void Initialize(IntPtr parent) - { - if (dinput == null) - dinput = new DirectInput(); - - if (keyboard == null || keyboard.Disposed) - keyboard = new Keyboard(dinput); - keyboard.SetCooperativeLevel(parent, CooperativeLevel.Background | CooperativeLevel.Nonexclusive); - keyboard.Properties.BufferSize = 8; - } - - static List EmptyList = new List(); - static List EventList = new List(); - - public static IEnumerable Update() - { - EventList.Clear(); - - if (keyboard.Acquire().IsFailure) - return EmptyList; - if (keyboard.Poll().IsFailure) - return EmptyList; - - for (; ; ) - { - var events = keyboard.GetBufferedData(); - if (Result.Last.IsFailure) - return EventList; - if (events.Count == 0) - break; - foreach (var e in events) - { - foreach (var k in e.PressedKeys) - EventList.Add(new KeyEvent { Key = k, Pressed = true }); - foreach (var k in e.ReleasedKeys) - EventList.Add(new KeyEvent { Key = k, Pressed = false }); - } - } - - return EventList; - } - - public struct KeyEvent - { - public Key Key; - public bool Pressed; - } - - - public static bool IsPressed(Key key) - { - if (state.IsPressed(key)) - return true; - - if (key == Key.LeftShift && state.IsPressed(Key.RightShift)) - return true; - if (key == Key.LeftControl && state.IsPressed(Key.RightControl)) - return true; - if (key == Key.LeftAlt && state.IsPressed(Key.RightAlt)) - return true; - - return false; - } - - public static bool ShiftModifier - { - get - { - if (state.IsPressed(Key.LeftShift)) return true; - if (state.IsPressed(Key.RightShift)) return true; - return false; - } - } - - public static bool CtrlModifier - { - get - { - if (state.IsPressed(Key.LeftControl)) return true; - if (state.IsPressed(Key.RightControl)) return true; - return false; - } - } - - public static bool AltModifier - { - get - { - if (state.IsPressed(Key.LeftAlt)) return true; - if (state.IsPressed(Key.RightAlt)) return true; - return false; - } - } - - public static Input.ModifierKey GetModifierKeysAsKeys() - { - Input.ModifierKey ret = Input.ModifierKey.None; - if (ShiftModifier) ret |= Input.ModifierKey.Shift; - if (CtrlModifier) ret |= Input.ModifierKey.Control; - if (AltModifier) ret |= Input.ModifierKey.Alt; - return ret; - } - - } - - internal static class KeyExtensions - { - public static bool IsModifier(this Key key) - { - if (key == Key.LeftShift) return true; - if (key == Key.RightShift) return true; - if (key == Key.LeftControl) return true; - if (key == Key.RightControl) return true; - if (key == Key.LeftAlt) return true; - if (key == Key.RightAlt) return true; - return false; - } - } -} diff --git a/BizHawk.Client.MultiHawk/InputManager.cs b/BizHawk.Client.MultiHawk/InputManager.cs deleted file mode 100644 index a1e7470727..0000000000 --- a/BizHawk.Client.MultiHawk/InputManager.cs +++ /dev/null @@ -1,121 +0,0 @@ -using System.Collections.Generic; -using System.Linq; - -using BizHawk.Emulation.Common; -using BizHawk.Client.Common.InputAdapterExtensions; - -using BizHawk.Client.Common; - -namespace BizHawk.Client.MultiHawk -{ - public class InputManager - { - Mainform _mainForm; - - public InputManager(Mainform mainForm) - { - _mainForm = mainForm; - } - - public void RewireInputChain() - { - Global.ControllerInputCoalescer.Clear(); - Global.ControllerInputCoalescer.Definition = Global.ActiveController.Definition; - - // TODO? - //Global.UD_LR_ControllerAdapter.Source = Global.ActiveController.Or(Global.AutoFireController); - Global.UD_LR_ControllerAdapter.Source = Global.ActiveController; - - Global.StickyXORAdapter.Source = Global.UD_LR_ControllerAdapter; - - // TODO? - //Global.AutofireStickyXORAdapter.Source = Global.StickyXORAdapter; - - //Global.MultitrackRewiringAdapter.Source = Global.AutofireStickyXORAdapter; - - Global.MultitrackRewiringAdapter.Source = Global.StickyXORAdapter; - Global.MovieInputSourceAdapter.Source = Global.MultitrackRewiringAdapter; - Global.ControllerOutput.Source = Global.MovieOutputHardpoint; - - Global.MovieSession.MovieControllerAdapter.Definition = Global.MovieInputSourceAdapter.Definition; - - // connect the movie session before MovieOutputHardpoint if it is doing anything - // otherwise connect the MovieInputSourceAdapter to it, effectively bypassing the movie session - if (Global.MovieSession != null) - { - Global.MovieOutputHardpoint.Source = Global.MovieSession.MovieControllerAdapter; - } - else - { - Global.MovieOutputHardpoint.Source = Global.MovieInputSourceAdapter; - } - } - - public void SyncControls() - { - var def = _mainForm.EmulatorWindows.First().Emulator.ControllerDefinition; - - Global.ActiveController = BindToDefinition(def, Global.Config.AllTrollers, Global.Config.AllTrollersAnalog); - // TODO? - //Global.AutoFireController = BindToDefinitionAF(def, Global.Config.AllTrollersAutoFire); - - // allow propogating controls that are in the current controller definition but not in the prebaked one - // these two lines shouldn't be required anymore under the new system? - Global.ActiveController.ForceType(new ControllerDefinition(def)); - Global.ClickyVirtualPadController.Definition = new ControllerDefinition(def); - RewireInputChain(); - } - - private Controller BindToDefinition(ControllerDefinition def, IDictionary> allbinds, IDictionary> analogbinds) - { - var ret = new Controller(def); - Dictionary binds; - if (allbinds.TryGetValue(def.Name, out binds)) - { - foreach (var cbutton in def.BoolButtons) - { - string bind; - if (binds.TryGetValue(cbutton, out bind)) - { - ret.BindMulti(cbutton, bind); - } - } - } - - Dictionary abinds; - if (analogbinds.TryGetValue(def.Name, out abinds)) - { - foreach (var cbutton in def.FloatControls) - { - Config.AnalogBind bind; - if (abinds.TryGetValue(cbutton, out bind)) - { - ret.BindFloat(cbutton, bind); - } - } - } - - return ret; - } - - // TODO? - //private AutofireController BindToDefinitionAF(ControllerDefinition def, IDictionary> allbinds) - //{ - // var ret = new AutofireController(def); - // Dictionary binds; - // if (allbinds.TryGetValue(def.Name, out binds)) - // { - // foreach (var cbutton in def.BoolButtons) - // { - // string bind; - // if (binds.TryGetValue(cbutton, out bind)) - // { - // ret.BindMulti(cbutton, bind); - // } - // } - // } - - // return ret; - //} - } -} \ No newline at end of file diff --git a/BizHawk.Client.MultiHawk/Mainform.Designer.cs b/BizHawk.Client.MultiHawk/Mainform.Designer.cs deleted file mode 100644 index 51157dee4f..0000000000 --- a/BizHawk.Client.MultiHawk/Mainform.Designer.cs +++ /dev/null @@ -1,548 +0,0 @@ -namespace BizHawk.Client.MultiHawk -{ - partial class Mainform - { - /// - /// Required designer variable. - /// - private System.ComponentModel.IContainer components = null; - - /// - /// Clean up any resources being used. - /// - /// true if managed resources should be disposed; otherwise, false. - protected override void Dispose(bool disposing) - { - if (disposing && (components != null)) - { - components.Dispose(); - } - base.Dispose(disposing); - } - - #region Windows Form Designer generated code - - /// - /// Required method for Designer support - do not modify - /// the contents of this method with the code editor. - /// - private void InitializeComponent() - { - this.components = new System.ComponentModel.Container(); - this.MainformMenu = new MenuStripEx(); - this.FileSubMenu = new System.Windows.Forms.ToolStripMenuItem(); - this.NewSessionMenuItem = new System.Windows.Forms.ToolStripMenuItem(); - this.OpenSessionMenuItem = new System.Windows.Forms.ToolStripMenuItem(); - this.SaveSessionMenuItem = new System.Windows.Forms.ToolStripMenuItem(); - this.SaveSessionAsMenuItem = new System.Windows.Forms.ToolStripMenuItem(); - this.RecentSessionSubMenu = new System.Windows.Forms.ToolStripMenuItem(); - this.toolStripSeparator6 = new System.Windows.Forms.ToolStripSeparator(); - this.toolStripSeparator7 = new System.Windows.Forms.ToolStripSeparator(); - this.OpenRomMenuItem = new System.Windows.Forms.ToolStripMenuItem(); - this.RecentRomSubMenu = new System.Windows.Forms.ToolStripMenuItem(); - this.toolStripSeparator1 = new System.Windows.Forms.ToolStripSeparator(); - this.toolStripSeparator5 = new System.Windows.Forms.ToolStripSeparator(); - this.RebootCoresMenuItem = new System.Windows.Forms.ToolStripMenuItem(); - this.toolStripSeparator3 = new System.Windows.Forms.ToolStripSeparator(); - this.ExitMenuItem = new System.Windows.Forms.ToolStripMenuItem(); - this.ViewSubMenu = new System.Windows.Forms.ToolStripMenuItem(); - this._1xMenuItem = new System.Windows.Forms.ToolStripMenuItem(); - this._2xMenuItem = new System.Windows.Forms.ToolStripMenuItem(); - this._3xMenuItem = new System.Windows.Forms.ToolStripMenuItem(); - this._4xMenuItem = new System.Windows.Forms.ToolStripMenuItem(); - this.MovieSubMenu = new System.Windows.Forms.ToolStripMenuItem(); - this.RecordMovieMenuItem = new System.Windows.Forms.ToolStripMenuItem(); - this.PlayMovieMenuItem = new System.Windows.Forms.ToolStripMenuItem(); - this.StopMovieMenuItem = new System.Windows.Forms.ToolStripMenuItem(); - this.RestartMovieMenuItem = new System.Windows.Forms.ToolStripMenuItem(); - this.RecentMovieSubMenu = new System.Windows.Forms.ToolStripMenuItem(); - this.toolStripSeparator8 = new System.Windows.Forms.ToolStripSeparator(); - this.toolStripSeparator2 = new System.Windows.Forms.ToolStripSeparator(); - this.ToggleReadonlyMenuItem = new System.Windows.Forms.ToolStripMenuItem(); - this.configToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); - this.controllerConfigToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); - this.hotkeyConfigToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); - this.toolStripSeparator4 = new System.Windows.Forms.ToolStripSeparator(); - this.saveConfigToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); - this.WorkspacePanel = new System.Windows.Forms.Panel(); - this.MainStatusBar = new System.Windows.Forms.StatusStrip(); - this.toolStripStatusLabel1 = new System.Windows.Forms.ToolStripStatusLabel(); - this.FameStatusBarLabel = new System.Windows.Forms.ToolStripStatusLabel(); - this.PlayRecordStatusButton = new System.Windows.Forms.ToolStripDropDownButton(); - this.StatusBarMessageLabel = new System.Windows.Forms.ToolStripStatusLabel(); - this.contextMenuStrip1 = new System.Windows.Forms.ContextMenuStrip(this.components); - this.RecordMovieContextMenuItem = new System.Windows.Forms.ToolStripMenuItem(); - this.PlayMovieContextMenuItem = new System.Windows.Forms.ToolStripMenuItem(); - this.LoadLastMovieContextMenuItem = new System.Windows.Forms.ToolStripMenuItem(); - this.StopMovieContextMenuItem = new System.Windows.Forms.ToolStripMenuItem(); - this.RestartMovieContextMenuItem = new System.Windows.Forms.ToolStripMenuItem(); - this.MainformMenu.SuspendLayout(); - this.WorkspacePanel.SuspendLayout(); - this.MainStatusBar.SuspendLayout(); - this.contextMenuStrip1.SuspendLayout(); - this.SuspendLayout(); - // - // MainformMenu - // - this.MainformMenu.ClickThrough = true; - this.MainformMenu.Items.AddRange(new System.Windows.Forms.ToolStripItem[] { - this.FileSubMenu, - this.ViewSubMenu, - this.MovieSubMenu, - this.configToolStripMenuItem}); - this.MainformMenu.Location = new System.Drawing.Point(0, 0); - this.MainformMenu.Name = "MainformMenu"; - this.MainformMenu.Size = new System.Drawing.Size(655, 24); - this.MainformMenu.TabIndex = 0; - this.MainformMenu.Text = "menuStrip1"; - // - // FileSubMenu - // - this.FileSubMenu.DropDownItems.AddRange(new System.Windows.Forms.ToolStripItem[] { - this.NewSessionMenuItem, - this.OpenSessionMenuItem, - this.SaveSessionMenuItem, - this.SaveSessionAsMenuItem, - this.RecentSessionSubMenu, - this.toolStripSeparator7, - this.OpenRomMenuItem, - this.RecentRomSubMenu, - this.toolStripSeparator5, - this.RebootCoresMenuItem, - this.toolStripSeparator3, - this.ExitMenuItem}); - this.FileSubMenu.Name = "FileSubMenu"; - this.FileSubMenu.Size = new System.Drawing.Size(37, 20); - this.FileSubMenu.Text = "&File"; - this.FileSubMenu.DropDownOpened += new System.EventHandler(this.FileSubMenu_DropDownOpened); - // - // NewSessionMenuItem - // - this.NewSessionMenuItem.Name = "NewSessionMenuItem"; - this.NewSessionMenuItem.Size = new System.Drawing.Size(165, 22); - this.NewSessionMenuItem.Text = "&New Session"; - this.NewSessionMenuItem.Click += new System.EventHandler(this.NewSessionMenuItem_Click); - // - // OpenSessionMenuItem - // - this.OpenSessionMenuItem.Name = "OpenSessionMenuItem"; - this.OpenSessionMenuItem.Size = new System.Drawing.Size(165, 22); - this.OpenSessionMenuItem.Text = "&Open Session"; - this.OpenSessionMenuItem.Click += new System.EventHandler(this.OpenSessionMenuItem_Click); - // - // SaveSessionMenuItem - // - this.SaveSessionMenuItem.Name = "SaveSessionMenuItem"; - this.SaveSessionMenuItem.Size = new System.Drawing.Size(165, 22); - this.SaveSessionMenuItem.Text = "&Save Session"; - this.SaveSessionMenuItem.Click += new System.EventHandler(this.SaveSessionMenuItem_Click); - // - // SaveSessionAsMenuItem - // - this.SaveSessionAsMenuItem.Name = "SaveSessionAsMenuItem"; - this.SaveSessionAsMenuItem.Size = new System.Drawing.Size(165, 22); - this.SaveSessionAsMenuItem.Text = "Save Session &As..."; - this.SaveSessionAsMenuItem.Click += new System.EventHandler(this.SaveSessionAsMenuItem_Click); - // - // RecentSessionSubMenu - // - this.RecentSessionSubMenu.DropDownItems.AddRange(new System.Windows.Forms.ToolStripItem[] { - this.toolStripSeparator6}); - this.RecentSessionSubMenu.Name = "RecentSessionSubMenu"; - this.RecentSessionSubMenu.Size = new System.Drawing.Size(165, 22); - this.RecentSessionSubMenu.Text = "Recent Session"; - this.RecentSessionSubMenu.DropDownOpened += new System.EventHandler(this.RecentSessionSubMenu_DropDownOpened); - // - // toolStripSeparator6 - // - this.toolStripSeparator6.Name = "toolStripSeparator6"; - this.toolStripSeparator6.Size = new System.Drawing.Size(57, 6); - // - // toolStripSeparator7 - // - this.toolStripSeparator7.Name = "toolStripSeparator7"; - this.toolStripSeparator7.Size = new System.Drawing.Size(162, 6); - // - // OpenRomMenuItem - // - this.OpenRomMenuItem.Image = global::BizHawk.Client.MultiHawk.Properties.Resources.OpenFile; - this.OpenRomMenuItem.Name = "OpenRomMenuItem"; - this.OpenRomMenuItem.Size = new System.Drawing.Size(165, 22); - this.OpenRomMenuItem.Text = "Open ROM"; - this.OpenRomMenuItem.Click += new System.EventHandler(this.OpenRomMenuItem_Click); - // - // RecentRomSubMenu - // - this.RecentRomSubMenu.DropDownItems.AddRange(new System.Windows.Forms.ToolStripItem[] { - this.toolStripSeparator1}); - this.RecentRomSubMenu.Image = global::BizHawk.Client.MultiHawk.Properties.Resources.Recent; - this.RecentRomSubMenu.Name = "RecentRomSubMenu"; - this.RecentRomSubMenu.Size = new System.Drawing.Size(165, 22); - this.RecentRomSubMenu.Text = "Recent"; - this.RecentRomSubMenu.DropDownOpened += new System.EventHandler(this.RecentRomSubMenu_DropDownOpened); - // - // toolStripSeparator1 - // - this.toolStripSeparator1.Name = "toolStripSeparator1"; - this.toolStripSeparator1.Size = new System.Drawing.Size(57, 6); - // - // toolStripSeparator5 - // - this.toolStripSeparator5.Name = "toolStripSeparator5"; - this.toolStripSeparator5.Size = new System.Drawing.Size(162, 6); - // - // RebootCoresMenuItem - // - this.RebootCoresMenuItem.Name = "RebootCoresMenuItem"; - this.RebootCoresMenuItem.Size = new System.Drawing.Size(165, 22); - this.RebootCoresMenuItem.Text = "Reboot Cores"; - this.RebootCoresMenuItem.Click += new System.EventHandler(this.RebootCoresMenuItem_Click); - // - // toolStripSeparator3 - // - this.toolStripSeparator3.Name = "toolStripSeparator3"; - this.toolStripSeparator3.Size = new System.Drawing.Size(162, 6); - // - // ExitMenuItem - // - this.ExitMenuItem.Name = "ExitMenuItem"; - this.ExitMenuItem.ShortcutKeyDisplayString = "Alt+F4"; - this.ExitMenuItem.Size = new System.Drawing.Size(165, 22); - this.ExitMenuItem.Text = "E&xit"; - this.ExitMenuItem.Click += new System.EventHandler(this.ExitMenuItem_Click); - // - // ViewSubMenu - // - this.ViewSubMenu.DropDownItems.AddRange(new System.Windows.Forms.ToolStripItem[] { - this._1xMenuItem, - this._2xMenuItem, - this._3xMenuItem, - this._4xMenuItem}); - this.ViewSubMenu.Enabled = false; - this.ViewSubMenu.Name = "ViewSubMenu"; - this.ViewSubMenu.Size = new System.Drawing.Size(44, 20); - this.ViewSubMenu.Text = "&View"; - this.ViewSubMenu.DropDownOpened += new System.EventHandler(this.ViewSubMenu_DropDownOpened); - // - // _1xMenuItem - // - this._1xMenuItem.Name = "_1xMenuItem"; - this._1xMenuItem.Size = new System.Drawing.Size(85, 22); - this._1xMenuItem.Text = "&1x"; - this._1xMenuItem.Click += new System.EventHandler(this._1xMenuItem_Click); - // - // _2xMenuItem - // - this._2xMenuItem.Name = "_2xMenuItem"; - this._2xMenuItem.Size = new System.Drawing.Size(85, 22); - this._2xMenuItem.Text = "&2x"; - this._2xMenuItem.Click += new System.EventHandler(this._2xMenuItem_Click); - // - // _3xMenuItem - // - this._3xMenuItem.Name = "_3xMenuItem"; - this._3xMenuItem.Size = new System.Drawing.Size(85, 22); - this._3xMenuItem.Text = "&3x"; - this._3xMenuItem.Click += new System.EventHandler(this._3xMenuItem_Click); - // - // _4xMenuItem - // - this._4xMenuItem.Name = "_4xMenuItem"; - this._4xMenuItem.Size = new System.Drawing.Size(85, 22); - this._4xMenuItem.Text = "&4x"; - this._4xMenuItem.Click += new System.EventHandler(this._4xMenuItem_Click); - // - // MovieSubMenu - // - this.MovieSubMenu.DropDownItems.AddRange(new System.Windows.Forms.ToolStripItem[] { - this.RecordMovieMenuItem, - this.PlayMovieMenuItem, - this.StopMovieMenuItem, - this.RestartMovieMenuItem, - this.RecentMovieSubMenu, - this.toolStripSeparator2, - this.ToggleReadonlyMenuItem}); - this.MovieSubMenu.Name = "MovieSubMenu"; - this.MovieSubMenu.Size = new System.Drawing.Size(52, 20); - this.MovieSubMenu.Text = "&Movie"; - this.MovieSubMenu.DropDownOpened += new System.EventHandler(this.MovieSubMenu_DropDownOpened); - // - // RecordMovieMenuItem - // - this.RecordMovieMenuItem.Image = global::BizHawk.Client.MultiHawk.Properties.Resources.RecordHS; - this.RecordMovieMenuItem.Name = "RecordMovieMenuItem"; - this.RecordMovieMenuItem.Size = new System.Drawing.Size(168, 22); - this.RecordMovieMenuItem.Text = "Record Movie"; - this.RecordMovieMenuItem.Click += new System.EventHandler(this.RecordMovieMenuItem_Click); - // - // PlayMovieMenuItem - // - this.PlayMovieMenuItem.Image = global::BizHawk.Client.MultiHawk.Properties.Resources.Play; - this.PlayMovieMenuItem.Name = "PlayMovieMenuItem"; - this.PlayMovieMenuItem.Size = new System.Drawing.Size(168, 22); - this.PlayMovieMenuItem.Text = "Play Movie"; - this.PlayMovieMenuItem.Click += new System.EventHandler(this.PlayMovieMenuItem_Click); - // - // StopMovieMenuItem - // - this.StopMovieMenuItem.Image = global::BizHawk.Client.MultiHawk.Properties.Resources.Stop; - this.StopMovieMenuItem.Name = "StopMovieMenuItem"; - this.StopMovieMenuItem.Size = new System.Drawing.Size(168, 22); - this.StopMovieMenuItem.Text = "&Stop Movie"; - this.StopMovieMenuItem.Click += new System.EventHandler(this.StopMovieMenuItem_Click); - // - // RestartMovieMenuItem - // - this.RestartMovieMenuItem.Image = global::BizHawk.Client.MultiHawk.Properties.Resources.restart; - this.RestartMovieMenuItem.Name = "RestartMovieMenuItem"; - this.RestartMovieMenuItem.Size = new System.Drawing.Size(168, 22); - this.RestartMovieMenuItem.Text = "Restart Movie"; - this.RestartMovieMenuItem.Click += new System.EventHandler(this.RestartMovieMenuItem_Click); - // - // RecentMovieSubMenu - // - this.RecentMovieSubMenu.DropDownItems.AddRange(new System.Windows.Forms.ToolStripItem[] { - this.toolStripSeparator8}); - this.RecentMovieSubMenu.Name = "RecentMovieSubMenu"; - this.RecentMovieSubMenu.Size = new System.Drawing.Size(168, 22); - this.RecentMovieSubMenu.Text = "Recent"; - this.RecentMovieSubMenu.DropDownOpened += new System.EventHandler(this.RecentMovieSubMenu_DropDownOpened); - // - // toolStripSeparator8 - // - this.toolStripSeparator8.Name = "toolStripSeparator8"; - this.toolStripSeparator8.Size = new System.Drawing.Size(57, 6); - // - // toolStripSeparator2 - // - this.toolStripSeparator2.Name = "toolStripSeparator2"; - this.toolStripSeparator2.Size = new System.Drawing.Size(165, 6); - // - // ToggleReadonlyMenuItem - // - this.ToggleReadonlyMenuItem.Image = global::BizHawk.Client.MultiHawk.Properties.Resources.ReadOnly; - this.ToggleReadonlyMenuItem.Name = "ToggleReadonlyMenuItem"; - this.ToggleReadonlyMenuItem.Size = new System.Drawing.Size(168, 22); - this.ToggleReadonlyMenuItem.Text = "Toggle Read-only"; - this.ToggleReadonlyMenuItem.Click += new System.EventHandler(this.ToggleReadonlyMenuItem_Click); - // - // configToolStripMenuItem - // - this.configToolStripMenuItem.DropDownItems.AddRange(new System.Windows.Forms.ToolStripItem[] { - this.controllerConfigToolStripMenuItem, - this.hotkeyConfigToolStripMenuItem, - this.toolStripSeparator4, - this.saveConfigToolStripMenuItem}); - this.configToolStripMenuItem.Name = "configToolStripMenuItem"; - this.configToolStripMenuItem.Size = new System.Drawing.Size(55, 20); - this.configToolStripMenuItem.Text = "&Config"; - // - // controllerConfigToolStripMenuItem - // - this.controllerConfigToolStripMenuItem.Image = global::BizHawk.Client.MultiHawk.Properties.Resources.GameController; - this.controllerConfigToolStripMenuItem.Name = "controllerConfigToolStripMenuItem"; - this.controllerConfigToolStripMenuItem.Size = new System.Drawing.Size(166, 22); - this.controllerConfigToolStripMenuItem.Text = "Controller Config"; - this.controllerConfigToolStripMenuItem.Click += new System.EventHandler(this.controllerConfigToolStripMenuItem_Click); - // - // hotkeyConfigToolStripMenuItem - // - this.hotkeyConfigToolStripMenuItem.Image = global::BizHawk.Client.MultiHawk.Properties.Resources.HotKeys; - this.hotkeyConfigToolStripMenuItem.Name = "hotkeyConfigToolStripMenuItem"; - this.hotkeyConfigToolStripMenuItem.Size = new System.Drawing.Size(166, 22); - this.hotkeyConfigToolStripMenuItem.Text = "Hotkey Config"; - this.hotkeyConfigToolStripMenuItem.Click += new System.EventHandler(this.hotkeyConfigToolStripMenuItem_Click); - // - // toolStripSeparator4 - // - this.toolStripSeparator4.Name = "toolStripSeparator4"; - this.toolStripSeparator4.Size = new System.Drawing.Size(163, 6); - // - // saveConfigToolStripMenuItem - // - this.saveConfigToolStripMenuItem.Image = global::BizHawk.Client.MultiHawk.Properties.Resources.Save; - this.saveConfigToolStripMenuItem.Name = "saveConfigToolStripMenuItem"; - this.saveConfigToolStripMenuItem.Size = new System.Drawing.Size(166, 22); - this.saveConfigToolStripMenuItem.Text = "Save Config"; - this.saveConfigToolStripMenuItem.Click += new System.EventHandler(this.saveConfigToolStripMenuItem_Click); - // - // WorkspacePanel - // - this.WorkspacePanel.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom) - | System.Windows.Forms.AnchorStyles.Left) - | System.Windows.Forms.AnchorStyles.Right))); - this.WorkspacePanel.BorderStyle = System.Windows.Forms.BorderStyle.Fixed3D; - this.WorkspacePanel.Controls.Add(this.MainStatusBar); - this.WorkspacePanel.Location = new System.Drawing.Point(0, 25); - this.WorkspacePanel.Name = "WorkspacePanel"; - this.WorkspacePanel.Size = new System.Drawing.Size(655, 405); - this.WorkspacePanel.TabIndex = 1; - // - // MainStatusBar - // - this.MainStatusBar.Items.AddRange(new System.Windows.Forms.ToolStripItem[] { - this.toolStripStatusLabel1, - this.FameStatusBarLabel, - this.PlayRecordStatusButton, - this.StatusBarMessageLabel}); - this.MainStatusBar.Location = new System.Drawing.Point(0, 379); - this.MainStatusBar.Name = "MainStatusBar"; - this.MainStatusBar.Size = new System.Drawing.Size(651, 22); - this.MainStatusBar.TabIndex = 0; - this.MainStatusBar.Text = "statusStrip1"; - // - // toolStripStatusLabel1 - // - this.toolStripStatusLabel1.Name = "toolStripStatusLabel1"; - this.toolStripStatusLabel1.Size = new System.Drawing.Size(46, 17); - this.toolStripStatusLabel1.Text = "Frame: "; - // - // FameStatusBarLabel - // - this.FameStatusBarLabel.Name = "FameStatusBarLabel"; - this.FameStatusBarLabel.Size = new System.Drawing.Size(13, 17); - this.FameStatusBarLabel.Text = "0"; - // - // PlayRecordStatusButton - // - this.PlayRecordStatusButton.DisplayStyle = System.Windows.Forms.ToolStripItemDisplayStyle.Image; - this.PlayRecordStatusButton.Image = global::BizHawk.Client.MultiHawk.Properties.Resources.Blank; - this.PlayRecordStatusButton.ImageTransparentColor = System.Drawing.Color.Magenta; - this.PlayRecordStatusButton.Name = "PlayRecordStatusButton"; - this.PlayRecordStatusButton.Size = new System.Drawing.Size(29, 20); - this.PlayRecordStatusButton.Text = "No movie is active"; - // - // StatusBarMessageLabel - // - this.StatusBarMessageLabel.Name = "StatusBarMessageLabel"; - this.StatusBarMessageLabel.Size = new System.Drawing.Size(35, 17); - this.StatusBarMessageLabel.Text = "Hello"; - // - // contextMenuStrip1 - // - this.contextMenuStrip1.Items.AddRange(new System.Windows.Forms.ToolStripItem[] { - this.RecordMovieContextMenuItem, - this.PlayMovieContextMenuItem, - this.RestartMovieContextMenuItem, - this.StopMovieContextMenuItem, - this.LoadLastMovieContextMenuItem}); - this.contextMenuStrip1.Name = "contextMenuStrip1"; - this.contextMenuStrip1.Size = new System.Drawing.Size(161, 114); - this.contextMenuStrip1.Opening += new System.ComponentModel.CancelEventHandler(this.contextMenuStrip1_Opening); - // - // RecordMovieContextMenuItem - // - this.RecordMovieContextMenuItem.Image = global::BizHawk.Client.MultiHawk.Properties.Resources.RecordHS; - this.RecordMovieContextMenuItem.Name = "RecordMovieContextMenuItem"; - this.RecordMovieContextMenuItem.Size = new System.Drawing.Size(160, 22); - this.RecordMovieContextMenuItem.Text = "Record Movie"; - this.RecordMovieContextMenuItem.Click += new System.EventHandler(this.RecordMovieMenuItem_Click); - // - // PlayMovieContextMenuItem - // - this.PlayMovieContextMenuItem.Image = global::BizHawk.Client.MultiHawk.Properties.Resources.Play; - this.PlayMovieContextMenuItem.Name = "PlayMovieContextMenuItem"; - this.PlayMovieContextMenuItem.Size = new System.Drawing.Size(160, 22); - this.PlayMovieContextMenuItem.Text = "Play Movie"; - this.PlayMovieContextMenuItem.Click += new System.EventHandler(this.PlayMovieMenuItem_Click); - // - // LoadLastMovieContextMenuItem - // - this.LoadLastMovieContextMenuItem.Image = global::BizHawk.Client.MultiHawk.Properties.Resources.Recent; - this.LoadLastMovieContextMenuItem.Name = "LoadLastMovieContextMenuItem"; - this.LoadLastMovieContextMenuItem.Size = new System.Drawing.Size(160, 22); - this.LoadLastMovieContextMenuItem.Text = "Load Last Movie"; - this.LoadLastMovieContextMenuItem.Click += new System.EventHandler(this.LoadLastMovieMenuItem_Click); - // - // StopMovieContextMenuItem - // - this.StopMovieContextMenuItem.Image = global::BizHawk.Client.MultiHawk.Properties.Resources.Stop; - this.StopMovieContextMenuItem.Name = "StopMovieContextMenuItem"; - this.StopMovieContextMenuItem.Size = new System.Drawing.Size(160, 22); - this.StopMovieContextMenuItem.Text = "Stop Movie"; - this.StopMovieContextMenuItem.Click += new System.EventHandler(this.StopMovieMenuItem_Click); - // - // RestartMovieContextMenuItem - // - this.RestartMovieContextMenuItem.Image = global::BizHawk.Client.MultiHawk.Properties.Resources.restart; - this.RestartMovieContextMenuItem.Name = "RestartMovieContextMenuItem"; - this.RestartMovieContextMenuItem.Size = new System.Drawing.Size(160, 22); - this.RestartMovieContextMenuItem.Text = "Restart Movie"; - this.RestartMovieContextMenuItem.Click += new System.EventHandler(this.RestartMovieMenuItem_Click); - // - // Mainform - // - this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); - this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; - this.ClientSize = new System.Drawing.Size(655, 431); - this.ContextMenuStrip = this.contextMenuStrip1; - this.Controls.Add(this.WorkspacePanel); - this.Controls.Add(this.MainformMenu); - this.MainMenuStrip = this.MainformMenu; - this.Name = "Mainform"; - this.Text = "MultiHawk"; - this.Load += new System.EventHandler(this.Mainform_Load); - this.MainformMenu.ResumeLayout(false); - this.MainformMenu.PerformLayout(); - this.WorkspacePanel.ResumeLayout(false); - this.WorkspacePanel.PerformLayout(); - this.MainStatusBar.ResumeLayout(false); - this.MainStatusBar.PerformLayout(); - this.contextMenuStrip1.ResumeLayout(false); - this.ResumeLayout(false); - this.PerformLayout(); - - } - - #endregion - - private MenuStripEx MainformMenu; - private System.Windows.Forms.ToolStripMenuItem FileSubMenu; - private System.Windows.Forms.ToolStripMenuItem OpenRomMenuItem; - private System.Windows.Forms.Panel WorkspacePanel; - private System.Windows.Forms.StatusStrip MainStatusBar; - private System.Windows.Forms.ToolStripStatusLabel toolStripStatusLabel1; - private System.Windows.Forms.ToolStripStatusLabel FameStatusBarLabel; - private System.Windows.Forms.ToolStripStatusLabel StatusBarMessageLabel; - private System.Windows.Forms.ToolStripMenuItem RecentRomSubMenu; - private System.Windows.Forms.ToolStripSeparator toolStripSeparator1; - private System.Windows.Forms.ToolStripMenuItem MovieSubMenu; - private System.Windows.Forms.ToolStripMenuItem RecordMovieMenuItem; - private System.Windows.Forms.ToolStripMenuItem PlayMovieMenuItem; - private System.Windows.Forms.ToolStripMenuItem StopMovieMenuItem; - private System.Windows.Forms.ToolStripSeparator toolStripSeparator2; - private System.Windows.Forms.ToolStripMenuItem ToggleReadonlyMenuItem; - private System.Windows.Forms.ToolStripDropDownButton PlayRecordStatusButton; - private System.Windows.Forms.ToolStripMenuItem configToolStripMenuItem; - private System.Windows.Forms.ToolStripMenuItem controllerConfigToolStripMenuItem; - private System.Windows.Forms.ToolStripMenuItem hotkeyConfigToolStripMenuItem; - private System.Windows.Forms.ToolStripSeparator toolStripSeparator3; - private System.Windows.Forms.ToolStripMenuItem ExitMenuItem; - private System.Windows.Forms.ToolStripSeparator toolStripSeparator4; - private System.Windows.Forms.ToolStripMenuItem saveConfigToolStripMenuItem; - private System.Windows.Forms.ToolStripSeparator toolStripSeparator5; - private System.Windows.Forms.ToolStripMenuItem RebootCoresMenuItem; - private System.Windows.Forms.ToolStripMenuItem OpenSessionMenuItem; - private System.Windows.Forms.ToolStripMenuItem SaveSessionMenuItem; - private System.Windows.Forms.ToolStripMenuItem RecentSessionSubMenu; - private System.Windows.Forms.ToolStripMenuItem NewSessionMenuItem; - private System.Windows.Forms.ToolStripMenuItem SaveSessionAsMenuItem; - private System.Windows.Forms.ToolStripSeparator toolStripSeparator6; - private System.Windows.Forms.ToolStripSeparator toolStripSeparator7; - private System.Windows.Forms.ToolStripMenuItem ViewSubMenu; - private System.Windows.Forms.ToolStripMenuItem _1xMenuItem; - private System.Windows.Forms.ToolStripMenuItem _2xMenuItem; - private System.Windows.Forms.ToolStripMenuItem _3xMenuItem; - private System.Windows.Forms.ToolStripMenuItem _4xMenuItem; - private System.Windows.Forms.ContextMenuStrip contextMenuStrip1; - private System.Windows.Forms.ToolStripMenuItem LoadLastMovieContextMenuItem; - private System.Windows.Forms.ToolStripMenuItem RecentMovieSubMenu; - private System.Windows.Forms.ToolStripSeparator toolStripSeparator8; - private System.Windows.Forms.ToolStripMenuItem RecordMovieContextMenuItem; - private System.Windows.Forms.ToolStripMenuItem StopMovieContextMenuItem; - private System.Windows.Forms.ToolStripMenuItem PlayMovieContextMenuItem; - private System.Windows.Forms.ToolStripMenuItem RestartMovieMenuItem; - private System.Windows.Forms.ToolStripMenuItem RestartMovieContextMenuItem; - } -} - diff --git a/BizHawk.Client.MultiHawk/Mainform.cs b/BizHawk.Client.MultiHawk/Mainform.cs deleted file mode 100644 index 10ca3fab7e..0000000000 --- a/BizHawk.Client.MultiHawk/Mainform.cs +++ /dev/null @@ -1,1560 +0,0 @@ -using System; -using System.Collections.Generic; -using System.ComponentModel; -using System.Data; -using System.Diagnostics; -using System.Drawing; -using System.IO; -using System.Linq; -using System.Text; -using System.Threading; -using System.Threading.Tasks; -using System.Windows.Forms; - -using BizHawk.Common; -using BizHawk.Common.IOExtensions; -using BizHawk.Client.EmuHawk; -using BizHawk.Bizware.BizwareGL; -using BizHawk.Emulation.Common; -using BizHawk.Emulation.Common.IEmulatorExtensions; -using BizHawk.Emulation.Cores.Nintendo.NES; -using BizHawk.Client.Common; -using BizHawk.Client.MultiHawk.ToolExtensions; - -namespace BizHawk.Client.MultiHawk -{ - public partial class Mainform : Form - { - static Mainform() - { - // If this isnt here, then our assemblyresolving hacks wont work due to the check for MainForm.INTERIM - // its.. weird. dont ask. - } - - public Mainform(string[] args) - { - GLManager.CreateInstance(GlobalWin.IGL_GL); - - InitializeComponent(); - _throttle = new BizHawk.Client.EmuHawk.Throttle(); - _inputManager = new InputManager(this); - Global.Config = ConfigService.Load(PathManager.DefaultIniPath); - Global.Config.DispFixAspectRatio = false; // TODO: don't hardcode this - Global.Config.ResolveDefaults(); - GlobalWin.MainForm = this; - - Global.ControllerInputCoalescer = new ControllerInputCoalescer(); - Global.FirmwareManager = new FirmwareManager(); - Global.MovieSession = new MovieSession - { - Movie = MovieService.DefaultInstance, - MovieControllerAdapter = MovieService.DefaultInstance.LogGeneratorInstance().MovieControllerAdapter, - MessageCallback = AddMessage, - - AskYesNoCallback = StateErrorAskUser, - PauseCallback = PauseEmulator, - ModeChangedCallback = SetMainformMovieInfo - }; - - new AutoResetEvent(false); - // TODO - //Icon = Properties.Resources.logo; - Global.Game = GameInfo.NullInstance; - - // In order to allow late construction of this database, we hook up a delegate here to dearchive the data and provide it on demand - // we could background thread this later instead if we wanted to be real clever - NES.BootGodDB.GetDatabaseBytes = () => - { - string xmlPath = Path.Combine(PathManager.GetExeDirectoryAbsolute(), "gamedb", "NesCarts.xml"); - string x7zPath = Path.Combine(PathManager.GetExeDirectoryAbsolute(), "gamedb", "NesCarts.7z"); - bool loadXml = File.Exists(xmlPath); - using (var NesCartFile = new HawkFile(loadXml ? xmlPath : x7zPath)) - { - if (!loadXml) { NesCartFile.BindFirst(); } - return NesCartFile - .GetStream() - .ReadAllBytes(); - } - }; - - Database.LoadDatabase(Path.Combine(PathManager.GetExeDirectoryAbsolute(), "gamedb", "gamedb.txt")); - - Input.Initialize(this.Handle); - InitControls(); - - // TODO - //CoreFileProvider.SyncCoreCommInputSignals(); - - Global.ActiveController = new Controller(NullController.Instance.Definition); - Global.AutoFireController = AutofireNullControls; - Global.AutofireStickyXORAdapter.SetOnOffPatternFromConfig(); - - Closing += (o, e) => - { - Global.MovieSession.Movie.Stop(); - - foreach (var ew in EmulatorWindows) - { - ew.ShutDown(); - } - - SaveConfig(); - }; - - if (Global.Config.MainWndx != -1 && Global.Config.MainWndy != -1 && Global.Config.SaveWindowPosition) - { - Location = new Point(Global.Config.MainWndx, Global.Config.MainWndy); - } - } - - // TODO: make this an actual property, set it when loading a Rom, and pass it dialogs, etc - // This is a quick hack to reduce the dependency on Global.Emulator - public IEmulator Emulator - { - get { return Global.Emulator; } - set { Global.Emulator = value; } - } - - private static bool StateErrorAskUser(string title, string message) - { - var result = MessageBox.Show( - message, - title, - MessageBoxButtons.YesNo, - MessageBoxIcon.Question - ); - - return result == DialogResult.Yes; - } - - private void Mainform_Load(object sender, EventArgs e) - { - SetMainformMovieInfo(); - - if (Global.Config.RecentRomSessions.AutoLoad) - { - LoadRomSessionFromRecent(Global.Config.RecentRomSessions.MostRecent); - - if (Global.Config.RecentMovies.AutoLoad && !Global.Config.RecentMovies.Empty) - { - LoadMoviesFromRecent(Global.Config.RecentMovies.MostRecent); - } - } - - if (Global.Config.SaveWindowPosition && Global.Config.MainWidth > 0 && Global.Config.MainHeight > 0) - { - this.Size = new Size(Global.Config.MainWidth, Global.Config.MainHeight); - - } - } - - public EmulatorWindowList EmulatorWindows = new EmulatorWindowList(); - private AutofireController AutofireNullControls; - private bool _exit; - - protected override void OnClosed(EventArgs e) - { - _exit = true; - base.OnClosed(e); - } - - private void SaveConfig() - { - if (Global.Config.SaveWindowPosition) - { - if (Global.Config.MainWndx != -32000) // When minimized location is -32000, don't save this into the config file! - { - Global.Config.MainWndx = Location.X; - } - - if (Global.Config.MainWndy != -32000) - { - Global.Config.MainWndy = Location.Y; - } - } - else - { - Global.Config.MainWndx = -1; - Global.Config.MainWndy = -1; - } - - Global.Config.MainWidth = this.Width; - Global.Config.MainHeight = this.Height; - - ConfigService.Save(PathManager.DefaultIniPath, Global.Config); - } - - private void InitControls() - { - var controls = new Controller( - new ControllerDefinition - { - Name = "Emulator Frontend Controls", - BoolButtons = Global.Config.HotkeyBindings.Select(x => x.DisplayName).ToList() - }); - - foreach (var b in Global.Config.HotkeyBindings) - { - controls.BindMulti(b.DisplayName, b.Bindings); - } - - Global.ClientControls = controls; - AutofireNullControls = new AutofireController(NullController.Instance.Definition, Emulator); - } - - private void OpenRomMenuItem_Click(object sender, EventArgs e) - { - var ofd = new OpenFileDialog - { - InitialDirectory = PathManager.GetExeDirectoryAbsolute() - }; - - ofd.Filter = FormatFilter( - "Rom Files", "*.nes;*.fds;*.sms;*.gg;*.sg;*.pce;*.sgx;*.bin;*.smd;*.rom;*.a26;*.a78;*.lnx;*.m3u;*.cue;*.ccd;*.exe;*.gb;*.gbc;*.gba;*.gen;*.md;*.col;.int;*.smc;*.sfc;*.prg;*.d64;*.g64;*.crt;*.sgb;*.xml;*.z64;*.v64;*.n64;*.ws;*.wsc;%ARCH%", - "Music Files", "*.psf;*.sid", - "Disc Images", "*.cue;*.ccd;*.m3u", - "NES", "*.nes;*.fds;%ARCH%", - "Super NES", "*.smc;*.sfc;*.xml;%ARCH%", - "Master System", "*.sms;*.gg;*.sg;%ARCH%", - "PC Engine", "*.pce;*.sgx;*.cue;*.ccd;%ARCH%", - "TI-83", "*.rom;%ARCH%", - "Archive Files", "%ARCH%", - "Savestate", "*.state", - "Atari 2600", "*.a26;*.bin;%ARCH%", - "Atari 7800", "*.a78;*.bin;%ARCH%", - "Atari Lynx", "*.lnx;%ARCH%", - "Genesis", "*.gen;*.smd;*.bin;*.md;*.cue;*.ccd;%ARCH%", - "Gameboy", "*.gb;*.gbc;*.sgb;%ARCH%", - "Gameboy Advance", "*.gba;%ARCH%", - "Colecovision", "*.col;%ARCH%", - "Intellivision (very experimental)", "*.int;*.bin;*.rom;%ARCH%", - "PSX Executables (experimental)", "*.exe", - "PSF Playstation Sound File", "*.psf;*.minipsf", - "Commodore 64 (experimental)", "*.prg; *.d64, *.g64; *.crt;%ARCH%", - "SID Commodore 64 Music File", "*.sid;%ARCH%", - "Nintendo 64", "*.z64;*.v64;*.n64", - "WonderSwan", "*.ws;*.wsc;%ARCH%", - "All Files", "*.*"); - - var result = ofd.ShowDialog(); - if (result != DialogResult.OK) - { - return; - } - - LoadRom(ofd.FileName); - } - - private readonly InputManager _inputManager; - - private bool ReloadRom(EmulatorWindow ew) - { - bool deterministic = ew.Emulator.DeterministicEmulation; - string path = ew.CurrentRomPath; - - var loader = new RomLoader - { - ChooseArchive = LoadArhiveChooser, - ChoosePlatform = ChoosePlatformForRom, - Deterministic = deterministic, - MessageCallback = AddMessage - }; - - - loader.OnLoadError += ShowLoadError; - loader.OnLoadSettings += CoreSettings; - loader.OnLoadSyncSettings += CoreSyncSettings; - - var nextComm = new CoreComm(ShowMessageCoreComm, AddMessage); - - var result = loader.LoadRom(path, nextComm); - - if (result) - { - ew.SaveRam(); - ew.Emulator.Dispose(); - ew.Emulator = loader.LoadedEmulator; - ew.CoreComm = nextComm; - - _inputManager.SyncControls(); - - if (EmulatorWindows.First() == ew) - { - Emulator = ew.Emulator; - } - - return true; - } - else - { - return false; - } - } - - private string StripArchivePath(string path) - { - if (path.Contains("|")) - { - return path.Split('|').Last(); - } - - return path; - } - - private bool LoadRom(string path) - { - bool deterministic = true; - - var loader = new RomLoader - { - ChooseArchive = LoadArhiveChooser, - ChoosePlatform = ChoosePlatformForRom, - Deterministic = deterministic, - MessageCallback = AddMessage - }; - - - loader.OnLoadError += ShowLoadError; - loader.OnLoadSettings += CoreSettings; - loader.OnLoadSyncSettings += CoreSyncSettings; - - var nextComm = new CoreComm(ShowMessageCoreComm, AddMessage); - nextComm.CoreFileProvider = new CoreFileProvider(s => MessageBox.Show(s)); - - var result = loader.LoadRom(path, nextComm); - - if (result) - { - var ew = new EmulatorWindow(this) - { - TopLevel = false, - Text = Path.GetFileNameWithoutExtension(StripArchivePath(path)), - Emulator = loader.LoadedEmulator, - GL = new Bizware.BizwareGL.Drivers.OpenTK.IGL_TK(2,0,false), - //GL = new Bizware.BizwareGL.Drivers.SlimDX.IGL_SlimDX9(), - GLManager = GLManager.Instance, - Game = loader.Game, - CurrentRomPath = loader.CanonicalFullPath - }; - - nextComm.ReleaseGLContext = (o) => GlobalWin.GLManager.ReleaseGLContext(o); - nextComm.RequestGLContext = (major, minor, forward) => GlobalWin.GLManager.CreateGLContext(major, minor, forward); - nextComm.ActivateGLContext = (gl) => GlobalWin.GLManager.Activate((GLManager.ContextRef)gl); - nextComm.DeactivateGLContext = () => GlobalWin.GLManager.Deactivate(); - - ew.CoreComm = nextComm; - ew.Init(); - - if (EmulatorWindows.Any()) - { - // Attempt to open the window is a smart location - var last = EmulatorWindows.Last(); - - int x = last.Location.X + last.Width + 5; - int y = last.Location.Y; - if (x + (last.Width / 2) > Width) // If it will go too far off screen - { - y += last.Height + 5; - x = EmulatorWindows.First().Location.X; - } - - ew.Location = new Point(x, y); - } - - - EmulatorWindows.Add(ew); - - WorkspacePanel.Controls.Add(ew); - ew.Show(); - - Global.Config.RecentRoms.Add(loader.CanonicalFullPath); - - if (EmulatorWindows.Count == 1) - { - Emulator = ew.Emulator; - ViewSubMenu.Enabled = true; - } - - _inputManager.SyncControls(); - - return true; - } - else - { - return false; - } - } - - /// - /// Controls whether the app generates input events. should be turned off for most modal dialogs - /// - public bool AllowInput - { - get - { - // the main form gets input - if (ActiveForm == this) - { - return true; - } - - // modals that need to capture input for binding purposes get input, of course - if (ActiveForm is BizHawk.Client.EmuHawk.HotkeyConfig - || ActiveForm is BizHawk.Client.EmuHawk.ControllerConfig - //|| ActiveForm is TAStudio - //|| ActiveForm is VirtualpadTool - ) - { - return true; - } - - return false; - } - } - - private static string FormatFilter(params string[] args) - { - var sb = new StringBuilder(); - if (args.Length % 2 != 0) - { - throw new ArgumentException(); - } - - var num = args.Length / 2; - for (int i = 0; i < num; i++) - { - sb.AppendFormat("{0} ({1})|{1}", args[i * 2], args[i * 2 + 1]); - if (i != num - 1) - { - sb.Append('|'); - } - } - - var str = sb.ToString().Replace("%ARCH%", "*.zip;*.rar;*.7z;*.gz"); - str = str.Replace(";", "; "); - return str; - } - - public void AddMessage(string message) - { - StatusBarMessageLabel.Text = message; - } - - private string ChoosePlatformForRom(RomGame rom) - { - // TODO - return null; - } - - private int? LoadArhiveChooser(HawkFile file) - { - var ac = new BizHawk.Client.EmuHawk.ArchiveChooser(file); - if (ac.ShowDialog(this) == DialogResult.OK) - { - return ac.SelectedMemberIndex; - } - else - { - return null; - } - } - - private void ShowLoadError(object sender, RomLoader.RomErrorArgs e) - { - string title = "load error"; - if (e.AttemptedCoreLoad != null) - { - title = e.AttemptedCoreLoad + " load error"; - } - - MessageBox.Show(this, e.Message, title, MessageBoxButtons.OK, MessageBoxIcon.Error); - } - - private static void CoreSettings(object sender, RomLoader.SettingsLoadArgs e) - { - e.Settings = Global.Config.GetCoreSettings(e.Core); - } - - private void CoreSyncSettings(object sender, RomLoader.SettingsLoadArgs e) - { - if (Global.MovieSession.QueuedMovie != null) - { - if (!string.IsNullOrWhiteSpace(Global.MovieSession.QueuedMovie.SyncSettingsJson)) - { - e.Settings = ConfigService.LoadWithType(Global.MovieSession.QueuedMovie.SyncSettingsJson); - } - else - { - MessageBox.Show( - "No sync settings found, using currently configured settings for this core.", - "No sync settings found", - MessageBoxButtons.OK, - MessageBoxIcon.Warning - ); - - e.Settings = Global.Config.GetCoreSyncSettings(e.Core); - } - } - else - { - e.Settings = Global.Config.GetCoreSyncSettings(e.Core); - } - - } - - public void FlagNeedsReboot() - { - // TODO - } - - private void ShowMessageCoreComm(string message) - { - MessageBox.Show(this, message, "Warning", MessageBoxButtons.OK, MessageBoxIcon.Warning); - } - - private static void CheckMessages() - { - Application.DoEvents(); - if (ActiveForm != null) - { - BizHawk.Client.EmuHawk.ScreenSaver.ResetTimerPeriodically(); - } - } - - // sends an alt+mnemonic combination - private void SendAltKeyChar(char c) - { - typeof(ToolStrip).InvokeMember("ProcessMnemonicInternal", System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.InvokeMethod | System.Reflection.BindingFlags.Instance, null, MainformMenu, new object[] { c }); - } - - // sends a simulation of a plain alt key keystroke - private void SendPlainAltKey(int lparam) - { - var m = new Message { WParam = new IntPtr(0xF100), LParam = new IntPtr(lparam), Msg = 0x0112, HWnd = Handle }; - base.WndProc(ref m); - } - - public void ProcessInput() - { - ControllerInputCoalescer conInput = Global.ControllerInputCoalescer as ControllerInputCoalescer; - - for (; ; ) - { - - // loop through all available events - var ie = Input.Instance.DequeueEvent(); - if (ie == null) { break; } - - // look for hotkey bindings for this key - var triggers = Global.ClientControls.SearchBindings(ie.LogicalButton.ToString()); - if (triggers.Count == 0) - { - // Maybe it is a system alt-key which hasnt been overridden - if (ie.EventType == Input.InputEventType.Press) - { - if (ie.LogicalButton.Alt && ie.LogicalButton.Button.Length == 1) - { - var c = ie.LogicalButton.Button.ToLower()[0]; - if ((c >= 'a' && c <= 'z') || c == ' ') - { - SendAltKeyChar(c); - } - } - if (ie.LogicalButton.Alt && ie.LogicalButton.Button == "Space") - { - SendPlainAltKey(32); - } - } - } - - bool handled; - switch (Global.Config.Input_Hotkey_OverrideOptions) - { - default: - case 0: // Both allowed - conInput.Receive(ie); - - handled = false; - if (ie.EventType == Input.InputEventType.Press) - { - handled = triggers.Aggregate(handled, (current, trigger) => current | CheckHotkey(trigger)); - } - - // hotkeys which arent handled as actions get coalesced as pollable virtual client buttons - if (!handled) - { - GlobalWin.HotkeyCoalescer.Receive(ie); - } - - break; - case 1: // Input overrides Hokeys - conInput.Receive(ie); - if (!Global.ActiveController.HasBinding(ie.LogicalButton.ToString())) - { - handled = false; - if (ie.EventType == Input.InputEventType.Press) - { - handled = triggers.Aggregate(handled, (current, trigger) => current | CheckHotkey(trigger)); - } - - // hotkeys which arent handled as actions get coalesced as pollable virtual client buttons - if (!handled) - { - GlobalWin.HotkeyCoalescer.Receive(ie); - } - } - break; - case 2: // Hotkeys override Input - handled = false; - if (ie.EventType == Input.InputEventType.Press) - { - handled = triggers.Aggregate(handled, (current, trigger) => current | CheckHotkey(trigger)); - } - - // hotkeys which arent handled as actions get coalesced as pollable virtual client buttons - if (!handled) - { - GlobalWin.HotkeyCoalescer.Receive(ie); - conInput.Receive(ie); - } - break; - } - } - } - - public void ProgramRunLoop() - { - CheckMessages(); - - for (; ; ) - { - Input.Instance.Update(); - - // handle events and dispatch as a hotkey action, or a hotkey button, or an input button - ProcessInput(); - Global.ClientControls.LatchFromPhysical(GlobalWin.HotkeyCoalescer); - - Global.ActiveController.LatchFromPhysical(Global.ControllerInputCoalescer); - - // TODO - //Global.ActiveController.ApplyAxisConstraints( - // (Emulator is N64 && Global.Config.N64UseCircularAnalogConstraint) ? "Natural Circle" : null); - - Global.ActiveController.OR_FromLogical(Global.ClickyVirtualPadController); - Global.AutoFireController.LatchFromPhysical(Global.ControllerInputCoalescer); - - if (Global.ClientControls["Autohold"]) - { - Global.StickyXORAdapter.MassToggleStickyState(Global.ActiveController.PressedButtons); - Global.AutofireStickyXORAdapter.MassToggleStickyState(Global.AutoFireController.PressedButtons); - } - else if (Global.ClientControls["Autofire"]) - { - Global.AutofireStickyXORAdapter.MassToggleStickyState(Global.ActiveController.PressedButtons); - } - - // autohold/autofire must not be affected by the following inputs - Global.ActiveController.Overrides(Global.LuaAndAdaptor); - - if (EmulatorWindows.Any()) - { - StepRunLoop_Core(); - StepRunLoop_Throttle(); - - foreach (var window in EmulatorWindows) - { - window.Render(); - } - } - - CheckMessages(); - - if (_exit) - { - break; - } - - Thread.Sleep(0); - } - - Shutdown(); - } - - private void Shutdown() - { - //TODO - //if (_currAviWriter != null) - //{ - // _currAviWriter.CloseFile(); - // _currAviWriter = null; - //} - } - - public void LoadQuickSave(string quickSlotName) - { - try - { - foreach (var window in EmulatorWindows) - { - window.LoadQuickSave(quickSlotName); - } - } - catch - { - MessageBox.Show("Could not load " + quickSlotName); - } - } - - public void SaveQuickSave(string quickSlotName) - { - try - { - foreach (var window in EmulatorWindows) - { - window.SaveQuickSave(quickSlotName); - } - } - catch - { - MessageBox.Show("Could not save " + quickSlotName); - } - } - - private void SelectSlot(int num) - { - Global.Config.SaveSlot = num; - UpdateStatusSlots(); - } - - private void UpdateStatusSlots() - { - // TODO - SaveSlotSelectedMessage(); - UpdateAfterFrameChanged(); - } - - private void SaveSlotSelectedMessage() - { - AddMessage("Slot " + Global.Config.SaveSlot + " selected."); - } - - public void TogglePause() - { - EmulatorPaused ^= true; - //SetPauseStatusbarIcon(); // TODO - } - private bool CheckHotkey(string trigger) - { - switch (trigger) - { - default: - return false; - - case "Pause": - TogglePause(); - break; - case "Reboot Core": - RebootCoresMenuItem_Click(null, null); - break; - case "Quick Load": - LoadQuickSave("QuickSave" + Global.Config.SaveSlot); - break; - case "Quick Save": - SaveQuickSave("QuickSave" + Global.Config.SaveSlot); - break; - - // Save States - case "Save State 0": - SaveQuickSave("QuickSave0"); - Global.Config.SaveSlot = 0; - UpdateStatusSlots(); - break; - case "Save State 1": - SaveQuickSave("QuickSave1"); - Global.Config.SaveSlot = 1; - UpdateStatusSlots(); - break; - case "Save State 2": - SaveQuickSave("QuickSave2"); - Global.Config.SaveSlot = 2; - UpdateStatusSlots(); - break; - case "Save State 3": - SaveQuickSave("QuickSave3"); - Global.Config.SaveSlot = 3; - UpdateStatusSlots(); - break; - case "Save State 4": - SaveQuickSave("QuickSave4"); - Global.Config.SaveSlot = 4; - UpdateStatusSlots(); - break; - case "Save State 5": - SaveQuickSave("QuickSave5"); - Global.Config.SaveSlot = 5; - UpdateStatusSlots(); - break; - case "Save State 6": - SaveQuickSave("QuickSave6"); - Global.Config.SaveSlot = 6; - UpdateStatusSlots(); - break; - case "Save State 7": - SaveQuickSave("QuickSave7"); - Global.Config.SaveSlot = 7; - UpdateStatusSlots(); - break; - case "Save State 8": - SaveQuickSave("QuickSave8"); - Global.Config.SaveSlot = 8; - UpdateStatusSlots(); - break; - case "Save State 9": - SaveQuickSave("QuickSave9"); - Global.Config.SaveSlot = 9; - //UpdateStatusSlots(); - break; - case "Load State 0": - LoadQuickSave("QuickSave0"); - Global.Config.SaveSlot = 0; - UpdateStatusSlots(); - break; - case "Load State 1": - LoadQuickSave("QuickSave1"); - Global.Config.SaveSlot = 1; - UpdateStatusSlots(); - break; - case "Load State 2": - LoadQuickSave("QuickSave2"); - Global.Config.SaveSlot = 2; - UpdateStatusSlots(); - break; - case "Load State 3": - LoadQuickSave("QuickSave3"); - Global.Config.SaveSlot = 3; - UpdateStatusSlots(); - break; - case "Load State 4": - LoadQuickSave("QuickSave4"); - Global.Config.SaveSlot = 4; - UpdateStatusSlots(); - break; - case "Load State 5": - LoadQuickSave("QuickSave5"); - Global.Config.SaveSlot = 5; - UpdateStatusSlots(); - break; - case "Load State 6": - LoadQuickSave("QuickSave6"); - Global.Config.SaveSlot = 6; - UpdateStatusSlots(); - break; - case "Load State 7": - LoadQuickSave("QuickSave7"); - Global.Config.SaveSlot = 7; - break; - case "Load State 8": - LoadQuickSave("QuickSave8"); - Global.Config.SaveSlot = 8; - UpdateStatusSlots(); - break; - case "Load State 9": - LoadQuickSave("QuickSave9"); - Global.Config.SaveSlot = 9; - UpdateStatusSlots(); - break; - - case "Select State 0": - SelectSlot(0); - break; - case "Select State 1": - SelectSlot(1); - break; - case "Select State 2": - SelectSlot(2); - break; - case "Select State 3": - SelectSlot(3); - break; - case "Select State 4": - SelectSlot(4); - break; - case "Select State 5": - SelectSlot(5); - break; - case "Select State 6": - SelectSlot(6); - break; - case "Select State 7": - SelectSlot(7); - break; - case "Select State 8": - SelectSlot(8); - break; - case "Select State 9": - SelectSlot(9); - break; - - // Movie - case "Stop Movie": - StopMovieMenuItem_Click(null, null); - break; - case "Toggle read-only": - ToggleReadonlyMenuItem_Click(null, null); - break; - // TODO - //case "Play from beginning": - // RestartMovie(); - // break; - // TODO - //case "Save Movie": - // SaveMovie(); - // break; - } - - return true; - } - - public bool PressFrameAdvance = false; - public bool PressRewind = false; - public bool FastForward = false; - public bool TurboFastForward = false; - public bool EmulatorPaused = true; - private readonly BizHawk.Client.EmuHawk.Throttle _throttle; - //private bool _unthrottled; // TODO - private bool _runloopFrameAdvance; - private bool _runloopFrameProgress; - private long _frameAdvanceTimestamp; - private bool _runloopLastFf; - private int _runloopFps; - private long _runloopSecond; - private int _runloopLastFps; - - public bool IsTurboing - { - get - { - return Global.ClientControls["Turbo"]; - } - } - - private void SyncThrottle() - { - // "unthrottled" = throttle was turned off with "Toggle Throttle" hotkey - // "turbo" = throttle is off due to the "Turbo" hotkey being held - // They are basically the same thing but one is a toggle and the other requires a - // hotkey to be held. There is however slightly different behavior in that turbo - // skips outputting the audio. There's also a third way which is when no throttle - // method is selected, but the clock throttle determines that by itself and - // everything appears normal here. - - var fastForward = Global.ClientControls["Fast Forward"] || FastForward; - var turbo = IsTurboing; - - int speedPercent = fastForward ? Global.Config.SpeedPercentAlternate : Global.Config.SpeedPercent; - - Global.DisableSecondaryThrottling = /*_unthrottled || TODO */ turbo || fastForward; - - // realtime throttle is never going to be so exact that using a double here is wrong - _throttle.SetCoreFps(EmulatorWindows.Master.Emulator.VsyncRate()); - _throttle.signal_paused = EmulatorPaused; - _throttle.signal_unthrottle = /*_unthrottled || TODO */ turbo; - _throttle.signal_overrideSecondaryThrottle = fastForward && (Global.Config.SoundThrottle || Global.Config.VSyncThrottle || Global.Config.VSync); - _throttle.SetSpeedPercent(speedPercent); - } - - private void StepRunLoop_Throttle() - { - SyncThrottle(); - _throttle.signal_frameAdvance = _runloopFrameAdvance; - _throttle.signal_continuousFrameAdvancing = _runloopFrameProgress; - - _throttle.Step(true, -1); - } - - public void PauseEmulator() - { - EmulatorPaused = true; - //SetPauseStatusbarIcon(); // TODO - } - - public void UnpauseEmulator() - { - EmulatorPaused = false; - //SetPauseStatusbarIcon(); // TODO - } - - private void StepRunLoop_Core() - { - var runFrame = false; - _runloopFrameAdvance = false; - var currentTimestamp = Stopwatch.GetTimestamp(); - double frameAdvanceTimestampDeltaMs = (double)(currentTimestamp - _frameAdvanceTimestamp) / Stopwatch.Frequency * 1000.0; - bool frameProgressTimeElapsed = frameAdvanceTimestampDeltaMs >= Global.Config.FrameProgressDelayMs; - - if (Global.ClientControls["Frame Advance"]) - { - // handle the initial trigger of a frame advance - if (_frameAdvanceTimestamp == 0) - { - PauseEmulator(); - runFrame = true; - _runloopFrameAdvance = true; - _frameAdvanceTimestamp = currentTimestamp; - } - else - { - // handle the timed transition from countdown to FrameProgress - if (frameProgressTimeElapsed) - { - runFrame = true; - _runloopFrameProgress = true; - UnpauseEmulator(); - } - } - } - else - { - // handle release of frame advance: do we need to deactivate FrameProgress? - if (_runloopFrameProgress) - { - _runloopFrameProgress = false; - PauseEmulator(); - } - - _frameAdvanceTimestamp = 0; - } - - if (!EmulatorPaused) - { - runFrame = true; - } - - if (runFrame) - { - var isFastForwarding = Global.ClientControls["Fast Forward"] || IsTurboing; - var updateFpsString = _runloopLastFf != isFastForwarding; - _runloopLastFf = isFastForwarding; - _runloopFps++; - - if ((double)(currentTimestamp - _runloopSecond) / Stopwatch.Frequency >= 1.0) - { - _runloopLastFps = _runloopFps; - _runloopSecond = currentTimestamp; - _runloopFps = 0; - updateFpsString = true; - } - - if (updateFpsString) - { - var fps_string = _runloopLastFps + " fps"; - if (IsTurboing) - { - fps_string += " >>>>"; - } - else if (isFastForwarding) - { - fps_string += " >>"; - } - - //GlobalWin.OSD.FPS = fps_string; // TODO - } - - Global.MovieSession.HandleMovieOnFrameLoop(); - - foreach (var window in EmulatorWindows) - { - window.FrameAdvance(); - } - - PressFrameAdvance = false; - - UpdateAfterFrameChanged(); - } - } - - private void UpdateAfterFrameChanged() - { - if (EmulatorWindows.Any()) - { - string frame = EmulatorWindows.Master.Emulator.Frame.ToString(); - - if (Global.MovieSession.Movie.IsActive) - { - if (Global.MovieSession.Movie.IsFinished) - { - frame += $" / {Global.MovieSession.Movie.FrameCount} (finished)"; - } - else if (Global.MovieSession.Movie.IsPlaying) - { - frame += $" / {Global.MovieSession.Movie.FrameCount}"; - } - } - - FameStatusBarLabel.Text = frame; - } - } - - private void FileSubMenu_DropDownOpened(object sender, EventArgs e) - { - SaveSessionMenuItem.Enabled = !string.IsNullOrWhiteSpace(EmulatorWindows.SessionName); - SaveSessionAsMenuItem.Enabled = EmulatorWindows.Any(); - } - - private void LoadRomFromRecent(string rom) - { - if (!LoadRom(rom)) - { - Global.Config.RecentRoms.HandleLoadError(rom); - } - } - - private void MovieSubMenu_DropDownOpened(object sender, EventArgs e) - { - PlayMovieMenuItem.Enabled = - RecordMovieMenuItem.Enabled = - EmulatorWindows.Any(); - - StopMovieMenuItem.Enabled = - RestartMovieMenuItem.Enabled = - Global.MovieSession.Movie.IsActive; - } - - private void RecordMovieMenuItem_Click(object sender, EventArgs e) - { - new RecordMovie(Emulator).ShowDialog(); - UpdateMainText(); - UpdateAfterFrameChanged(); - } - - private void PlayMovieMenuItem_Click(object sender, EventArgs e) - { - new PlayMovie().ShowDialog(); - UpdateMainText(); - UpdateAfterFrameChanged(); - } - - private void StopMovieMenuItem_Click(object sender, EventArgs e) - { - Global.MovieSession.StopMovie(true); - SetMainformMovieInfo(); - UpdateMainText(); - UpdateAfterFrameChanged(); - //UpdateStatusSlots(); // TODO - } - - private void ToggleReadonlyMenuItem_Click(object sender, EventArgs e) - { - Global.MovieSession.ReadOnly ^= true; - if (Global.MovieSession.ReadOnly) - { - AddMessage("Movie is now Read-only"); - } - else - { - AddMessage("Movie is now read+write"); - } - } - - private void LoadMoviesFromRecent(string path) - { - if (File.Exists(path)) - { - var movie = MovieService.Get(path); - Global.MovieSession.ReadOnly = true; - StartNewMovie(movie, false); - } - else - { - Global.Config.RecentMovies.HandleLoadError(path); - } - } - - public void SetMainformMovieInfo() - { - if (Global.MovieSession.Movie.IsPlaying) - { - PlayRecordStatusButton.Image = Properties.Resources.Play; - PlayRecordStatusButton.ToolTipText = "Movie is in playback mode"; - PlayRecordStatusButton.Visible = true; - } - else if (Global.MovieSession.Movie.IsRecording) - { - PlayRecordStatusButton.Image = Properties.Resources.RecordHS; - PlayRecordStatusButton.ToolTipText = "Movie is in record mode"; - PlayRecordStatusButton.Visible = true; - } - else if (!Global.MovieSession.Movie.IsActive) - { - PlayRecordStatusButton.Image = Properties.Resources.Blank; - PlayRecordStatusButton.ToolTipText = "No movie is active"; - PlayRecordStatusButton.Visible = false; - } - } - - public bool StartNewMovie(IMovie movie, bool record) - { - if (movie.IsActive) - { - movie.Save(); - } - - try - { - Global.MovieSession.QueueNewMovie(movie, record, Emulator); - } - catch (MoviePlatformMismatchException ex) - { - MessageBox.Show(this, ex.Message, "Movie/Platform Mismatch", MessageBoxButtons.OK, MessageBoxIcon.Error); - return false; - } - - RebootCoresMenuItem_Click(null, null); - - Emulator = EmulatorWindows.Master.Emulator; - - if (Global.MovieSession.PreviousNES_InQuickNES.HasValue) - { - Global.Config.NES_InQuickNES = Global.MovieSession.PreviousNES_InQuickNES.Value; - Global.MovieSession.PreviousNES_InQuickNES = null; - } - - if (Global.MovieSession.PreviousSNES_InSnes9x.HasValue) - { - Global.Config.SNES_InSnes9x = Global.MovieSession.PreviousSNES_InSnes9x.Value; - Global.MovieSession.PreviousSNES_InSnes9x = null; - } - - if (Global.MovieSession.PreviousGBA_UsemGBA.HasValue) - { - Global.Config.GBA_UsemGBA = Global.MovieSession.PreviousGBA_UsemGBA.Value; - Global.MovieSession.PreviousGBA_UsemGBA = null; - } - - Global.Config.RecentMovies.Add(movie.Filename); - - if (EmulatorWindows.Master.Emulator.HasSavestates() && movie.StartsFromSavestate) - { - if (movie.TextSavestate != null) - { - EmulatorWindows.Master.Emulator.AsStatable().LoadStateText(new StringReader(movie.TextSavestate)); - } - else - { - EmulatorWindows.Master.Emulator.AsStatable().LoadStateBinary(new BinaryReader(new MemoryStream(movie.BinarySavestate, false))); - } - - foreach (var ew in EmulatorWindows) - { - ew.Emulator.ResetCounters(); - } - } - - Global.MovieSession.RunQueuedMovie(record); - - SetMainformMovieInfo(); - UpdateAfterFrameChanged(); - return true; - } - - private void hotkeyConfigToolStripMenuItem_Click(object sender, EventArgs e) - { - if (new BizHawk.Client.EmuHawk.HotkeyConfig().ShowDialog() == DialogResult.OK) - { - InitControls(); - _inputManager.SyncControls(); - } - } - - private void controllerConfigToolStripMenuItem_Click(object sender, EventArgs e) - { - var controller = new BizHawk.Client.EmuHawk.ControllerConfig(EmulatorWindows.Master.Emulator.ControllerDefinition); - if (controller.ShowDialog() == DialogResult.OK) - { - InitControls(); - _inputManager.SyncControls(); - } - } - - public void EmulatorWindowClosed(EmulatorWindow ew) - { - EmulatorWindows.Remove(ew); - WorkspacePanel.Controls.Remove(ew); - - if (ew.Emulator == Emulator) - { - if (EmulatorWindows.Any()) - { - Emulator = EmulatorWindows.Master.Emulator; - } - else - { - Emulator = null; - ViewSubMenu.Enabled = false; - } - } - } - - private void ExitMenuItem_Click(object sender, EventArgs e) - { - Close(); - } - - private void saveConfigToolStripMenuItem_Click(object sender, EventArgs e) - { - SaveConfig(); - AddMessage("Saved settings"); - } - - private void RebootCoresMenuItem_Click(object sender, EventArgs e) - { - foreach (var ew in EmulatorWindows) - { - ReloadRom(ew); - } - - AddMessage("Rebooted all cores"); - } - - private void SaveSessionMenuItem_Click(object sender, EventArgs e) - { - if (!string.IsNullOrWhiteSpace(EmulatorWindows.SessionName)) - { - File.WriteAllText(EmulatorWindows.SessionName, EmulatorWindows.SessionJson); - AddMessage("Session saved."); - } - } - - private void SaveSessionAsMenuItem_Click(object sender, EventArgs e) - { - if (EmulatorWindows.Any()) - { - var file = GetSaveFileFromUser(); - if (file != null) - { - EmulatorWindows.SessionName = file.FullName; - Global.Config.RecentRomSessions.Add(file.FullName); - SaveSessionMenuItem_Click(sender, e); - UpdateMainText(); - } - } - } - - private FileInfo GetSaveFileFromUser() - { - var sfd = new SaveFileDialog(); - if (!string.IsNullOrWhiteSpace(EmulatorWindows.SessionName)) - { - sfd.FileName = Path.GetFileNameWithoutExtension(EmulatorWindows.SessionName); - sfd.InitialDirectory = Path.GetDirectoryName(EmulatorWindows.SessionName); - } - else if (EmulatorWindows.Master != null) - { - sfd.FileName = PathManager.FilesystemSafeName(EmulatorWindows.Master.Game); - sfd.InitialDirectory = PathManager.GetRomsPath("Global"); - } - else - { - sfd.FileName = "NULL"; - sfd.InitialDirectory = PathManager.GetRomsPath("Global"); - } - - sfd.Filter = "Rom Session Files (*.romses)|*.romses|All Files|*.*"; - sfd.RestoreDirectory = true; - var result = sfd.ShowDialog(); - if (result != DialogResult.OK) - { - return null; - } - - return new FileInfo(sfd.FileName); - } - - private void OpenSessionMenuItem_Click(object sender, EventArgs e) - { - var file = GetFileFromUser("Rom Session Files (*.romses)|*.romses|All Files|*.*"); - if (file != null) - { - NewSessionMenuItem_Click(null, null); - var json = File.ReadAllText(file.FullName); - EmulatorWindows.SessionName = file.FullName; - LoadRomSession(EmulatorWindowList.FromJson(json)); - Global.Config.RecentRomSessions.Add(file.FullName); - UpdateMainText(); - } - } - - private void UpdateMainText() - { - string text = "MultiHawk"; - - if (!string.IsNullOrWhiteSpace(EmulatorWindows.SessionName)) - { - text += " - " + Path.GetFileNameWithoutExtension(EmulatorWindows.SessionName); - } - - if (Global.MovieSession.Movie.IsActive) - { - text += " - " + Path.GetFileNameWithoutExtension(Global.MovieSession.Movie.Filename); - } - - Text = text; - } - - private static FileInfo GetFileFromUser(string filter) - { - var ofd = new OpenFileDialog - { - InitialDirectory = PathManager.GetRomsPath("Global"), - Filter = filter, - RestoreDirectory = true - }; - - if (!Directory.Exists(ofd.InitialDirectory)) - { - Directory.CreateDirectory(ofd.InitialDirectory); - } - - var result = ofd.ShowDialog(); - return result == DialogResult.OK ? new FileInfo(ofd.FileName) : null; - } - - private void CloseAllWindows() - { - foreach (var ew in EmulatorWindows) - { - ew.Close(); - } - - EmulatorWindows.Clear(); - } - - private void NewSessionMenuItem_Click(object sender, EventArgs e) - { - foreach (var ew in EmulatorWindows) - { - ew.Close(); - } - - EmulatorWindows.Clear(); - UpdateMainText(); - } - - private void LoadRomSession(IEnumerable entries) - { - foreach (var entry in entries) - { - LoadRom(entry.RomName); - EmulatorWindows.Last().Location = new Point(entry.Wndx, entry.Wndy); - UpdateMainText(); - } - } - - private void LoadRomSessionFromRecent(string path) - { - var file = new FileInfo(path); - if (file.Exists) - { - NewSessionMenuItem_Click(null, null); - var json = File.ReadAllText(file.FullName); - EmulatorWindows.SessionName = file.FullName; - LoadRomSession(EmulatorWindowList.FromJson(json)); - Global.Config.RecentRomSessions.Add(file.FullName); - UpdateMainText(); - } - else - { - Global.Config.RecentRomSessions.HandleLoadError(path); - } - } - - private void RecentSessionSubMenu_DropDownOpened(object sender, EventArgs e) - { - RecentSessionSubMenu.DropDownItems.Clear(); - RecentSessionSubMenu.DropDownItems.AddRange( - Global.Config.RecentRomSessions.RecentMenu(LoadRomSessionFromRecent, autoload: true)); - } - - private void RecentRomSubMenu_DropDownOpened(object sender, EventArgs e) - { - RecentRomSubMenu.DropDownItems.Clear(); - RecentRomSubMenu.DropDownItems.AddRange( - Global.Config.RecentRoms.RecentMenu(LoadRomFromRecent, autoload: false)); - } - - private void ViewSubMenu_DropDownOpened(object sender, EventArgs e) - { - _1xMenuItem.Checked = Global.Config.TargetZoomFactors[Emulator.SystemId] == 1; - _2xMenuItem.Checked = Global.Config.TargetZoomFactors[Emulator.SystemId] == 2; - _3xMenuItem.Checked = Global.Config.TargetZoomFactors[Emulator.SystemId] == 3; - _4xMenuItem.Checked = Global.Config.TargetZoomFactors[Emulator.SystemId] == 4; - } - - private void _1xMenuItem_Click(object sender, EventArgs e) - { - Global.Config.TargetZoomFactors[Emulator.SystemId] = 1; - ReRenderAllWindows(); - } - - private void _2xMenuItem_Click(object sender, EventArgs e) - { - Global.Config.TargetZoomFactors[Emulator.SystemId] = 2; - ReRenderAllWindows(); - } - - private void _3xMenuItem_Click(object sender, EventArgs e) - { - Global.Config.TargetZoomFactors[Emulator.SystemId] = 3; - ReRenderAllWindows(); - } - - private void _4xMenuItem_Click(object sender, EventArgs e) - { - Global.Config.TargetZoomFactors[Emulator.SystemId] = 4; - ReRenderAllWindows(); - } - - private void ReRenderAllWindows() - { - foreach (var ew in EmulatorWindows) - { - ew.FrameBufferResized(); - ew.Render(); - } - } - - private void LoadLastMovieMenuItem_Click(object sender, EventArgs e) - { - LoadMoviesFromRecent(Global.Config.RecentMovies.MostRecent); - } - - private void contextMenuStrip1_Opening(object sender, CancelEventArgs e) - { - LoadLastMovieContextMenuItem.Visible = !Global.Config.RecentMovies.Empty; - PlayMovieContextMenuItem.Visible = - RecordMovieContextMenuItem.Visible = - !Global.MovieSession.Movie.IsActive; - - StopMovieContextMenuItem.Visible = - RestartMovieContextMenuItem.Visible = - Global.MovieSession.Movie.IsActive; - - } - - private void RecentMovieSubMenu_DropDownOpened(object sender, EventArgs e) - { - RecentMovieSubMenu.DropDownItems.Clear(); - RecentMovieSubMenu.DropDownItems.AddRange( - Global.Config.RecentMovies.RecentMenu(LoadMoviesFromRecent, autoload: true)); - } - - private void RestartMovieMenuItem_Click(object sender, EventArgs e) - { - if (Global.MovieSession.Movie.IsActive) - { - StartNewMovie(Global.MovieSession.Movie, false); - AddMessage("Replaying movie file in read-only mode"); - } - } - } -} diff --git a/BizHawk.Client.MultiHawk/Mainform.resx b/BizHawk.Client.MultiHawk/Mainform.resx deleted file mode 100644 index bdf629369a..0000000000 --- a/BizHawk.Client.MultiHawk/Mainform.resx +++ /dev/null @@ -1,132 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - text/microsoft-resx - - - 2.0 - - - System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - - System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - - 17, 17 - - - 153, 17 - - - 153, 17 - - - 283, 17 - - \ No newline at end of file diff --git a/BizHawk.Client.MultiHawk/PresentationPanel.cs b/BizHawk.Client.MultiHawk/PresentationPanel.cs deleted file mode 100644 index 881f13960a..0000000000 --- a/BizHawk.Client.MultiHawk/PresentationPanel.cs +++ /dev/null @@ -1,64 +0,0 @@ -using System; -using System.Drawing; -using sd=System.Drawing; -using sysdrawingfont=System.Drawing.Font; -using sysdrawing2d=System.Drawing.Drawing2D; -using System.IO; -using System.Threading; -using System.Windows.Forms; -#if WINDOWS -using SlimDX; -#endif - -using BizHawk.Client.Common; -using BizHawk.Bizware.BizwareGL; - -using OpenTK.Graphics.OpenGL; - -namespace BizHawk.Client.MultiHawk -{ - /// - /// Thinly wraps a BizwareGL.GraphicsControl for EmuHawk's needs - /// - public class PresentationPanel - { - public PresentationPanel(Form parent, IGL gl) - { - GL = gl; - - GraphicsControl = new GraphicsControl(GL); - GraphicsControl.Dock = DockStyle.Fill; - GraphicsControl.BackColor = Color.Black; - - //pass through these events to the form. we might need a more scalable solution for mousedown etc. for zapper and whatnot. - //http://stackoverflow.com/questions/547172/pass-through-mouse-events-to-parent-control (HTTRANSPARENT) - - // TODO - //GraphicsControl.MouseClick += (o, e) => GlobalWin.MainForm.MainForm_MouseClick(o, e); - } - - bool IsDisposed = false; - public void Dispose() - { - if (IsDisposed) return; - IsDisposed = true; - GraphicsControl.Dispose(); - } - - //graphics resources - public IGL GL { get; set; } - public GraphicsControl GraphicsControl; - - public Control Control { get { return GraphicsControl; } } - public static implicit operator Control(PresentationPanel self) { return self.GraphicsControl; } - - public bool Resized { get; set; } - - public Size NativeSize { get { return GraphicsControl.ClientSize; } } - } - - - - public interface IBlitterFont { } - -} diff --git a/BizHawk.Client.MultiHawk/Program.cs b/BizHawk.Client.MultiHawk/Program.cs deleted file mode 100644 index 9ee5ddddc7..0000000000 --- a/BizHawk.Client.MultiHawk/Program.cs +++ /dev/null @@ -1,171 +0,0 @@ -using System; -using System.IO; -using System.Collections.Generic; -using System.Reflection; -using System.Runtime.InteropServices; -using System.Windows.Forms; -#if WINDOWS -using SlimDX.DirectSound; -using Microsoft.VisualBasic.ApplicationServices; -#endif - -using BizHawk.Common; -using BizHawk.Client.Common; - -namespace BizHawk.Client.MultiHawk -{ - static class Program - { - static Program() - { - //http://www.codeproject.com/Articles/310675/AppDomain-AssemblyResolve-Event-Tips -#if WINDOWS - // this will look in subdirectory "dll" to load pinvoked stuff - string dllDir = Path.Combine(Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location), "dll"); - SetDllDirectory(dllDir); - - //in case assembly resolution fails, such as if we moved them into the dll subdiretory, this event handler can reroute to them - AppDomain.CurrentDomain.AssemblyResolve += new ResolveEventHandler(CurrentDomain_AssemblyResolve); - - //but before we even try doing that, whack the MOTW from everything in that directory (thats a dll) - //otherwise, some people will have crashes at boot-up due to .net security disliking MOTW. - //some people are getting MOTW through a combination of browser used to download bizhawk, and program used to dearchive it - WhackAllMOTW(dllDir); -#endif - } - - - /// - /// The main entry point for the application. - /// - [STAThread] - static void Main(string[] args) - { - SubMain(args); - } - - - //NoInlining should keep this code from getting jammed into Main() which would create dependencies on types which havent been setup by the resolver yet... or something like that - [System.Runtime.CompilerServices.MethodImpl(System.Runtime.CompilerServices.MethodImplOptions.NoInlining)] - static void SubMain(string[] args) - { - Application.EnableVisualStyles(); - Application.SetCompatibleTextRenderingDefault(false); - string iniPath = Path.Combine(Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location), "config.ini"); - Global.Config = ConfigService.Load(iniPath); - Global.Config.ResolveDefaults(); - HawkFile.ArchiveHandlerFactory = new SevenZipSharpArchiveHandler(); - - //super hacky! this needs to be done first. still not worth the trouble to make this system fully proper - for (int i = 0; i < args.Length; i++) - { - var arg = args[i].ToLower(); - if (arg.StartsWith("--gdi")) - { - Global.Config.DispMethod = Config.EDispMethod.GdiPlus; - } - } - - - //WHY do we have to do this? some intel graphics drivers (ig7icd64.dll 10.18.10.3304 on an unknown chip on win8.1) are calling SetDllDirectory() for the process, which ruins stuff. - //The relevant initialization happened just before in "create IGL context". - //It isn't clear whether we need the earlier SetDllDirectory(), but I think we do. - //note: this is pasted instead of being put in a static method due to this initialization code being sensitive to things like that, and not wanting to cause it to break - //pasting should be safe (not affecting the jit order of things) - string dllDir = Path.Combine(Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location), "dll"); - SetDllDirectory(dllDir); - - try - { - using (var mf = new Mainform(args)) - { - var title = mf.Text; - mf.Show(); - mf.Text = title; - try - { - mf.ProgramRunLoop(); - } - catch (Exception e) when (Global.MovieSession.Movie.IsActive) - { - var result = MessageBox.Show( - "EmuHawk has thrown a fatal exception and is about to close.\nA movie has been detected. Would you like to try to save?\n(Note: Depending on what caused this error, this may or may not succeed)", - "Fatal error: " + e.GetType().Name, - MessageBoxButtons.YesNo, - MessageBoxIcon.Exclamation - ); - if (result == DialogResult.Yes) - { - Global.MovieSession.Movie.Save(); - } - } - } - } - catch (Exception e) - { - string message = e.ToString(); - if (e.InnerException != null) - { - message += "\n\nInner Exception:\n\n" + e.InnerException; - } - - message += "\n\nStackTrace:\n" + e.StackTrace; - MessageBox.Show(message); - } -#if WINDOWS - finally - { - GamePad.CloseAll(); - } -#endif - } - - - static Assembly CurrentDomain_AssemblyResolve(object sender, ResolveEventArgs args) - { - lock (AppDomain.CurrentDomain) - { - var asms = AppDomain.CurrentDomain.GetAssemblies(); - foreach (var asm in asms) - if (asm.FullName == args.Name) - return asm; - - //load missing assemblies by trying to find them in the dll directory - string dllname = new AssemblyName(args.Name).Name + ".dll"; - string directory = Path.Combine(Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location), "dll"); - string fname = Path.Combine(directory, dllname); - if (!File.Exists(fname)) return null; - //it is important that we use LoadFile here and not load from a byte array; otherwise mixed (managed/unamanged) assemblies can't load - return Assembly.LoadFile(fname); - } - } - - //declared here instead of a more usual place to avoid dependencies on the more usual place -#if WINDOWS - [DllImport("kernel32.dll", SetLastError = true)] - static extern uint SetDllDirectory(string lpPathName); - - [DllImport("kernel32.dll", EntryPoint = "DeleteFileW", SetLastError = true, CharSet = CharSet.Unicode, ExactSpelling = true)] - static extern bool DeleteFileW([MarshalAs(UnmanagedType.LPWStr)]string lpFileName); - static void RemoveMOTW(string path) - { - DeleteFileW(path + ":Zone.Identifier"); - } - - static void WhackAllMOTW(string dllDir) - { - var todo = new Queue(new[] { new DirectoryInfo(dllDir) }); - while (todo.Count > 0) - { - var di = todo.Dequeue(); - foreach (var disub in di.GetDirectories()) todo.Enqueue(disub); - foreach (var fi in di.GetFiles("*.dll")) - RemoveMOTW(fi.FullName); - foreach (var fi in di.GetFiles("*.exe")) - RemoveMOTW(fi.FullName); - } - - } -#endif - } -} diff --git a/BizHawk.Client.MultiHawk/Properties/AssemblyInfo.cs b/BizHawk.Client.MultiHawk/Properties/AssemblyInfo.cs deleted file mode 100644 index e0b3f137d4..0000000000 --- a/BizHawk.Client.MultiHawk/Properties/AssemblyInfo.cs +++ /dev/null @@ -1,36 +0,0 @@ -using System.Reflection; -using System.Runtime.CompilerServices; -using System.Runtime.InteropServices; - -// General Information about an assembly is controlled through the following -// set of attributes. Change these attribute values to modify the information -// associated with an assembly. -[assembly: AssemblyTitle("BizHawk.Client.MultiHawk")] -[assembly: AssemblyDescription("")] -[assembly: AssemblyConfiguration("")] -[assembly: AssemblyCompany("")] -[assembly: AssemblyProduct("BizHawk.Client.MultiHawk")] -[assembly: AssemblyCopyright("Copyright © 2015")] -[assembly: AssemblyTrademark("")] -[assembly: AssemblyCulture("")] - -// Setting ComVisible to false makes the types in this assembly not visible -// to COM components. If you need to access a type in this assembly from -// COM, set the ComVisible attribute to true on that type. -[assembly: ComVisible(false)] - -// The following GUID is for the ID of the typelib if this project is exposed to COM -[assembly: Guid("fcf20c42-6452-46c7-bb88-bc9f5bd0ce71")] - -// Version information for an assembly consists of the following four values: -// -// Major Version -// Minor Version -// Build Number -// Revision -// -// You can specify all the values or you can default the Build and Revision Numbers -// by using the '*' as shown below: -// [assembly: AssemblyVersion("1.0.*")] -[assembly: AssemblyVersion("1.0.0.0")] -[assembly: AssemblyFileVersion("1.0.0.0")] diff --git a/BizHawk.Client.MultiHawk/Properties/Resources.Designer.cs b/BizHawk.Client.MultiHawk/Properties/Resources.Designer.cs deleted file mode 100644 index 3855218b5a..0000000000 --- a/BizHawk.Client.MultiHawk/Properties/Resources.Designer.cs +++ /dev/null @@ -1,293 +0,0 @@ -//------------------------------------------------------------------------------ -// -// This code was generated by a tool. -// Runtime Version:4.0.30319.34209 -// -// Changes to this file may cause incorrect behavior and will be lost if -// the code is regenerated. -// -//------------------------------------------------------------------------------ - -namespace BizHawk.Client.MultiHawk.Properties { - using System; - - - /// - /// A strongly-typed resource class, for looking up localized strings, etc. - /// - // This class was auto-generated by the StronglyTypedResourceBuilder - // class via a tool like ResGen or Visual Studio. - // To add or remove a member, edit your .ResX file then rerun ResGen - // with the /str option, or rebuild your VS project. - [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "4.0.0.0")] - [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] - [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] - internal class Resources { - - private static global::System.Resources.ResourceManager resourceMan; - - private static global::System.Globalization.CultureInfo resourceCulture; - - [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] - internal Resources() { - } - - /// - /// Returns the cached ResourceManager instance used by this class. - /// - [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] - internal static global::System.Resources.ResourceManager ResourceManager { - get { - if (object.ReferenceEquals(resourceMan, null)) { - global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("BizHawk.Client.MultiHawk.Properties.Resources", typeof(Resources).Assembly); - resourceMan = temp; - } - return resourceMan; - } - } - - /// - /// Overrides the current thread's CurrentUICulture property for all - /// resource lookups using this strongly typed resource class. - /// - [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] - internal static global::System.Globalization.CultureInfo Culture { - get { - return resourceCulture; - } - set { - resourceCulture = value; - } - } - - /// - /// Looks up a localized resource of type System.Drawing.Bitmap. - /// - internal static System.Drawing.Bitmap Blank { - get { - object obj = ResourceManager.GetObject("Blank", resourceCulture); - return ((System.Drawing.Bitmap)(obj)); - } - } - - /// - /// Looks up a localized resource of type System.Byte[]. - /// - internal static byte[] courier16px { - get { - object obj = ResourceManager.GetObject("courier16px", resourceCulture); - return ((byte[])(obj)); - } - } - - /// - /// Looks up a localized resource of type System.Drawing.Bitmap. - /// - internal static System.Drawing.Bitmap courier16px_0 { - get { - object obj = ResourceManager.GetObject("courier16px_0", resourceCulture); - return ((System.Drawing.Bitmap)(obj)); - } - } - - /// - /// Looks up a localized resource of type System.Byte[]. - /// - internal static byte[] courier16px1 { - get { - object obj = ResourceManager.GetObject("courier16px1", resourceCulture); - return ((byte[])(obj)); - } - } - - /// - /// Looks up a localized resource of type System.Drawing.Bitmap. - /// - internal static System.Drawing.Bitmap CutHS { - get { - object obj = ResourceManager.GetObject("CutHS", resourceCulture); - return ((System.Drawing.Bitmap)(obj)); - } - } - - /// - /// Looks up a localized resource of type System.Drawing.Bitmap. - /// - internal static System.Drawing.Bitmap ExclamationRed { - get { - object obj = ResourceManager.GetObject("ExclamationRed", resourceCulture); - return ((System.Drawing.Bitmap)(obj)); - } - } - - /// - /// Looks up a localized resource of type System.Drawing.Bitmap. - /// - internal static System.Drawing.Bitmap GameController { - get { - object obj = ResourceManager.GetObject("GameController", resourceCulture); - return ((System.Drawing.Bitmap)(obj)); - } - } - - /// - /// Looks up a localized resource of type System.Drawing.Bitmap. - /// - internal static System.Drawing.Bitmap GreenCheck { - get { - object obj = ResourceManager.GetObject("GreenCheck", resourceCulture); - return ((System.Drawing.Bitmap)(obj)); - } - } - - /// - /// Looks up a localized resource of type System.Drawing.Bitmap. - /// - internal static System.Drawing.Bitmap Help { - get { - object obj = ResourceManager.GetObject("Help", resourceCulture); - return ((System.Drawing.Bitmap)(obj)); - } - } - - /// - /// Looks up a localized resource of type System.Drawing.Bitmap. - /// - internal static System.Drawing.Bitmap HotKeys { - get { - object obj = ResourceManager.GetObject("HotKeys", resourceCulture); - return ((System.Drawing.Bitmap)(obj)); - } - } - - /// - /// Looks up a localized resource of type System.Drawing.Bitmap. - /// - internal static System.Drawing.Bitmap OpenFile { - get { - object obj = ResourceManager.GetObject("OpenFile", resourceCulture); - return ((System.Drawing.Bitmap)(obj)); - } - } - - /// - /// Looks up a localized resource of type System.Drawing.Bitmap. - /// - internal static System.Drawing.Bitmap Pause { - get { - object obj = ResourceManager.GetObject("Pause", resourceCulture); - return ((System.Drawing.Bitmap)(obj)); - } - } - - /// - /// Looks up a localized resource of type System.Drawing.Bitmap. - /// - internal static System.Drawing.Bitmap Play { - get { - object obj = ResourceManager.GetObject("Play", resourceCulture); - return ((System.Drawing.Bitmap)(obj)); - } - } - - /// - /// Looks up a localized resource of type System.Drawing.Bitmap. - /// - internal static System.Drawing.Bitmap ReadOnly { - get { - object obj = ResourceManager.GetObject("ReadOnly", resourceCulture); - return ((System.Drawing.Bitmap)(obj)); - } - } - - /// - /// Looks up a localized resource of type System.Drawing.Bitmap. - /// - internal static System.Drawing.Bitmap reboot { - get { - object obj = ResourceManager.GetObject("reboot", resourceCulture); - return ((System.Drawing.Bitmap)(obj)); - } - } - - /// - /// Looks up a localized resource of type System.Drawing.Bitmap. - /// - internal static System.Drawing.Bitmap Recent { - get { - object obj = ResourceManager.GetObject("Recent", resourceCulture); - return ((System.Drawing.Bitmap)(obj)); - } - } - - /// - /// Looks up a localized resource of type System.Drawing.Bitmap. - /// - internal static System.Drawing.Bitmap RecordHS { - get { - object obj = ResourceManager.GetObject("RecordHS", resourceCulture); - return ((System.Drawing.Bitmap)(obj)); - } - } - - /// - /// Looks up a localized resource of type System.Drawing.Bitmap. - /// - internal static System.Drawing.Bitmap restart { - get { - object obj = ResourceManager.GetObject("restart", resourceCulture); - return ((System.Drawing.Bitmap)(obj)); - } - } - - /// - /// Looks up a localized resource of type System.Drawing.Bitmap. - /// - internal static System.Drawing.Bitmap Save { - get { - object obj = ResourceManager.GetObject("Save", resourceCulture); - return ((System.Drawing.Bitmap)(obj)); - } - } - - /// - /// Looks up a localized resource of type System.Drawing.Bitmap. - /// - internal static System.Drawing.Bitmap SaveAllHS { - get { - object obj = ResourceManager.GetObject("SaveAllHS", resourceCulture); - return ((System.Drawing.Bitmap)(obj)); - } - } - - /// - /// Looks up a localized resource of type System.Drawing.Bitmap. - /// - internal static System.Drawing.Bitmap SaveAs { - get { - object obj = ResourceManager.GetObject("SaveAs", resourceCulture); - return ((System.Drawing.Bitmap)(obj)); - } - } - - /// - /// Looks up a localized resource of type System.Drawing.Bitmap. - /// - internal static System.Drawing.Bitmap Scan { - get { - object obj = ResourceManager.GetObject("Scan", resourceCulture); - return ((System.Drawing.Bitmap)(obj)); - } - } - - /// - /// Looks up a localized resource of type System.Drawing.Bitmap. - /// - internal static System.Drawing.Bitmap Stop { - get { - object obj = ResourceManager.GetObject("Stop", resourceCulture); - return ((System.Drawing.Bitmap)(obj)); - } - } - } -} diff --git a/BizHawk.Client.MultiHawk/Properties/Resources.resx b/BizHawk.Client.MultiHawk/Properties/Resources.resx deleted file mode 100644 index 88761a4c4d..0000000000 --- a/BizHawk.Client.MultiHawk/Properties/Resources.resx +++ /dev/null @@ -1,190 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - text/microsoft-resx - - - 2.0 - - - System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - - System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - - - ..\images\Blank.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a - - - ..\Resources\courier16px.bmfc;System.Byte[], mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - - ..\Resources\courier16px.fnt;System.Byte[], mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - - ..\Resources\courier16px_0.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a - - - ..\images\CutHS.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a - - - ..\images\ExclamationRed.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a - - - ..\images\GreenCheck.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a - - - ..\images\OpenFile.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a - - - ..\images\Pause.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a - - - ..\images\Play.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a - - - ..\images\ReadOnly.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a - - - ..\images\reboot.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a - - - ..\images\Recent.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a - - - ..\images\RecordHS.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a - - - ..\images\SaveAllHS.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a - - - ..\images\SaveAs.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a - - - ..\images\Scan.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a - - - ..\images\Stop.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a - - - ..\images\GameController.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a - - - ..\images\Help.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a - - - ..\images\HotKeys.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a - - - ..\images\Save.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a - - - ..\images\restart.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a - - \ No newline at end of file diff --git a/BizHawk.Client.MultiHawk/Properties/Settings.Designer.cs b/BizHawk.Client.MultiHawk/Properties/Settings.Designer.cs deleted file mode 100644 index fb9499495c..0000000000 --- a/BizHawk.Client.MultiHawk/Properties/Settings.Designer.cs +++ /dev/null @@ -1,26 +0,0 @@ -//------------------------------------------------------------------------------ -// -// This code was generated by a tool. -// Runtime Version:4.0.30319.42000 -// -// Changes to this file may cause incorrect behavior and will be lost if -// the code is regenerated. -// -//------------------------------------------------------------------------------ - -namespace BizHawk.Client.MultiHawk.Properties { - - - [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] - [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "14.0.0.0")] - internal sealed partial class Settings : global::System.Configuration.ApplicationSettingsBase { - - private static Settings defaultInstance = ((Settings)(global::System.Configuration.ApplicationSettingsBase.Synchronized(new Settings()))); - - public static Settings Default { - get { - return defaultInstance; - } - } - } -} diff --git a/BizHawk.Client.MultiHawk/Properties/Settings.settings b/BizHawk.Client.MultiHawk/Properties/Settings.settings deleted file mode 100644 index abf36c5d3d..0000000000 --- a/BizHawk.Client.MultiHawk/Properties/Settings.settings +++ /dev/null @@ -1,7 +0,0 @@ - - - - - - - diff --git a/BizHawk.Client.MultiHawk/Resources/courier16px.bmfc b/BizHawk.Client.MultiHawk/Resources/courier16px.bmfc deleted file mode 100644 index df09355333..0000000000 --- a/BizHawk.Client.MultiHawk/Resources/courier16px.bmfc +++ /dev/null @@ -1,55 +0,0 @@ -# AngelCode Bitmap Font Generator configuration file -fileVersion=1 - -# font settings -fontName=Courier -fontFile= -charSet=0 -fontSize=16 -aa=1 -scaleH=100 -useSmoothing=0 -isBold=1 -isItalic=0 -useUnicode=1 -disableBoxChars=1 -outputInvalidCharGlyph=1 -dontIncludeKerningPairs=0 -useHinting=1 -renderFromOutline=0 -useClearType=1 - -# character alignment -paddingDown=0 -paddingUp=0 -paddingRight=0 -paddingLeft=0 -spacingHoriz=1 -spacingVert=1 -useFixedHeight=0 -forceZero=0 - -# output file -outWidth=128 -outHeight=256 -outBitDepth=32 -fontDescFormat=1 -fourChnlPacked=0 -textureFormat=png -textureCompression=0 -alphaChnl=0 -redChnl=4 -greenChnl=4 -blueChnl=4 -invA=0 -invR=0 -invG=0 -invB=0 - -# outline -outlineThickness=0 - -# selected chars -chars=32-127,129,141,143-144,157,160-255 - -# imported icon images diff --git a/BizHawk.Client.MultiHawk/Resources/courier16px.fnt b/BizHawk.Client.MultiHawk/Resources/courier16px.fnt deleted file mode 100644 index 0e8d5e8a1f..0000000000 --- a/BizHawk.Client.MultiHawk/Resources/courier16px.fnt +++ /dev/null @@ -1,208 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/BizHawk.Client.MultiHawk/Resources/courier16px_0.png b/BizHawk.Client.MultiHawk/Resources/courier16px_0.png deleted file mode 100644 index 36d5051db4114f511dfeaf24cb3a7c5114e813c1..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2268 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 diff --git a/BizHawk.Client.MultiHawk/images/GreenCheck.png b/BizHawk.Client.MultiHawk/images/GreenCheck.png deleted file mode 100644 index 9f243dcd9d395b3bca4fa899ada67bdec44d980f..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 576 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!63?wyl`GXl47)1hnLR^7d2=H9aqSFIn2Co%T z>t@jEVaVLABNWFFxj`y9?X`j}V!Kep4q>;&%-MSla*k>h9y3bV zp}-K#U_G0;<(#kUBBtQ&T+s&vqxK8>Z{!Hw$rHU-IAA?b%q}6pDhB6yjDcG?Licco z?BojD%ME1sZeR=9!6{$G;4q6R<|wb<2KKPsJkbXQqYelJZRLtPA?P%h3Fv_ObFL13 z?4g?kLpBPk#X`Lqw1Ef6QVnKN31oo^F)+j)5~)0EJ>y3D!rP@02Y8~6J}m&sg_i{R z1v4-*F)(m2FfjrJh4xJ;OVfitLpjp5osQ=kH_X+PfE*X>ne zU|uz z;YwDagliYCUN$%2F*h6j>`tQ*3;F`Wt~$(696+DzhwXb diff --git a/BizHawk.Client.MultiHawk/images/Help.png b/BizHawk.Client.MultiHawk/images/Help.png deleted file mode 100644 index 30a424bbf19ac57b09661d5c385b8c5326c66faf..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 646 zcmV;10(t$3P)6 z#nkk=$Ks#5>0prm?e_lg^ZKB;|Cy=Fh@a5r@cck<|B$f%pt$grtlYK4-ivP|E0U@#nba3P{4?!-{|b~-|zl~q2BQG`?k;SP>Arb!0+&*CkD0FD;q3WvnDFfN{*b8fHdT{wknm7=z~1lvRBfQQ#^<=u>=0Pc zP=MfosNi6b@W9yc;PC&7o4t#o)7$L*a*MoxpwQXs>{D!?y~*T)naSSn{-3zk+vM$4 zZJ?g4$hX7ac87$arikO1PVIP-ByF^Z^*aJuoNYXb$Wbvg9d^@YU)8I4U$&42>t zLKec@+*VPX(YDO?0YCvqCoXPrUKd7JW&w9kFQ9<8k1sDPt3RUzi$IWI2v8t2jE6N` zA|jH7iHS`t7UYh&czzZZenuvy#H3`fJ5o~9*d&>mCD}4Evmj2*&dJToFAx+fEQ0%{ gxTLhKyaKz&0V$gvQggI3mjD0&07*qoM6N<$g1H!FQvd(} diff --git a/BizHawk.Client.MultiHawk/images/HotKeys.png b/BizHawk.Client.MultiHawk/images/HotKeys.png deleted file mode 100644 index 962eb51ed7fee9b6e17109ff0766930ddb558aa1..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 751 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 diff --git a/BizHawk.Client.MultiHawk/images/Recent.png b/BizHawk.Client.MultiHawk/images/Recent.png deleted file mode 100644 index 42c559ad274a67cc851405b766c7c19ea7450efe..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 907 zcmX|8Ye|sOS2LSMX3B!lwBw(w4g%qnoe|D)UON)Gf^8}F{!Xpv#FI?a|op@ zr=Q#Mn>u&j)U>9Snr`ZBUZ&eLB8?f|a$jeD5j^j6p7We@-uJ-!BsM18-POkxA>EXeYam}&&kT@j=(Si`d%L_K*Dk0x~C*oQrLT;Y+LqY5sZy4amMkj<41Yxms0p{oJ zFq=CJ28nhA2Y`T-^evW7z{EtmLdM1#im`e?5ymZ+NmzQlh^&&VA8%{LpW}k^Paip> zI-#KHDZjB)r^TTPx0%hIMx#)6}&q*z%!ZE4V=flntGE-4L!i0dN>Mcwb7^m-6ni4ZGSa8tDK!xsZ}+d>NlX_ zE!amcW%c)RXJ!;IMOMY4m($a-J`ERc(~dMt+F!vXTUBLWFSm(XGW=CAGb0BRSg&tu zX|5O>Yi;H+L4z|jC57>!K_0K6gpZYWchwFLzlRh|DE-IC@O!bSsE| z{Ljl7@@d9E?wN~BvDxXCchOlvmh0&qNhjzQ-@v2VgX)xb7>0d65FT*EV=<*M7IsCE Lp)nzX;Kahea}z9& diff --git a/BizHawk.Client.MultiHawk/images/RecordHS.png b/BizHawk.Client.MultiHawk/images/RecordHS.png deleted file mode 100644 index 581741d36c85a5c28a2590955dccd6facc24b9c9..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 358 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!63?wyl`GbL!Lb6AYF9SoBDg#49GXulV|3LaB z14F3+1H-EX1_rAc3=HD=lj4uM0oAgkJNh~@Fl_9r`5ibJ$mcBZh%9Dc;1&j9Muu5) zB!Gfx0X`wF|Ns9#p6miaN0XcnB{=Pmb3C8x|8zph$N8-<+cVE5J8liOSRZ2j|LCS) zTjqY6UiGZlcaM+u91oN4D<^#DFL;vcddfq--CFlWRp`AKqazMtMS7~&+$Cljh{P+& zrO1o>Nl1MD+-U@~QK=-zFPOn$=7R?_9WDWF{(sQ{ME;)%A|62S%!>|gmVKH))i$0k zjv*Cuk`o=6b)Ik;G#%96!JsT1(eT$ehC!<-;NXc9U3v#jGy!oB5Vr{YILarsv%lbY ddez@;jFR;*zW@LLAY({UO#lFTEdT(3l>h+v)Bpg8QUCyP zM*sloV*mg-2><{g{GF)1UjP6A24YJ`L;(K){{a7>y{D4^00O;9L_t(|oNbazPZLoT z$N!}>eM}hzX`wu7AqXZAgd%K6jIzSG!G#NrtlYUFdH%m)PFX!gwtOfvM>`6ErejW@4;lf3& zYG8i{NDNyr-6mA^9rSSORZ6X=!BFrmfV~EQX`1`0svZS+jt8736bn@x$_7eQ!G5`f zh_Qy2K)jQ4ng`ATj%J{$>Ta!8b1cgOLI#o(JYs#Va3Mg}Y#>Up8F-J1UWzb_jb0d{ zs;UQyqG*O;pja$GjQP4V?r2gh+qN@=nIAW4!!2stoK^H#ZBMlzYi=;$b-(HOGZ3G_z> zz-)#KqS}n^O2Jr0^kjv#vMN#sUQXC#0!t>rhz@;j(q!3lK=n!AY({UO#lFTB>(_`g8%^e{{R4h=>PzA zFaQARU;qF*m;eA5Z<1fdMgRZ-*|$5nC&* zNkkjbKVW0jMmzll#`xJj%1g>&{}c4zOgIDvBsV8fKNGw(C+ z>~5nhOO6u94obdyxmapSi0=}D;=SUW;(f$RLY%U_y~*^Q@SH)uLdqzYpX3d&q*M0MYdbc*VKE#P}%Z z?I6Yq)(%nFVXXBO#*&gCE|8LtaHS@z@aglD#!gMM zvXCm0t$bx?hnSwa#{GLUG@E@mA4$oR%seTD{eQvxYC&^9R?x6bHa5xS$qAO0e_`6o z(A-bniAGtL+`2hCo#**uU__G;qeFv1LP3az7%afy0!N8|0|2hsjDqakqD%k)002ov JPDHLkV1nY^925Wm diff --git a/BizHawk.Client.MultiHawk/images/SaveAs.png b/BizHawk.Client.MultiHawk/images/SaveAs.png deleted file mode 100644 index 5ca4d10623771c63e51540bf6f8c832f7618143e..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 595 zcmV-Z0<8UsP)z@;j(q!3lK=n!AY({UO#lFTB>(_`g8%^e{{R4h=>PzA zFaQARU;qF*m;eA5Z<1fdMgRZ-$w@>(RCwB?lRaxxK@^6cn_RtXHuxLFACM*~SFn(* zV3R_71&0Z1tmV@B0bO^6sGMvUWHHKA(6m|4HQP?QH?w>!`Fwy?TZ z{nKqIiA$GXa+1CMn+0Y7RIPn593BeSK2odl>GK9=3h;jdBY3E|80jxxn-mBk0pPtq z6t2Bes}e%MERF?4(qAW-g7+gh@30)FBZ$bM@K6#?73cjZLfL{w&akqw$d#*a@iF4G z9oNOywN}Nca^dtTf{Y`S2N6O5RXBHck)54D2mw_^L`L=Q-Y!9epkZ=?5E9;l_ldez zUc9?8v5TrY#)(da$Qgo!X#rKkdl(E9@7qN_d$P__ug`;rk2qe=a`)bSez=+Dow;iOEajr&HdAzxa{rt$So7d@7 zvwZvdg-%uSVe1vy&ZA8xr9??AS}p?UxS002ovPDHLkV1gKF0Gkdg00001b5ch_0olnc ze*gdgAY({UO#lFTB>(_`g8%^e{{R4h=>PzAFaQARU;qF*m;eA5Z<1fdMgRZ+32;bR za{vGf6951U69E94oEQKA00d`2O+f$vv5tKEQIh}w0f|XOK~#7F?ZH7SgK-?d@gE26 zb+{_ryb7VLmozbMp84cA?`vVeO zDeSm8vK;ZuGe=~};kczK2_`>kKW=l3%?S<;C)gabjs2J(l^`59gNemDOI&iv66;u) zWN=*ZR~)-Y?O>B)5uGQV&{-sf%?=l-;+XikE9I$hN)jE9ci!>PNpebsJa;Ae+QaP| zFSPM!;sI5vfJYOLHZQ#Ka4TQ4XA9IY+2DWIS#Q%Qjcv7ia(_lSf!518dqGghDn`O3Mfs2 zSPtFC4H6jC@bIW%kig(Rz8sQZ5+S82ZIczQxn_k;l%}*qpL~ZtT%ER}t#m7GMXS^L iko-(#vN9oE|KA7w15e)6P|Du`0000=z^A}uSzH*g{`XNv610G%nJiND=TJEy4 zxwUTNQE&g(wRKM_s~(nC+)mB7lazXUOL9c4-A6Hi0FD<{7o&^-YwQ#h zIVS!>KC(!TD-Z0H z20How|2_#Y)dit?A}R1wVI`r|G=4A PpeYQVu6{1-oD!MRe?@~b`b!3Ci3?U-W%0OP_Rp?l! znOn?+WH4qnMTYuH{qFsJ-}%ltziZFW z%@hTO1rm`+uS+*z5B5%>FV?8ob%odjwT4Wsz@}Sshp2lUkpuG?VB6A&PBjqy(MOc}kSNquo7!mwILpsAW-!K3 zCMEhjG0`cPKR9@BxxAcNELW0}M&siz@7_J0kZ>_B?$WMZ;^#R?VD0U!zn^t=q2$)S zee;EdcXM)P^71Ct>eJh|$NBiM%1Y*Nu-;x)SNDNZxl~%poK9x7z7i7REw|hMJaWVu z8j7aLetxW{huLhbx*GAR@Nm}F#=5)b3|>F_WHMy3=4RH|xLi?T5Q(A%f}b)oS$%yZ zQRT*s?yRh%8#W9^MJ<+;fJV>OtrF-onPv+LUW6CWN`wI8>YhEnW@k^Nq~rw!K_Ecd zrP7M^>#^R;&;KDKb}wVzZ+9pEk2<;$N*%axcGWx&#N~yU7{n+!w_^u5EFC@!D740J1~@n?iQo_7noXO)8KS@k zfVhG4a1U0zD{}pftB>jox!wmx6mL1_&A|xhe$097UUT`;A_|`1+_PnbuNGb4cgmDL zod2%Sa(*L(E^`+Nn<28!w#y?ae^n zQloT>{{tt`#`NhL<4J+vgj&@hApg19!XF=9J!`EkmRLG(50=-MM$UXI+c`8*_B6#c z*4L>ypr7fOH%sbgEPb`3K?9j2lbcEQVeVJ6!*BO=)(D2euDp|R^1H+?#hB-%zZBst ztM%CR(bQr4s?_OuvY2BrDc!cmEmO8n7lKa&HK|t4%Rf$Q`C>fqe$)G>3*NZ4=sf$+ zt BcYFW< diff --git a/BizHawk.Client.MultiHawk/images/restart.png b/BizHawk.Client.MultiHawk/images/restart.png deleted file mode 100644 index 89eebbbd0415a390edf792111ecbf0e558b6f999..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 473 zcmV;~0Ve*5P)z@;j(q!3lK=n!AY({UO#lFTB>(_`g8%^e{{R4h=>PzA zFaQARU;qF*m;eA5Z<1fdMgRZ-Pf0{URCwCdleA)0stc6 zNR-c>^e8z7V2x#KrAVz(9@Y+bD*$xvUN~sQ$ZvrBR|SUFmE!ikKdkLEpK0v(*r?AB z6sU1Ma75B`()L_jKLHSntS118@@TEcSg;nMvX95@61{$xScV9bO;_q{lp_H_0bXN| zkPe|!PH#e#PEpzqcH@sl0(gAr0-&`<2tg7jBuUKdnm{S_1Caaw$Mi7(wBp17fNojn P00000NkvXXu0mjfDGIx+ diff --git a/BizHawk.Client.MultiHawk/movie/PlayMovie.Designer.cs b/BizHawk.Client.MultiHawk/movie/PlayMovie.Designer.cs deleted file mode 100644 index 39e0289bb3..0000000000 --- a/BizHawk.Client.MultiHawk/movie/PlayMovie.Designer.cs +++ /dev/null @@ -1,406 +0,0 @@ -namespace BizHawk.Client.MultiHawk -{ - partial class PlayMovie - { - /// - /// Required designer variable. - /// - private System.ComponentModel.IContainer components = null; - - /// - /// Clean up any resources being used. - /// - /// true if managed resources should be disposed; otherwise, false. - protected override void Dispose(bool disposing) - { - if (disposing && (components != null)) - { - components.Dispose(); - } - base.Dispose(disposing); - } - - #region Windows Form Designer generated code - - /// - /// Required method for Designer support - do not modify - /// the contents of this method with the code editor. - /// - private void InitializeComponent() - { - this.components = new System.ComponentModel.Container(); - System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(PlayMovie)); - this.Cancel = new System.Windows.Forms.Button(); - this.OK = new System.Windows.Forms.Button(); - this.BrowseMovies = new System.Windows.Forms.Button(); - this.DetailsView = new System.Windows.Forms.ListView(); - this.columnHeader5 = ((System.Windows.Forms.ColumnHeader)(new System.Windows.Forms.ColumnHeader())); - this.columnHeader6 = ((System.Windows.Forms.ColumnHeader)(new System.Windows.Forms.ColumnHeader())); - this.groupBox1 = new System.Windows.Forms.GroupBox(); - this.SubtitlesBtn = new System.Windows.Forms.Button(); - this.CommentsBtn = new System.Windows.Forms.Button(); - this.MovieCount = new System.Windows.Forms.Label(); - this.ReadOnlyCheckBox = new System.Windows.Forms.CheckBox(); - this.IncludeSubDirectories = new System.Windows.Forms.CheckBox(); - this.Scan = new System.Windows.Forms.Button(); - this.toolTip1 = new System.Windows.Forms.ToolTip(this.components); - this.MatchHashCheckBox = new System.Windows.Forms.CheckBox(); - this.contextMenuStrip1 = new System.Windows.Forms.ContextMenuStrip(this.components); - this.editToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); - this.StopOnFrameCheckbox = new System.Windows.Forms.CheckBox(); - this.StopOnFrameTextBox = new BizHawk.Client.EmuHawk.WatchValueBox(); - this.MovieView = new BizHawk.Client.EmuHawk.VirtualListView(); - this.columnHeader1 = ((System.Windows.Forms.ColumnHeader)(new System.Windows.Forms.ColumnHeader())); - this.columnHeader2 = ((System.Windows.Forms.ColumnHeader)(new System.Windows.Forms.ColumnHeader())); - this.columnHeader3 = ((System.Windows.Forms.ColumnHeader)(new System.Windows.Forms.ColumnHeader())); - this.columnHeader4 = ((System.Windows.Forms.ColumnHeader)(new System.Windows.Forms.ColumnHeader())); - this.LastFrameCheckbox = new System.Windows.Forms.CheckBox(); - this.TurboCheckbox = new System.Windows.Forms.CheckBox(); - this.groupBox1.SuspendLayout(); - this.contextMenuStrip1.SuspendLayout(); - this.SuspendLayout(); - // - // Cancel - // - this.Cancel.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right))); - this.Cancel.DialogResult = System.Windows.Forms.DialogResult.Cancel; - this.Cancel.Location = new System.Drawing.Point(687, 363); - this.Cancel.Name = "Cancel"; - this.Cancel.Size = new System.Drawing.Size(75, 23); - this.Cancel.TabIndex = 55; - this.Cancel.Text = "&Cancel"; - this.Cancel.UseVisualStyleBackColor = true; - this.Cancel.Click += new System.EventHandler(this.Cancel_Click); - // - // OK - // - this.OK.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right))); - this.OK.Location = new System.Drawing.Point(606, 363); - this.OK.Name = "OK"; - this.OK.Size = new System.Drawing.Size(75, 23); - this.OK.TabIndex = 50; - this.OK.Text = "&OK"; - this.toolTip1.SetToolTip(this.OK, "Load selected movie"); - this.OK.UseVisualStyleBackColor = true; - this.OK.Click += new System.EventHandler(this.Ok_Click); - // - // BrowseMovies - // - this.BrowseMovies.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left))); - this.BrowseMovies.Image = global::BizHawk.Client.MultiHawk.Properties.Resources.OpenFile; - this.BrowseMovies.Location = new System.Drawing.Point(12, 364); - this.BrowseMovies.Name = "BrowseMovies"; - this.BrowseMovies.Size = new System.Drawing.Size(31, 23); - this.BrowseMovies.TabIndex = 25; - this.toolTip1.SetToolTip(this.BrowseMovies, "Browse for additional movie files"); - this.BrowseMovies.UseVisualStyleBackColor = true; - this.BrowseMovies.Click += new System.EventHandler(this.BrowseMovies_Click); - // - // DetailsView - // - this.DetailsView.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom) - | System.Windows.Forms.AnchorStyles.Left) - | System.Windows.Forms.AnchorStyles.Right))); - this.DetailsView.Columns.AddRange(new System.Windows.Forms.ColumnHeader[] { - this.columnHeader5, - this.columnHeader6}); - this.DetailsView.FullRowSelect = true; - this.DetailsView.GridLines = true; - this.DetailsView.HideSelection = false; - this.DetailsView.Location = new System.Drawing.Point(15, 19); - this.DetailsView.Name = "DetailsView"; - this.DetailsView.Size = new System.Drawing.Size(228, 261); - this.DetailsView.TabIndex = 10; - this.toolTip1.SetToolTip(this.DetailsView, "Contains the header information for the selected movie"); - this.DetailsView.UseCompatibleStateImageBehavior = false; - this.DetailsView.View = System.Windows.Forms.View.Details; - this.DetailsView.ColumnClick += new System.Windows.Forms.ColumnClickEventHandler(this.DetailsView_ColumnClick); - // - // columnHeader5 - // - this.columnHeader5.Text = "Header"; - this.columnHeader5.Width = 102; - // - // columnHeader6 - // - this.columnHeader6.Text = "Value"; - this.columnHeader6.Width = 121; - // - // groupBox1 - // - this.groupBox1.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right))); - this.groupBox1.Controls.Add(this.SubtitlesBtn); - this.groupBox1.Controls.Add(this.CommentsBtn); - this.groupBox1.Controls.Add(this.DetailsView); - this.groupBox1.Location = new System.Drawing.Point(503, 28); - this.groupBox1.Name = "groupBox1"; - this.groupBox1.Size = new System.Drawing.Size(259, 322); - this.groupBox1.TabIndex = 6; - this.groupBox1.TabStop = false; - this.groupBox1.Text = "Details"; - // - // SubtitlesBtn - // - this.SubtitlesBtn.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right))); - this.SubtitlesBtn.Enabled = false; - this.SubtitlesBtn.Location = new System.Drawing.Point(125, 286); - this.SubtitlesBtn.Name = "SubtitlesBtn"; - this.SubtitlesBtn.Size = new System.Drawing.Size(75, 23); - this.SubtitlesBtn.TabIndex = 20; - this.SubtitlesBtn.Text = "Subtitles"; - this.SubtitlesBtn.UseVisualStyleBackColor = true; - this.SubtitlesBtn.Click += new System.EventHandler(this.SubtitlesBtn_Click); - // - // CommentsBtn - // - this.CommentsBtn.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left))); - this.CommentsBtn.Enabled = false; - this.CommentsBtn.Location = new System.Drawing.Point(15, 286); - this.CommentsBtn.Name = "CommentsBtn"; - this.CommentsBtn.Size = new System.Drawing.Size(75, 23); - this.CommentsBtn.TabIndex = 15; - this.CommentsBtn.Text = "Comments"; - this.CommentsBtn.UseVisualStyleBackColor = true; - this.CommentsBtn.Click += new System.EventHandler(this.CommentsBtn_Click); - // - // MovieCount - // - this.MovieCount.AutoSize = true; - this.MovieCount.Location = new System.Drawing.Point(12, 9); - this.MovieCount.Name = "MovieCount"; - this.MovieCount.Size = new System.Drawing.Size(31, 13); - this.MovieCount.TabIndex = 7; - this.MovieCount.Text = " "; - // - // ReadOnlyCheckBox - // - this.ReadOnlyCheckBox.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right))); - this.ReadOnlyCheckBox.AutoSize = true; - this.ReadOnlyCheckBox.Checked = true; - this.ReadOnlyCheckBox.CheckState = System.Windows.Forms.CheckState.Checked; - this.ReadOnlyCheckBox.Location = new System.Drawing.Point(503, 367); - this.ReadOnlyCheckBox.Name = "ReadOnlyCheckBox"; - this.ReadOnlyCheckBox.Size = new System.Drawing.Size(74, 17); - this.ReadOnlyCheckBox.TabIndex = 45; - this.ReadOnlyCheckBox.Text = "Read only"; - this.ReadOnlyCheckBox.UseVisualStyleBackColor = true; - // - // IncludeSubDirectories - // - this.IncludeSubDirectories.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left))); - this.IncludeSubDirectories.AutoSize = true; - this.IncludeSubDirectories.Location = new System.Drawing.Point(94, 375); - this.IncludeSubDirectories.Name = "IncludeSubDirectories"; - this.IncludeSubDirectories.Size = new System.Drawing.Size(131, 17); - this.IncludeSubDirectories.TabIndex = 35; - this.IncludeSubDirectories.Text = "Include Subdirectories"; - this.IncludeSubDirectories.UseVisualStyleBackColor = true; - this.IncludeSubDirectories.CheckedChanged += new System.EventHandler(this.IncludeSubDirectories_CheckedChanged); - // - // Scan - // - this.Scan.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left))); - this.Scan.Image = global::BizHawk.Client.MultiHawk.Properties.Resources.Scan; - this.Scan.Location = new System.Drawing.Point(49, 364); - this.Scan.Name = "Scan"; - this.Scan.Size = new System.Drawing.Size(27, 23); - this.Scan.TabIndex = 30; - this.toolTip1.SetToolTip(this.Scan, "Rescan Movie folder for movie files"); - this.Scan.UseVisualStyleBackColor = true; - this.Scan.Click += new System.EventHandler(this.Scan_Click); - // - // MatchHashCheckBox - // - this.MatchHashCheckBox.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left))); - this.MatchHashCheckBox.AutoSize = true; - this.MatchHashCheckBox.Location = new System.Drawing.Point(94, 357); - this.MatchHashCheckBox.Name = "MatchHashCheckBox"; - this.MatchHashCheckBox.Size = new System.Drawing.Size(147, 17); - this.MatchHashCheckBox.TabIndex = 56; - this.MatchHashCheckBox.Text = "Match current game hash"; - this.MatchHashCheckBox.UseVisualStyleBackColor = true; - this.MatchHashCheckBox.CheckedChanged += new System.EventHandler(this.MatchHashCheckBox_CheckedChanged); - // - // contextMenuStrip1 - // - this.contextMenuStrip1.Items.AddRange(new System.Windows.Forms.ToolStripItem[] { - this.editToolStripMenuItem}); - this.contextMenuStrip1.Name = "contextMenuStrip1"; - this.contextMenuStrip1.Size = new System.Drawing.Size(93, 26); - // - // editToolStripMenuItem - // - this.editToolStripMenuItem.Image = global::BizHawk.Client.MultiHawk.Properties.Resources.CutHS; - this.editToolStripMenuItem.Name = "editToolStripMenuItem"; - this.editToolStripMenuItem.Size = new System.Drawing.Size(92, 22); - this.editToolStripMenuItem.Text = "&Edit"; - this.editToolStripMenuItem.Click += new System.EventHandler(this.EditMenuItem_Click); - // - // StopOnFrameCheckbox - // - this.StopOnFrameCheckbox.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left))); - this.StopOnFrameCheckbox.AutoSize = true; - this.StopOnFrameCheckbox.Location = new System.Drawing.Point(342, 357); - this.StopOnFrameCheckbox.Name = "StopOnFrameCheckbox"; - this.StopOnFrameCheckbox.Size = new System.Drawing.Size(95, 17); - this.StopOnFrameCheckbox.TabIndex = 57; - this.StopOnFrameCheckbox.Text = "Stop on frame:"; - this.StopOnFrameCheckbox.UseVisualStyleBackColor = true; - this.StopOnFrameCheckbox.CheckedChanged += new System.EventHandler(this.StopOnFrameCheckbox_CheckedChanged); - // - // StopOnFrameTextBox - // - this.StopOnFrameTextBox.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left))); - this.StopOnFrameTextBox.ByteSize = BizHawk.Client.Common.WatchSize.DWord; - this.StopOnFrameTextBox.CharacterCasing = System.Windows.Forms.CharacterCasing.Upper; - this.StopOnFrameTextBox.Location = new System.Drawing.Point(438, 355); - this.StopOnFrameTextBox.MaxLength = 10; - this.StopOnFrameTextBox.Name = "StopOnFrameTextBox"; - this.StopOnFrameTextBox.Nullable = true; - this.StopOnFrameTextBox.Size = new System.Drawing.Size(54, 20); - this.StopOnFrameTextBox.TabIndex = 58; - this.StopOnFrameTextBox.Type = BizHawk.Client.Common.DisplayType.Unsigned; - this.StopOnFrameTextBox.TextChanged += new System.EventHandler(this.StopOnFrameTextBox_TextChanged_1); - // - // MovieView - // - this.MovieView.AllowDrop = true; - this.MovieView.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left) - | System.Windows.Forms.AnchorStyles.Right))); - this.MovieView.BlazingFast = false; - this.MovieView.Columns.AddRange(new System.Windows.Forms.ColumnHeader[] { - this.columnHeader1, - this.columnHeader2, - this.columnHeader3, - this.columnHeader4}); - this.MovieView.ContextMenuStrip = this.contextMenuStrip1; - this.MovieView.FullRowSelect = true; - this.MovieView.GridLines = true; - this.MovieView.HideSelection = false; - this.MovieView.ItemCount = 0; - this.MovieView.Location = new System.Drawing.Point(12, 28); - this.MovieView.MultiSelect = false; - this.MovieView.Name = "MovieView"; - this.MovieView.SelectAllInProgress = false; - this.MovieView.selectedItem = -1; - this.MovieView.Size = new System.Drawing.Size(480, 322); - this.MovieView.TabIndex = 5; - this.MovieView.UseCompatibleStateImageBehavior = false; - this.MovieView.UseCustomBackground = true; - this.MovieView.View = System.Windows.Forms.View.Details; - this.MovieView.ColumnClick += new System.Windows.Forms.ColumnClickEventHandler(this.MovieView_ColumnClick); - this.MovieView.SelectedIndexChanged += new System.EventHandler(this.MovieView_SelectedIndexChanged); - this.MovieView.DragDrop += new System.Windows.Forms.DragEventHandler(this.MovieView_DragDrop); - this.MovieView.DragEnter += new System.Windows.Forms.DragEventHandler(this.MovieView_DragEnter); - this.MovieView.DoubleClick += new System.EventHandler(this.MovieView_DoubleClick); - this.MovieView.KeyDown += new System.Windows.Forms.KeyEventHandler(this.MovieView_KeyDown); - // - // columnHeader1 - // - this.columnHeader1.Text = "File"; - this.columnHeader1.Width = 221; - // - // columnHeader2 - // - this.columnHeader2.Text = "SysID"; - this.columnHeader2.Width = 43; - // - // columnHeader3 - // - this.columnHeader3.Text = "Game"; - this.columnHeader3.Width = 129; - // - // columnHeader4 - // - this.columnHeader4.Text = "Length (est.)"; - this.columnHeader4.Width = 82; - // - // LastFrameCheckbox - // - this.LastFrameCheckbox.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left))); - this.LastFrameCheckbox.AutoSize = true; - this.LastFrameCheckbox.Location = new System.Drawing.Point(342, 376); - this.LastFrameCheckbox.Name = "LastFrameCheckbox"; - this.LastFrameCheckbox.Size = new System.Drawing.Size(75, 17); - this.LastFrameCheckbox.TabIndex = 59; - this.LastFrameCheckbox.Text = "Last frame"; - this.LastFrameCheckbox.UseVisualStyleBackColor = true; - this.LastFrameCheckbox.CheckedChanged += new System.EventHandler(this.LastFrameCheckbox_CheckedChanged); - // - // TurboCheckbox - // - this.TurboCheckbox.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left))); - this.TurboCheckbox.AutoSize = true; - this.TurboCheckbox.Location = new System.Drawing.Point(438, 376); - this.TurboCheckbox.Name = "TurboCheckbox"; - this.TurboCheckbox.Size = new System.Drawing.Size(54, 17); - this.TurboCheckbox.TabIndex = 60; - this.TurboCheckbox.Text = "Turbo"; - this.TurboCheckbox.UseVisualStyleBackColor = true; - // - // PlayMovie - // - this.AcceptButton = this.OK; - this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); - this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; - this.CancelButton = this.Cancel; - this.ClientSize = new System.Drawing.Size(774, 398); - this.Controls.Add(this.TurboCheckbox); - this.Controls.Add(this.LastFrameCheckbox); - this.Controls.Add(this.StopOnFrameTextBox); - this.Controls.Add(this.StopOnFrameCheckbox); - this.Controls.Add(this.MatchHashCheckBox); - this.Controls.Add(this.Scan); - this.Controls.Add(this.IncludeSubDirectories); - this.Controls.Add(this.ReadOnlyCheckBox); - this.Controls.Add(this.MovieCount); - this.Controls.Add(this.groupBox1); - this.Controls.Add(this.MovieView); - this.Controls.Add(this.BrowseMovies); - this.Controls.Add(this.OK); - this.Controls.Add(this.Cancel); - this.Icon = ((System.Drawing.Icon)(resources.GetObject("$this.Icon"))); - this.MaximizeBox = false; - this.MinimizeBox = false; - this.MinimumSize = new System.Drawing.Size(547, 228); - this.Name = "PlayMovie"; - this.StartPosition = System.Windows.Forms.FormStartPosition.CenterParent; - this.Text = "Play Movie"; - this.Load += new System.EventHandler(this.PlayMovie_Load); - this.groupBox1.ResumeLayout(false); - this.contextMenuStrip1.ResumeLayout(false); - this.ResumeLayout(false); - this.PerformLayout(); - - } - - #endregion - - private System.Windows.Forms.Button Cancel; - private System.Windows.Forms.Button OK; - private System.Windows.Forms.Button BrowseMovies; - private BizHawk.Client.EmuHawk.VirtualListView MovieView; - private System.Windows.Forms.ColumnHeader columnHeader1; - private System.Windows.Forms.ColumnHeader columnHeader2; - private System.Windows.Forms.ColumnHeader columnHeader3; - private System.Windows.Forms.ColumnHeader columnHeader4; - private System.Windows.Forms.ListView DetailsView; - private System.Windows.Forms.ColumnHeader columnHeader5; - private System.Windows.Forms.ColumnHeader columnHeader6; - private System.Windows.Forms.GroupBox groupBox1; - private System.Windows.Forms.Button SubtitlesBtn; - private System.Windows.Forms.Button CommentsBtn; - private System.Windows.Forms.Label MovieCount; - private System.Windows.Forms.CheckBox ReadOnlyCheckBox; - private System.Windows.Forms.CheckBox IncludeSubDirectories; - private System.Windows.Forms.Button Scan; - private System.Windows.Forms.ToolTip toolTip1; - private System.Windows.Forms.CheckBox MatchHashCheckBox; - private System.Windows.Forms.ContextMenuStrip contextMenuStrip1; - private System.Windows.Forms.ToolStripMenuItem editToolStripMenuItem; - private System.Windows.Forms.CheckBox StopOnFrameCheckbox; - private BizHawk.Client.EmuHawk.WatchValueBox StopOnFrameTextBox; - private System.Windows.Forms.CheckBox LastFrameCheckbox; - private System.Windows.Forms.CheckBox TurboCheckbox; - } -} \ No newline at end of file diff --git a/BizHawk.Client.MultiHawk/movie/PlayMovie.cs b/BizHawk.Client.MultiHawk/movie/PlayMovie.cs deleted file mode 100644 index 279ce50ee4..0000000000 --- a/BizHawk.Client.MultiHawk/movie/PlayMovie.cs +++ /dev/null @@ -1,673 +0,0 @@ -using System; -using System.Threading.Tasks; -using System.Collections.Generic; -using System.Drawing; -using System.IO; -using System.Linq; -using System.Text; -using System.Windows.Forms; - -using BizHawk.Client.Common; -using BizHawk.Common; -using BizHawk.Client.EmuHawk; -namespace BizHawk.Client.MultiHawk -{ - public partial class PlayMovie : Form - { - private readonly PlatformFrameRates PlatformFrameRates = new PlatformFrameRates(); - - private List _movieList = new List(); - private bool _sortReverse; - private string _sortedCol; - - private bool _sortDetailsReverse; - private string _sortedDetailsCol; - - public PlayMovie() - { - InitializeComponent(); - MovieView.QueryItemText += MovieView_QueryItemText; - MovieView.VirtualMode = true; - _sortReverse = false; - _sortedCol = ""; - - _sortDetailsReverse = false; - _sortedDetailsCol = ""; - } - - private void PlayMovie_Load(object sender, EventArgs e) - { - IncludeSubDirectories.Checked = Global.Config.PlayMovie_IncludeSubdir; - MatchHashCheckBox.Checked = Global.Config.PlayMovie_MatchHash; - ScanFiles(); - PreHighlightMovie(); - TurboCheckbox.Checked = Global.Config.TurboSeek; - } - - private void MovieView_QueryItemText(int index, int column, out string text) - { - text = ""; - if (column == 0) // File - { - text = Path.GetFileName(_movieList[index].Filename); - } - - if (column == 1) // System - { - text = _movieList[index].SystemID; - } - - if (column == 2) // Game - { - text = _movieList[index].GameName; - } - - if (column == 3) // Time - { - text = PlatformFrameRates.MovieTime(_movieList[index]).ToString(@"hh\:mm\:ss\.fff"); - } - } - - private void Run() - { - var indices = MovieView.SelectedIndices; - if (indices.Count > 0) // Import file if necessary - { - GlobalWin.MainForm.StartNewMovie(_movieList[MovieView.SelectedIndices[0]], false); - } - } - - private int? AddMovieToList(string filename, bool force) - { - using (var file = new HawkFile(filename)) - { - if (!file.Exists) - { - return null; - } - - var index = IsDuplicateOf(filename); - if (!index.HasValue) - { - //System.Diagnostics.Stopwatch watch = new System.Diagnostics.Stopwatch(); watch.Start(); - var movie = PreLoadMovieFile(file, force); - if (movie == null) - { - return null; - } - //watch.Stop(); Console.WriteLine("[{0}] {1}",watch.ElapsedMilliseconds,Path.GetFileName(filename)); - - lock (_movieList) - { - _movieList.Add(movie); - index = _movieList.Count - 1; - } - - _sortReverse = false; - _sortedCol = ""; - } - - return index; - } - - } - - private int? IsDuplicateOf(string filename) - { - for (var i = 0; i < _movieList.Count; i++) - { - if (_movieList[i].Filename == filename) - { - return i; - } - } - - return null; - } - - private IMovie PreLoadMovieFile(HawkFile hf, bool force) - { - var movie = MovieService.Get(hf.CanonicalFullPath); - - try - { - movie.PreLoadHeaderAndLength(hf); - - // Don't do this from browse - if (movie.Hash == Global.Game.Hash || - Global.Config.PlayMovie_MatchHash == false || force) - { - return movie; - } - } - catch (Exception ex) - { - // TODO: inform the user that a movie failed to parse in some way - Console.WriteLine(ex.Message); - } - - return null; - } - - private void UpdateList() - { - MovieView.Refresh(); - MovieCount.Text = _movieList.Count + " movie" - + (_movieList.Count != 1 ? "s" : ""); - } - - private void PreHighlightMovie() - { - if (Global.Game == null) - { - return; - } - - var indices = new List(); - - // Pull out matching names - for (var i = 0; i < _movieList.Count; i++) - { - if (PathManager.FilesystemSafeName(Global.Game) == _movieList[i].GameName) - { - indices.Add(i); - } - } - - if (indices.Count == 0) - { - return; - } - - if (indices.Count == 1) - { - HighlightMovie(indices[0]); - return; - } - - // Prefer tas files - var tas = new List(); - for (var i = 0; i < indices.Count; i++) - { - foreach (var ext in MovieService.MovieExtensions) - { - if (Path.GetExtension(_movieList[indices[i]].Filename).ToUpper() == "." + ext) - { - tas.Add(i); - } - } - } - - if (tas.Count == 1) - { - HighlightMovie(tas[0]); - return; - } - - if (tas.Count > 1) - { - indices = new List(tas); - } - - // Final tie breaker - Last used file - var file = new FileInfo(_movieList[indices[0]].Filename); - var time = file.LastAccessTime; - var mostRecent = indices.First(); - for (var i = 1; i < indices.Count; i++) - { - file = new FileInfo(_movieList[indices[0]].Filename); - if (file.LastAccessTime > time) - { - time = file.LastAccessTime; - mostRecent = indices[i]; - } - } - - HighlightMovie(mostRecent); - return; - } - - private void HighlightMovie(int index) - { - MovieView.SelectedIndices.Clear(); - MovieView.setSelection(index); - MovieView.SelectItem(index, true); - } - - private void ScanFiles() - { - _movieList.Clear(); - MovieView.ItemCount = 0; - MovieView.Update(); - - var directory = PathManager.MakeAbsolutePath(Global.Config.PathEntries.MoviesPathFragment, null); - if (!Directory.Exists(directory)) - { - Directory.CreateDirectory(directory); - } - - var dpTodo = new Queue(); - var fpTodo = new List(); - dpTodo.Enqueue(directory); - Dictionary ordinals = new Dictionary(); - - while (dpTodo.Count > 0) - { - string dp = dpTodo.Dequeue(); - - //enqueue subdirectories if appropriate - if (Global.Config.PlayMovie_IncludeSubdir) - foreach(var subdir in Directory.GetDirectories(dp)) - dpTodo.Enqueue(subdir); - - //add movies - fpTodo.AddRange(Directory.GetFiles(dp, "*." + MovieService.DefaultExtension)); - fpTodo.AddRange(Directory.GetFiles(dp, "*." + TasMovie.Extension)); - } - - //in parallel, scan each movie - Parallel.For(0, fpTodo.Count, (i) => - //for(int i=0;i ordinals[a.Filename].CompareTo(ordinals[b.Filename])); - - RefreshMovieList(); - } - - #region Events - - #region Movie List - - void RefreshMovieList() - { - MovieView.ItemCount = _movieList.Count; - UpdateList(); - } - - private void MovieView_DragEnter(object sender, DragEventArgs e) - { - e.Effect = e.Data.GetDataPresent(DataFormats.FileDrop) ? DragDropEffects.Copy : DragDropEffects.None; - } - - private void MovieView_DragDrop(object sender, DragEventArgs e) - { - var filePaths = (string[])e.Data.GetData(DataFormats.FileDrop); - - foreach (var path in filePaths.Where(path => MovieService.MovieExtensions.Contains(Path.GetExtension(path).Replace(".", "")))) - { - AddMovieToList(path, force: true); - } - - RefreshMovieList(); - } - - private void MovieView_KeyDown(object sender, KeyEventArgs e) - { - if (e.Control && e.KeyCode == Keys.C) - { - var indexes = MovieView.SelectedIndices; - if (indexes.Count > 0) - { - var copyStr = new StringBuilder(); - foreach (int index in indexes) - { - copyStr - .Append(_movieList[index].Filename).Append('\t') - .Append(_movieList[index].SystemID).Append('\t') - .Append(_movieList[index].GameName).Append('\t') - .Append(PlatformFrameRates.MovieTime(_movieList[index]).ToString(@"hh\:mm\:ss\.fff")) - .AppendLine(); - } - Clipboard.SetDataObject(copyStr.ToString()); - } - } - } - - private void MovieView_DoubleClick(object sender, EventArgs e) - { - Run(); - Close(); - } - - private void MovieView_ColumnClick(object sender, ColumnClickEventArgs e) - { - var columnName = MovieView.Columns[e.Column].Text; - switch (columnName) - { - case "File": - default: - _movieList = _movieList.OrderBy(x => Path.GetFileName(x.Filename)) - .ThenBy(x => x.SystemID) - .ThenBy(x => x.GameName) - .ThenBy(x => x.FrameCount) - .ToList(); - break; - case "SysID": - _movieList = _movieList.OrderBy(x => x.SystemID) - .ThenBy(x => Path.GetFileName(x.Filename)) - .ThenBy(x => x.GameName) - .ThenBy(x => x.FrameCount) - .ToList(); - break; - case "Game": - _movieList = _movieList.OrderBy(x => x.GameName) - .ThenBy(x => Path.GetFileName(x.Filename)) - .ThenBy(x => x.SystemID) - .ThenBy(x => x.FrameCount) - .ToList(); - break; - case "Length (est.)": - _movieList = _movieList.OrderBy(x => x.FrameCount) - .ThenBy(x => Path.GetFileName(x.Filename)) - .ThenBy(x => x.SystemID) - .ThenBy(x => x.GameName) - .ToList(); - break; - } - if (_sortedCol == columnName && _sortReverse) - { - _movieList.Reverse(); - _sortReverse = false; - } - else - { - _sortReverse = true; - _sortedCol = columnName; - } - MovieView.Refresh(); - } - - private void MovieView_SelectedIndexChanged(object sender, EventArgs e) - { - toolTip1.SetToolTip(DetailsView, ""); - DetailsView.Items.Clear(); - if (MovieView.SelectedIndices.Count < 1) - { - OK.Enabled = false; - return; - } - - OK.Enabled = true; - - var firstIndex = MovieView.SelectedIndices[0]; - MovieView.ensureVisible(firstIndex); - - foreach (var kvp in _movieList[firstIndex].HeaderEntries) - { - var item = new ListViewItem(kvp.Key); - item.SubItems.Add(kvp.Value); - - bool add = true; - - switch (kvp.Key) - { - case HeaderKeys.SHA1: - if (kvp.Value != Global.Game.Hash) - { - item.BackColor = Color.Pink; - toolTip1.SetToolTip(DetailsView, "Current SHA1: " + Global.Game.Hash); - } - break; - // TODO - //case HeaderKeys.EMULATIONVERSION: - // if (kvp.Value != VersionInfo.GetEmuVersion()) - // { - // item.BackColor = Color.Yellow; - // } - // break; - case HeaderKeys.PLATFORM: - if (kvp.Value != Global.Game.System) - { - item.BackColor = Color.Pink; - } - break; - } - - if(add) - DetailsView.Items.Add(item); - } - - var FpsItem = new ListViewItem("Fps"); - FpsItem.SubItems.Add($"{Fps(_movieList[firstIndex]):0.#######}"); - DetailsView.Items.Add(FpsItem); - - var FramesItem = new ListViewItem("Frames"); - FramesItem.SubItems.Add(_movieList[firstIndex].FrameCount.ToString()); - DetailsView.Items.Add(FramesItem); - CommentsBtn.Enabled = _movieList[firstIndex].Comments.Any(); - SubtitlesBtn.Enabled = _movieList[firstIndex].Subtitles.Any(); - } - - public double Fps(IMovie movie) - { - var system = movie.HeaderEntries[HeaderKeys.PLATFORM]; - var pal = movie.HeaderEntries.ContainsKey(HeaderKeys.PAL) && - movie.HeaderEntries[HeaderKeys.PAL] == "1"; - - return new PlatformFrameRates()[system, pal]; - - } - - private void EditMenuItem_Click(object sender, EventArgs e) - { - foreach (var movie in MovieView.SelectedIndices.Cast() - .Select(index => _movieList[index])) - { - System.Diagnostics.Process.Start(movie.Filename); - } - } - - #endregion - - #region Details - - private void DetailsView_ColumnClick(object sender, ColumnClickEventArgs e) - { - var detailsList = new List(); - for (var i = 0; i < DetailsView.Items.Count; i++) - { - detailsList.Add(new MovieDetails - { - Keys = DetailsView.Items[i].Text, - Values = DetailsView.Items[i].SubItems[1].Text, - BackgroundColor = DetailsView.Items[i].BackColor - }); - } - - var columnName = DetailsView.Columns[e.Column].Text; - if (_sortedDetailsCol != columnName) - { - _sortDetailsReverse = false; - } - - switch (columnName) - { - // Header, Value - case "Header": - if (_sortDetailsReverse) - { - detailsList = detailsList - .OrderByDescending(x => x.Keys) - .ThenBy(x => x.Values).ToList(); - } - else - { - detailsList = detailsList - .OrderBy(x => x.Keys) - .ThenBy(x => x.Values).ToList(); - } - - break; - case "Value": - if (_sortDetailsReverse) - { - detailsList = detailsList - .OrderByDescending(x => x.Values) - .ThenBy(x => x.Keys).ToList(); - } - else - { - detailsList = detailsList - .OrderBy(x => x.Values) - .ThenBy(x => x.Keys).ToList(); - } - - break; - } - - DetailsView.Items.Clear(); - foreach (var detail in detailsList) - { - var item = new ListViewItem { Text = detail.Keys, BackColor = detail.BackgroundColor }; - item.SubItems.Add(detail.Values); - DetailsView.Items.Add(item); - } - - _sortedDetailsCol = columnName; - _sortDetailsReverse = !_sortDetailsReverse; - } - - private void CommentsBtn_Click(object sender, EventArgs e) - { - var indices = MovieView.SelectedIndices; - if (indices.Count > 0) - { - var form = new EditCommentsForm(); - form.GetMovie(_movieList[MovieView.SelectedIndices[0]]); - form.Show(); - } - } - - private void SubtitlesBtn_Click(object sender, EventArgs e) - { - var indices = MovieView.SelectedIndices; - if (indices.Count > 0) - { - var s = new EditSubtitlesForm { ReadOnly = true }; - s.GetMovie(_movieList[MovieView.SelectedIndices[0]]); - s.Show(); - } - } - - #endregion - - #region Misc Widgets - - private void BrowseMovies_Click(object sender, EventArgs e) - { - var ofd = new OpenFileDialog - { - Filter = "Movie Files (*." + MovieService.DefaultExtension + ")|*." + MovieService.DefaultExtension + - "|TAS project Files (*." + TasMovie.Extension + ")|*." + TasMovie.Extension + - "|All Files|*.*", - InitialDirectory = PathManager.MakeAbsolutePath(Global.Config.PathEntries.MoviesPathFragment, null) - }; - - var result = ofd.ShowDialog(); - if (result == DialogResult.OK) - { - var file = new FileInfo(ofd.FileName); - if (!file.Exists) - { - return; - } - - int? index = AddMovieToList(ofd.FileName, true); - RefreshMovieList(); - if (index.HasValue) - { - MovieView.SelectedIndices.Clear(); - MovieView.setSelection(index.Value); - MovieView.SelectItem(index.Value, true); - } - } - } - - private void Scan_Click(object sender, EventArgs e) - { - ScanFiles(); - PreHighlightMovie(); - } - - private void IncludeSubDirectories_CheckedChanged(object sender, EventArgs e) - { - Global.Config.PlayMovie_IncludeSubdir = IncludeSubDirectories.Checked; - ScanFiles(); - PreHighlightMovie(); - } - - private void MatchHashCheckBox_CheckedChanged(object sender, EventArgs e) - { - Global.Config.PlayMovie_MatchHash = MatchHashCheckBox.Checked; - ScanFiles(); - PreHighlightMovie(); - } - - private void Ok_Click(object sender, EventArgs e) - { - Global.Config.TurboSeek = TurboCheckbox.Checked; - Run(); - Global.MovieSession.ReadOnly = ReadOnlyCheckBox.Checked; - - if (StopOnFrameCheckbox.Checked && - (StopOnFrameTextBox.ToRawInt().HasValue || LastFrameCheckbox.Checked)) - { - if (LastFrameCheckbox.Checked) - { - // TODO - //GlobalWin.MainForm.PauseOnFrame = Global.MovieSession.Movie.InputLogLength; - } - else - { - //GlobalWin.MainForm.PauseOnFrame = StopOnFrameTextBox.ToRawInt(); - } - } - - Close(); - } - - private void Cancel_Click(object sender, EventArgs e) - { - Close(); - } - - #endregion - - private bool _programmaticallyChangingStopFrameCheckbox = false; - private void StopOnFrameCheckbox_CheckedChanged(object sender, EventArgs e) - { - if (!_programmaticallyChangingStopFrameCheckbox) - { - StopOnFrameTextBox.Focus(); - } - } - - private void StopOnFrameTextBox_TextChanged_1(object sender, EventArgs e) - { - _programmaticallyChangingStopFrameCheckbox = true; - StopOnFrameCheckbox.Checked = !string.IsNullOrWhiteSpace(StopOnFrameTextBox.Text); - _programmaticallyChangingStopFrameCheckbox = false; - } - - private void LastFrameCheckbox_CheckedChanged(object sender, EventArgs e) - { - if (LastFrameCheckbox.Checked == true) - { - _programmaticallyChangingStopFrameCheckbox = true; - StopOnFrameCheckbox.Checked = true; - _programmaticallyChangingStopFrameCheckbox = false; - } - - StopOnFrameTextBox.Enabled = !LastFrameCheckbox.Checked; - } - - #endregion - } -} diff --git a/BizHawk.Client.MultiHawk/movie/PlayMovie.resx b/BizHawk.Client.MultiHawk/movie/PlayMovie.resx deleted file mode 100644 index b726d762b7..0000000000 --- a/BizHawk.Client.MultiHawk/movie/PlayMovie.resx +++ /dev/null @@ -1,155 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - text/microsoft-resx - - - 2.0 - - - System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - - System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - - 17, 17 - - - 114, 17 - - - - - AAABAAEAEBAAAAAAAABoBQAAFgAAACgAAAAQAAAAIAAAAAEACAAAAAAAQAEAAAAAAAAAAAAAAAAAAAAA - AAAAAAAA////AP64aABQUFAAwNjwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AAAAAAAAAAMDAAMDAwAAAAAAAAAAAAMCAgMDAwMDAwAAAAMDAAADAgICAwMDAwMDAwMCAgMAAAMCAwMD - AwMDAwMDAgIDAAMEBAQDAgMDAwMDAwICAgMDBAQEAwICAwQDAwQDAgIDAAMDAwICAgMCAgIDAwMDAAAA - AwICAgMCAgIDAgMAAAAAAAAAAwMEBAQEBAQCAwAAAAAAAwMEBAQDAwMDAwMAAAAAAwQEAwMEBAMEBAQC - AwAAAAMEBAMDBAMEBAQEAgMAAAAAAwMDBAQDBAMDAwIDAAAAAAMCAgICAgICAgMEBAMAAAAAAwICAgIC - AwMEBAQDAAAAAAADAwMDAwAAAwMDAJH/AAAAcwAAAAEAAIABAAAAAAAAAAAAAIABAADABwAA8AMAAOAD - AADAAQAAwAEAAOABAADgAAAA8AAAAPgxAAA= - - - \ No newline at end of file diff --git a/BizHawk.Client.MultiHawk/movie/RecordMovie.Designer.cs b/BizHawk.Client.MultiHawk/movie/RecordMovie.Designer.cs deleted file mode 100644 index 252508deab..0000000000 --- a/BizHawk.Client.MultiHawk/movie/RecordMovie.Designer.cs +++ /dev/null @@ -1,210 +0,0 @@ -namespace BizHawk.Client.MultiHawk -{ - partial class RecordMovie - { - /// - /// Required designer variable. - /// - private System.ComponentModel.IContainer components = null; - - /// - /// Clean up any resources being used. - /// - /// true if managed resources should be disposed; otherwise, false. - protected override void Dispose(bool disposing) - { - if (disposing && (components != null)) - { - components.Dispose(); - } - base.Dispose(disposing); - } - - #region Windows Form Designer generated code - - /// - /// Required method for Designer support - do not modify - /// the contents of this method with the code editor. - /// - private void InitializeComponent() - { - System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(RecordMovie)); - this.Cancel = new System.Windows.Forms.Button(); - this.OK = new System.Windows.Forms.Button(); - this.BrowseBtn = new System.Windows.Forms.Button(); - this.RecordBox = new System.Windows.Forms.TextBox(); - this.StartFromCombo = new System.Windows.Forms.ComboBox(); - this.groupBox1 = new System.Windows.Forms.GroupBox(); - this.DefaultAuthorCheckBox = new System.Windows.Forms.CheckBox(); - this.AuthorBox = new System.Windows.Forms.TextBox(); - this.label3 = new System.Windows.Forms.Label(); - this.label2 = new System.Windows.Forms.Label(); - this.label1 = new System.Windows.Forms.Label(); - this.groupBox1.SuspendLayout(); - this.SuspendLayout(); - // - // Cancel - // - this.Cancel.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right))); - this.Cancel.DialogResult = System.Windows.Forms.DialogResult.Cancel; - this.Cancel.Location = new System.Drawing.Point(391, 139); - this.Cancel.Name = "Cancel"; - this.Cancel.Size = new System.Drawing.Size(75, 23); - this.Cancel.TabIndex = 1; - this.Cancel.Text = "&Cancel"; - this.Cancel.UseVisualStyleBackColor = true; - this.Cancel.Click += new System.EventHandler(this.Cancel_Click); - // - // OK - // - this.OK.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right))); - this.OK.Location = new System.Drawing.Point(310, 139); - this.OK.Name = "OK"; - this.OK.Size = new System.Drawing.Size(75, 23); - this.OK.TabIndex = 0; - this.OK.Text = "&OK"; - this.OK.UseVisualStyleBackColor = true; - this.OK.Click += new System.EventHandler(this.Ok_Click); - // - // BrowseBtn - // - this.BrowseBtn.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right))); - this.BrowseBtn.Image = global::BizHawk.Client.MultiHawk.Properties.Resources.OpenFile; - this.BrowseBtn.Location = new System.Drawing.Point(423, 13); - this.BrowseBtn.Name = "BrowseBtn"; - this.BrowseBtn.Size = new System.Drawing.Size(25, 23); - this.BrowseBtn.TabIndex = 1; - this.BrowseBtn.UseVisualStyleBackColor = true; - this.BrowseBtn.Click += new System.EventHandler(this.BrowseBtn_Click); - // - // RecordBox - // - this.RecordBox.AllowDrop = true; - this.RecordBox.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left) - | System.Windows.Forms.AnchorStyles.Right))); - this.RecordBox.Location = new System.Drawing.Point(83, 13); - this.RecordBox.Name = "RecordBox"; - this.RecordBox.Size = new System.Drawing.Size(334, 20); - this.RecordBox.TabIndex = 0; - this.RecordBox.DragDrop += new System.Windows.Forms.DragEventHandler(this.RecordBox_DragDrop); - this.RecordBox.DragEnter += new System.Windows.Forms.DragEventHandler(this.RecordBox_DragEnter); - // - // StartFromCombo - // - this.StartFromCombo.DropDownStyle = System.Windows.Forms.ComboBoxStyle.DropDownList; - this.StartFromCombo.Enabled = false; - this.StartFromCombo.FormattingEnabled = true; - this.StartFromCombo.Items.AddRange(new object[] { - "Power-On"}); - this.StartFromCombo.Location = new System.Drawing.Point(83, 65); - this.StartFromCombo.MaxDropDownItems = 32; - this.StartFromCombo.Name = "StartFromCombo"; - this.StartFromCombo.Size = new System.Drawing.Size(152, 21); - this.StartFromCombo.TabIndex = 3; - // - // groupBox1 - // - this.groupBox1.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left) - | System.Windows.Forms.AnchorStyles.Right))); - this.groupBox1.Controls.Add(this.DefaultAuthorCheckBox); - this.groupBox1.Controls.Add(this.AuthorBox); - this.groupBox1.Controls.Add(this.StartFromCombo); - this.groupBox1.Controls.Add(this.BrowseBtn); - this.groupBox1.Controls.Add(this.label3); - this.groupBox1.Controls.Add(this.label2); - this.groupBox1.Controls.Add(this.label1); - this.groupBox1.Controls.Add(this.RecordBox); - this.groupBox1.Location = new System.Drawing.Point(12, 12); - this.groupBox1.Name = "groupBox1"; - this.groupBox1.Size = new System.Drawing.Size(454, 112); - this.groupBox1.TabIndex = 0; - this.groupBox1.TabStop = false; - // - // DefaultAuthorCheckBox - // - this.DefaultAuthorCheckBox.Anchor = System.Windows.Forms.AnchorStyles.Right; - this.DefaultAuthorCheckBox.AutoSize = true; - this.DefaultAuthorCheckBox.Location = new System.Drawing.Point(327, 64); - this.DefaultAuthorCheckBox.Name = "DefaultAuthorCheckBox"; - this.DefaultAuthorCheckBox.Size = new System.Drawing.Size(121, 17); - this.DefaultAuthorCheckBox.TabIndex = 6; - this.DefaultAuthorCheckBox.Text = "Make default author"; - this.DefaultAuthorCheckBox.UseVisualStyleBackColor = true; - // - // AuthorBox - // - this.AuthorBox.AllowDrop = true; - this.AuthorBox.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left) - | System.Windows.Forms.AnchorStyles.Right))); - this.AuthorBox.Location = new System.Drawing.Point(83, 39); - this.AuthorBox.Name = "AuthorBox"; - this.AuthorBox.Size = new System.Drawing.Size(365, 20); - this.AuthorBox.TabIndex = 2; - // - // label3 - // - this.label3.AutoSize = true; - this.label3.Location = new System.Drawing.Point(36, 41); - this.label3.Name = "label3"; - this.label3.Size = new System.Drawing.Size(41, 13); - this.label3.TabIndex = 2; - this.label3.Text = "Author:"; - // - // label2 - // - this.label2.AutoSize = true; - this.label2.Location = new System.Drawing.Point(6, 68); - this.label2.Name = "label2"; - this.label2.Size = new System.Drawing.Size(71, 13); - this.label2.TabIndex = 5; - this.label2.Text = "Record From:"; - // - // label1 - // - this.label1.AutoSize = true; - this.label1.Location = new System.Drawing.Point(51, 16); - this.label1.Name = "label1"; - this.label1.Size = new System.Drawing.Size(26, 13); - this.label1.TabIndex = 4; - this.label1.Text = "File:"; - // - // RecordMovie - // - this.AcceptButton = this.OK; - this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); - this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; - this.CancelButton = this.Cancel; - this.ClientSize = new System.Drawing.Size(478, 163); - this.Controls.Add(this.groupBox1); - this.Controls.Add(this.OK); - this.Controls.Add(this.Cancel); - this.Icon = ((System.Drawing.Icon)(resources.GetObject("$this.Icon"))); - this.MaximizeBox = false; - this.MaximumSize = new System.Drawing.Size(1440, 201); - this.MinimizeBox = false; - this.MinimumSize = new System.Drawing.Size(425, 201); - this.Name = "RecordMovie"; - this.StartPosition = System.Windows.Forms.FormStartPosition.CenterParent; - this.Text = "Record Movie"; - this.Load += new System.EventHandler(this.RecordMovie_Load); - this.groupBox1.ResumeLayout(false); - this.groupBox1.PerformLayout(); - this.ResumeLayout(false); - - } - - #endregion - - private System.Windows.Forms.Button Cancel; - private System.Windows.Forms.Button OK; - private System.Windows.Forms.Button BrowseBtn; - private System.Windows.Forms.TextBox RecordBox; - private System.Windows.Forms.ComboBox StartFromCombo; - private System.Windows.Forms.GroupBox groupBox1; - private System.Windows.Forms.Label label3; - private System.Windows.Forms.Label label2; - private System.Windows.Forms.Label label1; - private System.Windows.Forms.TextBox AuthorBox; - private System.Windows.Forms.CheckBox DefaultAuthorCheckBox; - } -} \ No newline at end of file diff --git a/BizHawk.Client.MultiHawk/movie/RecordMovie.cs b/BizHawk.Client.MultiHawk/movie/RecordMovie.cs deleted file mode 100644 index 4c5cdb4e66..0000000000 --- a/BizHawk.Client.MultiHawk/movie/RecordMovie.cs +++ /dev/null @@ -1,179 +0,0 @@ -using System; -using System.IO; -using System.Windows.Forms; -using System.Linq; - -using BizHawk.Common.ReflectionExtensions; -using BizHawk.Emulation.Common; -using BizHawk.Emulation.Common.IEmulatorExtensions; -using BizHawk.Client.Common; -using BizHawk.Client.Common.MovieConversionExtensions; - -namespace BizHawk.Client.MultiHawk -{ - public partial class RecordMovie : Form - { - private IEmulator Emulator; - - // TODO - Allow relative paths in record textbox - public RecordMovie(IEmulator core) - { - InitializeComponent(); - - Emulator = core; - - if (!Emulator.HasSavestates()) - { - StartFromCombo.Items.Remove( - StartFromCombo.Items - .OfType() - .First(i => i.ToString() - .ToLower() == "now")); - } - } - - private string MakePath() - { - var path = RecordBox.Text; - - if (!string.IsNullOrWhiteSpace(path)) - { - if (path.LastIndexOf(Path.DirectorySeparatorChar) == -1) - { - if (path[0] != Path.DirectorySeparatorChar) - { - path = path.Insert(0, Path.DirectorySeparatorChar.ToString()); - } - - path = PathManager.MakeAbsolutePath(Global.Config.PathEntries.MoviesPathFragment, null) + path; - - if (!MovieService.MovieExtensions.Contains(Path.GetExtension(path))) - { - // If no valid movie extension, add movie extension - path += "." + MovieService.DefaultExtension; - } - } - } - - return path; - } - - private void Ok_Click(object sender, EventArgs e) - { - var path = MakePath(); - if (!string.IsNullOrWhiteSpace(path)) - { - var test = new FileInfo(path); - if (test.Exists) - { - var result = MessageBox.Show(path + " already exists, overwrite?", "Confirm overwrite", MessageBoxButtons.OKCancel, MessageBoxIcon.Warning); - if (result == DialogResult.Cancel) - { - return; - } - } - - var movieToRecord = MovieService.Get(path); - - var fileInfo = new FileInfo(path); - if (!fileInfo.Exists) - { - Directory.CreateDirectory(fileInfo.DirectoryName); - } - - //if (StartFromCombo.SelectedItem.ToString() == "Now" && Emulator.HasSavestates()) - //{ - // var core = Emulator.AsStatable(); - - // movieToRecord.StartsFromSavestate = true; - - // if (core.BinarySaveStatesPreferred) - // { - // movieToRecord.BinarySavestate = (byte[])core.SaveStateBinary().Clone(); - // } - // else - // { - // using (var sw = new StringWriter()) - // { - // core.SaveStateText(sw); - // movieToRecord.TextSavestate = sw.ToString(); - // } - // } - // // TODO: do we want to support optionally not saving this? - // if (true) - // { - // // hack: some IMovies eat the framebuffer, so don't bother with them - // movieToRecord.SavestateFramebuffer = new int[0]; - // if (movieToRecord.SavestateFramebuffer != null) - // { - - // movieToRecord.SavestateFramebuffer = (int[])Emulator.VideoProvider().GetVideoBuffer().Clone(); - // } - // } - //} - - movieToRecord.PopulateWithDefaultHeaderValues(AuthorBox.Text); - movieToRecord.Save(); - GlobalWin.MainForm.StartNewMovie(movieToRecord, true); - - Global.Config.UseDefaultAuthor = DefaultAuthorCheckBox.Checked; - if (DefaultAuthorCheckBox.Checked) - { - Global.Config.DefaultAuthor = AuthorBox.Text; - } - - Close(); - } - else - { - MessageBox.Show("Please select a movie to record", "File selection error", MessageBoxButtons.OK, MessageBoxIcon.Error); - } - } - - private void Cancel_Click(object sender, EventArgs e) - { - Close(); - } - - private void BrowseBtn_Click(object sender, EventArgs e) - { - var sfd = new SaveFileDialog - { - InitialDirectory = PathManager.MakeAbsolutePath(Global.Config.PathEntries.MoviesPathFragment, null), - DefaultExt = "." + Global.MovieSession.Movie.PreferredExtension, - FileName = RecordBox.Text, - OverwritePrompt = false, - Filter = "Movie Files (*." + Global.MovieSession.Movie.PreferredExtension + ")|*." + Global.MovieSession.Movie.PreferredExtension + "|All Files|*.*" - }; - - var result = sfd.ShowDialog(); - if (result == DialogResult.OK - && !string.IsNullOrWhiteSpace(sfd.FileName)) - { - RecordBox.Text = sfd.FileName; - } - } - - private void RecordMovie_Load(object sender, EventArgs e) - { - RecordBox.Text = PathManager.FilesystemSafeName(GlobalWin.MainForm.EmulatorWindows.First().Game); - StartFromCombo.SelectedIndex = 0; - DefaultAuthorCheckBox.Checked = Global.Config.UseDefaultAuthor; - if (Global.Config.UseDefaultAuthor) - { - AuthorBox.Text = Global.Config.DefaultAuthor; - } - } - - private void RecordBox_DragEnter(object sender, DragEventArgs e) - { - e.Effect = e.Data.GetDataPresent(DataFormats.FileDrop) ? DragDropEffects.Copy : DragDropEffects.None; - } - - private void RecordBox_DragDrop(object sender, DragEventArgs e) - { - var filePaths = (string[])e.Data.GetData(DataFormats.FileDrop); - RecordBox.Text = filePaths[0]; - } - } -} diff --git a/BizHawk.Client.MultiHawk/movie/RecordMovie.resx b/BizHawk.Client.MultiHawk/movie/RecordMovie.resx deleted file mode 100644 index fb80888459..0000000000 --- a/BizHawk.Client.MultiHawk/movie/RecordMovie.resx +++ /dev/null @@ -1,149 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - text/microsoft-resx - - - 2.0 - - - System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - - System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - - - - AAABAAEAEBAAAAAAAABoBQAAFgAAACgAAAAQAAAAIAAAAAEACAAAAAAAQAEAAAAAAAAAAAAAAAAAAAAA - AAAAAAAA////AP64aABQUFAAwNjwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AAAAAAAAAAMDAAMDAwAAAAAAAAAAAAMCAgMDAwMDAwAAAAMDAAADAgICAwMDAwMDAwMCAgMAAAMCAwMD - AwMDAwMDAgIDAAMEBAQDAgMDAwMDAwICAgMDBAQEAwICAwQDAwQDAgIDAAMDAwICAgMCAgIDAwMDAAAA - AwICAgMCAgIDAgMAAAAAAAAAAwMEBAQEBAQCAwAAAAAAAwMEBAQDAwMDAwMAAAAAAwQEAwMEBAMEBAQC - AwAAAAMEBAMDBAMEBAQEAgMAAAAAAwMDBAQDBAMDAwIDAAAAAAMCAgICAgICAgMEBAMAAAAAAwICAgIC - AwMEBAQDAAAAAAADAwMDAwAAAwMDAJH/AAAAcwAAAAEAAIABAAAAAAAAAAAAAIABAADABwAA8AMAAOAD - AADAAQAAwAEAAOABAADgAAAA8AAAAPgxAAA= - - - \ No newline at end of file diff --git a/BizHawk.sln b/BizHawk.sln index 53559fc6dc..64985e34d0 100644 --- a/BizHawk.sln +++ b/BizHawk.sln @@ -55,8 +55,6 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "BizHawk.Bizware.BizwareGL.G EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "BizHawk.Bizware.BizwareGL.SlimDX", "Bizware\BizHawk.Bizware.BizwareGL.SlimDX\BizHawk.Bizware.BizwareGL.SlimDX.csproj", "{E6B436B1-A3CD-4C9A-8F76-5D7154726884}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "BizHawk.Client.MultiHawk", "BizHawk.Client.MultiHawk\BizHawk.Client.MultiHawk.csproj", "{B95649F5-A0AE-41EB-B62B-578A2AFF5E18}" -EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "BizHawk.Client.ApiHawk", "BizHawk.Client.ApiHawk\BizHawk.Client.ApiHawk.csproj", "{8E2F11F2-3955-4382-8C3A-CEBA1276CAEA}" EndProject Global @@ -117,10 +115,6 @@ Global {E6B436B1-A3CD-4C9A-8F76-5D7154726884}.Debug|Any CPU.Build.0 = Debug|Any CPU {E6B436B1-A3CD-4C9A-8F76-5D7154726884}.Release|Any CPU.ActiveCfg = Release|Any CPU {E6B436B1-A3CD-4C9A-8F76-5D7154726884}.Release|Any CPU.Build.0 = Release|Any CPU - {B95649F5-A0AE-41EB-B62B-578A2AFF5E18}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {B95649F5-A0AE-41EB-B62B-578A2AFF5E18}.Debug|Any CPU.Build.0 = Debug|Any CPU - {B95649F5-A0AE-41EB-B62B-578A2AFF5E18}.Release|Any CPU.ActiveCfg = Release|Any CPU - {B95649F5-A0AE-41EB-B62B-578A2AFF5E18}.Release|Any CPU.Build.0 = Release|Any CPU {8E2F11F2-3955-4382-8C3A-CEBA1276CAEA}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {8E2F11F2-3955-4382-8C3A-CEBA1276CAEA}.Debug|Any CPU.Build.0 = Debug|Any CPU {8E2F11F2-3955-4382-8C3A-CEBA1276CAEA}.Release|Any CPU.ActiveCfg = Release|Any CPU @@ -141,7 +135,6 @@ Global {2D2890A8-C338-4439-AD8B-CB9EE85A94F9} = {B51F1139-3D2C-41BE-A762-EF1F9B41EACA} {337CA23E-65E7-44E1-9411-97EE08BB8116} = {0540A9A6-977E-466D-8BD3-1D8590BD5282} {E6B436B1-A3CD-4C9A-8F76-5D7154726884} = {0540A9A6-977E-466D-8BD3-1D8590BD5282} - {B95649F5-A0AE-41EB-B62B-578A2AFF5E18} = {B51F1139-3D2C-41BE-A762-EF1F9B41EACA} {8E2F11F2-3955-4382-8C3A-CEBA1276CAEA} = {B51F1139-3D2C-41BE-A762-EF1F9B41EACA} EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution From bd0c81d7913d3b97b264b32e7e61d4f4b86fa6e0 Mon Sep 17 00:00:00 2001 From: adelikat Date: Sat, 19 Oct 2019 14:59:57 -0500 Subject: [PATCH 065/166] InputRoll - don't blow up if QueryItemBkColor isn't defined --- BizHawk.Client.EmuHawk/CustomControls/InputRoll.Drawing.cs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/BizHawk.Client.EmuHawk/CustomControls/InputRoll.Drawing.cs b/BizHawk.Client.EmuHawk/CustomControls/InputRoll.Drawing.cs index f26d76fe3a..9c453c76e5 100644 --- a/BizHawk.Client.EmuHawk/CustomControls/InputRoll.Drawing.cs +++ b/BizHawk.Client.EmuHawk/CustomControls/InputRoll.Drawing.cs @@ -481,7 +481,7 @@ namespace BizHawk.Client.EmuHawk } Color cellColor = rowColor; - QueryItemBkColor(cell.RowIndex.Value, cell.Column, ref cellColor); + QueryItemBkColor?.Invoke(cell.RowIndex.Value, cell.Column, ref cellColor); // Alpha layering for cell before selection float alpha = (float)cellColor.A / 255; @@ -566,7 +566,7 @@ namespace BizHawk.Client.EmuHawk for (int j = firstVisibleColumn; j <= lastVisible; j++) { Color itemColor = Color.White; - QueryItemBkColor(f + startIndex, visibleColumns[j], ref itemColor); + QueryItemBkColor?.Invoke(f + startIndex, visibleColumns[j], ref itemColor); if (itemColor == Color.White) { itemColor = rowColor; @@ -603,7 +603,7 @@ namespace BizHawk.Client.EmuHawk for (int j = FirstVisibleColumn; j <= lastVisible; j++) // Horizontal { Color itemColor = Color.White; - QueryItemBkColor(f + startIndex, visibleColumns[j], ref itemColor); + QueryItemBkColor?.Invoke(f + startIndex, visibleColumns[j], ref itemColor); if (itemColor == Color.White) { itemColor = rowColor; From 4ed50200c83a19c17bb6e8d976e738c655f94aa5 Mon Sep 17 00:00:00 2001 From: "J.D. Purcell" Date: Sat, 19 Oct 2019 17:50:24 -0400 Subject: [PATCH 066/166] Some cleanups in Input.cs --- BizHawk.Client.EmuHawk/Input/Input.cs | 81 +++++++++++++-------------- 1 file changed, 40 insertions(+), 41 deletions(-) diff --git a/BizHawk.Client.EmuHawk/Input/Input.cs b/BizHawk.Client.EmuHawk/Input/Input.cs index d187149c59..f950965f29 100644 --- a/BizHawk.Client.EmuHawk/Input/Input.cs +++ b/BizHawk.Client.EmuHawk/Input/Input.cs @@ -3,8 +3,6 @@ using System.Linq; using System.Collections.Generic; using System.Threading; -using SlimDX.DirectInput; - using BizHawk.Common; using BizHawk.Client.Common; @@ -213,31 +211,25 @@ namespace BizHawk.Client.EmuHawk private readonly WorkingDictionary ModifierState = new WorkingDictionary(); private readonly WorkingDictionary LastState = new WorkingDictionary(); private readonly WorkingDictionary UnpressState = new WorkingDictionary(); - private readonly HashSet IgnoreKeys = new HashSet(new[] { "LeftShift", "RightShift", "LeftControl", "RightControl", "LeftAlt", "RightAlt" }); private readonly WorkingDictionary FloatValues = new WorkingDictionary(); private readonly WorkingDictionary FloatDeltas = new WorkingDictionary(); private bool trackdeltas = false; void HandleButton(string button, bool newState, InputFocus source) { - bool isModifier = IgnoreKeys.Contains(button); - if (EnableIgnoreModifiers && isModifier) return; - if (LastState[button] && newState) return; - if (!LastState[button] && !newState) return; + ModifierKey currentModifier = ButtonToModifierKey(button); + if (EnableIgnoreModifiers && currentModifier != ModifierKey.None) return; + if (LastState[button] == newState) return; //apply //NOTE: this is not quite right. if someone held leftshift+rightshift it would be broken. seems unlikely, though. - if (button == "LeftShift") + if (currentModifier != ModifierKey.None) { - _Modifiers &= ~ModifierKey.Shift; if (newState) - _Modifiers |= ModifierKey.Shift; + _Modifiers |= currentModifier; + else + _Modifiers &= ~currentModifier; } - if (button == "RightShift") { _Modifiers &= ~ModifierKey.Shift; if (newState) _Modifiers |= ModifierKey.Shift; } - if (button == "LeftControl") { _Modifiers &= ~ModifierKey.Control; if (newState) _Modifiers |= ModifierKey.Control; } - if (button == "RightControl") { _Modifiers &= ~ModifierKey.Control; if (newState) _Modifiers |= ModifierKey.Control; } - if (button == "LeftAlt") { _Modifiers &= ~ModifierKey.Alt; if (newState) _Modifiers |= ModifierKey.Alt; } - if (button == "RightAlt") { _Modifiers &= ~ModifierKey.Alt; if (newState) _Modifiers |= ModifierKey.Alt; } if (UnpressState.ContainsKey(button)) { @@ -248,15 +240,10 @@ namespace BizHawk.Client.EmuHawk return; } - //dont generate events for things like Ctrl+LeftControl ModifierKey mods = _Modifiers; - if (button == "LeftShift") mods &= ~ModifierKey.Shift; - if (button == "RightShift") mods &= ~ModifierKey.Shift; - if (button == "LeftControl") mods &= ~ModifierKey.Control; - if (button == "RightControl") mods &= ~ModifierKey.Control; - if (button == "LeftAlt") mods &= ~ModifierKey.Alt; - if (button == "RightAlt") mods &= ~ModifierKey.Alt; + if (currentModifier != ModifierKey.None) + mods &= ~currentModifier; var ie = new InputEvent { @@ -297,7 +284,21 @@ namespace BizHawk.Client.EmuHawk _NewEvents.Add(ie); } - ModifierKey _Modifiers; + private static ModifierKey ButtonToModifierKey(string button) + { + switch (button) + { + case "LeftShift": return ModifierKey.Shift; + case "RightShift": return ModifierKey.Shift; + case "LeftControl": return ModifierKey.Control; + case "RightControl": return ModifierKey.Control; + case "LeftAlt": return ModifierKey.Alt; + case "RightAlt": return ModifierKey.Alt; + } + return ModifierKey.None; + } + + private ModifierKey _Modifiers; private readonly List _NewEvents = new List(); //do we need this? @@ -433,21 +434,23 @@ namespace BizHawk.Client.EmuHawk //HandleButton("WMouse 1", false); //HandleButton("WMouse 2", false); } - } - //WHAT!? WE SHOULD NOT BE SO NAIVELY TOUCHING MAINFORM FROM THE INPUTTHREAD. ITS BUSY RUNNING. - AllowInput allowInput = GlobalWin.MainForm.AllowInput(false); - - foreach (var ie in _NewEvents) + if (_NewEvents.Count != 0) { - //events are swallowed in some cases: - if (ie.LogicalButton.Alt && ShouldSwallow(GlobalWin.MainForm.AllowInput(true), ie)) - { } - else if (ie.EventType == InputEventType.Press && ShouldSwallow(allowInput, ie)) - { } - else + //WHAT!? WE SHOULD NOT BE SO NAIVELY TOUCHING MAINFORM FROM THE INPUTTHREAD. ITS BUSY RUNNING. + AllowInput allowInput = GlobalWin.MainForm.AllowInput(false); + + foreach (var ie in _NewEvents) + { + //events are swallowed in some cases: + if (ie.LogicalButton.Alt && ShouldSwallow(GlobalWin.MainForm.AllowInput(true), ie)) + continue; + if (ie.EventType == InputEventType.Press && ShouldSwallow(allowInput, ie)) + continue; + EnqueueEvent(ie); + } } } //lock(this) @@ -518,13 +521,10 @@ namespace BizHawk.Client.EmuHawk if (ShouldSwallow(allowInput, ie)) continue; - //as a special perk, we'll accept escape immediately - if (ie.EventType == InputEventType.Press && ie.LogicalButton.Button == "Escape") - goto ACCEPT; + //ignore presses, but as a special perk, we'll accept escape immediately + if (ie.EventType == InputEventType.Press && ie.LogicalButton.Button != "Escape") + continue; - if (ie.EventType == InputEventType.Press) continue; - - ACCEPT: Console.WriteLine("Bind Event: {0} ", ie); foreach (var kvp in LastState) @@ -556,6 +556,5 @@ namespace BizHawk.Client.EmuHawk UnpressState[keystr] = true; LastState[keystr] = true; } - } } From 279726d52c894f13dccb87b9619179c2258208b8 Mon Sep 17 00:00:00 2001 From: adelikat Date: Sat, 19 Oct 2019 15:00:29 -0500 Subject: [PATCH 067/166] convert TraceLogger to use InputRoll --- .../tools/TraceLogger.Designer.cs | 31 ++------ BizHawk.Client.EmuHawk/tools/TraceLogger.cs | 71 +++++++++++-------- BizHawk.sln.DotSettings | 1 + 3 files changed, 48 insertions(+), 55 deletions(-) diff --git a/BizHawk.Client.EmuHawk/tools/TraceLogger.Designer.cs b/BizHawk.Client.EmuHawk/tools/TraceLogger.Designer.cs index b9afaa15a2..50a93f6507 100644 --- a/BizHawk.Client.EmuHawk/tools/TraceLogger.Designer.cs +++ b/BizHawk.Client.EmuHawk/tools/TraceLogger.Designer.cs @@ -31,9 +31,7 @@ this.components = new System.ComponentModel.Container(); System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(TraceLogger)); this.TracerBox = new System.Windows.Forms.GroupBox(); - this.TraceView = new BizHawk.Client.EmuHawk.VirtualListView(); - this.Disasm = ((System.Windows.Forms.ColumnHeader)(new System.Windows.Forms.ColumnHeader())); - this.Registers = ((System.Windows.Forms.ColumnHeader)(new System.Windows.Forms.ColumnHeader())); + this.TraceView = new InputRoll(); this.TraceContextMenu = new System.Windows.Forms.ContextMenuStrip(this.components); this.CopyContextMenu = new System.Windows.Forms.ToolStripMenuItem(); this.SelectAllContextMenu = new System.Windows.Forms.ToolStripMenuItem(); @@ -81,36 +79,19 @@ this.TraceView.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom) | System.Windows.Forms.AnchorStyles.Left) | System.Windows.Forms.AnchorStyles.Right))); - this.TraceView.BlazingFast = false; - this.TraceView.Columns.AddRange(new System.Windows.Forms.ColumnHeader[] { - this.Disasm, - this.Registers}); this.TraceView.ContextMenuStrip = this.TraceContextMenu; this.TraceView.Font = new System.Drawing.Font("Courier New", 8F); this.TraceView.FullRowSelect = true; this.TraceView.GridLines = true; - this.TraceView.HideSelection = false; - this.TraceView.ItemCount = 0; + this.TraceView.RowCount = 0; this.TraceView.Location = new System.Drawing.Point(8, 18); this.TraceView.Name = "TraceView"; - this.TraceView.SelectAllInProgress = false; - this.TraceView.selectedItem = -1; this.TraceView.Size = new System.Drawing.Size(603, 414); this.TraceView.TabIndex = 4; this.TraceView.TabStop = false; - this.TraceView.UseCompatibleStateImageBehavior = false; this.TraceView.UseCustomBackground = true; - this.TraceView.View = System.Windows.Forms.View.Details; - // - // Disasm - // - this.Disasm.Text = "Disasm"; - this.Disasm.Width = 239; - // - // Registers - // - this.Registers.Text = "Registers"; - this.Registers.Width = 357; + this.TraceView.AllowColumnResize = true; + this.TraceView.AllowColumnReorder = false; // // TraceContextMenu // @@ -371,8 +352,7 @@ private System.Windows.Forms.GroupBox groupBox2; private System.Windows.Forms.CheckBox LoggingEnabled; private System.Windows.Forms.ToolStripMenuItem OptionsSubMenu; - private VirtualListView TraceView; - public System.Windows.Forms.ColumnHeader Disasm; + private InputRoll TraceView; private System.Windows.Forms.ToolStripMenuItem MaxLinesMenuItem; private System.Windows.Forms.RadioButton ToFileRadio; private System.Windows.Forms.RadioButton ToWindowRadio; @@ -381,7 +361,6 @@ private System.Windows.Forms.ToolStripMenuItem EditSubMenu; private System.Windows.Forms.ToolStripMenuItem CopyMenuItem; private System.Windows.Forms.ToolStripMenuItem SelectAllMenuItem; - private System.Windows.Forms.ColumnHeader Registers; private System.Windows.Forms.ToolStripMenuItem ClearMenuItem; private System.Windows.Forms.ContextMenuStrip TraceContextMenu; private System.Windows.Forms.ToolStripMenuItem CopyContextMenu; diff --git a/BizHawk.Client.EmuHawk/tools/TraceLogger.cs b/BizHawk.Client.EmuHawk/tools/TraceLogger.cs index d2690cf4cd..85eb746632 100644 --- a/BizHawk.Client.EmuHawk/tools/TraceLogger.cs +++ b/BizHawk.Client.EmuHawk/tools/TraceLogger.cs @@ -24,16 +24,19 @@ namespace BizHawk.Client.EmuHawk private int FileSizeCap { get; set; } [ConfigPersist] - private int DisasmColumnWidth { - get { return this.Disasm.Width; } - set { this.Disasm.Width = value; } - } - - [ConfigPersist] - private int RegistersColumnWidth + private List Columns { - get { return this.Registers.Width; } - set { this.Registers.Width = value; } + get { return TraceView.AllColumns; } + set + { + TraceView.AllColumns.Clear(); + foreach (var column in value) + { + TraceView.AllColumns.Add(column); + } + + TraceView.AllColumns.ColumnsChanged(); + } } private FileInfo _logFile; @@ -47,7 +50,7 @@ namespace BizHawk.Client.EmuHawk } } - private List _instructions = new List(); + private readonly List _instructions = new List(); private StreamWriter _streamWriter; private bool _splitFile; private string _baseName; @@ -55,12 +58,13 @@ namespace BizHawk.Client.EmuHawk private int _segmentCount; private ulong _currentSize; + private const string DisasmColumnName = "Disasm"; + private const string RegistersColumnName = "Registers"; public TraceLogger() { InitializeComponent(); TraceView.QueryItemText += TraceView_QueryItemText; - TraceView.VirtualMode = true; Closing += (o, e) => { @@ -72,6 +76,22 @@ namespace BizHawk.Client.EmuHawk MaxLines = 10000; FileSizeCap = 150; // make 1 frame of tracelog for n64/psx fit in _splitFile = FileSizeCap != 0; + + TraceView.AllColumns.Clear(); + TraceView.AllColumns.Add(new InputRoll.RollColumn + { + Name = DisasmColumnName, + Text = DisasmColumnName, + Width = 239, + Type = InputRoll.RollColumn.InputType.Text + }); + TraceView.AllColumns.Add(new InputRoll.RollColumn + { + Name = RegistersColumnName, + Text = RegistersColumnName, + Width = 357, + Type = InputRoll.RollColumn.InputType.Text + }); } public bool UpdateBefore @@ -89,17 +109,17 @@ namespace BizHawk.Client.EmuHawk //Tracer.Enabled = LoggingEnabled.Checked; } - private void TraceView_QueryItemText(int index, int column, out string text) + private void TraceView_QueryItemText(int index, InputRoll.RollColumn column, out string text, ref int offsetX, ref int offsetY) { text = ""; if (index < _instructions.Count) { - switch (column) + switch (column.Name) { - case 0: + case DisasmColumnName: text = _instructions[index].Disassembly.TrimEnd(); break; - case 1: + case RegistersColumnName: text = _instructions[index].RegisterInfo; break; } @@ -133,11 +153,7 @@ namespace BizHawk.Client.EmuHawk { if (ToWindowRadio.Checked) { - // setting to zero first fixes an exception when scrolling the view - // how or why I don't know - // it's hidden behind an internal class ListViewNativeItemCollection - TraceView.VirtualListSize = 0; - TraceView.VirtualListSize = _instructions.Count; + TraceView.RowCount = _instructions.Count; } else { @@ -152,12 +168,9 @@ namespace BizHawk.Client.EmuHawk //connect tracer to sink for next frame if (ToWindowRadio.Checked) { - //update listview with most recent results - TraceView.BlazingFast = !GlobalWin.MainForm.EmulatorPaused; - - Tracer.Sink = new CallbackSink() + Tracer.Sink = new CallbackSink { - putter = (info) => + putter = info => { if (_instructions.Count >= MaxLines) { @@ -210,7 +223,7 @@ namespace BizHawk.Client.EmuHawk private void ClearList() { _instructions.Clear(); - TraceView.ItemCount = 0; + TraceView.RowCount = 0; SetTracerBoxTitle(); } @@ -233,7 +246,7 @@ namespace BizHawk.Client.EmuHawk { _instructions.RemoveRange(0, _instructions.Count - MaxLines); } - TraceView.ItemCount = _instructions.Count; + TraceView.RowCount = _instructions.Count; } private void SetTracerBoxTitle() @@ -331,7 +344,7 @@ namespace BizHawk.Client.EmuHawk private void CopyMenuItem_Click(object sender, EventArgs e) { - var indices = TraceView.SelectedIndices; + var indices = TraceView.SelectedRows.ToList(); if (indices.Count > 0) { @@ -348,7 +361,7 @@ namespace BizHawk.Client.EmuHawk { for (var i = 0; i < _instructions.Count; i++) { - TraceView.SelectItem(i, true); + TraceView.SelectRow(i, true); } } diff --git a/BizHawk.sln.DotSettings b/BizHawk.sln.DotSettings index 7ac019c4ad..fc09226aa4 100644 --- a/BizHawk.sln.DotSettings +++ b/BizHawk.sln.DotSettings @@ -183,6 +183,7 @@ True True True + True True True True From 701533f4fe7d4d10b279321aca95bac7dd8c109e Mon Sep 17 00:00:00 2001 From: adelikat Date: Sat, 19 Oct 2019 15:21:45 -0500 Subject: [PATCH 068/166] convert CDL tool to use InputRoll --- BizHawk.Client.EmuHawk/tools/CDL.cs | 42 ++++--- BizHawk.Client.EmuHawk/tools/CDL.designer.cs | 113 +------------------ 2 files changed, 30 insertions(+), 125 deletions(-) diff --git a/BizHawk.Client.EmuHawk/tools/CDL.cs b/BizHawk.Client.EmuHawk/tools/CDL.cs index fa9e45556e..47354229de 100644 --- a/BizHawk.Client.EmuHawk/tools/CDL.cs +++ b/BizHawk.Client.EmuHawk/tools/CDL.cs @@ -1,6 +1,7 @@ using System; using System.Collections.Generic; using System.IO; +using System.Linq; using System.Windows.Forms; using BizHawk.Emulation.Common; @@ -59,6 +60,24 @@ namespace BizHawk.Client.EmuHawk InitializeComponent(); tsbViewStyle.SelectedIndex = 0; + + lvCDL.AllColumns.Clear(); + lvCDL.AllColumns.AddRange(new [] + { + new InputRoll.RollColumn { Name = "CDLFile", Text = "CDL File @", Width = 107, Type = InputRoll.RollColumn.InputType.Text }, + new InputRoll.RollColumn { Name = "Domain", Text = "Domain", Width = 126, Type = InputRoll.RollColumn.InputType.Text }, + new InputRoll.RollColumn { Name = "Percent", Text = "%", Width = 58, Type = InputRoll.RollColumn.InputType.Text }, + new InputRoll.RollColumn { Name = "Mapped", Text = "Mapped", Width = 64, Type = InputRoll.RollColumn.InputType.Text }, + new InputRoll.RollColumn { Name = "Size", Text = "Size", Width = 112, Type = InputRoll.RollColumn.InputType.Text }, + new InputRoll.RollColumn { Name = "0x01", Text = "0x01", Width = 56, Type = InputRoll.RollColumn.InputType.Text }, + new InputRoll.RollColumn { Name = "0x02", Text = "0x02", Width = 56, Type = InputRoll.RollColumn.InputType.Text }, + new InputRoll.RollColumn { Name = "0x04", Text = "0x04", Width = 56, Type = InputRoll.RollColumn.InputType.Text }, + new InputRoll.RollColumn { Name = "0x08", Text = "0x08", Width = 56, Type = InputRoll.RollColumn.InputType.Text }, + new InputRoll.RollColumn { Name = "0x10", Text = "0x10", Width = 56, Type = InputRoll.RollColumn.InputType.Text }, + new InputRoll.RollColumn { Name = "0x20", Text = "0x20", Width = 56, Type = InputRoll.RollColumn.InputType.Text }, + new InputRoll.RollColumn { Name = "0x40", Text = "0x40", Width = 56, Type = InputRoll.RollColumn.InputType.Text }, + new InputRoll.RollColumn { Name = "0x80", Text = "0x80", Width = 56, Type = InputRoll.RollColumn.InputType.Text } + }); } public void NewUpdate(ToolFormUpdateType type) { } @@ -98,23 +117,10 @@ namespace BizHawk.Client.EmuHawk if (_cdl == null) { - lvCDL.BeginUpdate(); - if (OSTailoredCode.CurrentOS == OSTailoredCode.DistinctOS.Windows) - { - lvCDL.Items.Clear(); - } - else - { - // this is a winforms implementation problem for mono - // see https://github.com/mono/mono/issues/11070 - // until this is resolved in mono we should just skip this call - } - lvCDL.EndUpdate(); + lvCDL.DeselectAll(); return; } - lvCDL.BeginUpdate(); - listContents = new string[_cdl.Count][]; int idx = 0; @@ -183,8 +189,7 @@ namespace BizHawk.Client.EmuHawk } } - lvCDL.VirtualListSize = _cdl.Count; - lvCDL.EndUpdate(); + lvCDL.RowCount = _cdl.Count; } public bool AskSaveChanges() @@ -571,9 +576,10 @@ namespace BizHawk.Client.EmuHawk CodeDataLogger.SetCDL(null); } - private void lvCDL_QueryItemText(int item, int subItem, out string text) + private void lvCDL_QueryItemText(int index, InputRoll.RollColumn column, out string text, ref int offsetX, ref int offsetY) { - text = listContents[item][subItem]; + var subItem = lvCDL.AllColumns.IndexOf(column); + text = listContents[index][subItem]; } private void tsbExportText_Click(object sender, EventArgs e) diff --git a/BizHawk.Client.EmuHawk/tools/CDL.designer.cs b/BizHawk.Client.EmuHawk/tools/CDL.designer.cs index a43f020105..5b24949487 100644 --- a/BizHawk.Client.EmuHawk/tools/CDL.designer.cs +++ b/BizHawk.Client.EmuHawk/tools/CDL.designer.cs @@ -52,20 +52,7 @@ this.tsbViewStyle = new System.Windows.Forms.ToolStripComboBox(); this.toolStripSeparator4 = new System.Windows.Forms.ToolStripSeparator(); this.tsbExportText = new System.Windows.Forms.ToolStripButton(); - this.lvCDL = new BizHawk.Client.EmuHawk.VirtualListView(); - this.colAddress = ((System.Windows.Forms.ColumnHeader)(new System.Windows.Forms.ColumnHeader())); - this.colDomain = ((System.Windows.Forms.ColumnHeader)(new System.Windows.Forms.ColumnHeader())); - this.colPct = ((System.Windows.Forms.ColumnHeader)(new System.Windows.Forms.ColumnHeader())); - this.colMapped = ((System.Windows.Forms.ColumnHeader)(new System.Windows.Forms.ColumnHeader())); - this.colSize = ((System.Windows.Forms.ColumnHeader)(new System.Windows.Forms.ColumnHeader())); - this.colFlag01 = ((System.Windows.Forms.ColumnHeader)(new System.Windows.Forms.ColumnHeader())); - this.colFlag02 = ((System.Windows.Forms.ColumnHeader)(new System.Windows.Forms.ColumnHeader())); - this.colFlag04 = ((System.Windows.Forms.ColumnHeader)(new System.Windows.Forms.ColumnHeader())); - this.colFlag08 = ((System.Windows.Forms.ColumnHeader)(new System.Windows.Forms.ColumnHeader())); - this.colFlag10 = ((System.Windows.Forms.ColumnHeader)(new System.Windows.Forms.ColumnHeader())); - this.colFlag20 = ((System.Windows.Forms.ColumnHeader)(new System.Windows.Forms.ColumnHeader())); - this.colFlag40 = ((System.Windows.Forms.ColumnHeader)(new System.Windows.Forms.ColumnHeader())); - this.colFlag80 = ((System.Windows.Forms.ColumnHeader)(new System.Windows.Forms.ColumnHeader())); + this.lvCDL = new InputRoll(); this.miAutoResume = new System.Windows.Forms.ToolStripMenuItem(); this.menuStrip1.SuspendLayout(); this.toolStrip1.SuspendLayout(); @@ -280,93 +267,18 @@ // // lvCDL // - this.lvCDL.BlazingFast = false; - this.lvCDL.Columns.AddRange(new System.Windows.Forms.ColumnHeader[] { - this.colAddress, - this.colDomain, - this.colPct, - this.colMapped, - this.colSize, - this.colFlag01, - this.colFlag02, - this.colFlag04, - this.colFlag08, - this.colFlag10, - this.colFlag20, - this.colFlag40, - this.colFlag80}); this.lvCDL.Dock = System.Windows.Forms.DockStyle.Fill; this.lvCDL.FullRowSelect = true; this.lvCDL.GridLines = true; - this.lvCDL.ItemCount = 0; + this.lvCDL.RowCount = 0; this.lvCDL.Location = new System.Drawing.Point(0, 49); this.lvCDL.Name = "lvCDL"; - this.lvCDL.SelectAllInProgress = false; - this.lvCDL.selectedItem = -1; this.lvCDL.Size = new System.Drawing.Size(992, 323); this.lvCDL.TabIndex = 9; - this.lvCDL.UseCompatibleStateImageBehavior = false; this.lvCDL.UseCustomBackground = true; - this.lvCDL.View = System.Windows.Forms.View.Details; - this.lvCDL.VirtualMode = true; - this.lvCDL.QueryItemText += new BizHawk.Client.EmuHawk.QueryItemTextHandler(this.lvCDL_QueryItemText); - // - // colAddress - // - this.colAddress.Text = "CDL File @"; - this.colAddress.Width = 107; - // - // colDomain - // - this.colDomain.Text = "Domain"; - this.colDomain.Width = 126; - // - // colPct - // - this.colPct.Text = "%"; - this.colPct.Width = 58; - // - // colMapped - // - this.colMapped.Text = "Mapped"; - this.colMapped.Width = 64; - // - // colSize - // - this.colSize.Text = "Size"; - this.colSize.Width = 102; - // - // colFlag01 - // - this.colFlag01.Text = "0x01"; - // - // colFlag02 - // - this.colFlag02.Text = "0x02"; - // - // colFlag04 - // - this.colFlag04.Text = "0x04"; - // - // colFlag08 - // - this.colFlag08.Text = "0x08"; - // - // colFlag10 - // - this.colFlag10.Text = "0x10"; - // - // colFlag20 - // - this.colFlag20.Text = "0x20"; - // - // colFlag40 - // - this.colFlag40.Text = "0x40"; - // - // colFlag80 - // - this.colFlag80.Text = "0x80"; + this.lvCDL.AllowColumnReorder = false; + this.lvCDL.AllowColumnResize = true; + this.lvCDL.QueryItemText += new InputRoll.QueryItemTextHandler(this.lvCDL_QueryItemText); // // miAutoResume // @@ -422,20 +334,7 @@ private System.Windows.Forms.ToolStripSeparator toolStripSeparator3; private System.Windows.Forms.ToolStripButton tsbViewUpdate; private System.Windows.Forms.ToolStripComboBox tsbViewStyle; - private VirtualListView lvCDL; - private System.Windows.Forms.ColumnHeader colAddress; - private System.Windows.Forms.ColumnHeader colDomain; - private System.Windows.Forms.ColumnHeader colPct; - private System.Windows.Forms.ColumnHeader colMapped; - private System.Windows.Forms.ColumnHeader colSize; - private System.Windows.Forms.ColumnHeader colFlag01; - private System.Windows.Forms.ColumnHeader colFlag02; - private System.Windows.Forms.ColumnHeader colFlag04; - private System.Windows.Forms.ColumnHeader colFlag08; - private System.Windows.Forms.ColumnHeader colFlag10; - private System.Windows.Forms.ColumnHeader colFlag20; - private System.Windows.Forms.ColumnHeader colFlag40; - private System.Windows.Forms.ColumnHeader colFlag80; + private InputRoll lvCDL; private System.Windows.Forms.ToolStripSeparator toolStripSeparator4; private System.Windows.Forms.ToolStripButton tsbExportText; private System.Windows.Forms.ToolStripMenuItem miAutoStart; From 9100526a0ca5cad4167d8d62be3046103487c759 Mon Sep 17 00:00:00 2001 From: adelikat Date: Sat, 19 Oct 2019 19:16:45 -0500 Subject: [PATCH 069/166] Convert debugger to use InputRoll instead of VirtualListView --- .../CustomControls/InputRoll.cs | 8 +- .../Debugger/GenericDebugger.Designer.cs | 34 ++------ .../Debugger/GenericDebugger.Disassembler.cs | 84 +++++++++---------- .../tools/Debugger/GenericDebugger.cs | 24 +++++- BizHawk.sln.DotSettings | 1 + 5 files changed, 74 insertions(+), 77 deletions(-) diff --git a/BizHawk.Client.EmuHawk/CustomControls/InputRoll.cs b/BizHawk.Client.EmuHawk/CustomControls/InputRoll.cs index ae12c73001..fabf42d68e 100644 --- a/BizHawk.Client.EmuHawk/CustomControls/InputRoll.cs +++ b/BizHawk.Client.EmuHawk/CustomControls/InputRoll.cs @@ -1573,11 +1573,11 @@ namespace BizHawk.Client.EmuHawk if (_horizontalOrientation) { - ColumnScroll?.Invoke(this, e); + ColumnScroll?.Invoke(_vBar, e); } else { - RowScroll?.Invoke(this, e); + RowScroll?.Invoke(_vBar, e); } } @@ -1590,11 +1590,11 @@ namespace BizHawk.Client.EmuHawk if (_horizontalOrientation) { - RowScroll?.Invoke(this, e); + RowScroll?.Invoke(_hBar, e); } else { - ColumnScroll?.Invoke(this, e); + ColumnScroll?.Invoke(_vBar, e); } } diff --git a/BizHawk.Client.EmuHawk/tools/Debugger/GenericDebugger.Designer.cs b/BizHawk.Client.EmuHawk/tools/Debugger/GenericDebugger.Designer.cs index ff6dc13a11..2eaa8ea454 100644 --- a/BizHawk.Client.EmuHawk/tools/Debugger/GenericDebugger.Designer.cs +++ b/BizHawk.Client.EmuHawk/tools/Debugger/GenericDebugger.Designer.cs @@ -46,9 +46,7 @@ this.DisassemblerBox = new System.Windows.Forms.GroupBox(); this.ToPCBtn = new System.Windows.Forms.Button(); this.label1 = new System.Windows.Forms.Label(); - this.DisassemblerView = new BizHawk.Client.EmuHawk.VirtualListView(); - this.Address = ((System.Windows.Forms.ColumnHeader)(new System.Windows.Forms.ColumnHeader())); - this.Instruction = ((System.Windows.Forms.ColumnHeader)(new System.Windows.Forms.ColumnHeader())); + this.DisassemblerView = new InputRoll(); this.DisassemblerContextMenu = new System.Windows.Forms.ContextMenuStrip(this.components); this.AddBreakpointContextMenuItem = new System.Windows.Forms.ToolStripMenuItem(); this.StepOutBtn = new System.Windows.Forms.Button(); @@ -239,39 +237,21 @@ this.DisassemblerView.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom) | System.Windows.Forms.AnchorStyles.Left) | System.Windows.Forms.AnchorStyles.Right))); - this.DisassemblerView.BlazingFast = false; - this.DisassemblerView.Columns.AddRange(new System.Windows.Forms.ColumnHeader[] { - this.Address, - this.Instruction}); + this.DisassemblerView.AllowColumnReorder = false; + this.DisassemblerView.AllowColumnResize = true; this.DisassemblerView.ContextMenuStrip = this.DisassemblerContextMenu; this.DisassemblerView.Font = new System.Drawing.Font("Courier New", 8F); this.DisassemblerView.FullRowSelect = true; this.DisassemblerView.GridLines = true; - this.DisassemblerView.HideSelection = false; - this.DisassemblerView.ItemCount = 0; + this.DisassemblerView.RowCount = 0; this.DisassemblerView.Location = new System.Drawing.Point(6, 39); this.DisassemblerView.Name = "DisassemblerView"; - this.DisassemblerView.SelectAllInProgress = false; - this.DisassemblerView.selectedItem = -1; this.DisassemblerView.Size = new System.Drawing.Size(395, 476); this.DisassemblerView.TabIndex = 1; - this.DisassemblerView.UseCompatibleStateImageBehavior = false; this.DisassemblerView.UseCustomBackground = true; - this.DisassemblerView.View = System.Windows.Forms.View.Details; - this.DisassemblerView.Scroll += new System.Windows.Forms.ScrollEventHandler(this.DisassemblerView_Scroll); + this.DisassemblerView.RowScroll += new InputRoll.RowScrollEvent(this.DisassemblerView_Scroll); this.DisassemblerView.SizeChanged += new System.EventHandler(this.DisassemblerView_SizeChanged); this.DisassemblerView.KeyDown += new System.Windows.Forms.KeyEventHandler(this.DisassemblerView_KeyDown); - this.DisassemblerView.MouseWheel += new System.Windows.Forms.MouseEventHandler(this.DisassemblerView_Wheel); - // - // Address - // - this.Address.Text = "Address"; - this.Address.Width = 94; - // - // Instruction - // - this.Instruction.Text = "Instruction"; - this.Instruction.Width = 291; // // DisassemblerContextMenu // @@ -412,9 +392,7 @@ private System.Windows.Forms.GroupBox BreakpointsGroupBox; private BreakpointControl BreakPointControl1; private System.Windows.Forms.GroupBox DisassemblerBox; - private VirtualListView DisassemblerView; - private System.Windows.Forms.ColumnHeader Address; - private System.Windows.Forms.ColumnHeader Instruction; + private InputRoll DisassemblerView; private System.Windows.Forms.Label label1; private System.Windows.Forms.Button StepOutBtn; private System.Windows.Forms.Button StepIntoBtn; diff --git a/BizHawk.Client.EmuHawk/tools/Debugger/GenericDebugger.Disassembler.cs b/BizHawk.Client.EmuHawk/tools/Debugger/GenericDebugger.Disassembler.cs index df9b7328aa..0fd2c0a047 100644 --- a/BizHawk.Client.EmuHawk/tools/Debugger/GenericDebugger.Disassembler.cs +++ b/BizHawk.Client.EmuHawk/tools/Debugger/GenericDebugger.Disassembler.cs @@ -43,16 +43,14 @@ namespace BizHawk.Client.EmuHawk { if (CanDisassemble) { - DisassemblerView.BlazingFast = true; Disassemble(); SetDisassemblerItemCount(); - DisassemblerView.BlazingFast = false; } } private void Disassemble() { - int lineCount = DisassemblerView.NumberOfVisibleRows; + int lineCount = DisassemblerView.RowCount + 2; _disassemblyLines.Clear(); uint a = _currentDisassemblerAddress; @@ -69,24 +67,24 @@ namespace BizHawk.Client.EmuHawk } } - private void DisassemblerView_QueryItemText(int index, int column, out string text) + private void DisassemblerView_QueryItemText(int index, InputRoll.RollColumn column, out string text, ref int offsetX, ref int offsetY) { text = ""; if (index < _disassemblyLines.Count) { - if (column == 0) + if (column.Name == AddressColumnName) { text = _disassemblyLines[index].Address.ToHexString(_pcRegisterSize); } - else if (column == 1) + else if (column.Name == InstructionColumnName) { text = _disassemblyLines[index].Mnemonic; } } } - private void DisassemblerView_QueryItemBkColor(int index, int column, ref Color color) + private void DisassemblerView_QueryItemBkColor(int index, InputRoll.RollColumn column, ref Color color) { if (_disassemblyLines.Any() && index < _disassemblyLines.Count) { @@ -97,9 +95,16 @@ namespace BizHawk.Client.EmuHawk } } + private void DecrementCurrentAddress() { + if (_currentDisassemblerAddress == 0) + { + return; + } + uint newaddress = _currentDisassemblerAddress; + while (true) { int bytestoadvance; @@ -137,51 +142,44 @@ namespace BizHawk.Client.EmuHawk } } - private void DisassemblerView_Scroll(object sender, ScrollEventArgs e) + + private bool _blockScroll; + private void DisassemblerView_Scroll(object sender, EventArgs e) { - if (e.Type == ScrollEventType.SmallIncrement) + // This is really really gross, but it works + if (_blockScroll) { - SmallIncrement(); + return; } - if (e.Type == ScrollEventType.SmallDecrement) + var scrollBar = sender as ScrollBar; + if (scrollBar != null) { - SmallDecrement(); - } - } + if (scrollBar.Value > 0) + { + SmallIncrement(); - private void DisassemblerView_Wheel(object sender, MouseEventArgs e) - { - if (e.Delta > 0) - { - SmallDecrement(); - } - if (e.Delta > 120) - { - SmallDecrement(); - } - if (e.Delta > 240) - { - SmallDecrement(); - } + _blockScroll = true; + scrollBar.Value = 14; + _blockScroll = false; + } + else + { + SmallDecrement(); - if (e.Delta < 0) - { - SmallIncrement(); - } - if (e.Delta < -120) - { - SmallIncrement(); - } - if (e.Delta < -240) - { - SmallIncrement(); + if (_currentDisassemblerAddress != 0) + { + _blockScroll = true; + scrollBar.Value = 14; + _blockScroll = false; + } + } } } private void SetDisassemblerItemCount() { - DisassemblerView.ItemCount = DisassemblerView.NumberOfVisibleRows + 1; + DisassemblerView.RowCount = DisassemblerView.VisibleRows + 2; } private void DisassemblerView_SizeChanged(object sender, EventArgs e) @@ -225,7 +223,7 @@ namespace BizHawk.Client.EmuHawk private void CopySelectedDisassembler() { - var indices = DisassemblerView.SelectedIndices; + var indices = DisassemblerView.SelectedRows.ToList(); if (indices.Count > 0) { @@ -256,12 +254,12 @@ namespace BizHawk.Client.EmuHawk private void DisassemblerContextMenu_Opening(object sender, EventArgs e) { - AddBreakpointContextMenuItem.Enabled = DisassemblerView.SelectedIndices.Count > 0; + AddBreakpointContextMenuItem.Enabled = DisassemblerView.SelectedRows.Any(); } private void AddBreakpointContextMenuItem_Click(object sender, EventArgs e) { - var indices = DisassemblerView.SelectedIndices; + var indices = DisassemblerView.SelectedRows.ToList(); if (indices.Count > 0) { diff --git a/BizHawk.Client.EmuHawk/tools/Debugger/GenericDebugger.cs b/BizHawk.Client.EmuHawk/tools/Debugger/GenericDebugger.cs index e15f973653..58fce366dc 100644 --- a/BizHawk.Client.EmuHawk/tools/Debugger/GenericDebugger.cs +++ b/BizHawk.Client.EmuHawk/tools/Debugger/GenericDebugger.cs @@ -10,6 +10,9 @@ namespace BizHawk.Client.EmuHawk { public partial class GenericDebugger : Form, IToolFormAutoConfig, IControlMainform { + private const string AddressColumnName = "Address"; + private const string InstructionColumnName = "Instruction"; + public GenericDebugger() { InitializeComponent(); @@ -17,7 +20,24 @@ namespace BizHawk.Client.EmuHawk DisassemblerView.QueryItemText += DisassemblerView_QueryItemText; DisassemblerView.QueryItemBkColor += DisassemblerView_QueryItemBkColor; - DisassemblerView.VirtualMode = true; + DisassemblerView.AllColumns.Clear(); + DisassemblerView.AllColumns.AddRange(new[] + { + new InputRoll.RollColumn + { + Name = AddressColumnName, + Text = AddressColumnName, + Width = 94, + Type = InputRoll.RollColumn.InputType.Text + }, + new InputRoll.RollColumn + { + Name = InstructionColumnName, + Text = InstructionColumnName, + Width = 291, + Type = InputRoll.RollColumn.InputType.Text + } + }); } private void GenericDebugger_Load(object sender, EventArgs e) @@ -75,7 +95,7 @@ namespace BizHawk.Client.EmuHawk else { DisassemblerBox.Enabled = false; - DisassemblerView.ItemCount = 0; + DisassemblerView.RowCount = 0; DisassemblerBox.Controls.Add(new Label { Location = new Point(UIHelper.ScaleX(35), UIHelper.ScaleY(23)), diff --git a/BizHawk.sln.DotSettings b/BizHawk.sln.DotSettings index fc09226aa4..b6b12fa574 100644 --- a/BizHawk.sln.DotSettings +++ b/BizHawk.sln.DotSettings @@ -184,6 +184,7 @@ True True True + True True True True From 4eea88a9885c9f5e2a2623f244e4e4f7c245555b Mon Sep 17 00:00:00 2001 From: "J.D. Purcell" Date: Sat, 19 Oct 2019 20:50:47 -0400 Subject: [PATCH 070/166] Hotkey Config: Fix when binding key combination if the modifier is released first (e.g. Ctrl+C with Ctrl released first). --- BizHawk.Client.EmuHawk/Input/Input.cs | 77 +++++++------------ BizHawk.Client.EmuHawk/config/HotkeyConfig.cs | 1 - BizHawk.Client.EmuHawk/config/InputWidget.cs | 16 +--- 3 files changed, 30 insertions(+), 64 deletions(-) diff --git a/BizHawk.Client.EmuHawk/Input/Input.cs b/BizHawk.Client.EmuHawk/Input/Input.cs index f950965f29..200e0e72a9 100644 --- a/BizHawk.Client.EmuHawk/Input/Input.cs +++ b/BizHawk.Client.EmuHawk/Input/Input.cs @@ -208,9 +208,8 @@ namespace BizHawk.Client.EmuHawk } } - private readonly WorkingDictionary ModifierState = new WorkingDictionary(); + private readonly Dictionary ModifierState = new Dictionary(); private readonly WorkingDictionary LastState = new WorkingDictionary(); - private readonly WorkingDictionary UnpressState = new WorkingDictionary(); private readonly WorkingDictionary FloatValues = new WorkingDictionary(); private readonly WorkingDictionary FloatDeltas = new WorkingDictionary(); private bool trackdeltas = false; @@ -231,15 +230,6 @@ namespace BizHawk.Client.EmuHawk _Modifiers &= ~currentModifier; } - if (UnpressState.ContainsKey(button)) - { - if (newState) return; - Console.WriteLine($"Removing Unpress {button} with {nameof(newState)} {newState}"); - UnpressState.Remove(button); - LastState[button] = false; - return; - } - //dont generate events for things like Ctrl+LeftControl ModifierKey mods = _Modifiers; if (currentModifier != ModifierKey.None) @@ -256,7 +246,7 @@ namespace BizHawk.Client.EmuHawk //track the pressed events with modifiers that we send so that we can send corresponding unpresses with modifiers //this is an interesting idea, which we may need later, but not yet. //for example, you may see this series of events: press:ctrl+c, release:ctrl, release:c - //but you might would rather have press:ctr+c, release:ctrl+c + //but you might would rather have press:ctrl+c, release:ctrl+c //this code relates the releases to the original presses. //UPDATE - this is necessary for the frame advance key, which has a special meaning when it gets stuck down //so, i am adding it as of 11-sep-2011 @@ -264,21 +254,17 @@ namespace BizHawk.Client.EmuHawk { ModifierState[button] = ie.LogicalButton; } - else + else if (ModifierState.TryGetValue(button, out LogicalButton buttonModifierState)) { - if (ModifierState[button] != null) - { - LogicalButton alreadyReleased = ie.LogicalButton; - var ieModified = new InputEvent - { - LogicalButton = (LogicalButton)ModifierState[button], - EventType = InputEventType.Release, - Source = source - }; - if (ieModified.LogicalButton != alreadyReleased) - _NewEvents.Add(ieModified); - } - ModifierState[button] = null; + var ieModified = new InputEvent + { + LogicalButton = buttonModifierState, + EventType = InputEventType.Release, + Source = source + }; + if (ieModified.LogicalButton != ie.LogicalButton) + _NewEvents.Add(ieModified); + ModifierState.Remove(button); } _NewEvents.Add(ie); @@ -502,7 +488,7 @@ namespace BizHawk.Client.EmuHawk } //returns the next Press event, if available. should be useful - public string GetNextBindEvent() + public string GetNextBindEvent(ref InputEvent lastPress) { //this whole process is intimately involved with the data structures, which can conflict with the input thread. lock (this) @@ -510,33 +496,31 @@ namespace BizHawk.Client.EmuHawk if (InputEvents.Count == 0) return null; AllowInput allowInput = GlobalWin.MainForm.AllowInput(false); - //we only listen to releases for input binding, because we need to distinguish releases of pure modifierkeys from modified keys + //wait for the first release after a press to complete input binding, because we need to distinguish pure modifierkeys from modified keys //if you just pressed ctrl, wanting to bind ctrl, we'd see: pressed:ctrl, unpressed:ctrl //if you just pressed ctrl+c, wanting to bind ctrl+c, we'd see: pressed:ctrl, pressed:ctrl+c, unpressed:ctrl+c, unpressed:ctrl - //so its the first unpress we need to listen for + //but in the 2nd example the unpresses will be swapped if ctrl is released first, so we'll take the last press before the release while (InputEvents.Count != 0) { - var ie = DequeueEvent(); + InputEvent ie = DequeueEvent(); if (ShouldSwallow(allowInput, ie)) continue; - //ignore presses, but as a special perk, we'll accept escape immediately - if (ie.EventType == InputEventType.Press && ie.LogicalButton.Button != "Escape") - continue; + if (ie.EventType == InputEventType.Press) + { + lastPress = ie; + //don't allow presses to directly complete binding except escape which we'll accept as a special perk + if (ie.LogicalButton.Button != "Escape") + continue; + } + else if (lastPress == null) continue; - Console.WriteLine("Bind Event: {0} ", ie); - - foreach (var kvp in LastState) - if (kvp.Value) - { - Console.WriteLine($"Unpressing {kvp.Key}"); - UnpressState[kvp.Key] = true; - } + Console.WriteLine("Bind Event: {0} ", lastPress); InputEvents.Clear(); - return ie.LogicalButton.ToString(); + return lastPress.LogicalButton.ToString(); } return null; @@ -547,14 +531,5 @@ namespace BizHawk.Client.EmuHawk //this should be used by hotkey binders, but we may want modifier key events //to get triggered in the main form public bool EnableIgnoreModifiers = false; - - //sets a key as unpressed for the binding system - public void BindUnpress(System.Windows.Forms.Keys key) - { - //only validated for Return - string keystr = key.ToString(); - UnpressState[keystr] = true; - LastState[keystr] = true; - } } } diff --git a/BizHawk.Client.EmuHawk/config/HotkeyConfig.cs b/BizHawk.Client.EmuHawk/config/HotkeyConfig.cs index 79ba49db1d..5ed5f999a0 100644 --- a/BizHawk.Client.EmuHawk/config/HotkeyConfig.cs +++ b/BizHawk.Client.EmuHawk/config/HotkeyConfig.cs @@ -220,7 +220,6 @@ namespace BizHawk.Client.EmuHawk if (w != null) { HotkeyTabControl.SelectTab((TabPage)w.Parent); - Input.Instance.BindUnpress(e.KeyCode); w.Focus(); } } diff --git a/BizHawk.Client.EmuHawk/config/InputWidget.cs b/BizHawk.Client.EmuHawk/config/InputWidget.cs index 7026051674..4e9d85e990 100644 --- a/BizHawk.Client.EmuHawk/config/InputWidget.cs +++ b/BizHawk.Client.EmuHawk/config/InputWidget.cs @@ -14,8 +14,8 @@ namespace BizHawk.Client.EmuHawk // TODO: when binding, make sure that the new key combo is not in one of the other bindings private readonly Timer _timer = new Timer(); private readonly List _bindings = new List(); - - private string _wasPressed = ""; + + private Input.InputEvent _lastPress; public InputCompositeWidget CompositeWidget { get; set; } @@ -88,9 +88,8 @@ namespace BizHawk.Client.EmuHawk protected override void OnEnter(EventArgs e) { + _lastPress = null; _timer.Start(); - - _wasPressed = Input.Instance.GetNextBindEvent(); BackColor = Color.FromArgb(unchecked((int)0xFFC0FFFF)); // Color.LightCyan is too light on Windows 8, this is a bit darker } @@ -129,11 +128,7 @@ namespace BizHawk.Client.EmuHawk private void ReadKeys() { Input.Instance.Update(); - var bindingStr = Input.Instance.GetNextBindEvent(); - if (!string.IsNullOrEmpty(_wasPressed) && bindingStr == _wasPressed) - { - return; - } + var bindingStr = Input.Instance.GetNextBindEvent(ref _lastPress); if (bindingStr != null) { @@ -171,7 +166,6 @@ namespace BizHawk.Client.EmuHawk _bindings.Add(bindingStr); } - _wasPressed = bindingStr; UpdateLabel(); Increment(); } @@ -188,8 +182,6 @@ namespace BizHawk.Client.EmuHawk { base.OnKeyUp(e); } - - _wasPressed = ""; } protected override void OnKeyDown(KeyEventArgs e) From 7fc4e82ef9fef740b1e5bc4ad21c7f6f63e0180e Mon Sep 17 00:00:00 2001 From: adelikat Date: Sat, 19 Oct 2019 19:32:34 -0500 Subject: [PATCH 071/166] Debugger Breakpoints - use ListView in virtual mode instead of VirtualListView --- .../Debugger/BreakpointControl.Designer.cs | 10 ++-- .../tools/Debugger/BreakpointControl.cs | 51 +++++++------------ 2 files changed, 21 insertions(+), 40 deletions(-) diff --git a/BizHawk.Client.EmuHawk/tools/Debugger/BreakpointControl.Designer.cs b/BizHawk.Client.EmuHawk/tools/Debugger/BreakpointControl.Designer.cs index a30300fc04..7ea0308c42 100644 --- a/BizHawk.Client.EmuHawk/tools/Debugger/BreakpointControl.Designer.cs +++ b/BizHawk.Client.EmuHawk/tools/Debugger/BreakpointControl.Designer.cs @@ -36,7 +36,7 @@ this.RemoveBreakpointButton = new System.Windows.Forms.Button(); this.DuplicateBreakpointButton = new System.Windows.Forms.Button(); this.EditBreakpointButton = new System.Windows.Forms.Button(); - this.BreakpointView = new BizHawk.Client.EmuHawk.VirtualListView(); + this.BreakpointView = new System.Windows.Forms.ListView(); this.columnHeader1 = ((System.Windows.Forms.ColumnHeader)(new System.Windows.Forms.ColumnHeader())); this.columnHeader2 = ((System.Windows.Forms.ColumnHeader)(new System.Windows.Forms.ColumnHeader())); this.columnHeader3 = ((System.Windows.Forms.ColumnHeader)(new System.Windows.Forms.ColumnHeader())); @@ -118,7 +118,6 @@ this.BreakpointView.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom) | System.Windows.Forms.AnchorStyles.Left) | System.Windows.Forms.AnchorStyles.Right))); - this.BreakpointView.BlazingFast = false; this.BreakpointView.CheckBoxes = true; this.BreakpointView.Columns.AddRange(new System.Windows.Forms.ColumnHeader[] { this.columnHeader1, @@ -129,16 +128,13 @@ this.BreakpointView.FullRowSelect = true; this.BreakpointView.GridLines = true; this.BreakpointView.HideSelection = false; - this.BreakpointView.ItemCount = 0; + this.BreakpointView.VirtualListSize = 0; this.BreakpointView.Location = new System.Drawing.Point(0, 19); this.BreakpointView.Name = "BreakpointView"; - this.BreakpointView.SelectAllInProgress = false; - this.BreakpointView.selectedItem = -1; this.BreakpointView.Size = new System.Drawing.Size(366, 365); this.BreakpointView.TabIndex = 5; this.BreakpointView.TabStop = false; this.BreakpointView.UseCompatibleStateImageBehavior = false; - this.BreakpointView.UseCustomBackground = true; this.BreakpointView.View = System.Windows.Forms.View.Details; this.BreakpointView.ItemActivate += new System.EventHandler(this.BreakpointView_ItemActivate); this.BreakpointView.SelectedIndexChanged += new System.EventHandler(this.BreakpointView_SelectedIndexChanged); @@ -184,7 +180,7 @@ #endregion - private VirtualListView BreakpointView; + private System.Windows.Forms.ListView BreakpointView; public System.Windows.Forms.ColumnHeader columnHeader1; private System.Windows.Forms.ColumnHeader columnHeader2; private System.Windows.Forms.Button AddBreakpointButton; diff --git a/BizHawk.Client.EmuHawk/tools/Debugger/BreakpointControl.cs b/BizHawk.Client.EmuHawk/tools/Debugger/BreakpointControl.cs index 5d8dfc5bc9..9594007e9d 100644 --- a/BizHawk.Client.EmuHawk/tools/Debugger/BreakpointControl.cs +++ b/BizHawk.Client.EmuHawk/tools/Debugger/BreakpointControl.cs @@ -22,8 +22,7 @@ namespace BizHawk.Client.EmuHawk public BreakpointControl() { InitializeComponent(); - BreakpointView.QueryItemText += BreakPointView_QueryItemText; - BreakpointView.QueryItemBkColor += BreakPointView_QueryItemBkColor; + BreakpointView.RetrieveVirtualItem += BreakPointView_QueryItemText; BreakpointView.VirtualMode = true; _breakpoints.Callback = BreakpointCallback; } @@ -33,30 +32,16 @@ namespace BizHawk.Client.EmuHawk UpdateStatsLabel(); } - private void BreakPointView_QueryItemText(int index, int column, out string text) + private void BreakPointView_QueryItemText(object sender, RetrieveVirtualItemEventArgs e) { - text = ""; - switch (column) - { - case 0: - text = $"{_breakpoints[index].Address:X}"; - break; - case 1: - text = $"{_breakpoints[index].AddressMask:X}"; - break; - case 2: - text = _breakpoints[index].Type.ToString(); - break; - case 3: - text = _breakpoints[index].Name; - break; - } - } + var entry = _breakpoints[e.ItemIndex]; + e.Item = new ListViewItem($"{entry.Address:X}"); + e.Item.SubItems.Add($"{entry.AddressMask:X}"); + e.Item.SubItems.Add(entry.Type.ToString()); + e.Item.SubItems.Add(entry.Name); - private void BreakPointView_QueryItemBkColor(int index, int column, ref Color color) - { - color = _breakpoints[index].ReadOnly ? SystemColors.Control - : _breakpoints[index].Active ? Color.LightCyan + e.Item.BackColor = entry.ReadOnly ? SystemColors.Control + : entry.Active ? Color.LightCyan : Color.White; } @@ -90,7 +75,7 @@ namespace BizHawk.Client.EmuHawk { CheckForNewBreakpoints(); - BreakpointView.ItemCount = _breakpoints.Count; + BreakpointView.VirtualListSize = _breakpoints.Count; UpdateStatsLabel(); } } @@ -124,7 +109,7 @@ namespace BizHawk.Client.EmuHawk _breakpoints.Add(new Breakpoint(Core, callback)); } - BreakpointView.ItemCount = _breakpoints.Count; + BreakpointView.VirtualListSize = _breakpoints.Count; BreakpointView.Refresh(); UpdateBreakpointRemoveButton(); UpdateStatsLabel(); @@ -146,7 +131,7 @@ namespace BizHawk.Client.EmuHawk { _breakpoints.Add(Core, MemoryDomains.SystemBus.Name, address, mask, type); - BreakpointView.ItemCount = _breakpoints.Count; + BreakpointView.VirtualListSize = _breakpoints.Count; UpdateBreakpointRemoveButton(); UpdateStatsLabel(); } @@ -160,7 +145,7 @@ namespace BizHawk.Client.EmuHawk _breakpoints.Add(Core, MemoryDomains.SystemBus.Name, b.Address, b.AddressMask, b.BreakType); } - BreakpointView.ItemCount = _breakpoints.Count; + BreakpointView.VirtualListSize = _breakpoints.Count; UpdateBreakpointRemoveButton(); UpdateStatsLabel(); } @@ -208,7 +193,7 @@ namespace BizHawk.Client.EmuHawk _breakpoints.Remove(item); } - BreakpointView.ItemCount = _breakpoints.Count; + BreakpointView.VirtualListSize = _breakpoints.Count; UpdateBreakpointRemoveButton(); UpdateStatsLabel(); } @@ -243,7 +228,7 @@ namespace BizHawk.Client.EmuHawk item.Active ^= true; } - BreakpointView.ItemCount = _breakpoints.Count; + BreakpointView.VirtualListSize = _breakpoints.Count; UpdateBreakpointRemoveButton(); UpdateStatsLabel(); } @@ -270,7 +255,7 @@ namespace BizHawk.Client.EmuHawk item.Active ^= true; } - BreakpointView.ItemCount = _breakpoints.Count; + BreakpointView.VirtualListSize = _breakpoints.Count; UpdateStatsLabel(); } @@ -288,7 +273,7 @@ namespace BizHawk.Client.EmuHawk } } - BreakpointView.ItemCount = _breakpoints.Count; + BreakpointView.VirtualListSize = _breakpoints.Count; UpdateBreakpointRemoveButton(); UpdateStatsLabel(); } @@ -310,7 +295,7 @@ namespace BizHawk.Client.EmuHawk } } - BreakpointView.ItemCount = _breakpoints.Count; + BreakpointView.VirtualListSize = _breakpoints.Count; UpdateBreakpointRemoveButton(); UpdateStatsLabel(); } From ccdf616d461a644424165b84e9eac51eccc90549 Mon Sep 17 00:00:00 2001 From: adelikat Date: Sat, 19 Oct 2019 20:02:46 -0500 Subject: [PATCH 072/166] convert Tastudio UndoHistory from VirtualListView to InputRoll --- .../TAStudio/UndoHistoryForm.Designer.cs | 32 ++------- .../tools/TAStudio/UndoHistoryForm.cs | 65 ++++++++++--------- 2 files changed, 42 insertions(+), 55 deletions(-) diff --git a/BizHawk.Client.EmuHawk/tools/TAStudio/UndoHistoryForm.Designer.cs b/BizHawk.Client.EmuHawk/tools/TAStudio/UndoHistoryForm.Designer.cs index 2e4168040e..14b81b3ec1 100644 --- a/BizHawk.Client.EmuHawk/tools/TAStudio/UndoHistoryForm.Designer.cs +++ b/BizHawk.Client.EmuHawk/tools/TAStudio/UndoHistoryForm.Designer.cs @@ -40,9 +40,7 @@ this.AutoScrollCheck = new System.Windows.Forms.CheckBox(); this.MaxStepsNum = new System.Windows.Forms.NumericUpDown(); this.label1 = new System.Windows.Forms.Label(); - this.HistoryView = new BizHawk.Client.EmuHawk.VirtualListView(); - this.columnHeader1 = ((System.Windows.Forms.ColumnHeader)(new System.Windows.Forms.ColumnHeader())); - this.columnHeader2 = ((System.Windows.Forms.ColumnHeader)(new System.Windows.Forms.ColumnHeader())); + this.HistoryView = new InputRoll(); this.RightClickMenu.SuspendLayout(); ((System.ComponentModel.ISupportInitialize)(this.MaxStepsNum)).BeginInit(); this.SuspendLayout(); @@ -168,35 +166,19 @@ this.HistoryView.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom) | System.Windows.Forms.AnchorStyles.Left) | System.Windows.Forms.AnchorStyles.Right))); - this.HistoryView.BlazingFast = false; - this.HistoryView.Columns.AddRange(new System.Windows.Forms.ColumnHeader[] { - this.columnHeader1, - this.columnHeader2}); - this.HistoryView.HideSelection = false; - this.HistoryView.ItemCount = 0; + this.HistoryView.RowCount = 0; this.HistoryView.Location = new System.Drawing.Point(10, 10); this.HistoryView.MultiSelect = false; this.HistoryView.Name = "HistoryView"; - this.HistoryView.SelectAllInProgress = false; - this.HistoryView.selectedItem = -1; this.HistoryView.Size = new System.Drawing.Size(369, 213); this.HistoryView.TabIndex = 2; - this.HistoryView.UseCompatibleStateImageBehavior = false; this.HistoryView.UseCustomBackground = true; - this.HistoryView.View = System.Windows.Forms.View.Details; this.HistoryView.DoubleClick += new System.EventHandler(this.HistoryView_DoubleClick); this.HistoryView.MouseDown += new System.Windows.Forms.MouseEventHandler(this.HistoryView_MouseDown); this.HistoryView.MouseUp += new System.Windows.Forms.MouseEventHandler(this.HistoryView_MouseUp); - // - // columnHeader1 - // - this.columnHeader1.Text = "ID"; - this.columnHeader1.Width = 40; - // - // columnHeader2 - // - this.columnHeader2.Text = "Undo Step"; - this.columnHeader2.Width = 322; + this.HistoryView.AllowColumnReorder = false; + this.HistoryView.AllowColumnResize = false; + this.HistoryView.FullRowSelect = true; // // UndoHistoryForm // @@ -225,9 +207,7 @@ private System.Windows.Forms.Button ClearButton; private System.Windows.Forms.Button UndoButton; - private VirtualListView HistoryView; - private System.Windows.Forms.ColumnHeader columnHeader1; - private System.Windows.Forms.ColumnHeader columnHeader2; + private InputRoll HistoryView; private System.Windows.Forms.Button RedoButton; private System.Windows.Forms.ContextMenuStrip RightClickMenu; private System.Windows.Forms.ToolStripMenuItem undoHereToolStripMenuItem; diff --git a/BizHawk.Client.EmuHawk/tools/TAStudio/UndoHistoryForm.cs b/BizHawk.Client.EmuHawk/tools/TAStudio/UndoHistoryForm.cs index 5b37c6f46d..b08c0e49db 100644 --- a/BizHawk.Client.EmuHawk/tools/TAStudio/UndoHistoryForm.cs +++ b/BizHawk.Client.EmuHawk/tools/TAStudio/UndoHistoryForm.cs @@ -1,5 +1,6 @@ using System; using System.Drawing; +using System.Linq; using System.Windows.Forms; using BizHawk.Client.Common; @@ -7,6 +8,9 @@ namespace BizHawk.Client.EmuHawk { public partial class UndoHistoryForm : Form { + private const string IdColumnName = "ID"; + private const string UndoColumnName = "Undo Step"; + private readonly TAStudio _tastudio; private string _lastUndoAction; private TasMovieChangeLog Log => _tastudio.CurrentTasMovie.ChangeLog; @@ -19,30 +23,30 @@ namespace BizHawk.Client.EmuHawk HistoryView.QueryItemText += HistoryView_QueryItemText; HistoryView.QueryItemBkColor += HistoryView_QueryItemBkColor; - HistoryView.Columns[1].Width = 280; + HistoryView.AllColumns.Clear(); + HistoryView.AllColumns.AddRange(new[] + { + new InputRoll.RollColumn { Name = IdColumnName, Text = IdColumnName, Width = 40, Type = InputRoll.RollColumn.InputType.Text }, + new InputRoll.RollColumn { Name = UndoColumnName, Text = UndoColumnName, Width = 280, Type = InputRoll.RollColumn.InputType.Text } + }); MaxStepsNum.Value = Log.MaxSteps; } - private void HistoryView_QueryItemText(int row, int column, out string text) + private void HistoryView_QueryItemText(int index, InputRoll.RollColumn column, out string text, ref int offsetX, ref int offsetY) { - text = column == 1 - ? Log.Names[row] - : row.ToString(); + text = column.Name == UndoColumnName + ? Log.Names[index] + : index.ToString(); } - private void HistoryView_QueryItemBkColor(int row, int column, ref Color color) + private void HistoryView_QueryItemBkColor(int index, InputRoll.RollColumn column, ref Color color) { - if (column == 0) - { - return; - } - - if (row == Log.UndoIndex) + if (index == Log.UndoIndex) { color = TAStudio.GreenZone_InputLog; } - else if (row > Log.UndoIndex) + else if (index > Log.UndoIndex) { color = TAStudio.LagZone_InputLog; } @@ -50,12 +54,12 @@ namespace BizHawk.Client.EmuHawk public void UpdateValues() { - HistoryView.ItemCount = Log.Names.Count; + HistoryView.RowCount = Log.Names.Count; if (AutoScrollCheck.Checked && _lastUndoAction != Log.NextUndoStepName) { - HistoryView.ensureVisible(Log.UndoIndex); - HistoryView.clearSelection(); - HistoryView.SelectItem(Log.UndoIndex - 1, true); + HistoryView.ScrollToIndex(Log.UndoIndex); + HistoryView.DeselectAll(); + HistoryView.SelectRow(Log.UndoIndex - 1, true); } _lastUndoAction = Log.NextUndoStepName; @@ -81,9 +85,13 @@ namespace BizHawk.Client.EmuHawk _tastudio.RefreshDialog(); } + private int SelectedItem => HistoryView.SelectedRows.Any() + ? HistoryView.SelectedRows.First() + : -1; + private void HistoryView_DoubleClick(object sender, EventArgs e) { - if (Log.UndoIndex <= HistoryView.selectedItem) + if (Log.UndoIndex <= SelectedItem) { return; } @@ -92,7 +100,7 @@ namespace BizHawk.Client.EmuHawk { Log.Undo(); } - while (Log.UndoIndex > HistoryView.selectedItem); + while (Log.UndoIndex > SelectedItem); UpdateValues(); } @@ -105,9 +113,9 @@ namespace BizHawk.Client.EmuHawk } else if (e.Button == MouseButtons.Left) { - if (HistoryView.selectedItem == -1) + if (SelectedItem == -1) { - HistoryView.SelectItem(_hackSelect, true); + HistoryView.SelectRow(_hackSelect, true); } } } @@ -117,13 +125,12 @@ namespace BizHawk.Client.EmuHawk private void HistoryView_MouseDown(object sender, MouseEventArgs e) { - HistoryView.SelectItem((e.Y / HistoryView.LineHeight) + HistoryView.VScrollPos - 1, true); - _hackSelect = HistoryView.selectedItem; + _hackSelect = SelectedItem; } private void UndoHereMenuItem_Click(object sender, EventArgs e) { - if (HistoryView.selectedItem == -1 || Log.UndoIndex < HistoryView.selectedItem) + if (SelectedItem == -1 || Log.UndoIndex < SelectedItem) { return; } @@ -132,14 +139,14 @@ namespace BizHawk.Client.EmuHawk { Log.Undo(); } - while (Log.UndoIndex >= HistoryView.selectedItem); + while (Log.UndoIndex >= SelectedItem); UpdateValues(); } private void RedoHereMenuItem_Click(object sender, EventArgs e) { - if (HistoryView.selectedItem == -1 || Log.UndoIndex >= HistoryView.selectedItem) + if (SelectedItem == -1 || Log.UndoIndex >= SelectedItem) { return; } @@ -148,16 +155,16 @@ namespace BizHawk.Client.EmuHawk { Log.Redo(); } - while (Log.UndoIndex < HistoryView.selectedItem); + while (Log.UndoIndex < SelectedItem); UpdateValues(); } private void ClearHistoryToHereMenuItem_Click(object sender, EventArgs e) { - if (HistoryView.selectedItem != -1) + if (SelectedItem != -1) { - Log.ClearLog(HistoryView.selectedItem); + Log.ClearLog(SelectedItem); } UpdateValues(); From bc4498b9ddaaf00f2369e0c0a9f5db40787efdd0 Mon Sep 17 00:00:00 2001 From: adelikat Date: Sat, 19 Oct 2019 20:06:59 -0500 Subject: [PATCH 073/166] VirtualListView begone! --- .../BizHawk.Client.EmuHawk.csproj | 1 - .../CustomControls/VirtualListView.cs | 854 ------------------ 2 files changed, 855 deletions(-) delete mode 100644 BizHawk.Client.EmuHawk/CustomControls/VirtualListView.cs diff --git a/BizHawk.Client.EmuHawk/BizHawk.Client.EmuHawk.csproj b/BizHawk.Client.EmuHawk/BizHawk.Client.EmuHawk.csproj index d1c2c3b684..02e3c5cbf7 100644 --- a/BizHawk.Client.EmuHawk/BizHawk.Client.EmuHawk.csproj +++ b/BizHawk.Client.EmuHawk/BizHawk.Client.EmuHawk.csproj @@ -637,7 +637,6 @@ Component - diff --git a/BizHawk.Client.EmuHawk/CustomControls/VirtualListView.cs b/BizHawk.Client.EmuHawk/CustomControls/VirtualListView.cs deleted file mode 100644 index 6f800dc407..0000000000 --- a/BizHawk.Client.EmuHawk/CustomControls/VirtualListView.cs +++ /dev/null @@ -1,854 +0,0 @@ -using System; -using System.ComponentModel; -using System.Diagnostics; -using System.Drawing; -using System.Runtime.InteropServices; -using System.Windows.Forms; - -namespace BizHawk.Client.EmuHawk -{ - #region win32interop - - [StructLayout(LayoutKind.Sequential)] - internal struct LvDispInfo - { - public NmHdr Hdr; - public LvItem Item; - } - - [StructLayout(LayoutKind.Sequential)] - internal struct NmHdr - { - public IntPtr HwndFrom; - public IntPtr IdFrom; - public int Code; - } - - [StructLayout(LayoutKind.Sequential)] - internal struct NmItemActivate - { - public NmHdr Hdr; - public int Item; - public int SubItem; - public uint NewState; - public uint OldState; - public uint uChanged; - public POINT Action; - public uint lParam; - public uint KeyFlags; - } - - [StructLayout(LayoutKind.Sequential)] - internal struct RECT - { - public int Top; - public int Left; - public int Bottom; - public int Right; - } - - [StructLayout(LayoutKind.Sequential)] - internal struct NmCustomDrawInfo - { - public NmHdr Hdr; - public uint dwDrawStage; - public IntPtr Hdc; - public RECT Rect; - public IntPtr dwItemSpec; - public uint ItemState; - private int _pad64bits; - public IntPtr lItemlParam; - } - - [StructLayout(LayoutKind.Sequential)] - internal struct NmLvCustomDraw - { - public NmCustomDrawInfo Nmcd; - public int ClearText; - public int ClearTextBackground; - public int SubItem; - } - - - - [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)] - internal struct LvItem - { - public uint Mask; - public int Item; - public int SubItem; - public uint State; - public uint StateMask; - public IntPtr PszText; - public int cchTextMax; - public int Image; - public IntPtr lParam; - public int Indent; - } - - [FlagsAttribute] - internal enum CustomDrawReturnFlags - { - CDRF_DODEFAULT = 0x00000000, - CDRF_NEWFONT = 0x00000002, - CDRF_SKIPDEFAULT = 0x00000004, - CDRF_NOTIFYPOSTPAINT = 0x00000010, - CDRF_NOTIFYITEMDRAW = 0x00000020, - CDRF_NOTIFYSUBITEMDRAW = 0x00000020, - CDRF_NOTIFYPOSTERASE = 0x00000040, - } - - [FlagsAttribute] - internal enum CustomDrawDrawStageFlags - { - CDDS_PREPAINT = 0x00000001, - CDDS_POSTPAINT = 0x00000002, - CDDS_PREERASE = 0x00000003, - CDDS_POSTERASE = 0x00000004, - - // the 0x000010000 bit means it's individual item specific - CDDS_ITEM = 0x00010000, - CDDS_ITEMPREPAINT = (CDDS_ITEM | CDDS_PREPAINT), - CDDS_ITEMPOSTPAINT = (CDDS_ITEM | CDDS_POSTPAINT), - CDDS_ITEMPREERASE = (CDDS_ITEM | CDDS_PREERASE), - CDDS_ITEMPOSTERASE = (CDDS_ITEM | CDDS_POSTERASE), - CDDS_SUBITEM = 0x00020000, - CDDS_SUBITEMPREPAINT = (CDDS_SUBITEM | CDDS_ITEMPREPAINT), - CDDS_SUBITEMPOSTPAINT = (CDDS_SUBITEM | CDDS_ITEMPOSTPAINT), - CDDS_SUBITEMPREERASE = (CDDS_SUBITEM | CDDS_ITEMPREERASE), - CDDS_SUBITEMPOSTERASE = (CDDS_SUBITEM | CDDS_ITEMPOSTERASE), - } - - [FlagsAttribute] - internal enum LvHitTestFlags - { - LVHT_NOWHERE = 0x0001, - LVHT_ONITEMICON = 0x0002, - LVHT_ONITEMLABEL = 0x0004, - LVHT_ONITEMSTATEICON = 0x0008, - LVHT_ONITEM = (LVHT_ONITEMICON | LVHT_ONITEMLABEL | LVHT_ONITEMSTATEICON), - - LVHT_ABOVE = 0x0008, - LVHT_BELOW = 0x0010, - LVHT_TORIGHT = 0x0020, - LVHT_TOLEFT = 0x0040 - } - - [StructLayout(LayoutKind.Sequential)] - internal struct POINT - { - public int X; - public int Y; - } - - [StructLayout(LayoutKind.Sequential)] - internal class LvHitTestInfo - { - public POINT Point; - public uint Flags; - public int Item; - public int SubItem; - } - - [StructLayout(LayoutKind.Sequential)] - internal struct NMLISTVIEW - { - public NmHdr hdr; - public int iItem; - public int iSubItem; - public uint uNewState; - public uint uOldState; - public uint uChanged; - public POINT ptAction; - public IntPtr lParam; - } - - - internal enum ListViewItemMask : short - { - LVIF_TEXT = 0x0001, - LVIF_IMAGE = 0x0002, - LVIF_PARAM = 0x0004, - LVIF_STATE = 0x0008, - - LVIF_INDENT = 0x0010, - LVIF_NORECOMPUTE = 0x0800, - LVIF_GROUPID = 0x0100, - LVIF_COLUMNS = 0x0200 - } - - internal enum LvNi - { - ALL = 0x0000, - FOCUSED = 0x0001, - SELECTED = 0x0002, - CUT = 0x0004, - DROPHILITED = 0x0008, - - ABOVE = 0x0100, - BELOW = 0x0200, - TOLEFT = 0x0400, - TORIGHT = 0x0800 - } - - internal enum ListViewMessages - { - LVM_FIRST = 0x1000, - LVM_GETITEMCOUNT = (LVM_FIRST + 4), - LVM_SETCALLBACKMASK = (LVM_FIRST + 11), - LVM_GETNEXTITEM = (LVM_FIRST + 12), - LVM_HITTEST = (LVM_FIRST + 18), - LVM_ENSUREVISIBLE = (LVM_FIRST + 19), - LVM_SETITEMSTATE = (LVM_FIRST + 43), - LVM_GETITEMSTATE = (LVM_FIRST + 44), - LVM_SETITEMCOUNT = (LVM_FIRST + 47), - LVM_GETSUBITEMRECT = (LVM_FIRST + 56) - } - - internal enum ListViewStyles : short - { - LVS_OWNERDATA = 0x1000, - LVS_SORTASCENDING = 0x0010, - LVS_SORTDESCENDING = 0x0020, - LVS_SHAREIMAGELISTS = 0x0040, - LVS_NOLABELWRAP = 0x0080, - LVS_AUTOARRANGE = 0x0100 - } - - internal enum ListViewStylesICF : uint - { - LVSICF_NOINVALIDATEALL = 0x00000001, - LVSICF_NOSCROLL = 0x00000002 - } - - internal enum WindowsMessage : uint - { - WM_ERASEBKGND = 0x0014, - WM_SCROLL = 0x115, - WM_LBUTTONDOWN = 0x0201, - WM_LBUTTONUP = 0x0202, - WM_LBUTTONDBLCLK = 0x0203, - WM_RBUTTONDOWN = 0x0204, - WM_RBUTTONUP = 0x0205, - WM_RBUTTONDBLCLK = 0x0206, - WM_SETFOCUS = 0x0007, - WM_NOTIFY = 0x004E, - WM_USER = 0x0400, - WM_REFLECT = WM_USER + 0x1c00 - } - - internal enum Notices - { - NM_FIRST = 0, - NM_CUSTOMDRAW = NM_FIRST - 12, - NM_CLICK = NM_FIRST - 2, - NM_DBLCLICK = NM_FIRST - 3, - } - - internal enum ListViewNotices - { - LVN_FIRST = (0 - 100), - LVN_LAST = (0 - 199), - LVN_BEGINDRAG = LVN_FIRST - 9, - LVN_BEGINRDRAG = LVN_FIRST - 11, - LVN_GETDISPINFOA = LVN_FIRST - 50, - LVN_GETDISPINFOW = LVN_FIRST - 77, - LVN_SETDISPINFOA = LVN_FIRST - 51, - LVN_SETDISPINFOW = LVN_FIRST - 78, - LVN_ODCACHEHINT = LVN_FIRST - 13, - LVN_ODFINDITEMW = LVN_FIRST - 79 - } - - [Flags] - internal enum ListViewCallBackMask : uint - { - LVIS_FOCUSED = 0x0001, - LVIS_SELECTED = 0x0002, - LVIS_CUT = 0x0004, - LVIS_DROPHILITED = 0x0008, - LVIS_GLOW = 0x0010, - LVIS_ACTIVATING = 0x0020, - - LVIS_OVERLAYMASK = 0x0F00, - LVIS_STATEIMAGEMASK = 0xF000, - } - - #endregion - - #region VirtualListView Delegates - - /// - /// Retrieve the background color for a Listview cell (item and subitem). - /// - /// Listview item (row). - /// Listview subitem (column). - /// Background color to use - public delegate void QueryItemBkColorHandler(int item, int subItem, ref Color color); - - /// - /// Retrieve the text for a Listview cell (item and subitem). - /// - /// Listview item (row). - /// Listview subitem (column). - /// Text to display. - public delegate void QueryItemTextHandler(int item, int subItem, out string text); - - /// - /// Retrieve the image index for a Listview item. - /// - /// Listview item (row). - /// Listview subitem (column) - should always be zero. - /// Index of associated ImageList. - public delegate void QueryItemImageHandler(int item, int subItem, out int imageIndex); - - /// - /// Retrieve the indent for a Listview item. The indent is always width of an image. - /// For example, 1 indents the Listview item one image width. - /// - /// Listview item (row). - /// The amount to indent the Listview item. - public delegate void QueryItemIndentHandler(int item, out int itemIndent); - - public delegate void QueryItemHandler(int idx, out ListViewItem item); - - #endregion - - /// - /// VirtualListView is a virtual Listview which allows for a large number of items(rows) - /// to be displayed. The virtual Listview contains very little actual information - - /// mainly item selection and focus information. - /// - public class VirtualListView : ListView - { - // store the item count to prevent the call to SendMessage(LVM_GETITEMCOUNT) - private int _itemCount; - - #region Display query callbacks - - /// - /// Fire the QueryItemBkColor event which requests the background color for the passed Listview cell - /// - public event QueryItemBkColorHandler QueryItemBkColor; - - /// - /// Fire the QueryItemText event which requests the text for the passed Listview cell. - /// - [Category("Data")] - public event QueryItemTextHandler QueryItemText; - - /// - /// Fire the QueryItemImage event which requests the ImageIndex for the passed Listview item. - /// - [Category("Data")] - public event QueryItemImageHandler QueryItemImage; - - /// - /// Fire the QueryItemIndent event which requests the indent for the passed Listview item. - /// - [Category("Data")] - public event QueryItemIndentHandler QueryItemIndent; - - [Category("Data")] - public event QueryItemHandler QueryItem; - - #endregion - - #region Properties - - /// - /// Gets or sets the sets the virtual number of items to be displayed. - /// - [Category("Behavior")] - public int ItemCount - { - get - { - return _itemCount; - } - - set - { - _itemCount = value; - - // If the virtual item count is set before the handle is created - // then the image lists don't get loaded properly - if (!IsHandleCreated) - { - return; - } - - SetVirtualItemCount(); - } - } - - /// - /// Gets or sets how list items are to be displayed. - /// Hide the ListView.View property. - /// Virtual Listviews only allow Details or List. - /// - public new View View - { - get - { - return base.View; - } - - set - { - if (value == View.LargeIcon || - value == View.SmallIcon) - { - throw new ArgumentException($"Icon views are invalid for virtual {nameof(ListView)}s", nameof(View)); - } - - base.View = value; - } - } - - /// - /// Gets the required creation parameters when the control handle is created. - /// Use LVS_OWNERDATA to set this as a virtual Listview. - /// - protected override CreateParams CreateParams - { - get - { - var cp = base.CreateParams; - - // LVS_OWNERDATA style must be set when the control is created - cp.Style |= (int)ListViewStyles.LVS_OWNERDATA; - return cp; - } - } - - #endregion - - [Browsable(false)] - [DesignerSerializationVisibilityAttribute(DesignerSerializationVisibility.Hidden)] - public int LineHeight { get; private set; } - - [Browsable(false)] - [DesignerSerializationVisibilityAttribute(DesignerSerializationVisibility.Hidden)] - public int NumberOfVisibleRows - { - get - { - return Height / LineHeight; - } - } - - #region Constructors - - /// - /// Initializes a new instance of the class. - /// Create a new instance of this control. - /// - public VirtualListView() - { - // virtual listviews must be Details or List view with no sorting - View = View.Details; - Sorting = SortOrder.None; - - UseCustomBackground = true; - - ptrlvhti = Marshal.AllocHGlobal(Marshal.SizeOf(typeof(LvHitTestInfo))); - - SetStyle(ControlStyles.OptimizedDoubleBuffer, true); - SetStyle(ControlStyles.Opaque, true); - SetStyle(ControlStyles.AllPaintingInWmPaint, true); - - LineHeight = this.Font.Height + 5; - } - - ~VirtualListView() - { - Marshal.FreeHGlobal(ptrlvhti); - } - - #endregion - - #region Methods - /// - /// Set the state of the passed Listview item's index. - /// - /// Listview item's index. - /// Select the passed item? - public void SelectItem(int index, bool selected) - { - var ptrItem = IntPtr.Zero; - - try - { - // Determine whether selecting or unselecting. - uint select = selected ? (uint)ListViewCallBackMask.LVIS_SELECTED : 0; - - // Fill in the LVITEM structure with state fields. - var stateItem = new LvItem - { - Mask = (uint)ListViewItemMask.LVIF_STATE, - Item = index, - SubItem = 0, - State = @select, - StateMask = (uint)ListViewCallBackMask.LVIS_SELECTED - }; - - // Copy the structure to unmanaged memory. - ptrItem = Marshal.AllocHGlobal(Marshal.SizeOf(stateItem.GetType())); - Marshal.StructureToPtr(stateItem, ptrItem, true); - - // Send the message to the control window. - Win32.SendMessage( - this.Handle, - (int)ListViewMessages.LVM_SETITEMSTATE, - (IntPtr)index, - ptrItem); - } - catch (Exception ex) - { - System.Diagnostics.Trace.WriteLine($"VirtualListView.SetItemState error={ex.Message}"); - - // TODO: should this eat any exceptions? - throw; - } - finally - { - // Always release the unmanaged memory. - if (ptrItem != IntPtr.Zero) - { - Marshal.FreeHGlobal(ptrItem); - } - } - } - - private void SetVirtualItemCount() - { - Win32.SendMessage( - this.Handle, - (int)ListViewMessages.LVM_SETITEMCOUNT, - (IntPtr)this._itemCount, - IntPtr.Zero); - } - - protected void OnDispInfoNotice(ref Message m, bool useAnsi) - { - var info = (LvDispInfo)m.GetLParam(typeof(LvDispInfo)); - - if ((info.Item.Mask & (uint)ListViewItemMask.LVIF_TEXT) > 0) - { - if (QueryItemText != null) - { - string lvtext; - QueryItemText(info.Item.Item, info.Item.SubItem, out lvtext); - if (lvtext != null) - { - try - { - int maxIndex = Math.Min(info.Item.cchTextMax - 1, lvtext.Length); - var data = new char[maxIndex + 1]; - lvtext.CopyTo(0, data, 0, lvtext.Length); - data[maxIndex] = '\0'; - Marshal.Copy(data, 0, info.Item.PszText, data.Length); - } - catch (Exception e) - { - Debug.WriteLine($"Failed to copy text name from client: {e}", $"{nameof(VirtualListView)}.{nameof(OnDispInfoNotice)}"); - } - } - } - } - - if ((info.Item.Mask & (uint)ListViewItemMask.LVIF_IMAGE) > 0) - { - int imageIndex = 0; - if (QueryItemImage != null) - { - QueryItemImage(info.Item.Item, info.Item.SubItem, out imageIndex); - } - - info.Item.Image = imageIndex; - Marshal.StructureToPtr(info, m.LParam, false); - } - - if ((info.Item.Mask & (uint)ListViewItemMask.LVIF_INDENT) > 0) - { - int itemIndent = 0; - if (QueryItemIndent != null) - { - QueryItemIndent(info.Item.Item, out itemIndent); - } - - info.Item.Indent = itemIndent; - Marshal.StructureToPtr(info, m.LParam, false); - } - - m.Result = new IntPtr(0); - } - - protected void OnCustomDrawNotice(ref Message m) - { - var cd = (NmLvCustomDraw)m.GetLParam(typeof(NmLvCustomDraw)); - switch (cd.Nmcd.dwDrawStage) - { - case (int)CustomDrawDrawStageFlags.CDDS_ITEMPREPAINT: - case (int)CustomDrawDrawStageFlags.CDDS_PREPAINT: - m.Result = new IntPtr((int)CustomDrawReturnFlags.CDRF_NOTIFYSUBITEMDRAW); - break; - case (int)CustomDrawDrawStageFlags.CDDS_SUBITEMPREPAINT: - if (QueryItemBkColor != null) - { - var color = Color.FromArgb(cd.ClearTextBackground & 0xFF, (cd.ClearTextBackground >> 8) & 0xFF, (cd.ClearTextBackground >> 16) & 0xFF); - QueryItemBkColor(cd.Nmcd.dwItemSpec.ToInt32(), cd.SubItem, ref color); - cd.ClearTextBackground = (color.B << 16) | (color.G << 8) | color.R; - Marshal.StructureToPtr(cd, m.LParam, false); - } - - m.Result = new IntPtr((int)CustomDrawReturnFlags.CDRF_DODEFAULT); - break; - } - } - - /// - /// Event to be fired whenever the control scrolls - /// - public event ScrollEventHandler Scroll; - protected virtual void OnScroll(ScrollEventArgs e) - { - var handler = this.Scroll; - if (handler != null) - { - handler(this, e); - } - } - - [DllImport("user32.dll", CharSet = CharSet.Auto)] - public static extern int GetScrollPos(IntPtr hWnd, Orientation nBar); - - /// - /// Gets the Vertical Scroll position of the control. - /// - public int VScrollPos - { - get { return GetScrollPos(this.Handle, Orientation.Vertical); } - } - - protected override void WndProc(ref Message m) - { - var messageProcessed = false; - switch (m.Msg) - { - case (int)WindowsMessage.WM_REFLECT + (int)WindowsMessage.WM_NOTIFY: - var nm1 = (NmHdr)m.GetLParam(typeof(NmHdr)); - switch (nm1.Code) - { - case (int)Notices.NM_CUSTOMDRAW: - OnCustomDrawNotice(ref m); - messageProcessed = true; - - if (QueryItemBkColor == null || !UseCustomBackground) - { - m.Result = (IntPtr)0; - } - - break; - case (int)ListViewNotices.LVN_GETDISPINFOW: - OnDispInfoNotice(ref m, false); - messageProcessed = true; - break; - case (int)ListViewNotices.LVN_BEGINDRAG: - OnBeginItemDrag(MouseButtons.Left, ref m); - messageProcessed = true; - break; - case (int)ListViewNotices.LVN_BEGINRDRAG: - OnBeginItemDrag(MouseButtons.Right, ref m); - messageProcessed = true; - break; - } - - break; - case (int)WindowsMessage.WM_SCROLL: - // http://stackoverflow.com/questions/1851620/handling-scroll-event-on-listview-in-c-sharp - OnScroll(new ScrollEventArgs((ScrollEventType)(m.WParam.ToInt32() & 0xffff), m.WParam.ToInt32())); - break; - case (int)WindowsMessage.WM_ERASEBKGND: - if (BlazingFast) - { - messageProcessed = true; - m.Result = new IntPtr(1); - } - - break; - } - - if (!messageProcessed) - { - try - { - base.WndProc(ref m); - } - catch (Exception ex) - { - Trace.WriteLine($"Message {m} caused an exception: {ex.Message}"); - } - } - } - - public bool BlazingFast { get; set; } - public bool UseCustomBackground { get; set; } - - protected ListViewItem GetItem(int idx) - { - ListViewItem item = null; - if (QueryItem != null) - { - QueryItem(idx, out item); - } - - if (item == null) - { - throw new ArgumentException($"cannot find item {idx} via {nameof(QueryItem)} event"); - } - - return item; - } - - protected void OnBeginItemDrag(MouseButtons mouseButton, ref Message m) - { - var info = (NMLISTVIEW)m.GetLParam(typeof(NMLISTVIEW)); - ListViewItem item = null; - if (QueryItem != null) - { - QueryItem(info.iItem, out item); - } - - OnItemDrag(new ItemDragEventArgs(mouseButton, item)); - } - - protected override void OnHandleCreated(EventArgs e) - { - base.OnHandleCreated(e); - - // ensure the value for ItemCount is sent to the control properly if the user set it - // before the handle was created - SetVirtualItemCount(); - } - - protected override void OnHandleDestroyed(EventArgs e) - { - // the ListView OnHandleDestroyed accesses the Items list for all selected items - ItemCount = 0; - base.OnHandleDestroyed(e); - } - - #endregion - - LvHitTestInfo lvhti = new LvHitTestInfo(); - IntPtr ptrlvhti; - int selection = -1; - - public int hitTest(int x, int y) - { - lvhti.Point.X = x; - lvhti.Point.Y = y; - Marshal.StructureToPtr(lvhti, ptrlvhti, true); - int z = (int)Win32.SendMessage(this.Handle, (int)ListViewMessages.LVM_HITTEST, (IntPtr)0, ptrlvhti); - Marshal.PtrToStructure(ptrlvhti, lvhti); - return z; - } - - public void ensureVisible(int index) - { - Win32.SendMessage(Handle, (int)ListViewMessages.LVM_ENSUREVISIBLE, (IntPtr)index, (IntPtr)1); - } - - public void ensureVisible() - { - ensureVisible(selectedItem); - } - - public void setSelection(int index) - { - clearSelection(); - selection = index; - SelectItem(selection, true); - } - - public int selectedItem - { - get - { - if (SelectedIndices.Count == 0) - { - return -1; - } - else - { - return SelectedIndices[0]; - } - } - - set - { - setSelection(value); - } - } - - public void clearSelection() - { - if (selection != -1) - { - SelectItem(selection, false); - } - - selection = -1; - } - - // Informs user that a select all event is in place, can be used in change events to wait until this is false - public bool SelectAllInProgress { get; set; } - - public void SelectAll() - { - this.BeginUpdate(); - SelectAllInProgress = true; - - for (var i = 0; i < _itemCount; i++) - { - if (i == _itemCount - 1) - { - SelectAllInProgress = false; - } - - this.SelectItem(i, true); - } - - this.EndUpdate(); - } - - public void DeselectAll() - { - this.BeginUpdate(); - SelectAllInProgress = true; - - for (var i = 0; i < _itemCount; i++) - { - if (i == _itemCount - 1) - { - SelectAllInProgress = false; - } - - this.SelectItem(i, false); - } - - this.EndUpdate(); - } - - protected override void OnKeyDown(KeyEventArgs e) - { - if (e.KeyCode == Keys.A && e.Control && !e.Alt && !e.Shift) // Select All - { - SelectAll(); - } - - base.OnKeyDown(e); - } - } -} From 33d9b08e390d912a75a139477ecc98fbd4e14ffa Mon Sep 17 00:00:00 2001 From: "J.D. Purcell" Date: Sat, 19 Oct 2019 21:17:47 -0400 Subject: [PATCH 074/166] Cleanup --- BizHawk.Client.EmuHawk/Input/Input.cs | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/BizHawk.Client.EmuHawk/Input/Input.cs b/BizHawk.Client.EmuHawk/Input/Input.cs index 200e0e72a9..bc45fb81a1 100644 --- a/BizHawk.Client.EmuHawk/Input/Input.cs +++ b/BizHawk.Client.EmuHawk/Input/Input.cs @@ -256,14 +256,14 @@ namespace BizHawk.Client.EmuHawk } else if (ModifierState.TryGetValue(button, out LogicalButton buttonModifierState)) { - var ieModified = new InputEvent - { - LogicalButton = buttonModifierState, - EventType = InputEventType.Release, - Source = source - }; - if (ieModified.LogicalButton != ie.LogicalButton) - _NewEvents.Add(ieModified); + if (buttonModifierState != ie.LogicalButton) + _NewEvents.Add( + new InputEvent + { + LogicalButton = buttonModifierState, + EventType = InputEventType.Release, + Source = source + }); ModifierState.Remove(button); } From db1dc7459119b4104525f0bbb41e3967f596f5c1 Mon Sep 17 00:00:00 2001 From: alyosha-tas Date: Sat, 19 Oct 2019 21:28:06 -0400 Subject: [PATCH 075/166] Mostly Fix #1696 --- BizHawk.Client.Common/tools/CheatList.cs | 7 ++++++- BizHawk.Client.EmuHawk/tools/Watch/WatchValueBox.cs | 2 +- 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/BizHawk.Client.Common/tools/CheatList.cs b/BizHawk.Client.Common/tools/CheatList.cs index 79a8cb95c7..01702817df 100644 --- a/BizHawk.Client.Common/tools/CheatList.cs +++ b/BizHawk.Client.Common/tools/CheatList.cs @@ -384,7 +384,9 @@ namespace BizHawk.Client.Common } else { - // Set to hex for saving + // Set to hex for saving + var temp_cheat_type = cheat.Type; + cheat.SetType(DisplayType.Hex); sb @@ -399,6 +401,9 @@ namespace BizHawk.Client.Common .Append((cheat.BigEndian ?? false) ? '1' : '0').Append('\t') .Append(cheat.ComparisonType).Append('\t') .AppendLine(); + + cheat.SetType(temp_cheat_type); + } } diff --git a/BizHawk.Client.EmuHawk/tools/Watch/WatchValueBox.cs b/BizHawk.Client.EmuHawk/tools/Watch/WatchValueBox.cs index ae4fbcc6cb..9ff28c358a 100644 --- a/BizHawk.Client.EmuHawk/tools/Watch/WatchValueBox.cs +++ b/BizHawk.Client.EmuHawk/tools/Watch/WatchValueBox.cs @@ -72,8 +72,8 @@ namespace BizHawk.Client.EmuHawk set { - _type = value; var val = ToRawInt(); + _type = value; SetMaxLength(); SetFromRawInt(val); } From b01f52c01b1aaaeafc48e3276dabcd9c51d5d16c Mon Sep 17 00:00:00 2001 From: "J.D. Purcell" Date: Sun, 20 Oct 2019 01:16:27 -0400 Subject: [PATCH 076/166] Ability to handle alternate keyboard layouts (e.g. Dvorak). Optional and off by default for now due to its experimental nature. Closes #1584 --- BizHawk.Client.Common/config/Config.cs | 1 + .../BizHawk.Client.EmuHawk.csproj | 1 + BizHawk.Client.EmuHawk/Input/Keyboard.cs | 4 +- .../Input/KeyboardMapping.cs | 416 ++++++++++++++++++ .../config/GuiOptions.Designer.cs | 15 +- BizHawk.Client.EmuHawk/config/GuiOptions.cs | 2 + 6 files changed, 436 insertions(+), 3 deletions(-) create mode 100644 BizHawk.Client.EmuHawk/Input/KeyboardMapping.cs diff --git a/BizHawk.Client.Common/config/Config.cs b/BizHawk.Client.Common/config/Config.cs index b48b85a0dc..dcd0654ca4 100644 --- a/BizHawk.Client.Common/config/Config.cs +++ b/BizHawk.Client.Common/config/Config.cs @@ -105,6 +105,7 @@ namespace BizHawk.Client.Common public bool RunInBackground = true; public bool AcceptBackgroundInput = false; public bool AcceptBackgroundInputControllerOnly = false; + public bool HandleAlternateKeyboardLayouts = false; public bool SingleInstanceMode = false; public bool AllowUD_LR = false; public bool ForbidUD_LR = false; diff --git a/BizHawk.Client.EmuHawk/BizHawk.Client.EmuHawk.csproj b/BizHawk.Client.EmuHawk/BizHawk.Client.EmuHawk.csproj index 02e3c5cbf7..1b30776f00 100644 --- a/BizHawk.Client.EmuHawk/BizHawk.Client.EmuHawk.csproj +++ b/BizHawk.Client.EmuHawk/BizHawk.Client.EmuHawk.csproj @@ -668,6 +668,7 @@ + diff --git a/BizHawk.Client.EmuHawk/Input/Keyboard.cs b/BizHawk.Client.EmuHawk/Input/Keyboard.cs index d42f5e6b6a..b7cda338cf 100644 --- a/BizHawk.Client.EmuHawk/Input/Keyboard.cs +++ b/BizHawk.Client.EmuHawk/Input/Keyboard.cs @@ -60,9 +60,9 @@ namespace BizHawk.Client.EmuHawk foreach (var e in events) { foreach (var k in e.PressedKeys) - _eventList.Add(new KeyEvent { Key = k, Pressed = true }); + _eventList.Add(new KeyEvent { Key = KeyboardMapping.Handle(k), Pressed = true }); foreach (var k in e.ReleasedKeys) - _eventList.Add(new KeyEvent { Key = k, Pressed = false }); + _eventList.Add(new KeyEvent { Key = KeyboardMapping.Handle(k), Pressed = false }); } } diff --git a/BizHawk.Client.EmuHawk/Input/KeyboardMapping.cs b/BizHawk.Client.EmuHawk/Input/KeyboardMapping.cs new file mode 100644 index 0000000000..270cf9eecb --- /dev/null +++ b/BizHawk.Client.EmuHawk/Input/KeyboardMapping.cs @@ -0,0 +1,416 @@ +using System.Collections.Generic; +using System.Linq; +using System.Runtime.InteropServices; +using System.Windows.Forms; +using BizHawk.Client.Common; +using SlimDX.DirectInput; + +namespace BizHawk.Client.EmuHawk +{ + internal static class KeyboardMapping + { + [DllImport("user32.dll", CharSet = CharSet.Auto)] + private static extern uint MapVirtualKey(uint uCode, uint uMapType); + + private const uint MAPVK_VSC_TO_VK_EX = 0x03; + + public static Key Handle(Key key) + { + if (!Global.Config.HandleAlternateKeyboardLayouts) return key; + ScanCode inputScanCode = SlimDXScanCodeMap[(int)key]; + Keys virtualKey = (Keys)MapVirtualKey((uint)inputScanCode, MAPVK_VSC_TO_VK_EX); + ScanCode standardScanCode = GetStandardScanCode(virtualKey); + if (standardScanCode == 0) + standardScanCode = inputScanCode; + return ScanCodeToSlimDXKey[standardScanCode]; + } + + private static ScanCode GetStandardScanCode(Keys virtualKey) + { + switch (virtualKey) + { + case Keys.Escape: return ScanCode.Escape; + case Keys.D1: return ScanCode.D1; + case Keys.D2: return ScanCode.D2; + case Keys.D3: return ScanCode.D3; + case Keys.D4: return ScanCode.D4; + case Keys.D5: return ScanCode.D5; + case Keys.D6: return ScanCode.D6; + case Keys.D7: return ScanCode.D7; + case Keys.D8: return ScanCode.D8; + case Keys.D9: return ScanCode.D9; + case Keys.D0: return ScanCode.D0; + case Keys.OemMinus: return ScanCode.Minus; + case Keys.Oemplus: return ScanCode.Equals; + case Keys.Back: return ScanCode.Back; + case Keys.Tab: return ScanCode.Tab; + case Keys.Q: return ScanCode.Q; + case Keys.W: return ScanCode.W; + case Keys.E: return ScanCode.E; + case Keys.R: return ScanCode.R; + case Keys.T: return ScanCode.T; + case Keys.Y: return ScanCode.Y; + case Keys.U: return ScanCode.U; + case Keys.I: return ScanCode.I; + case Keys.O: return ScanCode.O; + case Keys.P: return ScanCode.P; + case Keys.OemOpenBrackets: return ScanCode.LBracket; + case Keys.OemCloseBrackets: return ScanCode.RBracket; + case Keys.Return: return ScanCode.Return; + case Keys.LControlKey: return ScanCode.LControl; + case Keys.A: return ScanCode.A; + case Keys.S: return ScanCode.S; + case Keys.D: return ScanCode.D; + case Keys.F: return ScanCode.F; + case Keys.G: return ScanCode.G; + case Keys.H: return ScanCode.H; + case Keys.J: return ScanCode.J; + case Keys.K: return ScanCode.K; + case Keys.L: return ScanCode.L; + case Keys.OemSemicolon: return ScanCode.Semicolon; + case Keys.OemQuotes: return ScanCode.Apostrophe; + case Keys.Oemtilde: return ScanCode.Grave; + case Keys.LShiftKey: return ScanCode.LShift; + case Keys.OemPipe: return ScanCode.Backslash; + case Keys.Z: return ScanCode.Z; + case Keys.X: return ScanCode.X; + case Keys.C: return ScanCode.C; + case Keys.V: return ScanCode.V; + case Keys.B: return ScanCode.B; + case Keys.N: return ScanCode.N; + case Keys.M: return ScanCode.M; + case Keys.Oemcomma: return ScanCode.Comma; + case Keys.OemPeriod: return ScanCode.Period; + case Keys.OemQuestion: return ScanCode.Slash; + case Keys.RShiftKey: return ScanCode.RShift; + case Keys.Multiply: return ScanCode.Multiply; + case Keys.LMenu: return ScanCode.LMenu; + case Keys.Space: return ScanCode.Space; + case Keys.Capital: return ScanCode.Capital; + case Keys.F1: return ScanCode.F1; + case Keys.F2: return ScanCode.F2; + case Keys.F3: return ScanCode.F3; + case Keys.F4: return ScanCode.F4; + case Keys.F5: return ScanCode.F5; + case Keys.F6: return ScanCode.F6; + case Keys.F7: return ScanCode.F7; + case Keys.F8: return ScanCode.F8; + case Keys.F9: return ScanCode.F9; + case Keys.F10: return ScanCode.F10; + case Keys.NumLock: return ScanCode.NumLock; + case Keys.Scroll: return ScanCode.Scroll; + case Keys.Subtract: return ScanCode.Subtract; + case Keys.Add: return ScanCode.Add; + case Keys.OemBackslash: return ScanCode.Oem_102; + case Keys.F11: return ScanCode.F11; + case Keys.F12: return ScanCode.F12; + case Keys.F13: return ScanCode.F13; + case Keys.F14: return ScanCode.F14; + case Keys.F15: return ScanCode.F15; + } + return 0; + } + + private enum ScanCode + { + Escape = 0x01, + D1 = 0x02, + D2 = 0x03, + D3 = 0x04, + D4 = 0x05, + D5 = 0x06, + D6 = 0x07, + D7 = 0x08, + D8 = 0x09, + D9 = 0x0A, + D0 = 0x0B, + Minus = 0x0C, + Equals = 0x0D, + Back = 0x0E, + Tab = 0x0F, + Q = 0x10, + W = 0x11, + E = 0x12, + R = 0x13, + T = 0x14, + Y = 0x15, + U = 0x16, + I = 0x17, + O = 0x18, + P = 0x19, + LBracket = 0x1A, + RBracket = 0x1B, + Return = 0x1C, + LControl = 0x1D, + A = 0x1E, + S = 0x1F, + D = 0x20, + F = 0x21, + G = 0x22, + H = 0x23, + J = 0x24, + K = 0x25, + L = 0x26, + Semicolon = 0x27, + Apostrophe = 0x28, + Grave = 0x29, + LShift = 0x2A, + Backslash = 0x2B, + Z = 0x2C, + X = 0x2D, + C = 0x2E, + V = 0x2F, + B = 0x30, + N = 0x31, + M = 0x32, + Comma = 0x33, + Period = 0x34, + Slash = 0x35, + RShift = 0x36, + Multiply = 0x37, + LMenu = 0x38, + Space = 0x39, + Capital = 0x3A, + F1 = 0x3B, + F2 = 0x3C, + F3 = 0x3D, + F4 = 0x3E, + F5 = 0x3F, + F6 = 0x40, + F7 = 0x41, + F8 = 0x42, + F9 = 0x43, + F10 = 0x44, + NumLock = 0x45, + Scroll = 0x46, + NumPad7 = 0x47, + NumPad8 = 0x48, + NumPad9 = 0x49, + Subtract = 0x4A, + NumPad4 = 0x4B, + NumPad5 = 0x4C, + NumPad6 = 0x4D, + Add = 0x4E, + NumPad1 = 0x4F, + NumPad2 = 0x50, + NumPad3 = 0x51, + NumPad0 = 0x52, + Decimal = 0x53, + Oem_102 = 0x56, + F11 = 0x57, + F12 = 0x58, + F13 = 0x64, + F14 = 0x65, + F15 = 0x66, + Kana = 0x70, + Abnt_C1 = 0x73, + Convert = 0x79, + NoConvert = 0x7B, + Yen = 0x7D, + Abnt_C2 = 0x7E, + NumPadEquals = 0x8D, + PrevTrack = 0x90, + AT = 0x91, + Colon = 0x92, + Underline = 0x93, + Kanji = 0x94, + Stop = 0x95, + AX = 0x96, + Unlabeled = 0x97, + NextTrack = 0x99, + NumPadEnter = 0x9C, + RControl = 0x9D, + Mute = 0xA0, + Calculator = 0xA1, + PlayPause = 0xA2, + MediaStop = 0xA4, + VolumeDown = 0xAE, + VolumeUp = 0xB0, + WebHome = 0xB2, + NumPadComma = 0xB3, + Divide = 0xB5, + SysRq = 0xB7, + RMenu = 0xB8, + Pause = 0xC5, + Home = 0xC7, + Up = 0xC8, + Prior = 0xC9, + Left = 0xCB, + Right = 0xCD, + End = 0xCF, + Down = 0xD0, + Next = 0xD1, + Insert = 0xD2, + Delete = 0xD3, + LWin = 0xDB, + RWin = 0xDC, + Apps = 0xDD, + Power = 0xDE, + Sleep = 0xDF, + Wake = 0xE3, + WebSearch = 0xE5, + WebFavorites = 0xE6, + WebRefresh = 0xE7, + WebStop = 0xE8, + WebForward = 0xE9, + WebBack = 0xEA, + MyComputer = 0xEB, + Mail = 0xEC, + MediaSelect = 0xED + } + + private static ScanCode[] SlimDXScanCodeMap = new ScanCode[] + { + ScanCode.D0, // 0 + ScanCode.D1, // 1 + ScanCode.D2, // 2 + ScanCode.D3, // 3 + ScanCode.D4, // 4 + ScanCode.D5, // 5 + ScanCode.D6, // 6 + ScanCode.D7, // 7 + ScanCode.D8, // 8 + ScanCode.D9, // 9 + ScanCode.A, // 10 + ScanCode.B, // 11 + ScanCode.C, // 12 + ScanCode.D, // 13 + ScanCode.E, // 14 + ScanCode.F, // 15 + ScanCode.G, // 16 + ScanCode.H, // 17 + ScanCode.I, // 18 + ScanCode.J, // 19 + ScanCode.K, // 20 + ScanCode.L, // 21 + ScanCode.M, // 22 + ScanCode.N, // 23 + ScanCode.O, // 24 + ScanCode.P, // 25 + ScanCode.Q, // 26 + ScanCode.R, // 27 + ScanCode.S, // 28 + ScanCode.T, // 29 + ScanCode.U, // 30 + ScanCode.V, // 31 + ScanCode.W, // 32 + ScanCode.X, // 33 + ScanCode.Y, // 34 + ScanCode.Z, // 35 + ScanCode.Abnt_C1, // 36 + ScanCode.Abnt_C2, // 37 + ScanCode.Apostrophe, // 38 + ScanCode.Apps, // 39 + ScanCode.AT, // 40 + ScanCode.AX, // 41 + ScanCode.Back, // 42 + ScanCode.Backslash, // 43 + ScanCode.Calculator, // 44 + ScanCode.Capital, // 45 + ScanCode.Colon, // 46 + ScanCode.Comma, // 47 + ScanCode.Convert, // 48 + ScanCode.Delete, // 49 + ScanCode.Down, // 50 + ScanCode.End, // 51 + ScanCode.Equals, // 52 + ScanCode.Escape, // 53 + ScanCode.F1, // 54 + ScanCode.F2, // 55 + ScanCode.F3, // 56 + ScanCode.F4, // 57 + ScanCode.F5, // 58 + ScanCode.F6, // 59 + ScanCode.F7, // 60 + ScanCode.F8, // 61 + ScanCode.F9, // 62 + ScanCode.F10, // 63 + ScanCode.F11, // 64 + ScanCode.F12, // 65 + ScanCode.F13, // 66 + ScanCode.F14, // 67 + ScanCode.F15, // 68 + ScanCode.Grave, // 69 + ScanCode.Home, // 70 + ScanCode.Insert, // 71 + ScanCode.Kana, // 72 + ScanCode.Kanji, // 73 + ScanCode.LBracket, // 74 + ScanCode.LControl, // 75 + ScanCode.Left, // 76 + ScanCode.LMenu, // 77 + ScanCode.LShift, // 78 + ScanCode.LWin, // 79 + ScanCode.Mail, // 80 + ScanCode.MediaSelect, // 81 + ScanCode.MediaStop, // 82 + ScanCode.Minus, // 83 + ScanCode.Mute, // 84 + ScanCode.MyComputer, // 85 + ScanCode.NextTrack, // 86 + ScanCode.NoConvert, // 87 + ScanCode.NumLock, // 88 + ScanCode.NumPad0, // 89 + ScanCode.NumPad1, // 90 + ScanCode.NumPad2, // 91 + ScanCode.NumPad3, // 92 + ScanCode.NumPad4, // 93 + ScanCode.NumPad5, // 94 + ScanCode.NumPad6, // 95 + ScanCode.NumPad7, // 96 + ScanCode.NumPad8, // 97 + ScanCode.NumPad9, // 98 + ScanCode.NumPadComma, // 99 + ScanCode.NumPadEnter, // 100 + ScanCode.NumPadEquals, // 101 + ScanCode.Subtract, // 102 + ScanCode.Decimal, // 103 + ScanCode.Add, // 104 + ScanCode.Divide, // 105 + ScanCode.Multiply, // 106 + ScanCode.Oem_102, // 107 + ScanCode.Next, // 108 + ScanCode.Prior, // 109 + ScanCode.Pause, // 110 + ScanCode.Period, // 111 + ScanCode.PlayPause, // 112 + ScanCode.Power, // 113 + ScanCode.PrevTrack, // 114 + ScanCode.RBracket, // 115 + ScanCode.RControl, // 116 + ScanCode.Return, // 117 + ScanCode.Right, // 118 + ScanCode.RMenu, // 119 + ScanCode.RShift, // 120 + ScanCode.RWin, // 121 + ScanCode.Scroll, // 122 + ScanCode.Semicolon, // 123 + ScanCode.Slash, // 124 + ScanCode.Sleep, // 125 + ScanCode.Space, // 126 + ScanCode.Stop, // 127 + ScanCode.SysRq, // 128 + ScanCode.Tab, // 129 + ScanCode.Underline, // 130 + ScanCode.Unlabeled, // 131 + ScanCode.Up, // 132 + ScanCode.VolumeDown, // 133 + ScanCode.VolumeUp, // 134 + ScanCode.Wake, // 135 + ScanCode.WebBack, // 136 + ScanCode.WebFavorites, // 137 + ScanCode.WebForward, // 138 + ScanCode.WebHome, // 139 + ScanCode.WebRefresh, // 140 + ScanCode.WebSearch, // 141 + ScanCode.WebStop, // 142 + ScanCode.Yen, // 143 + 0 // 144 + }; + + private static Dictionary ScanCodeToSlimDXKey = + SlimDXScanCodeMap + .Select((n, i) => new { Value = n, Index = i }) + .ToDictionary(n => n.Value, n => (Key)n.Index); + } +} diff --git a/BizHawk.Client.EmuHawk/config/GuiOptions.Designer.cs b/BizHawk.Client.EmuHawk/config/GuiOptions.Designer.cs index 4b273ae153..038f9c74bf 100644 --- a/BizHawk.Client.EmuHawk/config/GuiOptions.Designer.cs +++ b/BizHawk.Client.EmuHawk/config/GuiOptions.Designer.cs @@ -74,6 +74,7 @@ this.toolTip1 = new System.Windows.Forms.ToolTip(this.components); this.label9 = new System.Windows.Forms.Label(); this.label10 = new System.Windows.Forms.Label(); + this.HandleAlternateKeyboardLayoutsCheckBox = new System.Windows.Forms.CheckBox(); this.tabControl1.SuspendLayout(); this.tabPage1.SuspendLayout(); this.groupBox1.SuspendLayout(); @@ -121,6 +122,7 @@ // // tabPage1 // + this.tabPage1.Controls.Add(this.HandleAlternateKeyboardLayoutsCheckBox); this.tabPage1.Controls.Add(this.groupBox1); this.tabPage1.Controls.Add(this.NeverAskSaveCheckbox); this.tabPage1.Controls.Add(this.label2); @@ -146,7 +148,7 @@ this.groupBox1.Controls.Add(this.StartFullScreenCheckbox); this.groupBox1.Controls.Add(this.label3); this.groupBox1.Controls.Add(this.SingleInstanceModeCheckbox); - this.groupBox1.Location = new System.Drawing.Point(6, 182); + this.groupBox1.Location = new System.Drawing.Point(6, 205); this.groupBox1.Name = "groupBox1"; this.groupBox1.Size = new System.Drawing.Size(369, 140); this.groupBox1.TabIndex = 13; @@ -562,6 +564,16 @@ this.label10.TabIndex = 1; this.label10.Text = "every"; // + // HandleAlternateKeyboardLayoutsCheckBox + // + this.HandleAlternateKeyboardLayoutsCheckBox.AutoSize = true; + this.HandleAlternateKeyboardLayoutsCheckBox.Location = new System.Drawing.Point(6, 175); + this.HandleAlternateKeyboardLayoutsCheckBox.Name = "HandleAlternateKeyboardLayoutsCheckBox"; + this.HandleAlternateKeyboardLayoutsCheckBox.Size = new System.Drawing.Size(255, 17); + this.HandleAlternateKeyboardLayoutsCheckBox.TabIndex = 11; + this.HandleAlternateKeyboardLayoutsCheckBox.Text = "Handle alternate keyboard layouts (e.g. Dvorak) [experimental]"; + this.HandleAlternateKeyboardLayoutsCheckBox.UseVisualStyleBackColor = true; + // // EmuHawkOptions // this.AcceptButton = this.OkBtn; @@ -640,5 +652,6 @@ private System.Windows.Forms.NumericUpDown AutosaveSRAMtextBox; private System.Windows.Forms.Label label10; private System.Windows.Forms.Label label9; + private System.Windows.Forms.CheckBox HandleAlternateKeyboardLayoutsCheckBox; } } \ No newline at end of file diff --git a/BizHawk.Client.EmuHawk/config/GuiOptions.cs b/BizHawk.Client.EmuHawk/config/GuiOptions.cs index 76e29d2a03..f05e73be46 100644 --- a/BizHawk.Client.EmuHawk/config/GuiOptions.cs +++ b/BizHawk.Client.EmuHawk/config/GuiOptions.cs @@ -50,6 +50,7 @@ namespace BizHawk.Client.EmuHawk RunInBackgroundCheckbox.Checked = Global.Config.RunInBackground; AcceptBackgroundInputCheckbox.Checked = Global.Config.AcceptBackgroundInput; AcceptBackgroundInputControllerOnlyCheckBox.Checked = Global.Config.AcceptBackgroundInputControllerOnly; + HandleAlternateKeyboardLayoutsCheckBox.Checked = Global.Config.HandleAlternateKeyboardLayouts; NeverAskSaveCheckbox.Checked = Global.Config.SupressAskSave; SingleInstanceModeCheckbox.Checked = Global.Config.SingleInstanceMode; @@ -85,6 +86,7 @@ namespace BizHawk.Client.EmuHawk Global.Config.RunInBackground = RunInBackgroundCheckbox.Checked; Global.Config.AcceptBackgroundInput = AcceptBackgroundInputCheckbox.Checked; Global.Config.AcceptBackgroundInputControllerOnly = AcceptBackgroundInputControllerOnlyCheckBox.Checked; + Global.Config.HandleAlternateKeyboardLayouts = HandleAlternateKeyboardLayoutsCheckBox.Checked; Global.Config.SupressAskSave = NeverAskSaveCheckbox.Checked; Global.Config.SingleInstanceMode = SingleInstanceModeCheckbox.Checked; From a2215fb5df84a107a6ad5bf96a62fcdfe8385517 Mon Sep 17 00:00:00 2001 From: "J.D. Purcell" Date: Sun, 20 Oct 2019 01:24:28 -0400 Subject: [PATCH 077/166] Fix AppVeyor build. --- BizHawk.Client.EmuHawk/Input/Input.cs | 24 +++++++++++++++--------- 1 file changed, 15 insertions(+), 9 deletions(-) diff --git a/BizHawk.Client.EmuHawk/Input/Input.cs b/BizHawk.Client.EmuHawk/Input/Input.cs index bc45fb81a1..abd129b99e 100644 --- a/BizHawk.Client.EmuHawk/Input/Input.cs +++ b/BizHawk.Client.EmuHawk/Input/Input.cs @@ -254,16 +254,22 @@ namespace BizHawk.Client.EmuHawk { ModifierState[button] = ie.LogicalButton; } - else if (ModifierState.TryGetValue(button, out LogicalButton buttonModifierState)) + else { - if (buttonModifierState != ie.LogicalButton) - _NewEvents.Add( - new InputEvent - { - LogicalButton = buttonModifierState, - EventType = InputEventType.Release, - Source = source - }); + LogicalButton buttonModifierState; + if (ModifierState.TryGetValue(button, out buttonModifierState)) + { + if (buttonModifierState != ie.LogicalButton) + { + _NewEvents.Add( + new InputEvent + { + LogicalButton = buttonModifierState, + EventType = InputEventType.Release, + Source = source + }); + } + } ModifierState.Remove(button); } From 1fadcb97f21c29a20ff720cff65617bb09091fa0 Mon Sep 17 00:00:00 2001 From: "J.D. Purcell" Date: Sun, 20 Oct 2019 01:43:08 -0400 Subject: [PATCH 078/166] Misplaced this in last commit. --- BizHawk.Client.EmuHawk/Input/Input.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/BizHawk.Client.EmuHawk/Input/Input.cs b/BizHawk.Client.EmuHawk/Input/Input.cs index abd129b99e..4acea6455b 100644 --- a/BizHawk.Client.EmuHawk/Input/Input.cs +++ b/BizHawk.Client.EmuHawk/Input/Input.cs @@ -269,8 +269,8 @@ namespace BizHawk.Client.EmuHawk Source = source }); } + ModifierState.Remove(button); } - ModifierState.Remove(button); } _NewEvents.Add(ie); From ff35dfab57411fd9dbb58d2329250fc22bb509a2 Mon Sep 17 00:00:00 2001 From: alyosha-tas Date: Sun, 20 Oct 2019 09:42:54 -0400 Subject: [PATCH 079/166] fix #1697 --- BizHawk.Client.EmuHawk/tools/ToolManager.cs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/BizHawk.Client.EmuHawk/tools/ToolManager.cs b/BizHawk.Client.EmuHawk/tools/ToolManager.cs index 2adc46a38f..463a18a7e2 100644 --- a/BizHawk.Client.EmuHawk/tools/ToolManager.cs +++ b/BizHawk.Client.EmuHawk/tools/ToolManager.cs @@ -764,8 +764,9 @@ namespace BizHawk.Client.EmuHawk } var sysName = Global.Emulator.DisplayName(); + var sysId = Global.Emulator.SystemId; return !attr.UnsupportedCores.Contains(sysName) // not unsupported - && (!attr.SupportedSystems.Any() || attr.SupportedSystems.Contains(sysName)); // supported (no supported list -> assumed all supported) + && (attr.SupportedSystems.Contains(sysId) || attr.SupportedSystems.Contains(sysName)); // supported (no supported list -> assumed all supported) } public bool IsAvailable() => IsAvailable(typeof(T)); From 7e38bf61c96f5466d8c285e1855f1940c5b709b4 Mon Sep 17 00:00:00 2001 From: "J.D. Purcell" Date: Sun, 20 Oct 2019 10:17:13 -0400 Subject: [PATCH 080/166] ToolManager.IsAvailable fix. --- BizHawk.Client.EmuHawk/tools/ToolManager.cs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/BizHawk.Client.EmuHawk/tools/ToolManager.cs b/BizHawk.Client.EmuHawk/tools/ToolManager.cs index 463a18a7e2..a2e428a405 100644 --- a/BizHawk.Client.EmuHawk/tools/ToolManager.cs +++ b/BizHawk.Client.EmuHawk/tools/ToolManager.cs @@ -763,10 +763,10 @@ namespace BizHawk.Client.EmuHawk return true; // no ToolAttribute on given type -> assumed all supported } - var sysName = Global.Emulator.DisplayName(); - var sysId = Global.Emulator.SystemId; - return !attr.UnsupportedCores.Contains(sysName) // not unsupported - && (attr.SupportedSystems.Contains(sysId) || attr.SupportedSystems.Contains(sysName)); // supported (no supported list -> assumed all supported) + var displayName = Global.Emulator.DisplayName(); + var systemId = Global.Emulator.SystemId; + return !attr.UnsupportedCores.Contains(displayName) // not unsupported + && (!attr.SupportedSystems.Any() || attr.SupportedSystems.Contains(systemId)); // supported (no supported list -> assumed all supported) } public bool IsAvailable() => IsAvailable(typeof(T)); From 4445a425a2b37005c2896945e8561683851404a0 Mon Sep 17 00:00:00 2001 From: "J.D. Purcell" Date: Sun, 20 Oct 2019 10:47:23 -0400 Subject: [PATCH 081/166] ToolManager cleanup. --- BizHawk.Client.EmuHawk/tools/ToolManager.cs | 180 ++------------------ 1 file changed, 17 insertions(+), 163 deletions(-) diff --git a/BizHawk.Client.EmuHawk/tools/ToolManager.cs b/BizHawk.Client.EmuHawk/tools/ToolManager.cs index a2e428a405..1c0a1c17e7 100644 --- a/BizHawk.Client.EmuHawk/tools/ToolManager.cs +++ b/BizHawk.Client.EmuHawk/tools/ToolManager.cs @@ -774,166 +774,35 @@ namespace BizHawk.Client.EmuHawk // Note: Referencing these properties creates an instance of the tool and persists it. They should be referenced by type if this is not desired #region Tools - public RamWatch RamWatch + private T GetTool() where T : class, IToolForm, new() { - get + T tool = _tools.OfType().FirstOrDefault(); + if (tool != null) { - var tool = _tools.FirstOrDefault(t => t is RamWatch); - if (tool != null) + if (!tool.IsDisposed) { - if (tool.IsDisposed) - { - _tools.Remove(tool); - } - else - { - return tool as RamWatch; - } + return tool; } - - var newTool = new RamWatch(); - _tools.Add(newTool); - return newTool; + _tools.Remove(tool); } + tool = new T(); + _tools.Add(tool); + return tool; } - public RamSearch RamSearch - { - get - { - var tool = _tools.FirstOrDefault(t => t is RamSearch); - if (tool != null) - { - if (tool.IsDisposed) - { - _tools.Remove(tool); - } - else - { - return tool as RamSearch; - } - } + public RamWatch RamWatch => GetTool(); - var newTool = new RamSearch(); - _tools.Add(newTool); - return newTool; - } - } + public RamSearch RamSearch => GetTool(); - public Cheats Cheats - { - get - { - var tool = _tools.FirstOrDefault(t => t is Cheats); - if (tool != null) - { - if (tool.IsDisposed) - { - _tools.Remove(tool); - } - else - { - return tool as Cheats; - } - } + public Cheats Cheats => GetTool(); - var newTool = new Cheats(); - _tools.Add(newTool); - return newTool; - } - } + public HexEditor HexEditor => GetTool(); - public HexEditor HexEditor - { - get - { - var tool = _tools.FirstOrDefault(t => t is HexEditor); - if (tool != null) - { - if (tool.IsDisposed) - { - _tools.Remove(tool); - } - else - { - return tool as HexEditor; - } - } + public VirtualpadTool VirtualPad => GetTool(); - var newTool = new HexEditor(); - _tools.Add(newTool); - return newTool; - } - } + public SNESGraphicsDebugger SNESGraphicsDebugger => GetTool(); - public VirtualpadTool VirtualPad - { - get - { - var tool = _tools.FirstOrDefault(t => t is VirtualpadTool); - if (tool != null) - { - if (tool.IsDisposed) - { - _tools.Remove(tool); - } - else - { - return tool as VirtualpadTool; - } - } - - var newTool = new VirtualpadTool(); - _tools.Add(newTool); - return newTool; - } - } - - public SNESGraphicsDebugger SNESGraphicsDebugger - { - get - { - var tool = _tools.FirstOrDefault(t => t is SNESGraphicsDebugger); - if (tool != null) - { - if (tool.IsDisposed) - { - _tools.Remove(tool); - } - else - { - return tool as SNESGraphicsDebugger; - } - } - - var newTool = new SNESGraphicsDebugger(); - _tools.Add(newTool); - return newTool; - } - } - - public LuaConsole LuaConsole - { - get - { - var tool = _tools.FirstOrDefault(t => t is LuaConsole); - if (tool != null) - { - if (tool.IsDisposed) - { - _tools.Remove(tool); - } - else - { - return tool as LuaConsole; - } - } - - var newTool = new LuaConsole(); - _tools.Add(newTool); - return newTool; - } - } + public LuaConsole LuaConsole => GetTool(); public TAStudio TAStudio { @@ -945,22 +814,7 @@ namespace BizHawk.Client.EmuHawk System.Diagnostics.Debug.Fail("TAStudio does not exist!"); } - var tool = _tools.FirstOrDefault(t => t is TAStudio); - if (tool != null) - { - if (tool.IsDisposed) - { - _tools.Remove(tool); - } - else - { - return tool as TAStudio; - } - } - - var newTool = new TAStudio(); - _tools.Add(newTool); - return newTool; + return GetTool(); } } From 09314bdedaa89e093ff860605093cd67aa78296e Mon Sep 17 00:00:00 2001 From: "J.D. Purcell" Date: Sun, 20 Oct 2019 11:06:39 -0400 Subject: [PATCH 082/166] Add readonly keyword. --- BizHawk.Client.EmuHawk/Input/KeyboardMapping.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/BizHawk.Client.EmuHawk/Input/KeyboardMapping.cs b/BizHawk.Client.EmuHawk/Input/KeyboardMapping.cs index 270cf9eecb..4e73b5450f 100644 --- a/BizHawk.Client.EmuHawk/Input/KeyboardMapping.cs +++ b/BizHawk.Client.EmuHawk/Input/KeyboardMapping.cs @@ -259,7 +259,7 @@ namespace BizHawk.Client.EmuHawk MediaSelect = 0xED } - private static ScanCode[] SlimDXScanCodeMap = new ScanCode[] + private static readonly ScanCode[] SlimDXScanCodeMap = new ScanCode[] { ScanCode.D0, // 0 ScanCode.D1, // 1 @@ -408,7 +408,7 @@ namespace BizHawk.Client.EmuHawk 0 // 144 }; - private static Dictionary ScanCodeToSlimDXKey = + private static readonly Dictionary ScanCodeToSlimDXKey = SlimDXScanCodeMap .Select((n, i) => new { Value = n, Index = i }) .ToDictionary(n => n.Value, n => (Key)n.Index); From 23433b856fceec42c0f0845bcee5a7237f7ca0c2 Mon Sep 17 00:00:00 2001 From: "J.D. Purcell" Date: Sun, 20 Oct 2019 13:47:22 -0400 Subject: [PATCH 083/166] Hotkey/controller config: Fix issue where input events get queued and processed by the main form after the dialog is closed. For example if you opened the hotkey config, typed "-" in the search box, and closed the dialog, it would trigger Decrease Speed in the main form. Also redo an old hack fix the right way. --- BizHawk.Client.EmuHawk/Input/Input.cs | 1 - .../config/ControllerConfig.Designer.cs | 3 ++- .../config/ControllerConfig.cs | 24 +++++++++---------- .../config/HotkeyConfig.Designer.cs | 3 ++- BizHawk.Client.EmuHawk/config/HotkeyConfig.cs | 12 +++++----- BizHawk.Client.EmuHawk/config/InputWidget.cs | 7 ++++++ 6 files changed, 29 insertions(+), 21 deletions(-) diff --git a/BizHawk.Client.EmuHawk/Input/Input.cs b/BizHawk.Client.EmuHawk/Input/Input.cs index 4acea6455b..3e71096b13 100644 --- a/BizHawk.Client.EmuHawk/Input/Input.cs +++ b/BizHawk.Client.EmuHawk/Input/Input.cs @@ -293,7 +293,6 @@ namespace BizHawk.Client.EmuHawk private ModifierKey _Modifiers; private readonly List _NewEvents = new List(); - //do we need this? public void ClearEvents() { lock (this) diff --git a/BizHawk.Client.EmuHawk/config/ControllerConfig.Designer.cs b/BizHawk.Client.EmuHawk/config/ControllerConfig.Designer.cs index 20d7076fdf..cc024b4a27 100644 --- a/BizHawk.Client.EmuHawk/config/ControllerConfig.Designer.cs +++ b/BizHawk.Client.EmuHawk/config/ControllerConfig.Designer.cs @@ -302,7 +302,8 @@ this.Name = "ControllerConfig"; this.StartPosition = System.Windows.Forms.FormStartPosition.CenterParent; this.Text = "Controller Config"; - this.Load += new System.EventHandler(this.NewControllerConfig_Load); + this.FormClosed += new System.Windows.Forms.FormClosedEventHandler(this.ControllerConfig_FormClosed); + this.Load += new System.EventHandler(this.ControllerConfig_Load); this.tabControl1.ResumeLayout(false); this.tableLayoutPanel1.ResumeLayout(false); ((System.ComponentModel.ISupportInitialize)(this.pictureBox1)).EndInit(); diff --git a/BizHawk.Client.EmuHawk/config/ControllerConfig.cs b/BizHawk.Client.EmuHawk/config/ControllerConfig.cs index 25b246d55f..b930b136be 100644 --- a/BizHawk.Client.EmuHawk/config/ControllerConfig.cs +++ b/BizHawk.Client.EmuHawk/config/ControllerConfig.cs @@ -49,7 +49,11 @@ namespace BizHawk.Client.EmuHawk ControllerImages.Add("Apple IIe Keyboard", Properties.Resources.AppleIIKeyboard); ControllerImages.Add("VirtualBoy Controller", Properties.Resources.VBoyController); ControllerImages.Add("NeoGeo Portable Controller", Properties.Resources.NGPController); - + } + + private ControllerConfig() + { + InitializeComponent(); } protected override void OnActivated(EventArgs e) @@ -64,13 +68,14 @@ namespace BizHawk.Client.EmuHawk Input.Instance.ControlInputFocus(this, Input.InputFocus.Mouse, false); } - private ControllerConfig() + private void ControllerConfig_Load(object sender, EventArgs e) { - InitializeComponent(); - Closing += (o, e) => - { - buttonOK.Focus(); // A very dirty hack to avoid https://code.google.com/p/bizhawk/issues/detail?id=161 - }; + Text = $"{_theDefinition.Name} Configuration"; + } + + private void ControllerConfig_FormClosed(object sender, FormClosedEventArgs e) + { + Input.Instance.ClearEvents(); } private delegate Control PanelCreator(Dictionary settings, List buttons, Size size); @@ -365,11 +370,6 @@ namespace BizHawk.Client.EmuHawk Close(); } - private void NewControllerConfig_Load(object sender, EventArgs e) - { - Text = $"{_theDefinition.Name} Configuration"; - } - private static TabControl GetTabControl(IEnumerable controls) { if (controls != null) diff --git a/BizHawk.Client.EmuHawk/config/HotkeyConfig.Designer.cs b/BizHawk.Client.EmuHawk/config/HotkeyConfig.Designer.cs index 7047ff8b90..d37183c230 100644 --- a/BizHawk.Client.EmuHawk/config/HotkeyConfig.Designer.cs +++ b/BizHawk.Client.EmuHawk/config/HotkeyConfig.Designer.cs @@ -228,7 +228,8 @@ this.Name = "HotkeyConfig"; this.StartPosition = System.Windows.Forms.FormStartPosition.CenterParent; this.Text = "Configure Hotkeys"; - this.Load += new System.EventHandler(this.NewHotkeyWindow_Load); + this.FormClosed += new System.Windows.Forms.FormClosedEventHandler(this.HotkeyConfig_FormClosed); + this.Load += new System.EventHandler(this.HotkeyConfig_Load); this.HotkeyTabControl.ResumeLayout(false); this.clearBtnContextMenu.ResumeLayout(false); this.ResumeLayout(false); diff --git a/BizHawk.Client.EmuHawk/config/HotkeyConfig.cs b/BizHawk.Client.EmuHawk/config/HotkeyConfig.cs index 5ed5f999a0..79ee9abc29 100644 --- a/BizHawk.Client.EmuHawk/config/HotkeyConfig.cs +++ b/BizHawk.Client.EmuHawk/config/HotkeyConfig.cs @@ -14,11 +14,6 @@ namespace BizHawk.Client.EmuHawk { InitializeComponent(); - Closing += (o, e) => - { - IDB_SAVE.Focus(); // A very dirty hack to avoid https://code.google.com/p/bizhawk/issues/detail?id=161 - }; - tabPage1.Focus(); } @@ -34,7 +29,7 @@ namespace BizHawk.Client.EmuHawk Input.Instance.ControlInputFocus(this, Input.InputFocus.Mouse, false); } - private void NewHotkeyWindow_Load(object sender, EventArgs e) + private void HotkeyConfig_Load(object sender, EventArgs e) { var source = new AutoCompleteStringCollection(); source.AddRange(Global.Config.HotkeyBindings.Select(x => x.DisplayName).ToArray()); @@ -47,6 +42,11 @@ namespace BizHawk.Client.EmuHawk DoFocus(); } + private void HotkeyConfig_FormClosed(object sender, FormClosedEventArgs e) + { + Input.Instance.ClearEvents(); + } + private void IDB_CANCEL_Click(object sender, EventArgs e) { GlobalWin.OSD.AddMessage("Hotkey config aborted"); diff --git a/BizHawk.Client.EmuHawk/config/InputWidget.cs b/BizHawk.Client.EmuHawk/config/InputWidget.cs index 4e9d85e990..c34c500d5f 100644 --- a/BizHawk.Client.EmuHawk/config/InputWidget.cs +++ b/BizHawk.Client.EmuHawk/config/InputWidget.cs @@ -88,6 +88,7 @@ namespace BizHawk.Client.EmuHawk protected override void OnEnter(EventArgs e) { + Input.Instance.ClearEvents(); _lastPress = null; _timer.Start(); BackColor = Color.FromArgb(unchecked((int)0xFFC0FFFF)); // Color.LightCyan is too light on Windows 8, this is a bit darker @@ -101,6 +102,12 @@ namespace BizHawk.Client.EmuHawk base.OnLeave(e); } + protected override void OnHandleDestroyed(EventArgs e) + { + _timer.Stop(); + base.OnHandleDestroyed(e); + } + private void Timer_Tick(object sender, EventArgs e) { ReadKeys(); From b0c7bab94ee6fa537ec4c2627654901eb4112327 Mon Sep 17 00:00:00 2001 From: "J.D. Purcell" Date: Sun, 20 Oct 2019 14:42:14 -0400 Subject: [PATCH 084/166] Fix small binding regression (tabbing into the first input widget could trigger a tab bind). --- BizHawk.Client.EmuHawk/Input/Input.cs | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/BizHawk.Client.EmuHawk/Input/Input.cs b/BizHawk.Client.EmuHawk/Input/Input.cs index 3e71096b13..2066ee5d28 100644 --- a/BizHawk.Client.EmuHawk/Input/Input.cs +++ b/BizHawk.Client.EmuHawk/Input/Input.cs @@ -213,6 +213,7 @@ namespace BizHawk.Client.EmuHawk private readonly WorkingDictionary FloatValues = new WorkingDictionary(); private readonly WorkingDictionary FloatDeltas = new WorkingDictionary(); private bool trackdeltas = false; + private bool IgnoreEventsNextPoll = false; void HandleButton(string button, bool newState, InputFocus source) { @@ -259,7 +260,7 @@ namespace BizHawk.Client.EmuHawk LogicalButton buttonModifierState; if (ModifierState.TryGetValue(button, out buttonModifierState)) { - if (buttonModifierState != ie.LogicalButton) + if (buttonModifierState != ie.LogicalButton && !IgnoreEventsNextPoll) { _NewEvents.Add( new InputEvent @@ -273,7 +274,10 @@ namespace BizHawk.Client.EmuHawk } } - _NewEvents.Add(ie); + if (!IgnoreEventsNextPoll) + { + _NewEvents.Add(ie); + } } private static ModifierKey ButtonToModifierKey(string button) @@ -298,6 +302,8 @@ namespace BizHawk.Client.EmuHawk lock (this) { InputEvents.Clear(); + // To "clear" anything currently in the input device buffers + IgnoreEventsNextPoll = true; } } @@ -443,6 +449,8 @@ namespace BizHawk.Client.EmuHawk EnqueueEvent(ie); } } + + IgnoreEventsNextPoll = false; } //lock(this) //arbitrary selection of polling frequency: @@ -535,6 +543,6 @@ namespace BizHawk.Client.EmuHawk //controls whether modifier keys will be ignored as key press events //this should be used by hotkey binders, but we may want modifier key events //to get triggered in the main form - public bool EnableIgnoreModifiers = false; + public volatile bool EnableIgnoreModifiers = false; } } From b9a470613355aaa541063bc9ab8b25c787f9bdc7 Mon Sep 17 00:00:00 2001 From: "J.D. Purcell" Date: Sun, 20 Oct 2019 16:08:08 -0400 Subject: [PATCH 085/166] Some C# style rules in editorconfig --- .editorconfig | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/.editorconfig b/.editorconfig index 27259f5155..3d0b97c090 100644 --- a/.editorconfig +++ b/.editorconfig @@ -2,3 +2,12 @@ root = true [*] indent_style = tab + +[*.cs] +csharp_new_line_before_open_brace = all +csharp_new_line_before_else = true +csharp_new_line_before_catch = true +csharp_new_line_before_finally = true +csharp_indent_switch_labels = true +csharp_indent_case_contents = true +csharp_indent_labels = one_less_than_current From bda6206cb2d5ca1262282a1e0f6f31c39542adb4 Mon Sep 17 00:00:00 2001 From: "J.D. Purcell" Date: Sun, 20 Oct 2019 17:29:30 -0400 Subject: [PATCH 086/166] See if AppVeyor can use MSBuild 16 --- Dist/BuildAndPackage.bat | 10 +++------- Dist/vswhere.exe | Bin 0 -> 458872 bytes 2 files changed, 3 insertions(+), 7 deletions(-) create mode 100644 Dist/vswhere.exe diff --git a/Dist/BuildAndPackage.bat b/Dist/BuildAndPackage.bat index 616b39d95a..8884698994 100644 --- a/Dist/BuildAndPackage.bat +++ b/Dist/BuildAndPackage.bat @@ -9,15 +9,11 @@ if "%1"=="" ( git --version > NUL @if errorlevel 1 goto MISSINGGIT -reg query "HKLM\SOFTWARE\Microsoft\MSBuild\ToolsVersions\14.0" /v MSBuildToolsPath > nul 2>&1 -if ERRORLEVEL 1 goto MISSINGMSBUILD +for /f "usebackq tokens=*" %%A in (`vswhere -version "[16.0,17.0)" -requires Microsoft.Component.MSBuild -find MSBuild\**\Bin\MSBuild.exe`) do SET MSBUILDPATH=%%A -for /f "skip=2 tokens=2,*" %%A in ('reg.exe query "HKLM\SOFTWARE\Microsoft\MSBuild\ToolsVersions\14.0" /v MSBuildToolsPath') do SET MSBUILDDIR=%%B +IF "%MSBUILDPATH%"=="" GOTO MISSINGMSBUILD -IF NOT EXIST %MSBUILDDIR%nul goto MISSINGMSBUILD -IF NOT EXIST %MSBUILDDIR%msbuild.exe goto MISSINGMSBUILD - -call "%MSBUILDDIR%msbuild.exe" ..\BizHawk.sln /p:Configuration=Release /p:Platform="Any Cpu" /t:rebuild +call "%MSBUILDPATH%" ..\BizHawk.sln /p:Configuration=Release /p:Platform="Any Cpu" /t:rebuild @if errorlevel 1 goto MSBUILDFAILED diff --git a/Dist/vswhere.exe b/Dist/vswhere.exe new file mode 100644 index 0000000000000000000000000000000000000000..582e82868dddc97bec4a8c8353f729348be55f56 GIT binary patch literal 458872 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

rG9aqQ9oNre|=>m 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 z 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

B(E)|cNo@{AOD>9yyD)Nk< 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%0D#_#BHV;EJ>euFqi5NMmquoA+;)UnLId z;!`iUr#&Mz8?&>Cw}-TG+l+ZXU;@?*xc_EL&~l^Y&ATwVH9?Dl^Z0+`{VO|!?Q->9 zLdIPwk9))-SW>#3LkjtQhrdGFCmrBA^B)4GBK&!DL2MTV@1-IM)ci+orE_ud{l%+`kwM4% zi|@a$*r!t`M!2!U}-(! zP=0}3HRQVzOzRG(r%`SXIHDIE<$A+0j_(BY)*R!x)-wK9IEEv%@MJB_HYU$3Eq=C! zJiDX(`EbmeHU;J6z?tCk;r!sZXtS)va4hR;4etXoz66eP*1(bfVK_F?vs(ChAj`EC zj`_R{N4lMGEY~M+O#c#&>Aq+Twv*D>J(2OKd0NoogUi^S_zVB>C;ODzEhC;2G%3IB zdhLU)3-|ppJnaUNoc@nXV>|6X_CUrXzxNHZM2R@X`@}}`rV){;U%EvPdg{8N!)EY( zf$$EGb=k9SuD{>Qe;invQ)8>odA-T%Mut6~qz`)`?Xd6GpNHIi^yB=WPcIud@yBPD zu!B*m+{^nu&i34$F?!&*ksUik-#Mi9*j;mD_wM@&<@SDPWTnUCw_aU2;HC$|KUx24 z_fPh(8P>gN<-ScrUZ2KJ3m@9Lljr(>UbpqZH|M_c+|-W;h9&jI-Cn)i5`N;r%G%-q%Lb?6Oe`dB^y3HT zm3$r<+n6%wl@k-Z$G>O&^}C1dedkyAci?yw~2iAZ12w*3EbO`hA<= z9ys>YsDBSjNPF_GLofAHV;>9{>2Y0N?z929{n^^#qlbpS?w(-1@%PVAtz9fty0hZtMEAM^^rO z@0$xuP5XyF{fu*I-`uW!p9wrO`mR1RW8VMdh3}$g-8+C4_-E0k^Bt<~*Kbf3wQP5M zc=8pWT_?UhZS^w8-4RgOui;$I-iIg8{PfUc!{)s9?H9wouiWy|-(mEjGO@MIXIn}K z-+LgZTT-6;2b1?L3Tln<==E>E`4xWzw4D8T(u*VeSKRf*?gyf>R=MT=?)}W%0m~g* zA5xTW-r6nZd)Nc0Bp-h}G}x zJKQ1ZmzkL-UKmoas{F3$(4h1S-C}pdXFGWun%Mc>3jAL64|A&j_~xxBx1YD)WAe8Ru^wIhdsX8b zo%(hOPYqi!W6{=6#zcHOBPYk}rZZ#aemA$zo*_?s*%Yv*>G97B!=~N%M$o{irjXYk zKl;fZ>ra0C_4NCzGv_?NDC@0t<9qwx6}<}6O@!aD*z0oVy^-4d>bgNcpStkEJB>eo zbKRNuGR72_?zny8h^h}B{(4(~kMy(0r)Rg_+B19ZQlDKX!w-kuT$K6r=w&Aky!qSi ztaMoFO5@oj#TVW@I_IZKQ|!~N^PYIE+vPXh?tW=RY}R8R+&J8C|G`&}eO^~^@V29# zbG~|X<1+`Js{H7VA-)AIJ-U`wp0|4s487PZ=DXJ)Oq=ih!$(gzv%VZU(b~A<{#Q3H z7&LCo7DtyAcRZ|44J!OS_o*MkyZ77Q`iQ4@%aSv_Ec=E;mi>O{nTNaE-dx$%X>HKt z?OBe%pb=~4z2yD#z*;4I#li1VtDM=Tb>81?{|(lJ25NX zdGf9UH~IbEb#-)XcHOIAu8jM}W6O(AJCxG#jn`4O68^|>?_b>Cx2F4g?z!!O3$GRV z41aUx#c@wG4e1*k7}vdL$LGVwUk-TpVrgO0A3%eZ)R154)*@?72DdVcTe>Gw4?6>`A>(|&vMRs>$~X}uIn=DrTF*1 z`SP`HGk!|laCh^rPi_j&IIfiReg1pLzmA+4K5ETs7QgYj!t@KjeRkJ`f(mt%&#H{L zvtvg7QuXVDJ-qs4ZHlv1dJRnu@8dSUTj^a#Zu)=hy$M_nU;qCN!Fr8s8pil zs&loVh(eLIMNw2LMToA*9zrNfvS;5yxHMPxCA3M1%9=fu6s6z$J#(&G_}t(7{(bM? z|MC0(|KHE_I6cqnY;)$!nYm`poOzGQUaL_r&diX;!=HY-`+X9^|JOX zny@RUPlQ^(Sf}k-nHrbUM_9PtJkmE+eE!Gb*%sYgO)c(d*k!Ey5!V0V#0yI{YdSP` z%o$ww#QIhKGKHY_d9odUd_HY=^w7D>Ge0VJ&fv(mSW+*<0^U3@I6=wEdQB$<;L@ zUzv->Twasz)yLAItK2Hhm+TLXh9>zobEiye?0`Iv3Sivzu`j9iQnMnY#w&ub8#qvrp-R zTi1G*2DP+WmZ|@t<%X&6LR~t{e7t%?)S}4A{kMc(H9wo!|Eh!0jWu(R>OWP*o#bzy zy=D3R6l2GS9bb!fncCLQu$}9&$nn7IxkFzycHa_KRQBoKE%^s~R$mNe{GXpH8L>B1 zF@0z1ptX@VJk~Ufy%w2McsbJ{bjriAITKFzd-Fph*mvZWj*ri8JiUFy=bi4a>r298 zrzrH^(dX&*?zlciZNs@ID5R^-JD}f!idiHf)JAmW$gv+XC?(rE;nA|?>u1V#hZdt4lA z7-RZqRa9D{XrRWK$0mu+_d*uRz0gm=i#NDDf?e1Gu7Bi|7#TSgMn+zpk!h*T$hPdt z$SN2xvWg~53&nm+3ne?I1xzcKYc-0IYds0xCR2Gts?$fA)}54OTX!~)ZQTXWAO7Gf;1^4+2h4w5D#HjJ+AyL`$?*I6MV`5}1*ea~ z^(2mnHowD|2&179a4#_n=0QeL|3og;6bO-yobqYBxo{kJMq4L1O70E$aCA8mMp&a^ z6g3c60*g2NN%J&MVFR;jr$WA&kUNqqZ5pHu1C8~H1pjQVT;4u`4ftn47(RE4f_trC zSTmN5&wG9kW{=GkG|3WTm_9x5ydw5`HGdR5>~HSo49WMhNO*~ zHYcZS*}83e>W;LXyLRu{yKjH`frEz*A31vL_=%IJGESd4n|bd11@Xl!R+4?`@|COC zuHU$M>vqnayZ3VQ@(T*@7d!Tlc%L+<QMs zP6=FZa0cLTf$LNWj^p71V{#I_f5l}}GyiJv<5(vyYnu6C&t*y8`N+cB!uNZJ^cRp?)|q8KSt;| zh^q(MV{!+7ncrZ}Hd7$=-<|Eq#87|O04FAi`jc#(n8VcX;^+i(;~n8D66f~2a^>+F z=Zazo&MoHGBMtX}5n<`vU_K1z>W+X^9*}wzH(tz#kAS(s!y$YW%(ZlER<;Ld42NgH z+#6(I>zMO{EjFMxw7W4!27C;2=PIAKfwJkLBQx-kBZKxB(anu=Wb(jej(1{ig2QFN zHAm*d9Y?0aT}NieJxAsXIQ8Rvo@XX}8cc`zahU+=ad7}*SPiV}5jgZ89|Lm`z!{H) z=lbA|gH!W@xdY&m!4-nj90&6Wz$Jn!17|%Rp6`Rp1@{769XQ1akOthZ&rSZE4}x4K>%^HT7F^5x{=DbUdgC1w&d$TxnK%;$>yMV+nwMn` zW&Nw||L5hPMYCB@Cf1OjY1Dka46WwBEFZ12VNG#1Al?V!%)S7~qo;eTCke(&KuvNW%>*8e(h zG}mf;AI03*M}Fr1XZdkm(laa0m5YSCXPjGx^St=l;2ky2GW)d^|5@dzb>cw z7GfR$JUV{1AofHYallz)Xtx!Y=A$FhFs$iMi?08yovu)wf z@wy1x!`0En$z$d(S^lvdKSLn}q=V$#vtRqLFn2T=Jr_2VUbJ{{Uufa%z7L0Qw9NF! zw9;`R>9`QkNIEtILqkT=@gWSyF(S-^;nK09fZk?iW)KEuOc}6W%7Ecg1`L)mV5Su8 z;RZ2amK5VS!=$`@Q+RKeH*SjQc*CZUUuxDA%jd0{LYY5JnleLS%nHnyGGM)w0lTHZ zxeQn<1sBYKjZy}TlQLkElmSzu3|Jt=^l0%E^Khn5v0TpbDUh>!3PfwC7>>qHkx&lU zIz?N+)X*t}Q8TAlF12b3?}Put!YSk#4)2A78$P^`zki>(Tsi)*80!v)MHfADVPTw| zZ9+n9@aqLoK6m^<9ylgLLGu<*@w*!VaEzkn=a&!W&TW_;&lb{rKP{Fvx1S2pv>d5* zRB3t5Ev8D#{%I){^YQEXSuVdmJhT1`<1M0MTC{+Qb?4t%u!nO?1l73lyj@eC!Jv5? zrdW5hRtoLOos(f461IIdXeS7t!sSEDt5UnF()Hk(3fIFmD_tkflf`mzz5Kj=ex2N| z;L5;NfU5(i z=nZpr!5M=Sf^!Gw4=xy7B)AxG@!%4`C4t)pZV$M_;4;98!Ce7Y2(AKL4LD5C_`o)S z(*|b*P5{mooDaB2a53QG!6k!}fGY%tizYa;DZFh1OCZiHum+-S1p!b8=mgXNx&pfa zJ%IR_X(CVs=nusCIKemuw6xLb=BzQ)bTM80pJvUxWFu$fTGR7imFQzK~nTrkVXc2coP9u0&J4(stZ^KB*hfAM- zR1!YCDOO7JX)9mH7JCvlP40o>jKgHki1RZKom@=TTwT<3k-bYk4fyuM!SoeAE2+ag zK;e*fUs?XxsHFA$2QeNO5%-@dqq>Zy!(N0-oirUUA$=1~0lub^{SVG9nHqjVMaV}t zHK_={_IFfH?ohk2k?>(j>HOqVG*F1P1gje?X4pk7`2jRPm{{J)`mVwvz{JSWBmW9tz`5H^_ zq;MPYxo#9(li-^1ExBK}^Vb%_H<$iw`#;lQ8}h$O1>W%G+cklSd zAhxeATnp$zUc3_Vg?%#fFX|<=-|~BX`Ih^$J{ax`($RBw)7J_f3;)oQEz2Q5L_%1eH-%8gAzp-$fVv9+)0ed)ZFMltO zb07XpgLT3(@SV87is#QA{2Yeg%g50g9QnXK&FB8Jd`!cSXXrw0q({u3>2Pd^pXVVx z17mu;C*bE$U??uX*MT47!6O9Q?62a3;kdzmj_95fBvd1_;V|s*|7Eb zzWaN9@Jtp>w-fv1pYi-S3(iHs<@b2pd;GZxk8=K9$KTWNdzn86{Z$zlk2U1;^Y=!7 zmVw6#zVZHN9k9(Y7SA@)y@uzT-^;*u;QJ+hv*OQqe7hTesqo!L`~~3K6ps`9g~MM^ z{!LPR`xpBy{t7ieuB7KP>G?}~zWVj|0__W6&%)!AKM(MImhbOqQ2_f0{#s*g@V7&{ zE`0kR$8{rND}OHo_chMim!_5euHrkc{4XrNuN(kJJ-(%krTk1QJ^$k!s4ll|tQT%Q z&WXqI%;q)3u%GR1!fgv4HP{w-bYZWZ!R7t0em|PWVGa2$!!o45Ie2FM^*5(^T=P7C z{`MHccKrI=gCm64=D07hO>hgRaYtbYSJz+T`7;2f#-m0buFufIq9^#RoB1a;^NXn8 z9?~R(A1zlofIppvc_TH4Ek9gUGSrYFkF|A`mqi^)Q@$Gr+zFy4g6?<4C^nUeoS9M{g_^P zI-ds98-X9U9qaD|ezY!z;XdF;TQ;M>AKA>GO#LGuTnv7+h=g^k06$t8!o12ect3_4 zQ$McPnfl$pA58sNw;72PmShvIA$9Bf;&E(RI;A|mD zs2|I@(aewQ&IOGlIb1!!k5;L0-Id_SevI{Q;QZsEWatN>KhtP8^IL)+`!2SZ6Zp{r z6t;^O7d{?h;9S$p9}RwK`3cSZY2ZhTH`qp*;Kywn2L2o1M{7m6oiD&YjP`?uX5rd1 ze}&yzO5_U<(LS1Ihulf$~5jU`wDGPyuKS#LPmV63`il^AX&EIL_h)R0jG0 zaoi>ls0s`NwgE;1@h(*a#BrD9Ky_duPy?6@)C8sh+X2&oI39Bxh~qPvKpeM`06PM2 z0C5~C7l`9J#Xx)?sSJqYLKQ$AU?or&SO@F|WMcSn9c*7ckcy!7foeblpf=DDs0-`? zGy?VnngM$Ot%1FPLZC6w8E67@2lfGa0s8}efH-G95NHhy0}cR21MPq!Al~{f2MU3S zKk7f!KeJ1F>&r0=Z)mi08)}KD10pc4@7|GNXx{{KWE+W*I~ zzt+G&(8|C_Alm;I0nz?{0Pp4Asp@hi-BnW{{|54 z{}%$afn`9n|NkC{_W$dEX#ZbsA@m2J8W8ROcLt*UejSNUW3HwL2p ze`_Gx|91kS{eKT&0MH*e0~iSm2F3&9fQdjEIDu>fqWymydx95AnRL)-|33qW_Wvb7 zwEv$2MEn26K(zn=0*LniD}iYLzX6E${}tn4KLd4vX#d|Bi1z=TfN1~U9q0(02t@n; zkw6(ZQN;t%{(mA6?f-8BqW%ALAlm=W0HXbW2@vi7=K#_E{|g}6|E~nX1Y`KP4wM5_ z2BQ6cZ6MnJ*9W5ge={K3{}%w!{=YL2?f-iK(f+?b5bghm0nz?{3=r-AF9)Li|0E#V z|4##={r|&2wEuqvi1z;rfoT7~42bss-viP9e;p9*|I00g^uW$Q88}fI1JVA!H4yFp zI|0%DzdI1^{|5qPbfI4Xm4NZUR=`Az2X4c7eW(Y<12Zumcm?BuxfpK*^}%@HdyEIx zVYo5WCmzCqYCyFA-x(-l2FE9c11&KeD8z6}I6g5P=!M}xe+;*V_CgJeK`nsxLJdqp zEo7K9)WE|?C#WaV8S062g?b|0;W!1N{r?Ie+W)Tu;@u!Fyk#~V!}H~|bX@d*ihW}o zhr|W%t8l?NLb&i2u#mj||GQmd+-B?(XsZ-|qj|f1f7&+w-?e9qW64rWlX$23-?d@P z+XVaDR`K7qig~-jy!|)ck7HU=i@`YJ^V5&xqI{bFui7g1hclAY7A}re{cWF^zmMk6 zC4bu|Mw@`Y+W!69K5_HkG8~uTkDI^k6JxueZAV=2UKq#R@E#s6Q5oF?{`*f1j3MA+ z47wO-4SWQ20-gZ61Ji&Lfop+*zy2s{f^ zgLqk>7iiovBhYd{f6zGA5C&WZG=p$?U<_!ugyzPAaBOHf=v}}h;5uL$5XUAC15W`n zfro%N#(>vNS3s`<3ZXm&U?FH6!*B+z2rL7=8~7f02UrI@43t~LfB#7hxE^$8;CY}C z@G8&}m;n?5i-4}cT%Z>a$42~t5?~mx0O$_uQv$|-&I2w7J^>~H9{|&Uw}6L%r-7Nk zY~U4OAut!X2Ur3;0;~X*0&9R9fXrH$mjzG;UI1zX?*jFK4gK7!TSN7zXjCz(mlqfIbl48n_K~ z5-=UO7nlJ&3X}kc19O09fW<&D5XX#gtm*~m?sVwRe;8z-GD;KX9TncJsrq^)&V$y_60^mdR3r1 zXt-tL#t_>8CxYGx3B48rq zZwtgRG6LKK;VXa{z|j~F;TAv%=(#{6&<4O9(9?jrp!I>ppr-;~0M`J$AiOuQ5_AZ# z0k{}g0pYel#dZAmpNc^b1g!}=9w-8B2Gj+;9cT=k1GEN40iA%Jz+|YmI?x^TCg4P% z2QU!08JGs~8o)@4)hYB+B~V z;67jtFa=l!`8olWH}Kzo(gscfoecHq3)BZa4~S!^LVy|Ql|Tu^TLXolMZg=N2LN3` z#{ny#+|EER(364wz))Z%gm(dkf%XQbL%x2%7|=059IMs^E(h%gtb_Djfk~i!fN7B4 z5(zpLmSo1p)1`~Cbks{Ws~-;dVg`57$Id8$%-{`mIV z-}d`)9uF>3`~H91@8|FF@c8`Oe!tWvKhCYfyM*Q%uik%Zyhh=lef;vM#sXaVI2okGp$y?E zv8UAHDSH2gU;ibZq7Gmr_8(wJB>}bNPh1lt(C6 z@{~-Y97MzQc`_|1pK4m zg`QLopzK1!WvG7jf^V-|l*f1qH}YiW({LZEhwv1cP_0S%{W;$r&v=S%QhkCalR|YI zjSr&XqbLVb>Qk!l6xBZC%Pr%{+@j2&;i)_&%c-74IhoRh(vqh{hw9cmnXlzs`OI_5 zdpv~~cuMwDokZi~C_^bH(0FH_l73X{(fGEMP1H8o2cE*mJViHYcqY~RX#7UXc*n951VK|&j^3|@_lO>my)lw4+l4-;+G5NnH#*?L>_C7@mD2- zK(F8I*KsE)>R?2{12SiRzf%Kw@Q%;RIOq7alU0feG6m(zFs<+3< z%T9fgHn$%E=@0l-9ympu##T!2aF~3$Gf1 zj{dYq;X0{%)n(k^o)}p$(Gki&Jl%86O``U3Oy2U&mbOe;?-pkF zZjpd>?9;whrjY-rhJ{KF`S5Jj330n&po@y?UG9*cCOa>UJ&oIEvhwEQyQE56CGSfw zC&<6)xs&)FvGSN|RDWs+=>AHD(YZu+oVsG|XKPy~@ub0B^*r+O{Gc|Smq7bgKA+S2 za30ycP_DJwW@5`6&rjUzm`^4ZzNv`X3i0k6j*NYrPwXzO)caytFMvDQEU)ka^0el; zL!K72*Ku#B_?Cqvq~ZIpom&UnGP&A23%3-Ky*aY8tnOfYwS6|h<_i9Lle>;lA@Eot+p&jecL;~?;}#Q+W29V7wiw8n``=HJtB*9o+X;kf$hz;>k;7m znE2?VDh)ji+ou+-x-j=K(Y>eA`O-@GYKB_qd7p75gs)H0cHN(kE*nQA$&l<2N|7#9|b{V^dmxUrOM4_azEXxcXcQ#p6x0a8Xj zu5x>=KDmc2W8|?qQdCABx4IiWFkv9H*FATw>@u=+Qa@3oiJ3CDJNd}3M+5! zhW4!(`XonKPO|eCc6fA4$Ch!9w4EXDPJt+DGi@ zWH+}ja)U22$Dbc<+3pc5N;vs=LzB}*#%%A(7h4{(Um9(h2cfDL8Qs#c1G+tAV@W5; zbZt9`ms{EWKry?xc=bJ9vCBn9GLj87D`q#zJBJ$H7<3UPP08D2K41q~Iqmpb)9)ga z)?l^I{sF6^UAd#iKzNZ69(wnf+n=Lw>j)zQZc%uDuZN59NvMDv}Fw z*a0`zzqs>7{vuO0q07XE+pP6z2i3&*9-tS0PcyvDo({o$ds$>5%HyYUKJ zlNzS6;Ue^pw4MfMu3cs)vYQqi&v$_O>tszoInz4TWb}&x2pZbstAS{tX8OBhIk5?7FtdKWGl|Z}W#-%V5vCO>BF`@g4N1 zT}iziPO;k0r`fo4g6$EGzZWGw!ERohs&R4w)JIfOmu_>MHS#$2rkgqRH__UfHK9jX z@ub-!1wEmEGJy}WW*%hqAH+PK+8OufqU^@#{jA04V^u4yEFs>ryJ_qm_D;yv4TBw^ zzlr+qby>8N9X7huTcs29S4Q_^zfRlP;Z+$XXLYbY%`;!%u$kR(yv4B3%n;COD*02^ zvE;ei)N>VZJTsN9I>yV`SufjoS-QabnCOrzN^@BKH+ROIpMvfCR||iiAZ+6A2ZTQ; z8z~zozf*prtf#D_{7P9%`GvBEvYN7r@-t;6aBBhX$p_Hi7cuFB9Ln%?A@svVJ zhEk$T<0*xd45g$sji(e+GL({5G@epO$xup^XgsBmlA)9+(s)WCB||Aupz)MKN`_L> zlEzaCDH%$MJdLLmQZkehIT}wXq+}>1EoeNYkdmR4$kKR9Atgg8k)iRFLP~~G!q9k1 zAtjtM`1_#0IyJzPv!3qVh^Mbvt&&nVTS!vYyRRkbQe#n;Fj5J$#AinqAyxyG$BJ*l z^$_E;+iLG1vh-LFU&a8grx?lY;WLJjqF$+D9Y45!W6ZQ}CcBefibss!&x7k(M$KO~ zW;DqfcEF=YDO^9p1?4F3G333b-{uvSaD4>UJkC3eBP$EP{iqpa2wI{tz;Ggottnl0 zd&B^YFT1PcO-hdp^0Sy^54!H%#abWIS^ez&sd_G;%f9Uh^doK-iS33=%Ke9e;PX324b#^<}|C{GvW*`2@J0XL9F`tPde} zC%VRrwZ{4_zrS_HOmfLiJ^aZ@xZYz5U)F_&k$Ji@A@fym{gFp|8iffM9(D3UO7l zN$;h4i9^O=eVjYKIy8rbD>#Z)T*my%f4B!k6EpSJhL6|7^(o_(k==DJxhi}5iZ#;? zw5GticrNMI-e|t<9cR$Gn=;nTBj^2%hv;NGfG)h$f7pDIzrE`1ASEn6=~9+l44ISF zce(j%>|YrhU9(~cTQ^zF%LMm-vY>3v0%F!VF}2$gZ2z>gbIli$nC@4OeIJSaNnfGE zyM^R@^^6r$6|jEsy|ebjl5OqJ`z`jw{+GDkvX6-LT0PABwxAbi!Iq*(5xL(oXLWRI z>>sKYC-OvO&bWJH4D5S@Zpc_;8b_jade5@DgzamsH*-}S$qp#^w0$b-%9v3Vab%eM ztf!ePPowF_I3BiVf)o(KaPken&Iqg z%N}_DV7jpAUOd_PuB&b0Xt@4omiH($UP7$S*QI-<>4CP)DqOLIINmCm@%|FV`#BW9 zT0*W=9Ujyr4BNvY$>>hkP3H_+m?$ube_?i*Vkv<~YCy25bf-f-5DS<=1V zcif(uoOv$c?9A5%PhKlx`ob2|KZLPz>21EJSD}u%J$4;vl^aJTeen9ROwXxb80*$_ z=w6?`s4F{6J~@-sT%_!hb+j939~JX&p{$(dE~gWYSU<(?G7h2ail`2)CU--fJNE91 z5cWxZmWjz7xE^Mbk0$2@v+*M`-c^O+^`5(-PlsT3{Z~=jODS-D&s1dT`_5nwoLatr z#PPPEt)pM1PiId~P?b|Lf$Lqydeq*^Aa?G`qYDpq#rD17>T4auPFVZ!@VvozJ(xSK zqbQJ_A*e18TI2q3-kp1W8oR)1@uT(c4L~b4Ep9W74VhMGZg>c<_nG;YW2dq|wx4m) zXvFJT?e@=71K0)U-1eMLw+C%qknqZ%t@fTMPFOS?wEHnjQ-4U z!lpcx`)ct9`$OHe`4|1z=chd`jlBrh(~OU7CwV`%%rq&YdVv;buSsWJec3zxhhI&N zfcqsT_knwo5BvGfz-xO|F@M_-<5*2YMfnmFte^Xu@r%9KkRQdCOI+}N zLTDABK9=o#%dIhOS05~|%k-U|?A8pIl;B1zFVQ~8%!7>^8{Yb06xJtgmmfQdeXSJ} zQelJbDG`ntF_I-QLoQ|cND=#KHC z%h3-7Y*eqe{k!|;ia}pmqiMyqh*li(qLka7W2@cF*^}GcjP4DD`!hz=_MK)Ac8T?< zC&fv)Js$@HYU2i1l=CHg#tdQ^9#T9@jsJVjl2 zGM%aJNOcFElJ-1>T2yONtwD8Lo+34#OdG0Is8;4FX~k2hM709dEqOBXJVh<2mZh4Z zx=EAYAB{YP4OD-lx}GOf$5T{G^%ttEc?zp|N-C-TMD+)%-}7YN@f5wGx`OIgJcTcL zN}f~wjOsF;qEepBQ>sg-eoXa4p2A|Dk|L__Q(eGQl+TmNqxv4zcX>*3cnWV*eUs`N zRA1vMy2_KeLiHu8vw2Ebp294u#Z+J5$(-jY%B1=%)u*Y>;3+xDQ+R^vV^kmI$sFM+ zIz;tBs?&K2_w$tOrFsw5yQtpDlS$(#N~L-`)mwQAxA2rCQ@xq$jXXt3JedttucJDV z>fL<5lkDOtq!jI>;c2vAQVMtQT9iuTx6^n^;Wiq+m4;IaxA0n&LgSNZJf(0mjo(DW zDTNzpcoI*^1{zN(Tu;^v5rSX)) zXc|9<#?R&{q!dNb@JOBvrEnInMG-VUoW@fM!)W+S8crz;<+Uh;#s|}QO5qF|Kb?kC z3WI2PAWz9O8c!*lO5+1)yg!Yn6iuPwel(m?=*w%74~_Sx@sz^JG=35drxZ@4;S+dD z#?yF8;W!%aMdQcPcuLV28tzHMDTN-q7LBIyqi8&(a3l?Pr{R=BH(rZI(D>mro>J&a z4sp*)3@A{QF&%#)#%{{H`dT_DvGm?dd9?#))FvOC`IFljQ(4Lj44Gr?nD;r$Wn zJiFRKmfh|PkcGF%x+2P)U z%O57kys&%ps#njv?@kzBEYG~QYtd+UvU5G&uQJgJ%v(FtfmgOCY{vUP##xE^U^jB^ zn+s7#@qVAFY$f_+C%d|FAq*!d-XEluiz_peNHYv!xnF2zXyHMuCTFuz};du zjL%VJzS%j5bw^}w;o=k2MBnW$P2Xm?xRG0*rn;oTu1rpJ$8ZS_d2L8<)Uq07a-`cH z)9F_AeNg*rrpc3hHCNq>Yq3?-P`LbkbZ7D{st*Zn0}MCM1eeC z9#L8I{R7<3GDaOmilo;q=V`ua-1@F{5-O2Hj_0>^&EfWML>HzNdHiKoT){hg%->5# z(u%C_IK(697^ipX`m`o1hV8h&DxKTk5#4o_$t$O@lRn`ZnBG;tOqn!PExcL#fNL*H z!!#9gQsqLq{3|YfVGp4yx%aNHef)N={}lFQ+K?XZmGZH-zF_^H_Lj6EQ@>bVIx&UY zzVBK>H4;9yMPBH9yuW5j+b61#PtzQAQ-g5)gsIi8R3qALy&eu*&y}y)(Y-AhGVp|I z#i;HWZ`J8|TaspdH?FV16}4|?HFctLAYyR-@?oeackxjtpS#?%DKgQ?k=xUI{Ep4w=-F}1hYuinvLBf;A_R?#?^~dhrb2Z4$>E~K4n#k!eJu^)b z<6<>lua?_im-Q1h$>ejLUimr=#qzosR%(*UOLoRR%(?nH^bocq8gVwMy+?5UcfV0u zJ0dclcjUZ~ORv$3(ITsoPkjDyk~?0O^!Cvrb2fNdk`*#oUW2hji#UBc)kggX*S`mv zsJ!$UOzUYhA;!xNwX=C{dve%r+L-#fE~p<^m}wIYx2Fzw>bU&9 zEJfPH&wZVoecfW*-mCq}v`L)mk%0a2@O&Mt8CVHBkeCVc7cK0?wWsQUv<~FQ-VU!G zp5yjsq)lZ9GGtQGv&I$N{_7!d??`gyhg^v2#}%461$Mx?T_wET!Q0kO!4r_ zF2pP{ce6|h*Z=RjxpyV4p7pqRvkO=MsF7)1$(|pU2EwD<`D^xQMu+q|(kgt;H?Ds# z^z_jo!*n&uGcIz+->R_^9WprIJ#^q|><^-Q#%j9c&7_?z8wzmyMaN96b;-?ZYg~42 z;Nn@+KwVO~zh8aGZEpYO_es_zkM8NFD3){mslx1rE;)Q+pZf77T>bLRD|Ja?_w(n< zH8}mzLbn?ce-O>xs}Ilf8IiIjj0abHt1G?kiv3Gu+E3JtOj=bF^>Pr7mx{XgPwz&8 zSL$_rBGV5vGt{cM8!+YmRCpvfT2^{Ye z71#uJCw`6^kG4y={#!UOu{(*9dD-RpD2!)X+e*3{nVgC?G2Ak=VzP9Ec7mw%8&+5)T`Xn%B zmEsj!ZhuX4Nz^ChZ%Yo0sK)kS*r5`AvcxhVt@S1DcrP1Pp--Bg&yN@E!|`j8?Qm@a z5;bnG`srXF4K^-h@W<&hdS1e(U?$SNK`bPs=80+`oCI!oA&I-EfziZ z+|s`Y@ptn}wOFeXza=5(aJ-HgUchRxne6th6!E?D=%%`n&$aG2XJMsU17*(g}?R9dNvfd0TX^9cyvCOZcO0=BQI2 z>}bb^`*ytUe!vm+$l{sp*mKO?j|Kw=pq70|+Og`dy;qqX;^OB#)M>|BPBZBLdM~#= z!$+Sq+2QNA4VJ4jl8|&C$eDsqh4K~m8{^H4(Oi*`udQXF`j!XM==01)$F)N=Q(_j_Y zs>1EXE~rgPV>Q?e4Vy`}Za5yp+%0v}VD;vBPk*?UTYqSojt09oaj8-7LAn^PT>eR& zHF-N`VT^Yd)am7{I{U7R!-6Z`_NX17tyO1-bt_3v7{}G8<>HXU)s_>dQ+ZP`sG?^~6{aqTbj@>pB;#F&&%PeQr& z+3+&9Ej!XvZE|fSw?6$>Zf)7N8fRNxj<3S@IQdGaEqgiZLupVBmtXk$lNvkhp!LU? zffiVP&TCeU6=oYX%Gq=6Ii_N*8oO~{QU8wZx&CmXVx}5iuu_$ZPeHn3kNsMvf(!Qf^t>wlymp&|2VY|hcT58^_$M{~4 zcBrsrXW|zuTF%9HeN0r?A>F5kw6cTw3-G|8q*R$*+N(7C=z2HQ4JEP4teJ}LE}I>k zu6UxO%_7J~VT4G`D?~uXGgI z2l%RloPdTVr9mp*~YR;aBjVij1|?bl~d(jJ8RTZN7Sn=&T(iSh+5f94yu zB`b5vp`~OtSO18&-YwbJQ+9rNb%I-8uXj!I?52K(irU%S@mKb4hddjer(R#0$K_xD zp2)K{9oLOIx|chj2tSm{u_bGE=(mx_@oeV(hgdmQb=dkRvUxpFPy9&a*tpz-^Edi& z+b{d6v;~`1r9bG%Y_9+8`xM)Pb$K(#dfg~4{oqQS7VMBZ@98Ivdt&})m8>j#wD)+~CO){)OkBI%s4qScrRqc>rmBb!N=Q?uR-?G|UhHa~U z?VIcnZhvp8ZerNydR>Fq96c;ww`K>!4qW+ka`9R2_)4!K4BOwxXJ~yA*Iy^TWt+0j zI6GYI+O8j__j%X!Bg^OMyYr^z-1%+dd-5Y|Wco=(RhFxt$A{R)tS5poPG#S@_Hg>h zHe?OIcXEb}CwF|m_(&SEG~1;b_c$es<=yxc`#mc&aN~nJo?QP)uVlYvd8X{Tb|aZP zKH@(&)n`Q}E^8sI;MVU|Me4J(t2b^;yT|oU{p#4dtfgfurW93k<-f0Hzh=!X%~R=< z%(d^~nx@*U>k5&rA9!&4H}DIo&3eF%LVZUU}dwG1yz4Q@SpQPHRnymRt z>+?*O;qw+o@RihL4OyxuB5k?)m3@t^&f2%YWX{7koEFuwRawe&PQ+(V=k}j=ebeWx zkuRc~6uP#@{OR@Nb5`xe<-OEe;qw8;@>^_WR{D!KtCYSOqYnEL`zdQ-NtWk0U9P>f zYhyoV6<*G}z2z*oJ!)T@-e)aZvb8BJlk4AgUt`~8g*>rV`)rF{WrchJG zO(j{kzqcJ^8`BEQ6E!qF%!(@27`|MjfLhqtRFsu+bij+<60ZMOHZ~Px$=v;RVL*0& zF8zK^GJ?lcE!%X96f zWUT5n#Qij@U>`Kt(X@!=Q~sP^(68_J1GZX~Ckz1qBwF%yMp86DoH>_)ShRvRtuiiKIu6ltdbZCPCP4Jmmt2e zHA;KXGWZTc{K;WiOML~4tFPU%ORXgRe9g6^o!1H4tf&w6I$cRx`IZbd-Ipx*IwYd^ z`kYD>PoeF*&oBF+y%)dC|%7?8p#3LuD=gMe& zCIhxQ4N$wfNt|OIEV|`9k>WCw14p+wd?u;=KW}0CY!HuJv-d{w_|HV? z(8qJrg^L99M=lU#MtmkwD<7P*PmB}4U7cWEzw$Gg(Pnd=p4vKb)a{w?ChY!9UIe<# zcb%|CP&iR8zU;zhqEKtvZ|Ue1@xgO}=F18{6M_FOCR8R>(B)x6clQsU$*QySWs^(S ziHj2amJe)MMUvu&#zkFUE!b4DV4aIj75T6?DQV$>MFMNTsL*-VRU|_G`k95tQv_t+ zNw>QrtH_?3nk>)km4YWR&jJR`s3H&F2vhoATqKB_@};~qzKSeRAqh6FTg2s0b-rv* ztsErt`BkLQ{;|gp*+jvZK6VF=y{{sR z_3jU9b1PiX?yPyMA1$lNi$&)7(`%Lr%!^$c!n#$H7&+}VueYrfG->&tR1{Q`z2o}F zck8i1@Oj62@2g{~iP7K@6F*K|CBA*Y#%h0fHC#_Suy1WPiKiCJha63)CSti1!Rn2v z;;%biT0Y)iO`d)6E$aUwO8hcifB&)inRB?Apb=Q4QtI37b%C<_6Rth?c z4$BStR!yqw$JFcPZWi}4{o1XSRtZ`L`eda`(Py8FW~<~1aFuJ`jN*W<({D|~$v zN7RseqEB-3wmJ*OGF?8{Pp=`fSNi7-OWG#L6=a{@wX}v*`X!#(ojptNwBSKyuiZ6d zOjcgC-|ZAZk6!)nKVoahGl%!bHajj5s61&*IayLe`bJL|KYpJq*l)aj_R0Dh@_g*L ze5F%KVuz{sc0JPiLOyP|7_?;eTJa*c?PGddej$eiC%RT$aNkeLv_p^J?1g%m;K_05IqtG|%fUA9ap-?&K7)5H0R!XbzsGFaZ#Vw2$P z;BhMrZ+;=WmIlRj8YU1pcRSK<=IbwH(kqc!{l2XNrIOj_%H?axkf&p|Iy~DTUgBwU ze4&0V*_0t%n7w#|Sod;{DzhSGNm(H#j_5$7JA0j z5`Vj|PDibM1a}6;PEAd#C7%8#H7uWO6|;|8N2yC{iE`_vX=7GIi2HO55S%QnB?p%a z0&TKph~tw+)-PzPCAF$c4cZ8nizB_?S48Q2B`NckFC7vZCytEU>%4`0B?IpV1V2nq z6yKcYFy@{2S5gpSK6adbqL@s2>J}vWN{qE+TV+m77A%u_H%oKpSJEd%?&F+x@nVZ? zGno(BU&;O9T6wPOI|P0s?)9&J_LVH0+wQ#Vq%eVcM>~%ma&@HF<`BQ7G3&(|cU@Cf z7}Svm7VQeVxNa98xvn?3n_e(Cr+%~y=dK)dXiNYetd9D zi~#PrJ4~slC!wydqHpO(3j$tFnm<+f8?m_Gd6LVx4dT8gL*H*T`$i7+FIh0rY?EM; zf!)a#p5I8h{p!b|eYT6ePMK+>&izKNO}Tn&;q9#gwsEfKjMQ($yz#5*&2NcVv_E_lV6(t_pa;Mqxz2Avx zPY>0ChE#EW_OQgRIp0Zqs>!@u+eHGUt`8<$s`^eMw#^{78dJsFMlE@=wL=4W;_SX6 zKrK!%FSp72kg$QYy0*B?YS31}u)MLRpQkmz@#Wk!eEE98>DMijLe@4Ar->qG@!@bm zP~xW&-LnnkvCEsh+byC5-!4z`Y+c$wBDOCYJ+OGSIA(>yP!oklvTfd6M=S9*an%YH z#btdO$($wI!{a7A>%>be9=CXP zppjUd4hdrPwh4SPWU9LrG?Gi&mC<7#trvK2o!@tJLnE0mOxx|w-gV-hJHKcSHvB<0 zY0iu5ab~l)maKYh>i&bQ%{d@ik-Av0*!BANk@J3#^3}?>y5C$w4&BH#H5q~CD*dBuP}>GeP*=_|*_Ncn3zhG|mxJ%rOD`~ooA0`~;# z9Qw_Y@Za+J?R!a*$Nc<8pc?npqqPoFLRPrG;l5VHGkS-+hEoCYI;E~-{t4%|@e5z> z&;QbJo8x$p;@%^TYZW>7P z`)w+bo!&scrf4tRaY#$p@5G#vs(DqcqP-~_Ja0U|ebUwa!WXU5Tf~q~Uq_l)%j5X$ z(=*%0t|Ibg-+w60fbk{Krl&{4l1P{Gb;{8V10ddRjp?H;q+?hpyr%=>cam{mi;tuc zuw|h%vR5aFpK|T%x7~z%iTmu=UlHOzjqBQeKY8qNk953<dejgFJq?#GN)RfG2V{9b3<2~y}ex+^Jz`bh#BJGDDS zHcm^B6Fswn_^YBG8!|}sUcWnsuk?ZXzL`8r{tVf%V5i=_%k81Op{wW2I7{Y*rm0u7 z=nVN^jA&hyNfx<|$a%@Y_6YU6XY@T!`i-4t8TJ{*-$eU8&TPCuu8)|lKUuXWynppZ z*6^*E+`etPsAt|g0h1P-o#Bv0-V9$|-R7kMtbh6m`PD4hKj-YOy=!{eGP;7RTSFvd z(6{oBtK;zb#?!-gD%s>{<>K3eR(7>zawFT3%xqHFwBd7y)-s^okIiuT|LX(CbJIuy9U+3`oijCUM;^(BGRI}>oq}p2~E#GZ<#}4E_&W+cN^O; zxN!Tr91?N(Rnp)ys__1shVS>bcS!3^N7p^J>{6MTXAL{3`aFngq zUGidsX;sj67=KNZEivA5mn{1nm-yu!#3v@r_R_gWn8fyP-yKtc^*`1TrQ9Qdo2tGp znAIJ&M`_T6R=FhBV6@(Z8PMJp->pQ>x#XJqxpNz)Lw`)~HpYBeE;(AwE_mb%^~;>z zCHz`0f$N6VL*Kymrsv;z*py2|+dtQ;_JjT&eJQJtFpsP{-`zo10QE@>>aclU9!Z&K z(rs=P^nb6zX7f(xk%jS1es=euJu+?DJ+90nrK-w$rd~bZ{VoSLRl|Hzud~NUZDBho zukAiRzkH(JLD{t9adlg!*ijOmoKNOjr5+9%&>Q-1>)F}&^9ifiChO^28|V)g_McKN zAQr`EI;5c+^JzCJs(n5Ry^X)A5xZycrB$whu2c3Wj*B5ODUSfYbo7Z z@LEdU1I1i=Da$;0Eu~S@11?@lpJTk1GTEEgQs%bdwUnaEMO=O<)93M8%3O0^OBwe5 zK9^ofwf(%7(kOt}QVR8WEoJVDLN33QKKpnrW#9~6OIc^kYbm3@6ma>a6rJa_l+0pY zOIbI9*HT8er}-(vp6B!1Ls@o`*HRWQbMY_;KOG zk-P;9USq5@M4E;V!%}du0PA>G;LO1)n>kqQG6Op)R`9<+SQ+cbSw@2a_p=8LeTEjf z92+R;C*IJ1((HgKkuxI%9(KBsGiT}s&kO~FZyl`S9b6w@8oVaP|8rbuBbqGZ7735R z(Vb2@toOAWyo|j+XYtxD6A#ycUBd1{#!gSji~{E~M991VH&i*ceL?5f!*?5pKfbVI zcZiKH*eRJiD>49##YKhA2%R}6R5u_Zg8TO8w1Cinh#;^u9T^c6I;~k{V4b=3U&jH!V?XETs*GqfHE>jG8XpR+ zh~Kn|;J%Fn1K1F60PSP?$AA1*FMfjyQ{oqrrh@H1Q?Mh4U#!CKaRr0zJp3LTe#2@e z#JF=Q@vC6?HF;C8Jc-|1!*%grAjU7Y@ymZ!F2A0sP#S(W57&*~lnRET|Fd!(p(Oma z@c&}(ZQ!h$zW?zv(=??gNu^SZF&I6br+d$RIOpCwH8VY!YBbY>lzF_>Fi+;*smUh{ zpOEw+gbZ`Q1H_Fil4 zwbx#I@3r^2ox{G^L~nh<11r?ifWMTe7OIEZLtig5T59+neP@c^$76geF?L=SG$pC@ zJuv#NouNCT4oIeY=<86F$lCPPF-r8sIr{Qsna)Xd6YUJWjPxK$L7j@e#AaA{n$Az( zZ!=^V`qEp1NUG5;dPlkOr7`+`m+}2N<7MEpd1#1)#5S z(U%2TpHhBB^-TI^dz$IPwKbs%-9t-D%G1h9=!@ZaKnNgy%B!p?E2#{oRnzC;*Ozr) zGi~0}!`4XyQfD4HJb2;nc*ouN0CyeWZoos&1~`6gfSUja0UiLnZ-K6V;9Zmj0q$8q z0rq0K*o#fX+eyd452wWNj45$Fc?$R&07OxszZX-$TlfZJ9-$=YvkbcyEctx%byZ32 zkWerjHL0AqZ~I-#+=l`$mv^Yl-*xY|cd6a4f4uGLky_a}pR z-)gyDUnHM=FI(?ZvUzkq^|awlV?aUQ-lG(cCSR9g_)t8W36Np+(P*DHw2RJ*NR52u zjC2U0&uL`QcUI|315CFN-f2qTxHP`ES%NnpQn{gbNS{q&`8LTL2Riy*V-2Lyb!6Nb zHZ#7eNA=P7_#zge_lk$~8La}^FpF_`Hz|!cno02h9h%Y@AB;Di76H>ZA-!lsvuj*p zw&dXz^vyTA5~HpPoAW#|t|k*ZW?|#|6UNsxYxMVwMvqha9<4EtEd3Mj@x4Ew!-c?p zKqlbDn*-b$lr6tIpaZ`oz}<`MpOH^xJ5ko{mVgfVcLumlxMpRWQ1&`#2+C3R3h+Y! z;;VlpY2!-|tjoUnmz){z@yGv}iP02zFu*;wKESO9>;UAh2ynXqhj4xG^9HPYIKVxR z>##{r_b;2k=0ap4>Nrpa@x8=D2w+Ap2 z^^O1>#x>LDVce5Gg`j8h?fP8!NJKWtBYmnWLikMg^t9T#n(1{VRcR%4)9b5()%yGu ztf~#qw&dt@TTS)MU|mRGjF+RXWUSM)Rv*Ciiq+6BIhUL9M1UJ~et;{%{6w}qXH9^+ z33>kpM@F3se34gc)*}X zwuRS-w#tK-)(4|zD*UT6=zHt(p*n=y)=#mF=25^$zQtx{31XkPnpEj8y4i7LUrLWIste?v>+B^gvR z(_h61kL0#b$>lO$$Jzn72zI8pXfRePx}r63unzQ>!#iw=VyeE58I+McDknZlbQWmF zm!&l|mDUiGE2*rmM;NI0ST%Z3zpkvEQDWxRV#THF(#n$RO9(@M`UWRmmsN-BXpSnw zJ@r3b)6Azs#q|0Z%9>gFr{U?#n)D^oI^@+N^dx$k zhp2z_>-y?4BhQ$r={i(fQbs;zdhA8b2 zlYfTyR|DFDrd<;DdbnO;-nYU18eFe4??-@U6Rx+K_i4D_iR(Q8ka8)2eYiegmec)F zTyuL3`KN%W6Rx|P_sJ+v!*!;4{}IY%T&w1NSCo&yb-sB|^-sZdF@Wl$`*K`Yn&p(& zfa^JC`JaE{P#4$p0I4Wz1lZF7_}<1&S=<8PpOdpVSKD0foX%O?T;Nf_TTN`|OLU*q zoJ`8*`xX~Oki@mfZq7(l)&G(5rLfQAKLxnHskvMg>@owmW0x#$4KUe>YiHm*;K9hx zJU8Q_!TksLFPu7O%AkK-KG36`(V=sD8lRbX&wd8R@l?D|`Evao-jx-h=zt9^N^76X z&Fz!LeFS(OkbElYL>|>?%pCN$OmDk!ADNliyhx>tY9OxXfS;`on=IE^Wo5xoC~am% zO=SrM&1r+us%z556&8+6D=!I`oI#ZgMa*128{u+ASrNt4dL|WE(!L8lQ|XrcdMIE- zr&MmlVH#N&7iL)}Tz3a7K-mIYS!d)gZo_d)QMS}p)&*tOwA6a@KfJCj&gIfh$kpG+ zzwS_WG&c>Rzafq2n#<(_!q?_<1Ak<77_mDO-@YQ3>-!bv2Q!h~2IAfY*mlgwCmN;_ zJ#`_{0Km#ec^ROaVUyK>`?(fbL=#Jvm5*d)gKmvQ7P^GnKyqyIh>mooWYx{eOJ(Jt zOW7Z3C&}xM`wW0pKcb5z&&o^k=7O%!B9C~=abF8yb|actZME`|tSMLKa!W0;NVnCv zZvxCiA24}D7fUxQFUebhdJmfNsD9o1zs5HU0Ly>FS^?O09Pi)oa;qNR3FvdU!qMhVBIU7X7;vB_MC`=%H&i8hu@#?NGiL3hw5 zllum19>A_A(Z-U=_?gT_pvwk7C1%q?+*bk?BVM%2CHh!4WipuDCeSUh$R(bYxNid3 zWfE;HT^T=ORiN0 zl`jGRYJk1H1Hm7wy$e9gbRhnnxIY+!KQ9jd78`%x0~iYcd;OJh_&b5tn&yG7*vw<& zq89gaW5^`hSZ!kbOzs}gt+C16fcxz+WD;#GnT(&wbXDeZ?Z1n*T`$}Z1lZe7w6SC| zekOAg=%!d?wnafD?&ktx^(oQE@(Ct`$!!4L8jD=w*?{})0K2Y48%tNl&tz@|UHk8C z?Z^E8wBI6=V%$pH&jTz6#PUnxAv;mB&W$7|A7!!Z(}XfgY}{>a zMZQjG{;7q$;}%}huhS2R_W|+rBc53LF*!{BV$e;397;^D8Mto*#2QaTAFFLl29tXb zbgM0LiKhwo+W_`{BHCE}#Q2%ae9$o)vb+)1xm>S<5&fy2Ox&vgdp$%Os~*PBWG)3= zrA_7>+%JqFlW1efWc*C#VbC?%WNyX%z8ErzHkM4r&t!J5$>q8qif(%b?p*+T+le-o zOvcY-%AlKJkx4$(fcu4jSaSi<$MOdzgUOu)x+aTU;@OJ(eE_?zL>o(2#?NG~23_|b zZSBXs3t*Q?w6SC|ekL=e7VWplq_Nh3`$d4&fLL<@@sOP;S?2O6M*!?H zi8hu@#?NGSszduNGRfcO;eI)w2@q>M5D(djl65?g92sS??6VVPl-PJU(29JW(EL*f zdA)v#@REL+xX%W}(~o#!>Br?Lg1JT9W+gf=^UL)wXSmY7UPTcPYuzfPokiL|xx)I;fIQ1;SZx~cSEx?*cej4)D z#gREM1`pLe3HjT>!;)2xVw9x-V%4YH2W8eoI+K0}tddFF}Wm*_*MW@TPRuEU5>JNI+6~BHhCn6cs2pY z^3T;Mi`8DLd$~;($sqduz${sHJBl(k9#}cmdC(?@_=z^9KDL|y*4VxPYa%%=TORT2 zw7{|YwH#+nvCarcF3BUFM#xmbAFKZsq0BzNFo` zZcU_5FXS^G(#_6O4xZN9Lq3{kp06?4eW3%{VJR@xLCGq2HOl4z?ER+qzfBg&Ao_K2 z+I5uV*m$VUgSI^4C)%CBv253f-=P!&V$F*#aSXqSrgSyb@iPY zTONnsw`{lZP`ypaQ^CWM)t;MBwj5yRqjny)$)b9xj!M8$0Ht}r-SImCO3QJ*)68$O zT(dmJ!|03Sw1bDdJ#oqcC|fZrcKh>D#y7++D@NHGl(A&BK`qr6r>qfWBWB0uTZl52 z$X*#{+bNIkdE32eyB}e>r+zB5-A}RIms{?s4zeHF%9_Y-WFu=Ldy#FdiR?r+k^d3f zUcK;pi-Ran!|xNUiQ3f(W!6M8h(14#ta6m8fLO97*<_InqOXl3YcOf0<#80$Mz+_8GRym7MHUkiAjiWhX zu1y}vA)Y;P^xBECwKg8oYnv^P_=(n<=FY)cHqPzyf!mq|R$aHEY!V>Wc{!0&J;cX@ zhGfNB^GJSc{KOLm&1&$+TJz?itUDl)9;uMC26Wa$?V>hV(|+U)#BW2k0+arftZgnw znF_EbqRT)Y@v>y)A$jd%@KOIyvdN-)sSaz(xE%h1yiUNebUKQ%tu`K_TZ=s6Wyz`& z$y*YGk90aY}eC(70Un9hus>f36QMKXwfQyf{D_`{L-=6=QY3jfduit;kEmb8?of^TKwNtpV8iXw0OTW1sO+ zy;R4XIIkv?0*3F z$8GY6j_RRgwTYE?^!>@)SAd1y zPXdkr#=V@vT?g0#=-rgUjRedDJOJ1P_!iLXl@u-qFbgpB)f8?C;8nm6fD!9cxOsqs zfPNcNxDepqfIWb;*HXBtfLj2s0}cSvHbQSeBcSAUlmVImp8(o#O5x4~OaROWJP3Fn z@EhRF&ENyf1Uvxv8lb$9!d(Qo9F9034q;O*ab%2)vr@jT9 z0c!#K0X^SN;c@{B0M7$H02~DjdMAaO47d*PB;YH+pslbOpdRo7;8(z)cT>1(z|(+T zfDZ4aZ~?%DfSG_t06zozy`RF32RsG%7|>-~3U@A`9B@0}B|y6mU}M01z^j0-0O=n> zf52scM*(jEjsed3D1{3H?gxAb=&~LC3%CF<2ku%K+~HI)4tI1`Gp?E66U$`ohz3Ue4CsCq6m#`J2{! zxRJ(cj%P~Nl%iQRb(c<~7Cu(3H}O>M7%bmBErwaLUZktQo<&;NaTwQqU6p+4w`y z1J@@34_xPpE{m*JqSb%!vXfd}(^*);rHuO@asY+PZ+q+wY^v%!`}nVXPD zzndFu&;?4 z<&B7vSE$qFBX8+pw4;vt2i^5$Tcch2eMTYG+5Ri!r8Alg`k69*H<-$0l8+d4p$3Cp z|E=S}Nd9G)T~=O-F6LZaQ;j~a3zub#%+mEyqw*%}`UI?bg$7-ARGvXMg5`xP>1WSe zp5;CR_xZTjZHMxV$p+6PC_hGOWO?arZ|!{&ZWeYm*6caJ)`TkbwYMWM{hk_K#PvEU zS6_z<)@I`lFD3>iI!d%oSKyxLs)1>|&IG3Y<`uxHz}Et!`P_}>{hh#QI(NT${|GRX zN8|Ph+!KDz#IFFu6xZ+Zo|0LobsdIvaaFUhV% z8)79YqZs2jWHZ{u324uK&Y-0>Z%9Bp6||IsCayAh_4am)trOXfbUO0DP+ccoK%75B zOL|j3CdR|^o@qrV z7kC4V5csXEh)$KJ{5h@2C%akL^>$MI3vF_DXB%?Kz8h@v7(dhd53{YQFB<*S1(*_H z>JOr8-!r<+IsyJL8G=bmejz8Ituf`#0w(^efvHda1x$Uv7?|{a0GQ^ERlrP-g$ZPD zGigcQx&*YxK}#v+rHJ1hOu(Zvn15JbFrOWGO6xYtLp_uVfvMf)mU?F-;Jw4-U1st= zYVwkumM7r-$mHE^@_uFFA50l!e^t+pf;>bAmflJ<5yEgQj;O;1QVYG%>3+V0$EuW+Kk?< zx3}6to1cL8Zj+YUHV3rS)&({m%45FAFtYSSWduvX6VP*vKeq;r`GCr{+2k=YCiioT zzFeQy+t&4!$k-VOT9T1%<6&}HJsNnddQ&;Im+&O;27p;QS{2cIflV%>Ve&7ATuRi3 z6pJ;rLQiz0!!0JyJ-{Sq1u*II6fn(2F9DN(ZU!bF+XkEpyc?M2x^I9fHvbuz)?n_{ zZ2f&19f2u6?FmeA;u*k{1_G0QBx}m4t=qQP!Jj_ zSDU=^Ej*hN@H}hsylnE2zQ+^rF#8d0=IO25qTR+w+Y1xWdO=HR7%<5`&*Y_kUzmWm z0ko`diI;R__hkDH$lKnE3>54151Kl>Wa{vdDfcH}^0iK{8-ADxO!Bi#JkrGHoA?4? zs+amLFRgVOU1{>nH+iVNjo_hnEVc1c9@Pt^r`6!0ytSqbGg}`!q%W1Nfs6nv0N#72 zv9{>`Z`O0Pm3pl8kr644)+FE^XVQ}2?@2&A+mwHmMSk~;*4zHQNlWWfAOS6#pH6+#7{6x&lU@Qa z*+B(n^T&b&vdTeA>2i~Y`m`wl&r*|?>N=2s_ASuTIQhWDyDar&p4GZdxGhFIsGhS(=EHEXqKgF_XXB+cVCtzzL zy(qS!7?IW&x^Dmt>Au61vDcLO4KVfZ&%k7hHg6g0NJn7O`DEZ!U`iyD{DWbZPxVZ> z($FFMO=F&;vXwTykfkTmhjbYR*_497lviuw24K>K>LT2Tdp4H1bBubB9hI2O)g~>q zX%xt

nA&iki61p(P=8cH29?dR$zpaxQQZDm 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 VGj Date: Sun, 20 Oct 2019 17:30:54 -0400 Subject: [PATCH 087/166] How about MSBuild 15 --- Dist/BuildAndPackage.bat | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Dist/BuildAndPackage.bat b/Dist/BuildAndPackage.bat index 8884698994..e80ecea594 100644 --- a/Dist/BuildAndPackage.bat +++ b/Dist/BuildAndPackage.bat @@ -9,7 +9,7 @@ if "%1"=="" ( git --version > NUL @if errorlevel 1 goto MISSINGGIT -for /f "usebackq tokens=*" %%A in (`vswhere -version "[16.0,17.0)" -requires Microsoft.Component.MSBuild -find MSBuild\**\Bin\MSBuild.exe`) do SET MSBUILDPATH=%%A +for /f "usebackq tokens=*" %%A in (`vswhere -version "[15.0,16.0)" -requires Microsoft.Component.MSBuild -find MSBuild\**\Bin\MSBuild.exe`) do SET MSBUILDPATH=%%A IF "%MSBUILDPATH%"=="" GOTO MISSINGMSBUILD From 2f4a38d8413519d2cf16e43f50298ed5dafc198c Mon Sep 17 00:00:00 2001 From: "J.D. Purcell" Date: Sun, 20 Oct 2019 17:44:50 -0400 Subject: [PATCH 088/166] MSBuild 16 --- Dist/BuildAndPackage.bat | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Dist/BuildAndPackage.bat b/Dist/BuildAndPackage.bat index e80ecea594..8884698994 100644 --- a/Dist/BuildAndPackage.bat +++ b/Dist/BuildAndPackage.bat @@ -9,7 +9,7 @@ if "%1"=="" ( git --version > NUL @if errorlevel 1 goto MISSINGGIT -for /f "usebackq tokens=*" %%A in (`vswhere -version "[15.0,16.0)" -requires Microsoft.Component.MSBuild -find MSBuild\**\Bin\MSBuild.exe`) do SET MSBUILDPATH=%%A +for /f "usebackq tokens=*" %%A in (`vswhere -version "[16.0,17.0)" -requires Microsoft.Component.MSBuild -find MSBuild\**\Bin\MSBuild.exe`) do SET MSBUILDPATH=%%A IF "%MSBUILDPATH%"=="" GOTO MISSINGMSBUILD From 75320862353de4415fdf9bcccd39fcf03552f189 Mon Sep 17 00:00:00 2001 From: "J.D. Purcell" Date: Sun, 20 Oct 2019 18:00:54 -0400 Subject: [PATCH 089/166] Add appveyor.yml --- appveyor.yml | 37 +++++++++++++++++++++++++++++++++++++ 1 file changed, 37 insertions(+) create mode 100644 appveyor.yml diff --git a/appveyor.yml b/appveyor.yml new file mode 100644 index 0000000000..377825f63f --- /dev/null +++ b/appveyor.yml @@ -0,0 +1,37 @@ +version: 0.0.0.{build} +branches: + only: + - master + - waterbox2 +image: Visual Studio 2019 +assembly_info: + patch: true + file: '**\AssemblyInfo.*' + assembly_version: '{version}' + assembly_file_version: '{version}' + assembly_informational_version: '{version}' +build_script: + - cmd: >- + SET TS=%APPVEYOR_REPO_COMMIT_TIMESTAMP% + + SET BUILDCODE=%TS:~0,10%-%TS:~11,2%%TS:~14,2%%TS:~17,2%-#%APPVEYOR_REPO_COMMIT% + + SET BUILDFILE=BizHawk_Developer-%BUILDCODE%.zip + + echo %BUILDFILE% + + + cd dist + + call BuildAndPackage_Developer.bat + + + move BizHawk-Developer.zip ..\%BUILDFILE% + + + cd .. + + appveyor PushArtifact %BUILDFILE% + + + rem appveyor UpdateBuild -Version %BUILDFILE% \ No newline at end of file From efebef42c0bbed0ec53e9e266155746454766d90 Mon Sep 17 00:00:00 2001 From: "J.D. Purcell" Date: Sun, 20 Oct 2019 18:03:37 -0400 Subject: [PATCH 090/166] Test --- appveyor.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/appveyor.yml b/appveyor.yml index 377825f63f..9be130f34b 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -11,7 +11,7 @@ assembly_info: assembly_file_version: '{version}' assembly_informational_version: '{version}' build_script: - - cmd: >- +- cmd: >- SET TS=%APPVEYOR_REPO_COMMIT_TIMESTAMP% SET BUILDCODE=%TS:~0,10%-%TS:~11,2%%TS:~14,2%%TS:~17,2%-#%APPVEYOR_REPO_COMMIT% From bd6658aa4109f1424346f76600ff32c3de0a3571 Mon Sep 17 00:00:00 2001 From: "J.D. Purcell" Date: Sun, 20 Oct 2019 18:16:55 -0400 Subject: [PATCH 091/166] Bump MinimumVisualStudioVersion in solution to require VS2019 --- BizHawk.sln | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/BizHawk.sln b/BizHawk.sln index 64985e34d0..adc162544e 100644 --- a/BizHawk.sln +++ b/BizHawk.sln @@ -1,7 +1,7 @@ Microsoft Visual Studio Solution File, Format Version 12.00 -# Visual Studio 15 -VisualStudioVersion = 15.0.27703.2047 -MinimumVisualStudioVersion = 12.0.31101.0 +# Visual Studio 16 +VisualStudioVersion = 16.0.28729.10 +MinimumVisualStudioVersion = 16.0.28729.10 Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Version", "Version\Version.csproj", "{0CE8B337-08E3-4602-BF10-C4D4C75D2F13}" EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "BizHawk.Client.Common", "BizHawk.Client.Common\BizHawk.Client.Common.csproj", "{24A0AA3C-B25F-4197-B23D-476D6462DBA0}" From 69bb2322a1b3717cab0d77ae8d96d0fb9805b6f3 Mon Sep 17 00:00:00 2001 From: "J.D. Purcell" Date: Sun, 20 Oct 2019 20:41:25 -0400 Subject: [PATCH 092/166] Try to clean up ROM loading a bit. It's not much but it's a start. --- BizHawk.Client.EmuHawk/MainForm.cs | 107 ++++++++++++++--------------- 1 file changed, 50 insertions(+), 57 deletions(-) diff --git a/BizHawk.Client.EmuHawk/MainForm.cs b/BizHawk.Client.EmuHawk/MainForm.cs index 0d32cd12f9..1333a9329a 100644 --- a/BizHawk.Client.EmuHawk/MainForm.cs +++ b/BizHawk.Client.EmuHawk/MainForm.cs @@ -587,6 +587,7 @@ namespace BizHawk.Client.EmuHawk public string CurrentlyOpenRom { get; private set; } // todo - delete me and use only args instead public LoadRomArgs CurrentlyOpenRomArgs { get; private set; } + private string CurrentlyOpenRomOpenAdvancedArgs { get; set; } = ""; public bool PauseAvi { get; set; } public bool PressFrameAdvance { get; set; } public bool HoldFrameAdvance { get; set; } // necessary for tastudio > button @@ -852,7 +853,7 @@ namespace BizHawk.Client.EmuHawk public void RebootCore() { - var ioa = OpenAdvancedSerializer.ParseWithLegacy(_currentlyOpenRomPoopForAdvancedLoaderPleaseRefactorMe); + var ioa = OpenAdvancedSerializer.ParseWithLegacy(CurrentlyOpenRomOpenAdvancedArgs); if (ioa is OpenAdvanced_LibretroNoGame) { LoadRom("", CurrentlyOpenRomArgs); @@ -3587,8 +3588,8 @@ namespace BizHawk.Client.EmuHawk public bool LoadRom(string path, LoadRomArgs args) { - bool ret = _LoadRom(path, args); - if(!ret) return false; + if (!LoadRomInternal(path, args)) + return false; //what's the meaning of the last rom path when opening an archive? based on the archive file location if (args.OpenAdvanced is OpenAdvanced_OpenRom) @@ -3601,7 +3602,7 @@ namespace BizHawk.Client.EmuHawk } // Still needs a good bit of refactoring - public bool _LoadRom(string path, LoadRomArgs args) + private bool LoadRomInternal(string path, LoadRomArgs args) { path = HawkFile.Util_ResolveLink(path); @@ -3659,29 +3660,30 @@ namespace BizHawk.Client.EmuHawk var nextComm = CreateCoreComm(); - // we need to inform LoadRom which Libretro core to use... IOpenAdvanced ioa = args.OpenAdvanced; - if (ioa is IOpenAdvancedLibretro) - { - var ioaretro = (IOpenAdvancedLibretro)ioa; + var oa_openrom = ioa as OpenAdvanced_OpenRom; + var oa_retro = ioa as OpenAdvanced_Libretro; + var ioa_retro = ioa as IOpenAdvancedLibretro; + // we need to inform LoadRom which Libretro core to use... + if (ioa_retro != null) + { // prepare a core specification // if it wasnt already specified, use the current default - if (ioaretro.CorePath == null) + if (ioa_retro.CorePath == null) { - ioaretro.CorePath = Global.Config.LibretroCore; + ioa_retro.CorePath = Global.Config.LibretroCore; } - nextComm.LaunchLibretroCore = ioaretro.CorePath; + nextComm.LaunchLibretroCore = ioa_retro.CorePath; if (nextComm.LaunchLibretroCore == null) { throw new InvalidOperationException("Can't load a file via Libretro until a core is specified"); } } - if (ioa is OpenAdvanced_OpenRom) + if (oa_openrom != null) { - var ioa_openrom = (OpenAdvanced_OpenRom)ioa; // path already has the right value, while ioa.Path is null (interestingly, these are swapped below) // I doubt null is meant to be assigned here, and it just prevents gameload //path = ioa_openrom.Path; @@ -3693,61 +3695,54 @@ namespace BizHawk.Client.EmuHawk // we need to replace the path in the OpenAdvanced with the canonical one the user chose. // It can't be done until loder.LoadRom happens (for CanonicalFullPath) // i'm not sure this needs to be more abstractly engineered yet until we have more OpenAdvanced examples - if (ioa is OpenAdvanced_Libretro) + if (oa_retro != null) { - var oaretro = ioa as OpenAdvanced_Libretro; - oaretro.token.Path = loader.CanonicalFullPath; + oa_retro.token.Path = loader.CanonicalFullPath; } - if (ioa is OpenAdvanced_OpenRom) + if (oa_openrom != null) { - ((OpenAdvanced_OpenRom)ioa).Path = loader.CanonicalFullPath; + oa_openrom.Path = loader.CanonicalFullPath; } if (result) { - - string loaderName = $"*{OpenAdvancedSerializer.Serialize(ioa)}"; + string openAdvancedArgs = $"*{OpenAdvancedSerializer.Serialize(ioa)}"; Emulator = loader.LoadedEmulator; Global.Game = loader.Game; CoreFileProvider.SyncCoreCommInputSignals(nextComm); InputManager.SyncControls(); - if (ioa is OpenAdvanced_OpenRom) + if (oa_openrom != null && Path.GetExtension(oa_openrom.Path.Replace("|","")).ToLower() == ".xml") { - OpenAdvanced_OpenRom ioa_openRom = ioa as OpenAdvanced_OpenRom; + // this is a multi-disk bundler file + // determine the xml assets and create RomStatusDetails for all of them + var xmlGame = XmlGame.Create(new HawkFile(oa_openrom.Path)); - if (Path.GetExtension(ioa_openRom.Path.Replace("|","")).ToLower() == ".xml") + StringWriter xSw = new StringWriter(); + + for (int xg = 0; xg < xmlGame.Assets.Count; xg++) { - // this is a multi-disk bundler file - // determine the xml assets and create RomStatusDetails for all of them - var xmlGame = XmlGame.Create(new HawkFile(ioa_openRom.Path)); + var ext = Path.GetExtension(xmlGame.AssetFullPaths[xg]).ToLower(); - StringWriter xSw = new StringWriter(); - - for (int xg = 0; xg < xmlGame.Assets.Count; xg++) + if (ext == ".cue" || ext == ".ccd" || ext == ".toc" || ext == ".mds") { - var ext = Path.GetExtension(xmlGame.AssetFullPaths[xg]).ToLower(); - - if (ext == ".cue" || ext == ".ccd" || ext == ".toc" || ext == ".mds") - { - xSw.WriteLine(Path.GetFileNameWithoutExtension(xmlGame.Assets[xg].Key)); - xSw.WriteLine("SHA1:N/A"); - xSw.WriteLine("MD5:N/A"); - xSw.WriteLine(); - } - else - { - xSw.WriteLine(xmlGame.Assets[xg].Key); - xSw.WriteLine($"SHA1:{xmlGame.Assets[xg].Value.HashSHA1()}"); - xSw.WriteLine($"MD5:{xmlGame.Assets[xg].Value.HashMD5()}"); - xSw.WriteLine(); - } + xSw.WriteLine(Path.GetFileNameWithoutExtension(xmlGame.Assets[xg].Key)); + xSw.WriteLine("SHA1:N/A"); + xSw.WriteLine("MD5:N/A"); + xSw.WriteLine(); + } + else + { + xSw.WriteLine(xmlGame.Assets[xg].Key); + xSw.WriteLine($"SHA1:{xmlGame.Assets[xg].Value.HashSHA1()}"); + xSw.WriteLine($"MD5:{xmlGame.Assets[xg].Value.HashMD5()}"); + xSw.WriteLine(); } - - Emulator.CoreComm.RomStatusDetails = xSw.ToString(); - Emulator.CoreComm.RomStatusAnnotation = "Multi-disk bundler"; } + + Emulator.CoreComm.RomStatusDetails = xSw.ToString(); + Emulator.CoreComm.RomStatusAnnotation = "Multi-disk bundler"; } if (Emulator is TI83 && Global.Config.TI83autoloadKeyPad) @@ -3796,13 +3791,13 @@ namespace BizHawk.Client.EmuHawk // restarts the lua console if a different rom is loaded. // im not really a fan of how this is done.. - if (Global.Config.RecentRoms.Empty || Global.Config.RecentRoms.MostRecent != loaderName) + if (Global.Config.RecentRoms.Empty || Global.Config.RecentRoms.MostRecent != openAdvancedArgs) { GlobalWin.Tools.Restart(); } - Global.Config.RecentRoms.Add(loaderName); - JumpLists.AddRecentItem(loaderName, ioa.DisplayName); + Global.Config.RecentRoms.Add(openAdvancedArgs); + JumpLists.AddRecentItem(openAdvancedArgs, ioa.DisplayName); // Don't load Save Ram if a movie is being loaded if (!Global.MovieSession.MovieIsQueued) @@ -3834,14 +3829,14 @@ namespace BizHawk.Client.EmuHawk } SetWindowText(); - _currentlyOpenRomPoopForAdvancedLoaderPleaseRefactorMe = loaderName; - CurrentlyOpenRom = loaderName.Replace("*OpenRom*", ""); // POOP + CurrentlyOpenRom = oa_openrom?.Path ?? openAdvancedArgs; + CurrentlyOpenRomArgs = args; + CurrentlyOpenRomOpenAdvancedArgs = openAdvancedArgs; HandlePlatformMenus(); _stateSlots.Clear(); UpdateCoreStatusBarButton(); UpdateDumpIcon(); SetMainformMovieInfo(); - CurrentlyOpenRomArgs = args; GlobalWin.DisplayManager.Blank(); Global.Rewinder.Initialize(); @@ -3901,8 +3896,6 @@ namespace BizHawk.Client.EmuHawk } } - private string _currentlyOpenRomPoopForAdvancedLoaderPleaseRefactorMe = ""; - private void CommitCoreSettingsToConfig() { // save settings object @@ -4007,7 +4000,7 @@ namespace BizHawk.Client.EmuHawk UpdateStatusSlots(); CurrentlyOpenRom = null; CurrentlyOpenRomArgs = null; - _currentlyOpenRomPoopForAdvancedLoaderPleaseRefactorMe = ""; + CurrentlyOpenRomOpenAdvancedArgs = ""; } } From 99f63f9a9fdf4c4efe409b012c3c9fd7fbd5e40f Mon Sep 17 00:00:00 2001 From: "J.D. Purcell" Date: Sun, 20 Oct 2019 21:27:53 -0400 Subject: [PATCH 093/166] Don't even need this variable. --- BizHawk.Client.EmuHawk/MainForm.cs | 25 +++++++------------------ 1 file changed, 7 insertions(+), 18 deletions(-) diff --git a/BizHawk.Client.EmuHawk/MainForm.cs b/BizHawk.Client.EmuHawk/MainForm.cs index 1333a9329a..978ac86acf 100644 --- a/BizHawk.Client.EmuHawk/MainForm.cs +++ b/BizHawk.Client.EmuHawk/MainForm.cs @@ -587,7 +587,6 @@ namespace BizHawk.Client.EmuHawk public string CurrentlyOpenRom { get; private set; } // todo - delete me and use only args instead public LoadRomArgs CurrentlyOpenRomArgs { get; private set; } - private string CurrentlyOpenRomOpenAdvancedArgs { get; set; } = ""; public bool PauseAvi { get; set; } public bool PressFrameAdvance { get; set; } public bool HoldFrameAdvance { get; set; } // necessary for tastudio > button @@ -853,15 +852,8 @@ namespace BizHawk.Client.EmuHawk public void RebootCore() { - var ioa = OpenAdvancedSerializer.ParseWithLegacy(CurrentlyOpenRomOpenAdvancedArgs); - if (ioa is OpenAdvanced_LibretroNoGame) - { - LoadRom("", CurrentlyOpenRomArgs); - } - else - { - LoadRom(ioa.SimplePath, CurrentlyOpenRomArgs); - } + if (CurrentlyOpenRomArgs == null) return; + LoadRom(CurrentlyOpenRomArgs.OpenAdvanced.SimplePath, CurrentlyOpenRomArgs); } public void PauseEmulator() @@ -3604,13 +3596,12 @@ namespace BizHawk.Client.EmuHawk // Still needs a good bit of refactoring private bool LoadRomInternal(string path, LoadRomArgs args) { - path = HawkFile.Util_ResolveLink(path); - - // default args + if (path == null) + throw new ArgumentNullException(nameof(path)); if (args == null) - { - args = new LoadRomArgs(); - } + throw new ArgumentNullException(nameof(args)); + + path = HawkFile.Util_ResolveLink(path); // if this is the first call to LoadRom (they will come in recursively) then stash the args bool firstCall = false; @@ -3831,7 +3822,6 @@ namespace BizHawk.Client.EmuHawk SetWindowText(); CurrentlyOpenRom = oa_openrom?.Path ?? openAdvancedArgs; CurrentlyOpenRomArgs = args; - CurrentlyOpenRomOpenAdvancedArgs = openAdvancedArgs; HandlePlatformMenus(); _stateSlots.Clear(); UpdateCoreStatusBarButton(); @@ -4000,7 +3990,6 @@ namespace BizHawk.Client.EmuHawk UpdateStatusSlots(); CurrentlyOpenRom = null; CurrentlyOpenRomArgs = null; - CurrentlyOpenRomOpenAdvancedArgs = ""; } } From b1554be720b446f23ceca5e7c1b53a2b2ca8cb6f Mon Sep 17 00:00:00 2001 From: Loren <47842483+sornerol@users.noreply.github.com> Date: Sun, 20 Oct 2019 21:35:31 -0500 Subject: [PATCH 094/166] Use WebUtility.HtmlDecode() to decode game names (#1698) Change '&' to '&' in gamedb_goodnes.txt. Fixes #1667. --- Assets/gamedb/gamedb_goodnes.txt | 788 +++++++++++++++---------------- 1 file changed, 394 insertions(+), 394 deletions(-) diff --git a/Assets/gamedb/gamedb_goodnes.txt b/Assets/gamedb/gamedb_goodnes.txt index 6c1262745c..f89ab9dae5 100644 --- a/Assets/gamedb/gamedb_goodnes.txt +++ b/Assets/gamedb/gamedb_goodnes.txt @@ -179,7 +179,7 @@ acc01149108010328c2839783c09b030650696a8 G 2-in-1 - Cosmo Cop + Cyber Monster (S 7c4d0353d9f3ff2f064a47b11497fb159f41b1f0 U 2-in-1 - Donkey Kong Country + Jungle Book (Unl) NES 33930c8fd186490d99ee2fe387b987ac0831c123 G 2-in-1 - Donkey Kong Country 4 + Jungle Book 2 (Unl) [!] NES 25943e4d0130c62aed75d92fafab75f8470c0e75 C 2-in-1 - Donkey Kong Country 4 + Jungle Book 2 (Unl) [t1] NES -47fcca3baebba912638d0eda77fb1676e5f0bc8e G 2-in-1 - Family Kid & Aladdin 4 (Ch) [!] NES +47fcca3baebba912638d0eda77fb1676e5f0bc8e G 2-in-1 - Family Kid & Aladdin 4 (Ch) [!] NES fdc4b64f9d981bf024c93c0bf39c332e2189eb2e G 2-in-1 - Mortal Kombat 3 Extra 60 People + Super Shinobi (King005) (Ch) [!] NES ec5e8712f994f929218cea18dc9d7dff7eb55495 G 2-in-1 - Mortal Kombat V Turbo 30 + Super Aladdin (Unl) [p1][!] NES 754512f9474fba9a3bf50cf315ff5b33d106b29c U 2-in-1 - Mortal Kombat VI + Mortal Kombat VII (NT-639) (Ch) NES @@ -521,7 +521,7 @@ ebd9d408ae00cc23b460a60a77c39336008c5671 H Abarenradin (Abarenbou Tengu Hack) NE eafc03f2f232660ed3e9eccf27c2f2527c8fe50b U ABM Study Card v5.0 (Ch) NES 0f75aec9810879bdc65269bbb1596542bd23ddf5 H Abnormal Contra (Hack) NES 64a897591d15f88ffd05773baf690dfa60f0d0d2 U About 8 Eyes (R) (PD) NES -f8287728e18eefd9b190597555f1f370b183a388 U About Advanced Dungeons & Dragons - Heroes of the Lance (R) (PD) NES +f8287728e18eefd9b190597555f1f370b183a388 U About Advanced Dungeons & Dragons - Heroes of the Lance (R) (PD) NES 9f194dc9272c92ffa84f2ac2eee4dd0548f56c54 U About Adventures in the Magic Kingdom (R) (PD) NES c9671a576386702a8dc2242bd2b8f20e53025ffd U About Adventures of Bayou Billy, The (R) (PD) NES 2835208676b1e9ac56a06389762b58cd4caf186b U About Armadillo (R) (PD) NES @@ -563,7 +563,7 @@ a7db1747bc516ed061c4d5c70afcaa474ddb5cb0 U Action53 Games 0.03 by Damian Yerrick e2e0219e2da3727d01306e46d358f69ef83c92e1 U Action53 Games MGC2012_2MBIT by Damian Yerrick (PD) NES d94968e5a043ff6a75d22a4351f86963c444b56f U Action53 Games MGC2012_4MBIT by Damian Yerrick (PD) NES 906b9c03ebb1fdb7ccfe263efcbb97ac19608757 H Actual Haou no Tairiku (Haou no Tairiku Hack) NES -45bb116d48c9726104def6268a49384e628054fe U Add & Sub (Unl) NES +45bb116d48c9726104def6268a49384e628054fe U Add & Sub (Unl) NES 22ad5c56344105eee089b6fa8d00657180ed0e00 U Add Em Up (Ch) (Wxn) NES 08c039c6114ee51b987b27d301b273c3c20114cc G Addams Family, The (E) (M3) [!] NES c831410a86a9b759a1e5ec53e8e1ee6789c79569 G Addams Family, The (U) [!] NES @@ -587,39 +587,39 @@ ec1811b0248129413f5be023c0b0d81a87f6e0d2 T Addams Family, The - Pugsley's Scaven cd6914dd1a78ba33570b4e578f4347df2f4e31b6 C Addams Family, The - Pugsley's Scavenger Hunt (U) [t1] NES cf504f5bc99886f933161057a20a9539b6f86ed6 B Adoventoro Tcheco v1.0 (Kero Kero Keroppi no Daibouken 2 Hack) [o1] NES 93985ed946c8f21bb18f8b88c4830eaf8b62d551 H Adoventoro Tcheco v1.0 (Kero Kero Keroppi no Daibouken 2 Hack) NES -273f99684dbdfcf27cfca58136132898217bfbc5 G Advanced Dungeons & Dragons - Dragon Strike (U) [!] NES -7a888c56b64ffd5a1b2653fa6b6d9c207fb6006f B Advanced Dungeons & Dragons - Dragon Strike (U) [b1] NES -d8737a92ad99191fa6653dc2094be81e6c9a1b9e B Advanced Dungeons & Dragons - Dragon Strike (U) [o1] NES -cca11ec6eb0721d6d2e7decbca51b66d5d8548c8 B Advanced Dungeons & Dragons - Dragon Strike (U) [o2] NES -00ae1a7b6cdf1c9b624b29488f54485103b8dcf1 C Advanced Dungeons & Dragons - Dragon Strike (U) [t1] NES -fba99cd8cfb0d44eaaee300dcd194520b41a92b2 G Advanced Dungeons & Dragons - Dragons of Flame (J) [!] NES -f788bbc014cd740449e1a0299feae7234d69a5cf B Advanced Dungeons & Dragons - Dragons of Flame (J) [b1] NES -071c57824564e1081f721ced5db1981c6d3ca034 B Advanced Dungeons & Dragons - Dragons of Flame (J) [o1] NES -25f20b279a150136b337b10f618a251a34c90b73 T Advanced Dungeons & Dragons - Dragons of Flame (J) [T+Eng1.03_DvD Translations] NES -e40073be785c7cce9c256e4be575b425e8719340 G Advanced Dungeons & Dragons - Heroes of the Lance (J) [!] NES -963bea44db79635410a56faa0eefcec79509ca93 U Advanced Dungeons & Dragons - Heroes of the Lance (U) (Prototype) NES -d9328b02916d365c97ed21074333257968e55f91 G Advanced Dungeons & Dragons - Heroes of the Lance (U) [!] NES -b091cd121984c85dd850979948401f6c10613e5a B Advanced Dungeons & Dragons - Heroes of the Lance (U) [b1] NES -e5564fb5a4b54dbd103803e2e15acd6d390b1cdf B Advanced Dungeons & Dragons - Heroes of the Lance (U) [b2] NES -cc4a023e907b5fa3f415ebb284d64f7b95f92114 B Advanced Dungeons & Dragons - Heroes of the Lance (U) [b3] NES -5207100c4d9eb4dd9cd2e2f8b5814fa4ed3aca6e B Advanced Dungeons & Dragons - Heroes of the Lance (U) [o1] NES -9c2a89479470349deddb38cdbda242b26b6589fd B Advanced Dungeons & Dragons - Heroes of the Lance (U) [o2] NES -2611badd4923ab1ef83db2e98b6c944416dc1367 T Advanced Dungeons & Dragons - Heroes of the Lance (U) [T+Rus0.30_Chief-Net] NES -5bc6b4d5e2b27983e678376a95b041ecb3abe819 G Advanced Dungeons & Dragons - Hillsfar (J) [!] NES -5f86c4b515c1cdaf18dd22f60a2d59116e9b2f05 B Advanced Dungeons & Dragons - Hillsfar (J) [b1] NES -988c9199cafb56b54691af8bedaf161fbf9353d1 B Advanced Dungeons & Dragons - Hillsfar (J) [b2] NES -94af82688883d02b83733b36e300d1e742940e1a B Advanced Dungeons & Dragons - Hillsfar (J) [o1] NES -806eb65696593368bef9b62e63b1d8624c637030 G Advanced Dungeons & Dragons - Hillsfar (U) [!] NES -4aedc8efec6f8df4bfbab548a9523778b6fc9594 B Advanced Dungeons & Dragons - Hillsfar (U) [o1] NES -22261fef73fb2161c513632ff614af0ca17d8105 G Advanced Dungeons & Dragons - Pool of Radiance (J) [!] NES -7eca79e1a9684dbbf30dd282c3b44f0fd25deae4 B Advanced Dungeons & Dragons - Pool of Radiance (J) [b1] NES -8612381815f8d64128310ee201bb1b8560c98ab9 B Advanced Dungeons & Dragons - Pool of Radiance (J) [b1][o1] NES -28eaac4e09ed87fa70a10cca7f70a112502f5c8f B Advanced Dungeons & Dragons - Pool of Radiance (J) [o1] NES -a056d59aae542b15ce5361ab49954e746863029b B Advanced Dungeons & Dragons - Pool of Radiance (J) [o2] NES -81eefb9fa6552b95bb086552a043097d6ecdd051 G Advanced Dungeons & Dragons - Pool of Radiance (U) [!] NES -7ddd3a1811b62e94a59d1f5c17045dfd786640a7 B Advanced Dungeons & Dragons - Pool of Radiance (U) [b1] NES -995527d6333875de6ab0d99b00a77b3b6901db8c B Advanced Dungeons & Dragons - Pool of Radiance (U) [b2] NES -b9aab0a607081b9409da575ce15aa5e1517e52d9 B Advanced Dungeons & Dragons - Pool of Radiance (U) [o1] NES +273f99684dbdfcf27cfca58136132898217bfbc5 G Advanced Dungeons & Dragons - Dragon Strike (U) [!] NES +7a888c56b64ffd5a1b2653fa6b6d9c207fb6006f B Advanced Dungeons & Dragons - Dragon Strike (U) [b1] NES +d8737a92ad99191fa6653dc2094be81e6c9a1b9e B Advanced Dungeons & Dragons - Dragon Strike (U) [o1] NES +cca11ec6eb0721d6d2e7decbca51b66d5d8548c8 B Advanced Dungeons & Dragons - Dragon Strike (U) [o2] NES +00ae1a7b6cdf1c9b624b29488f54485103b8dcf1 C Advanced Dungeons & Dragons - Dragon Strike (U) [t1] NES +fba99cd8cfb0d44eaaee300dcd194520b41a92b2 G Advanced Dungeons & Dragons - Dragons of Flame (J) [!] NES +f788bbc014cd740449e1a0299feae7234d69a5cf B Advanced Dungeons & Dragons - Dragons of Flame (J) [b1] NES +071c57824564e1081f721ced5db1981c6d3ca034 B Advanced Dungeons & Dragons - Dragons of Flame (J) [o1] NES +25f20b279a150136b337b10f618a251a34c90b73 T Advanced Dungeons & Dragons - Dragons of Flame (J) [T+Eng1.03_DvD Translations] NES +e40073be785c7cce9c256e4be575b425e8719340 G Advanced Dungeons & Dragons - Heroes of the Lance (J) [!] NES +963bea44db79635410a56faa0eefcec79509ca93 U Advanced Dungeons & Dragons - Heroes of the Lance (U) (Prototype) NES +d9328b02916d365c97ed21074333257968e55f91 G Advanced Dungeons & Dragons - Heroes of the Lance (U) [!] NES +b091cd121984c85dd850979948401f6c10613e5a B Advanced Dungeons & Dragons - Heroes of the Lance (U) [b1] NES +e5564fb5a4b54dbd103803e2e15acd6d390b1cdf B Advanced Dungeons & Dragons - Heroes of the Lance (U) [b2] NES +cc4a023e907b5fa3f415ebb284d64f7b95f92114 B Advanced Dungeons & Dragons - Heroes of the Lance (U) [b3] NES +5207100c4d9eb4dd9cd2e2f8b5814fa4ed3aca6e B Advanced Dungeons & Dragons - Heroes of the Lance (U) [o1] NES +9c2a89479470349deddb38cdbda242b26b6589fd B Advanced Dungeons & Dragons - Heroes of the Lance (U) [o2] NES +2611badd4923ab1ef83db2e98b6c944416dc1367 T Advanced Dungeons & Dragons - Heroes of the Lance (U) [T+Rus0.30_Chief-Net] NES +5bc6b4d5e2b27983e678376a95b041ecb3abe819 G Advanced Dungeons & Dragons - Hillsfar (J) [!] NES +5f86c4b515c1cdaf18dd22f60a2d59116e9b2f05 B Advanced Dungeons & Dragons - Hillsfar (J) [b1] NES +988c9199cafb56b54691af8bedaf161fbf9353d1 B Advanced Dungeons & Dragons - Hillsfar (J) [b2] NES +94af82688883d02b83733b36e300d1e742940e1a B Advanced Dungeons & Dragons - Hillsfar (J) [o1] NES +806eb65696593368bef9b62e63b1d8624c637030 G Advanced Dungeons & Dragons - Hillsfar (U) [!] NES +4aedc8efec6f8df4bfbab548a9523778b6fc9594 B Advanced Dungeons & Dragons - Hillsfar (U) [o1] NES +22261fef73fb2161c513632ff614af0ca17d8105 G Advanced Dungeons & Dragons - Pool of Radiance (J) [!] NES +7eca79e1a9684dbbf30dd282c3b44f0fd25deae4 B Advanced Dungeons & Dragons - Pool of Radiance (J) [b1] NES +8612381815f8d64128310ee201bb1b8560c98ab9 B Advanced Dungeons & Dragons - Pool of Radiance (J) [b1][o1] NES +28eaac4e09ed87fa70a10cca7f70a112502f5c8f B Advanced Dungeons & Dragons - Pool of Radiance (J) [o1] NES +a056d59aae542b15ce5361ab49954e746863029b B Advanced Dungeons & Dragons - Pool of Radiance (J) [o2] NES +81eefb9fa6552b95bb086552a043097d6ecdd051 G Advanced Dungeons & Dragons - Pool of Radiance (U) [!] NES +7ddd3a1811b62e94a59d1f5c17045dfd786640a7 B Advanced Dungeons & Dragons - Pool of Radiance (U) [b1] NES +995527d6333875de6ab0d99b00a77b3b6901db8c B Advanced Dungeons & Dragons - Pool of Radiance (U) [b2] NES +b9aab0a607081b9409da575ce15aa5e1517e52d9 B Advanced Dungeons & Dragons - Pool of Radiance (U) [o1] NES 1e28999c356e61b1df86830e6a44a28064b5c817 G Adventure Island (E) [!] NES 22ee75b82f4a6412aa6bb940e109704975b95185 G Adventure Island (U) [!] NES 1fda3bdfb434a51ce1b0d8ecc1048bead586aa78 B Adventure Island (U) [b1] NES @@ -762,7 +762,7 @@ a13dd4b5b89d9409f17cddac89d6cd9565ce515f G Adventures of Gilligan's Island, The 3ab83784dae8e89b6008210e0b5cfbd70819afcf C Adventures of Gilligan's Island, The (U) [t1] NES 38b3d3a93b7d6f586eea866323bd3fb9e4eca3a8 H Adventures of Ice Mario (SMB1 Hack) [a1] NES 6f8e6102756ba3bc48ae2a859f6f9d0b29f790df H Adventures of Ice Mario (SMB1 Hack) NES -31c22dc41dc70de595ba39e4851a71072d6c5f2c U Adventures of Lex & Grim, The (PD) NES +31c22dc41dc70de595ba39e4851a71072d6c5f2c U Adventures of Lex & Grim, The (PD) NES c43118388202bf348bae335eb2311ab8a0562bcb U Adventures of Lolo (E) (VC) NES d37c8003bf052404248ffaca106f7d32c75c8076 G Adventures of Lolo (E) [!] NES ad9ef7f61d97ecfc837f5f1eeb952935867306d7 G Adventures of Lolo (J) [!] NES @@ -887,8 +887,8 @@ f532c6e8d7d0443005f236bcfa2e6da52c0ac538 G Ai Senshi Nicol (FDS Conversion) [p2] df393788cf372f5b2e173ae3ee2b488d5d8b9efb B Aigiina no Yogen - From The Legend of Balubalouk (J) [b1] NES e277bdd8af36aaef9637477498834b1ed2074ae8 B Aigiina no Yogen - From The Legend of Balubalouk (J) [b2] NES e58d3146df2f09b3f98e4a35d132e05aa3347843 B Aigiina no Yogen - From The Legend of Balubalouk (J) [p1] NES -a4f42cbcb63f4d827055cbe1ced904ae0ccac4f7 T Aigiina no Yogen - From The Legend of Balubalouk (J) [T+Eng0.30_KP Hacks&Trans] NES -6305751b6a7c3b24aa7f5f182dec3a4358bf3bcc T Aigiina no Yogen - From The Legend of Balubalouk (J) [T+Eng0.30_KP Hacks&Trans][t1] NES +a4f42cbcb63f4d827055cbe1ced904ae0ccac4f7 T Aigiina no Yogen - From The Legend of Balubalouk (J) [T+Eng0.30_KP Hacks&Trans] NES +6305751b6a7c3b24aa7f5f182dec3a4358bf3bcc T Aigiina no Yogen - From The Legend of Balubalouk (J) [T+Eng0.30_KP Hacks&Trans][t1] NES 4bf385b7915e35d7fef3cd311caf9fdc7cb38048 C Aigiina no Yogen - From The Legend of Balubalouk (J) [t1] NES 93e4145c080847cf0d1c95e69d0f78e957fa4101 H Air (SMB1 Hack) NES e6aa612a23d571cf1b2196d13f0a4ec420d15efb U AIR - NES Visual Novel System V20040617 by NES Hack Factory (PD) NES @@ -1558,14 +1558,14 @@ c1dd041495a2ea02ffbbc583344b87137df8e984 B Back to the Future (U) [b4] NES 48404a7e46e0070aa1920130858315926d31b97e B Back to the Future (U) [o1] NES 5f262291edbcb4b4a72ca057bf8b379853af4556 T Back to the Future (U) [T+Pol] NES 24cc7674f742deec05ed246824f1bd6511ffdad6 H Back to the Future 4 by RyanVG (Back to the Future Hack) NES -641de451615a4f7004039308628c043b5ade6c31 H Back to the Future 5 & 6 by RyanVG (Back to the Future II & III Hack) NES +641de451615a4f7004039308628c043b5ade6c31 H Back to the Future 5 & 6 by RyanVG (Back to the Future II & III Hack) NES 4c79761269d0b9aaff4f9f9dcb28d8a106fa92b6 G Back to the Future IV (Unl) [!] NES -42ac1fcea405552892bed982a90a99d1292e4cdb G Back to the Future Part II & III (U) [!] NES -8338134a546f6c068c2b9e1bfdec45cab78d9571 B Back to the Future Part II & III (U) [b1] NES -4476ea6bbd674b081d4b36574c2746afad97abd6 B Back to the Future Part II & III (U) [b2] NES -060e5dde73dc19d931d561b28251a7c501771182 B Back to the Future Part II & III (U) [b3] NES -22ee09afdc4cb6f9790b9f87b0f49bcb19c6dce7 B Back to the Future Part II & III (U) [o1] NES -081f5da36bb4aaa0ad0b3bfafbf71a2ff1062697 C Back to the Future Part II & III (U) [t1] NES +42ac1fcea405552892bed982a90a99d1292e4cdb G Back to the Future Part II & III (U) [!] NES +8338134a546f6c068c2b9e1bfdec45cab78d9571 B Back to the Future Part II & III (U) [b1] NES +4476ea6bbd674b081d4b36574c2746afad97abd6 B Back to the Future Part II & III (U) [b2] NES +060e5dde73dc19d931d561b28251a7c501771182 B Back to the Future Part II & III (U) [b3] NES +22ee09afdc4cb6f9790b9f87b0f49bcb19c6dce7 B Back to the Future Part II & III (U) [o1] NES +081f5da36bb4aaa0ad0b3bfafbf71a2ff1062697 C Back to the Future Part II & III (U) [t1] NES 798d3f6cc1bf9a2dfcbb586c92fbd3e63ae7c172 U Background Music by Tony Young (PD) NES 86d389f46bde561394a7e69ff960f747a5ef297b U Backstroke (Ch) (Wxn) NES 92584bffe7d2ee47a01b480826466f78ff59f7dc U Bad Apple 2 v2009-12-24 (PD) NES @@ -1988,9 +1988,9 @@ fc950662b264fea1ad9f240360fde542283f04e1 U Batman Title Screen Remake by Macbee 91643c910a8c26b65e32cd8e4e8426d78d33713c H Batman V1.1 by Macbee (Batman Hack) NES e517ce0acda2a46341290b96fec12b2be51924ee H Batman V1.2 by Macbee (Batman Hack) NES 1a9fe00ebc831950bced93c556d1116543456460 U Bator Demo (PD) NES -f6177c581ed0b1d4625ec478caec3aa5939dc229 G Batsu & Terii - Makyou no Tetsujin Race (J) [!] NES -6a7a694a7bbcf59df990eec4be2c1157f104d43c B Batsu & Terii - Makyou no Tetsujin Race (J) [o1] NES -b7256a34856009ac3cdfeeb8142dd3fcc9c17c2e G Batsu & Terii - Makyou no Tetsujin Race (R) [!] NES +f6177c581ed0b1d4625ec478caec3aa5939dc229 G Batsu & Terii - Makyou no Tetsujin Race (J) [!] NES +6a7a694a7bbcf59df990eec4be2c1157f104d43c B Batsu & Terii - Makyou no Tetsujin Race (J) [o1] NES +b7256a34856009ac3cdfeeb8142dd3fcc9c17c2e G Batsu & Terii - Makyou no Tetsujin Race (R) [!] NES e3b20fb71dc6b44c911627cd321968a36578ea66 U Battle Ball (1-0) by UDISI (PD) NES 5915f487be763881a1f06cfdce689b1e1a503dd2 U Battle Ball (1-1) by UDISI (PD) NES 19fbe1d547f0cf085c99a80bbd3073f4d1ed33a0 U Battle Ball (1-21) by UDISI (PD) NES @@ -2161,16 +2161,16 @@ bd753272dcf11cb9b4c5d1e8d45436754897c97d B Battleship (U) [b2] NES 086e81e018013de624c9d18fb24771e503d68c47 B Battleship (U) [b4] NES 94dca436e97e7b6bfcfd4e13da6f08c5c81f2e2c B Battletank 2000 (Joust Hack) [o1] NES 5f0c7a2228e747d174590dc54a090daa73c74761 H Battletank 2000 (Joust Hack) NES -a5ab91d6a0df0bce2349a6322c536f4705287a4f G Battletoads & Double Dragon - The Ultimate Team (E) [!] NES -61832d0f955cff169ff059bd557be4f522b15b7c G Battletoads & Double Dragon - The Ultimate Team (U) [!] NES -b87d42a12a0f94a08b8476b1b2a0f1a36e050e3c B Battletoads & Double Dragon - The Ultimate Team (U) [o1] NES -a2f86721e107a039157724de5f69d3c1625ca214 G Battletoads & Double Dragon - The Ultimate Team (U) [p1][!] NES -3af7d0f3d2c7a105f958b205ae71fee6fa31536d B Battletoads & Double Dragon - The Ultimate Team (U) [p2] NES -dfe30b43464bb61470b4306d9f24f6ef43c685c2 B Battletoads & Double Dragon - The Ultimate Team (U) [p3] NES -ecdfa52d66575bede303075206e73c4a0aeb619a C Battletoads & Double Dragon - The Ultimate Team (U) [t1] NES -01ba0fa9342c6f8e196eeb8dbf49a3407df37a34 C Battletoads & Double Dragon - The Ultimate Team (U) [t2] NES -4cea01a1ca8d219a696c4c8b0f04465da3aa872f C Battletoads & Double Dragon - The Ultimate Team (U) [t3] NES -1b7750a413fcd4d907da8654a9b78c7aa0ed423c H Battletoads & Double Dragon - The Ultimate Team by myaso (Hack) NES +a5ab91d6a0df0bce2349a6322c536f4705287a4f G Battletoads & Double Dragon - The Ultimate Team (E) [!] NES +61832d0f955cff169ff059bd557be4f522b15b7c G Battletoads & Double Dragon - The Ultimate Team (U) [!] NES +b87d42a12a0f94a08b8476b1b2a0f1a36e050e3c B Battletoads & Double Dragon - The Ultimate Team (U) [o1] NES +a2f86721e107a039157724de5f69d3c1625ca214 G Battletoads & Double Dragon - The Ultimate Team (U) [p1][!] NES +3af7d0f3d2c7a105f958b205ae71fee6fa31536d B Battletoads & Double Dragon - The Ultimate Team (U) [p2] NES +dfe30b43464bb61470b4306d9f24f6ef43c685c2 B Battletoads & Double Dragon - The Ultimate Team (U) [p3] NES +ecdfa52d66575bede303075206e73c4a0aeb619a C Battletoads & Double Dragon - The Ultimate Team (U) [t1] NES +01ba0fa9342c6f8e196eeb8dbf49a3407df37a34 C Battletoads & Double Dragon - The Ultimate Team (U) [t2] NES +4cea01a1ca8d219a696c4c8b0f04465da3aa872f C Battletoads & Double Dragon - The Ultimate Team (U) [t3] NES +1b7750a413fcd4d907da8654a9b78c7aa0ed423c H Battletoads & Double Dragon - The Ultimate Team by myaso (Hack) NES 37e99fa67463140b2875d1079ade1ea7f3f2821f G Battletoads (E) [!] NES cbe809d8091d4421548e63c7b5e0b7ae972b45cf G Battletoads (J) [!] NES a9fd5d06382c88293462161bd8d882eb859b98d0 C Battletoads (J) [t2] NES @@ -2195,7 +2195,7 @@ a5b0bf325118b719367f8d7816504e04877452e7 B Be-Bop-Highschool - Koukousei Gokurak f07f637a55fa92b6875adb08ab9864446141440c H Beast Machines (Ikari Hack) NES b44a2ba9f96d3810d10801e6e3a4f68f112fbb6a G Beat n Box (K) (Unl) [!] NES 8bd8815ac4c09077145f2640bc37a5ac0e2b41ef G Beauty and the Beast (E) [!] NES -062f1bca6345f1346f96bf776768cb4a5fec7f2b U Beavis & Butt-head Title Screen by Macbee 1.0 (PD) NES +062f1bca6345f1346f96bf776768cb4a5fec7f2b U Beavis & Butt-head Title Screen by Macbee 1.0 (PD) NES b47df8791af3e39ac486b5d09b313109e8aeebcf G Bee 52 (Camerica) [!] NES 4af2961903378200d6db3ebc2cb77a28af7e3c3c B Bee 52 (Camerica) [o1] NES 48a7de1e5288428c6efb51c2d036efcce7f13384 T Bee 52 (Camerica) [T+Rus_Magicteam] NES @@ -2255,16 +2255,16 @@ b77195b1c6bfc9be2e2b7c8e00a4f1e4eb717f52 B Bible Adventures (Wisdom Tree) (V1.3) 9459027fe75f19e2bf8f6c86ffd3410445a2f28e B Bible Buffet (Wisdom Tree) (V6.0) [b1] NES f28787091c0a1d219de7c1ac574b5f8ba94dfe04 B Bible Buffet (Wisdom Tree) (V6.0) [o1] NES 10e4ad1a87f4522960574d651f2a832596ce156f H Bicycle Race (F-1 Race Hack) NES -75c71cc6d187c855b3e982edcea8eccb729ee917 G Big Bird's Hide & Speak (U) [!] NES -12eb07f634424deb6a2336c2c3f0ce34722ebbca B Big Bird's Hide & Speak (U) [b1] NES -396b8bad5215abd2ce509edaf5cd4a65ed0c6548 B Big Bird's Hide & Speak (U) [b1][o1] NES -1fdbfdda17130146dc78c3914976de451726d0e1 B Big Bird's Hide & Speak (U) [b2] NES -5002d3ce6a5c809969e6eda26f58c872045e017c B Big Bird's Hide & Speak (U) [b3] NES -f529a06bd217c6e5678a6eb3e4bf6db5120a7d43 B Big Bird's Hide & Speak (U) [b4] NES -56564ef56008813863efeb82acc0f9008c9a7175 B Big Bird's Hide & Speak (U) [b6] NES -8d9dda7bfb0ee4192f8e1c6ddfed3167b565bb75 B Big Bird's Hide & Speak (U) [b7] NES -91201e10a1e91f10a06b98512275108ebd7d3f1d B Big Bird's Hide & Speak (U) [o1] NES -89d7f554a62ce24f3442b64cfea4cc7bd5ecb0d1 B Big Bird's Hide & Speak (U) [o2] NES +75c71cc6d187c855b3e982edcea8eccb729ee917 G Big Bird's Hide & Speak (U) [!] NES +12eb07f634424deb6a2336c2c3f0ce34722ebbca B Big Bird's Hide & Speak (U) [b1] NES +396b8bad5215abd2ce509edaf5cd4a65ed0c6548 B Big Bird's Hide & Speak (U) [b1][o1] NES +1fdbfdda17130146dc78c3914976de451726d0e1 B Big Bird's Hide & Speak (U) [b2] NES +5002d3ce6a5c809969e6eda26f58c872045e017c B Big Bird's Hide & Speak (U) [b3] NES +f529a06bd217c6e5678a6eb3e4bf6db5120a7d43 B Big Bird's Hide & Speak (U) [b4] NES +56564ef56008813863efeb82acc0f9008c9a7175 B Big Bird's Hide & Speak (U) [b6] NES +8d9dda7bfb0ee4192f8e1c6ddfed3167b565bb75 B Big Bird's Hide & Speak (U) [b7] NES +91201e10a1e91f10a06b98512275108ebd7d3f1d B Big Bird's Hide & Speak (U) [o1] NES +89d7f554a62ce24f3442b64cfea4cc7bd5ecb0d1 B Big Bird's Hide & Speak (U) [o2] NES 6208f86f22c8445d3936ad5fd715069083ab6ab8 H Big Kids Pro-Wrestling by RyanVG (Tag Team Pro-Wrestling Hack) NES 91cf3e24b02ae75b7be395e524d9545bee50ab81 G Big Nose Freaks Out (Camerica) (Aladdin) [!] NES 60550d03da8eba47778b2c6ea708ca96364d0148 B Big Nose Freaks Out (Camerica) (Aladdin) [o1] NES @@ -2312,10 +2312,10 @@ ed31a87395748473cc106d7fa454ba04a53f1dbd B Bikkuriman World - Gekitou Sei Senshi dab4f077c1220c1cee5c56d8c9fdaf797af78d15 B Bikkuriman World - Gekitou Sei Senshi (J) [o2] NES d07fc347b34340ec3bee5b5366d51a97d235f0f5 H Bikkuriman World - Gekitou Sei Senshi (J) [p1][hM02] NES 14de52da6383e9f6c72d812c728d8be95cc4d8ff T Bikkuriman World - Gekitou Sei Senshi (J) [T+Eng] NES -bb3a2c8fcc6801a3658b5cd4e5c10bbbe1a96cb1 G Bill & Ted's Excellent Video Game Adventure (U) [!] NES -e1abcfdf970177b00e8a3c8a37f433bbd66c6f58 B Bill & Ted's Excellent Video Game Adventure (U) [b1] NES -1fd46ea2cb68aa9a02eb7e42703df393af6c65ef B Bill & Ted's Excellent Video Game Adventure (U) [b2] NES -b6e33ffe9574e09443c80bd07f20aa7cbdce98c8 B Bill & Ted's Excellent Video Game Adventure (U) [o1] NES +bb3a2c8fcc6801a3658b5cd4e5c10bbbe1a96cb1 G Bill & Ted's Excellent Video Game Adventure (U) [!] NES +e1abcfdf970177b00e8a3c8a37f433bbd66c6f58 B Bill & Ted's Excellent Video Game Adventure (U) [b1] NES +1fd46ea2cb68aa9a02eb7e42703df393af6c65ef B Bill & Ted's Excellent Video Game Adventure (U) [b2] NES +b6e33ffe9574e09443c80bd07f20aa7cbdce98c8 B Bill & Ted's Excellent Video Game Adventure (U) [o1] NES a677abfc4fa5ddd76092e41ae02cf3fd7eb05f9b G Bill Elliott's NASCAR Challenge (U) [!] NES e81f0dd2d7982ca6caefe8bc9afb09235cc58a47 B Bill Elliott's NASCAR Challenge (U) [b1] NES 3320ccda897692e186aa559d4939dea6cab7aafd B Bill Elliott's NASCAR Challenge (U) [b2] NES @@ -2689,8 +2689,8 @@ ea8923de0101a2fa05aa86b193244e06746d5a9f C Booby Kids (J) [t1] NES d73bff0c21555d9d313b3adaf95e56dcba0fdf94 B Boogerman II (Rex-Soft) [o1] NES 1569ea8845e6bb128da9823fcb493d3aec0cc130 G Boogerman II (Rex-Soft) [U][!].unf NES b2d980ac5e1a19e11e8240fb627973c8642311b7 B Boogerman II (Rex-Soft) [U][o1].unf NES -f3908331337357ec80b4a24f49b73ebbb0f3048d T Boris & Boa Boa (Nuts & Milk Hack) [T+Rus_Cool-Spot] NES -a7346085c5d6b761d04b9b2744a2ede13603fe3e H Boris & Boa Boa (Nuts & Milk Hack) NES +f3908331337357ec80b4a24f49b73ebbb0f3048d T Boris & Boa Boa (Nuts & Milk Hack) [T+Rus_Cool-Spot] NES +a7346085c5d6b761d04b9b2744a2ede13603fe3e H Boris & Boa Boa (Nuts & Milk Hack) NES fbfd34bb9a3a36789b5dac2d7aed0bf85217c2fc H Boss Rush (Castlevania Hack) [a1] NES 1d8a29a5d9c203e7d735696ef2099a9e746226ab H Boss Rush (Castlevania Hack) NES 0096f2938f633e1708c5e310dd0d80e2ec628b67 U Boss Test (PD) NES @@ -2780,7 +2780,7 @@ b65d1ff7c15dc37808fdc6c92919c868b1694b65 B BreakThru (U) [b4] NES bb336fb04e0003ea495afdc19cb13aad1007a230 B BreakThru (U) [o5] NES 8e43fc66fb280ac4330320f2a979a0e48e34fa9a T BreakThru (U) [T+Rus1.2_Multisoft] NES 58114b87cd95478361eb22ce3b0f173ca81729fc G Brilliant Com Pack 2 (K) [!] NES -0538fdcac01639743e5fc053ef83089b6d7654cd G Bruce & Leo (Tom & Jerry) (Unl) [!] NES +0538fdcac01639743e5fc053ef83089b6d7654cd G Bruce & Leo (Tom & Jerry) (Unl) [!] NES c3637f75754e7c3c665f5d9583502663dccf1ea0 B Brush Roller (Unl) [b1] NES 1895e8d17b8721e49f802c0c247765f3dca1a1eb B Brush Roller (Unl) [o1] NES 314700b6c4e1006b4f48ba856fd290b07c54c6d2 U Brush Roller (Unl) NES @@ -3139,8 +3139,8 @@ dc441137c9c0cf5fde9cb7fd8d8ae795777ca372 H Captain Tsubasa Vol. II - Chin3 by Zi 54d55d350114fd3346020c3f11b57774c9b7ea00 H Captain Tsubasa Vol. II - China vs Japan (Hack) NES d9d049618757de596a2e3230726cf7c4a099c961 H Captain Tsubasa Vol. II - Chinese Team Going Forward in Rainstorm (Hack) NES cd12f75b44883312c1c92817a47ca97bb082e585 H Captain Tsubasa Vol. II - Chinese Team Running in the Rain (Hack) NES -45a1cded0f8ab9763fe99476e6c7d7192ad92f37 H Captain Tsubasa Vol. II - Circle & Cross (Hack) NES -b915156298b2e589b7fa1711a19fb61d19f9ff8b H Captain Tsubasa Vol. II - Club Plus & Fix Edition (Hack) NES +45a1cded0f8ab9763fe99476e6c7d7192ad92f37 H Captain Tsubasa Vol. II - Circle & Cross (Hack) NES +b915156298b2e589b7fa1711a19fb61d19f9ff8b H Captain Tsubasa Vol. II - Club Plus & Fix Edition (Hack) NES ca77e6d6d0f3762fb0e28ef8393a6dfb3a859720 B Captain Tsubasa Vol. II - Comback of Twins J Edition (Hack) [o1] NES a94d3768b57d1037b76cae5e559937cea1152f22 H Captain Tsubasa Vol. II - Comback of Twins J Edition (Hack) NES ad449f5d79a68b2b98b0ace2907dd58d36e13011 H Captain Tsubasa Vol. II - Comback of Twins K Edition (Hack) NES @@ -3257,7 +3257,7 @@ ed65670dcfadc367c4d141669654d27a29907aaa H Captain Tsubasa Vol. II - New Artists 497c6fe476abef31de7d1e692aa5fb9ad31ad7ec H Captain Tsubasa Vol. II - New Platinum Partner (Hack) NES 72b411a5e93105c1c02f16419513884b547c550b H Captain Tsubasa Vol. II - New Road of Emperor Plus (Hack) NES a02b202044bff2c06f9649e45adea5c10f88c764 H Captain Tsubasa Vol. II - New Road of Emperor Remake Run Wildly Edition (Hack) NES -4ae227e0d97577b4f1d0a4386a7f2833b70bbede H Captain Tsubasa Vol. II - Nippon no Ovari by sisqo & kral 89 (Hack) NES +4ae227e0d97577b4f1d0a4386a7f2833b70bbede H Captain Tsubasa Vol. II - Nippon no Ovari by sisqo & kral 89 (Hack) NES af9d5e442cac049bc6ee97bef21832c915f8fcbe H Captain Tsubasa Vol. II - OMG by Heroy (Hack) NES 1c7d72b8019bf8977f3694121c94de3a05707348 H Captain Tsubasa Vol. II - Onur Edition 2011 (Hack) NES c4947d4d58cffc8d80e6b3240e0f2e775d0e6a92 H Captain Tsubasa Vol. II - Orbit of Honor (Hack) NES @@ -3275,7 +3275,7 @@ ad0c06288f4ac3427524ee33f72c64e2026828ce H Captain Tsubasa Vol. II - Prince Nye 2025ce107819e051765845e15bdabbdcabb2450b H Captain Tsubasa Vol. II - Prince with Unlimited Allure (Hack) NES 6641d0f7166219e302b53a0391e78f2bdca0c942 H Captain Tsubasa Vol. II - Prologue of New Legend (Hack) NES 32f51d3c805b1594bca7a5128663fcbe377f9df9 H Captain Tsubasa Vol. II - Prologue of New Tanaru Legend (Hack) NES -1f229c31596e5dec91d410c72b616d519aea78d5 H Captain Tsubasa Vol. II - Raiju & Ocelot Edition (Hack) NES +1f229c31596e5dec91d410c72b616d519aea78d5 H Captain Tsubasa Vol. II - Raiju & Ocelot Edition (Hack) NES ce161826da7f3e46f3943bc05da23b5c866aaaae H Captain Tsubasa Vol. II - Raise of Western (Hack) NES adddaf33336b9721aa4dafb07eda260fd5229bdf H Captain Tsubasa Vol. II - Rampion Edition (Hack) NES a0759a83d16996fc6084eb95af2f0db1b2f345e9 H Captain Tsubasa Vol. II - Relin Edition v1.1 by mazong1123 (Hack) NES @@ -3313,7 +3313,7 @@ e8e48b44700c1efaf8c03e1752b03190febecc4f H Captain Tsubasa Vol. II - Sino-Korean e4d0b8f696fca5c834215e8f1c92ca7008687a46 H Captain Tsubasa Vol. II - Soccer Kiss (Hack) NES 9de5ffb7096c436ec5914d1d6dbbff508487638b H Captain Tsubasa Vol. II - Soccer Master in Argentina (Hack) NES 15a5fc93c408ca75e9c7af3ec20355b101566941 H Captain Tsubasa Vol. II - Sonunda Basardim Ilk Hackim (Hack) NES -dacfa7746cd9772000bf7a7797727bf69003b447 H Captain Tsubasa Vol. II - Speed of Ball Controlable & All Footballer (Hack) NES +dacfa7746cd9772000bf7a7797727bf69003b447 H Captain Tsubasa Vol. II - Speed of Ball Controlable & All Footballer (Hack) NES ae4dcc4971b095da02cdd15506a95a848ad0994e H Captain Tsubasa Vol. II - Speed of Ball Controlable (Hack) NES 90f3a515d7fc88faa4dcecc02544df6dcfb28fff H Captain Tsubasa Vol. II - Star 4 (Hack) NES 390b7a42c5a05cb85ef3758886aec39e0433be95 H Captain Tsubasa Vol. II - Story of Ryuji Amamiya (Hack) NES @@ -3359,7 +3359,7 @@ f1110e5206ebe7261caca6bf65dc8629ba3aa643 H Captain Tsubasa Vol. II - The New Joi 78d3750224ac99d57c8c549f49daf8bd4327f5e3 H Captain Tsubasa Vol. II - The Road to the King of World Cup of Romania (Hack) NES 08d80198896115199a243fd8989549eb824bf19f H Captain Tsubasa Vol. II - The World of King (Hack) NES fec3bd3b15e2c178ba6ccddf168321b86a5b4b90 H Captain Tsubasa Vol. II - The World of Master (Hack) NES -d638f9a142c98b9a295a303e5de3a9fb32731daf H Captain Tsubasa Vol. II - The World of Matsuyama & Emperor (Hack) NES +d638f9a142c98b9a295a303e5de3a9fb32731daf H Captain Tsubasa Vol. II - The World of Matsuyama & Emperor (Hack) NES db23d6e2e46a103a98ab28da85c9d8ca6ff46177 H Captain Tsubasa Vol. II - Three Musketeers of Uruguay (Hack) NES 9bc51e53dcb4a006d4548909b3d0d8046a1b80ab H Captain Tsubasa Vol. II - Tiger Arrive by hy1897 (Hack) NES 263445f5044a2ecda0da9bb742033c143d8111ae H Captain Tsubasa Vol. II - Tiger Arrive III (Hack) NES @@ -3369,9 +3369,9 @@ bea5f2dd7f36a90f796bfb4b5dbb8caec26cc8cf H Captain Tsubasa Vol. II - Tiger Threa dec1df219d5440f0dfd1bb89bf8c9cf112052187 H Captain Tsubasa Vol. II - Tiger Wake Up (Hack) NES abcc4f5e5956bd4b81907417f9c9449627cbb209 H Captain Tsubasa Vol. II - To Cleave a Path Toward the World (Hack) NES 4b938a7c140412a36d901ec34d4e6e3ab2316733 H Captain Tsubasa Vol. II - Tong's Final Perfect Edition (Hack) NES -1fbd50eac32baa20a3c691607e2b7dccabc5a988 H Captain Tsubasa Vol. II - True & False Poland (Hack) NES +1fbd50eac32baa20a3c691607e2b7dccabc5a988 H Captain Tsubasa Vol. II - True & False Poland (Hack) NES c56e2fc9b792d1d4955f09d9406645f4dda3b422 H Captain Tsubasa Vol. II - Two Brothers Edition (Hack) NES -909592b6fa254e85e6dfdd39450602ccd087d337 H Captain Tsubasa Vol. II - Two Dragons Among Sky & Land (Hack) NES +909592b6fa254e85e6dfdd39450602ccd087d337 H Captain Tsubasa Vol. II - Two Dragons Among Sky & Land (Hack) NES 3ce8b238c3112085e1c8fb7803c37dfeeb5121c0 H Captain Tsubasa Vol. II - Two Stars (Hack) NES 9dc7a0de94dc1533aa787cb326ae285b1cf3100c H Captain Tsubasa Vol. II - Ucuncu Edition (Hack) NES f12da591683afe725fbd7c31f6dcb96d943c1be1 H Captain Tsubasa Vol. II - United Team (Hack) NES @@ -3413,8 +3413,8 @@ d78d1b5a76ba5e791ed37678b0099bfb51c69e09 H Captain Tsubasa Vol. II by EricPonti fc72f4d7e9b57f86d30510db962162cee3d81ad7 H Captain Tsubasa Vol. II by Farouk (Hack) NES 5278e84254d596732eabccb63f59133f98cbc700 H Captain Tsubasa Vol. II by Greatsocrar (90807) (Hack) NES 84f25e8916f06b02034f0f2d1629f6a26c2f5db6 H Captain Tsubasa Vol. II by Hambg (Hack) NES -19fdc8c7b290cc0b4baa05217c4003a26caff94c H Captain Tsubasa Vol. II by Kral89 & Sisqo (101003) (Hack) NES -ece3a2266a8274efcae34d605821c526573418a8 H Captain Tsubasa Vol. II by Kral89 & Sisqo (90824) (Hack) NES +19fdc8c7b290cc0b4baa05217c4003a26caff94c H Captain Tsubasa Vol. II by Kral89 & Sisqo (101003) (Hack) NES +ece3a2266a8274efcae34d605821c526573418a8 H Captain Tsubasa Vol. II by Kral89 & Sisqo (90824) (Hack) NES 509f6256210049d730719f86852393dd51459352 H Captain Tsubasa Vol. II by RUI (V071103) (Hack) NES 5723575f7f28cac92ea1b620eec3f5e5c0769d37 H Captain Tsubasa Vol. II by Shinigami (120419) (Hack) NES f895c25e330122f9d848bc3c19dbec92c0fa6a9c H Captain Tsubasa Vol. II by Xiangfuxi (081104) (Hack) NES @@ -3828,12 +3828,12 @@ f53c5c4f9e6b3d0bdb9960157aef5deba002c8f7 U Chinese Character Demo (PD) NES 4f68fe97f00351696f83fb6a4b1ad868474316e9 G Chinese Checkers (Sachen-JAP) [U][!].unf NES 6662918d3ca6b789b71b7dffd0288d04edeb617a G Chinese Checkers (Sachen-USA) [!] NES a58b71b4b9ff14be13f3539405b23bccbca93b69 G Chinese Checkers (Sachen-USA) [U][!].unf NES -0db90c9ca321bb3accc6e376cab46018d934e149 G Chip & Dale 3 (Heavy Barrel) (Unl) [p1][!] NES -f874f6cceea1b5bfb950ae05e636238550c8b5f0 U Chip & Dale 3 (Heavy Barrel) (Unl) [p1][a1] NES -711ce9a3c6672fc26f5d3715fd6b240a1c2c2d42 U Chip & Dale 3 (Heavy Barrel) (Unl) [p1][a2] NES -9137af6f4a6da817eb5fd40ff4d5bdc9899151d5 B Chip & Dale 3 (Heavy Barrel) (Unl) [p1][o1] NES -9bc93a75bd86efa25173dc0190cb22f70f897890 T Chip & Dale 3 (Heavy Barrel) (Unl) [p1][T+Rus_Cool-Spot] NES -0b3ae3706a2038e6396cddd64c1a5f66f3db4634 T Chip & Dale 3 (Heavy Barrel) (Unl) [p1][T+Rus_Paha13] NES +0db90c9ca321bb3accc6e376cab46018d934e149 G Chip & Dale 3 (Heavy Barrel) (Unl) [p1][!] NES +f874f6cceea1b5bfb950ae05e636238550c8b5f0 U Chip & Dale 3 (Heavy Barrel) (Unl) [p1][a1] NES +711ce9a3c6672fc26f5d3715fd6b240a1c2c2d42 U Chip & Dale 3 (Heavy Barrel) (Unl) [p1][a2] NES +9137af6f4a6da817eb5fd40ff4d5bdc9899151d5 B Chip & Dale 3 (Heavy Barrel) (Unl) [p1][o1] NES +9bc93a75bd86efa25173dc0190cb22f70f897890 T Chip & Dale 3 (Heavy Barrel) (Unl) [p1][T+Rus_Cool-Spot] NES +0b3ae3706a2038e6396cddd64c1a5f66f3db4634 T Chip & Dale 3 (Heavy Barrel) (Unl) [p1][T+Rus_Paha13] NES 0752c8fa49ef9ca6828ba2e08b22f2a673e5469c G Chip 'n Dale Rescue Rangers (E) [!] NES 93140bf336c482ec8bbec50fcd586a2889830e6b T Chip 'n Dale Rescue Rangers (E) [T+Fre100%_Terminus] NES c16130b878cb7f4b799ba5eb373e066ac7e5b7d7 T Chip 'n Dale Rescue Rangers (E) [T+Ger_TischlDeckDich] NES @@ -4008,10 +4008,10 @@ df432e5bd5c9afa1c91e7c76ff5e5521d136643d U Chu Chu Rocket V.d by DWEdit (PD) NES d07c459890ae980bf2cd0ddfcb793ff9bdcbec74 U Chu Chu Rocket V.h by DWEdit (PD) NES 681f4869dbee15da0f71d1ea6aca743b1acc787e U Chu Chu Rocket V.xx by DWEdit (PD) NES 828b78d6b479566b2e58c8764fcc8a8b08a1292f U Chu Da D (Ch) NES -d4f3b7146af41e6e6914002569d0952a00dd9a7c U Chu Han Zheng Ba - The War Between Chu & Han (Ch) (Wxn) NES -cc5f73da064f2d9960a4992b23c188e84fae7577 B Chu Han Zheng Ba - The War Between Chu & Han (Ch) [b1] NES -1cf6a0e4337112405be96cad63a673d1193376dc H Chu Han Zheng Ba - The War Between Chu & Han (Ch) [f1] NES -3c7099746e8a9e63a6f2dcc86d1610944458a5fe U Chu Han Zheng Ba - The War Between Chu & Han (Ch) NES +d4f3b7146af41e6e6914002569d0952a00dd9a7c U Chu Han Zheng Ba - The War Between Chu & Han (Ch) (Wxn) NES +cc5f73da064f2d9960a4992b23c188e84fae7577 B Chu Han Zheng Ba - The War Between Chu & Han (Ch) [b1] NES +1cf6a0e4337112405be96cad63a673d1193376dc H Chu Han Zheng Ba - The War Between Chu & Han (Ch) [f1] NES +3c7099746e8a9e63a6f2dcc86d1610944458a5fe U Chu Han Zheng Ba - The War Between Chu & Han (Ch) NES 8aeac2380737ada73c4b6e87f751751785e416bf H Chu Liu Xiang (Ch) (Wxn) [f1] NES 2abe3e855bc7d3ee0c38fd16f8d4fc387d3a991e U Chu Liu Xiang (Ch) (Wxn) NES f69a7ff64f4f2c6f6ab89925b267e199152c00cd U Chu Liu Xiang (Ch) NES @@ -4517,7 +4517,7 @@ e283f529f23c1defcfdcf27b2eda4289f3c9d920 T Cosmo Genesis (J) [T-Eng1.0_Aeon Gene fd3d9f8a6c862773194c3e23b420aabe9453d2d6 T Cosmo Police Galivan (J) [T+Eng1.00_Jair] NES 6f38d0ada341f86f3055f689dd0f90c62556d91e U Cosmo Police Galivan (J) NES ec493cbab694b87477ff240d3b86bca0c4e62451 G Cosmos Cop (CN-08) (Unl) [!] NES -c4020f7aa09357974739e640673ef60af8386e21 H Counteroffensive of Mamoru Izawa & Kazuki Sorimachi (Captain Tsubasa II Hack) NES +c4020f7aa09357974739e640673ef60af8386e21 H Counteroffensive of Mamoru Izawa & Kazuki Sorimachi (Captain Tsubasa II Hack) NES 08c1a73e515cf5d3cc3573b6406a8ef351bc34f7 U Cow Boy (Unl) NES 3f12e2ac5e074e7970735d896331bb7e5ef5bb73 G Cowboy Kid (U) [!] NES 80eadde91d7172ef7694662aaaede874ecac7379 B Cowboy Kid (U) [o1] NES @@ -5047,8 +5047,8 @@ eb9b77ea091d80f61a612f3b0a04fdc68ba2a23f B Dian Shi Ma Li (Ch) [b2] NES fcfc928aecb25f3ee16dc42018b1c73d5283b5b4 B Dian Shi Ma Li (Ch) [b2][o1] NES 4eccc37c236b3f18c308631c68c7b2ce1614d28c B Dian Shi Ma Li (Ch) [b3] NES 050671f45712f65fec84dc490214a6942a8c53ff B Dian Shi Ma Li (Ch) [p1] NES -1c3b08f68ebe4981b84c074520b96a42d3b45d79 B Dick & Milk (Nuts & Milk Hack) [o1] NES -717328a839ca5aecc45cc1bdb48f5a0a87d913b9 H Dick & Milk (Nuts & Milk Hack) NES +1c3b08f68ebe4981b84c074520b96a42d3b45d79 B Dick & Milk (Nuts & Milk Hack) [o1] NES +717328a839ca5aecc45cc1bdb48f5a0a87d913b9 H Dick & Milk (Nuts & Milk Hack) NES 6ac01a581a1fd6b74ed6092943bd63066e14dbf0 H Dick Baseball (Baseball Hack) NES 29ecd49dc1a66ffc0a1abf9117a84a96a5f976a3 B Dick Dug (Dig Dug Hack) [o1] NES 1cff27dd1346d2a068e56c26d0282a7773738fb9 B Dick Dug (Dig Dug Hack) [o2] NES @@ -5257,11 +5257,11 @@ c26482ee39405d332aafcfff65fd378cbfd49cf6 T Donkey Kong (W) (PRG1) [T+Nor1.00_Jus e745fda35e90bcbbe470fa62f5dfd9b7cadefa5a T Donkey Kong (W) (PRG1) [T+Rus_Cool-Spot] NES 037b98dffd8203777ec37a8acd54945f4baae3ae T Donkey Kong (W) (PRG1) [T+Spa_PaladinKnights] NES 7156d06e0e1cea71c71005aad8160939fa12efdf H Donkey Kong - Dendyman's Revenge (Hack) NES -b2ba46743405fd399e86b34211310805a17986b6 H Donkey Kong 2 (Nuts & Milk Hack) [a1] NES -ea58fb27efbcc20f34ecb7781de299766b9ee76a T Donkey Kong 2 (Nuts & Milk Hack) [T+Rus_Cool-Spot] NES -800163f4b72901412b6a1899c2ba13123375abfb H Donkey Kong 2 (Nuts & Milk Hack) NES -f0e1d4d624573b4f7be5273947871417d87cfe5a T Donkey Kong 2 Demo Ver.5 (Nuts & Milk Hack) [T+Rus_Cool-Spot] NES -50b7580c05843cea716cf2624057df6bb9cfe061 H Donkey Kong 2 Demo Ver.5 (Nuts & Milk Hack) NES +b2ba46743405fd399e86b34211310805a17986b6 H Donkey Kong 2 (Nuts & Milk Hack) [a1] NES +ea58fb27efbcc20f34ecb7781de299766b9ee76a T Donkey Kong 2 (Nuts & Milk Hack) [T+Rus_Cool-Spot] NES +800163f4b72901412b6a1899c2ba13123375abfb H Donkey Kong 2 (Nuts & Milk Hack) NES +f0e1d4d624573b4f7be5273947871417d87cfe5a T Donkey Kong 2 Demo Ver.5 (Nuts & Milk Hack) [T+Rus_Cool-Spot] NES +50b7580c05843cea716cf2624057df6bb9cfe061 H Donkey Kong 2 Demo Ver.5 (Nuts & Milk Hack) NES c4e4062a91ea9fdbd575b77535bc7a4194e46694 U Donkey Kong 3 (U) (GBA e-Reader) NES 2fdc5f68313f0fb619fa1f741cd517cc0cb18c56 T Donkey Kong 3 (U) [T+Rus_Cool-Spot][a1] NES ec6fa944c672a2522c8bc270a25842281c65ff5d G Donkey Kong 3 (W) [!] NES @@ -5446,7 +5446,7 @@ dd3490d98b8ced80263db9d17721e34dbf12db85 T Double Dragon II - The Revenge (U) (P c46342b03cec7f9a895db964125760237340f116 H Double Dragon II - The Revenge - Classic Strengthened Edition (Hack) NES 35844839991c094e86ab59205d5c0c29dda490f3 H Double Dragon II - The Revenge - Clone of Bosses Edition (Hack) NES a3c419051711233cd192405f14986059805626a4 H Double Dragon II - The Revenge - Ultimate Strengthened Edition (Hack) NES -c19b034e5886c97da670b1381bb94dfa9873e96e H Double Dragon II - The Revenge by D.S.ghtMaster&KRIZAL (Hack) NES +c19b034e5886c97da670b1381bb94dfa9873e96e H Double Dragon II - The Revenge by D.S.ghtMaster&KRIZAL (Hack) NES 3a0fadff2b3beec2dc1f13b12eb7840af588aad7 H Double Dragon II - The Revenge by KRIZAL (Hack) NES dd37c6f3de1ceaed9a8bd1abcf9aafbf47b74059 H Double Dragon II - The Revenge Control Hack by Evgeny (Hack) NES 9fca8eb7eb3a635ad71afa3e719aa5cd1ba9a7c3 H Double Dragon III - Skip Level (Hack) [a1] NES @@ -5465,7 +5465,7 @@ f878cbd0d7065df4a4ca1733085f03955b64819f C Double Dragon III - The Rosetta Stone a0ccc44a8723ceb83a644c45fd6e724b4dadcb90 C Double Dragon III - The Rosetta Stone (J) [t3] NES 9ad84eeb300efaf15a69955ffbc6d65dfc50f99c H Double Dragon III - The Rosetta Stone - Additional Moves by shinwa (Hack) NES 88d2150bac12098680e23e92be8f5de8869cc421 H Double Dragon III - The Rosetta Stone - Bosses Usable Edition by shinwa (Hack) NES -f57e4ae9c12e05343b6dee3e4af21b2513971345 H Double Dragon III - The Rosetta Stone - Combined Skill & Enemies Changed Edition (Hack) NES +f57e4ae9c12e05343b6dee3e4af21b2513971345 H Double Dragon III - The Rosetta Stone - Combined Skill & Enemies Changed Edition (Hack) NES 2a88c78e830290d901a4010e5950f9149ab0db2d H Double Dragon III - The Rosetta Stone - Combined Skill Edition (Hack) NES f2fdc2ae7491dec5c9980678645dbd9b65160709 H Double Dragon III - The Rosetta Stone - Shuang Zai Long 3 by madcell (Hack) NES a1da64a21156c537b75162f0b64da651eee1a6b8 H Double Dragon III - The Rosetta Stone - Super Skill Edition (Hack) NES @@ -5995,7 +5995,7 @@ e81a4d42dd06ba171ef5e812623115b291f295b6 T Dream Master (J) [T+Eng] NES 5a71c261b50146962940fbbd840be8617b47e07b G DreamGEAR 75-in-1 (Unl) [U][!].unf NES 907564f256368d67d9ce6b361896e7d375ad7589 U Dreamworld Pogie (Prototype) NES 7525ca4bb891940d308164dee33c497d826c1960 H Dreamworld Pogie Revival (Dreamworld Pogie Hack) NES -882a3686982874112af0d20875e3f7e9496a7392 U Driar by Stefan Adolfsson & David Eriksson (PD) NES +882a3686982874112af0d20875e3f7e9496a7392 U Driar by Stefan Adolfsson & David Eriksson (PD) NES 0cc28dc56c8ee9bb5114708b98348a592da9aec4 U Dringle (Unl) NES af8febe0ef1011e5838bf3c38933ecea06721042 U Drip for NES Ported by quietust (2006-08-16) (PD) [U].unf NES 54261d0c387cd62161d5a0ad4cff9b0d3f48c3c7 U Drip for NES Ported by quietust (2006-10) (PD) [U].unf NES @@ -6089,9 +6089,9 @@ bfcf258c012d2369ec581038abae2021f147f531 U Duel, The by Bokudono (PD) NES d6c42a64492dd75bf31b07fd8f0dba421b30ba99 B Dumbass (PD) [b1] NES 19af20fc254fe8ff443f7db8d4461b7d71dee0cf U Dune War (Unl) (VT03) NES 26b782d3f6d080bb0fb0cbd236be3d0e7ad174b2 U Dung Dung No 1 (Ch) NES -04295f33c9555d4694c57aa6423dbe1466b98836 G Dungeon & Magic - Swords of Element (J) [!] NES -d8054f63f849e6b01497450d763867ba43423a26 B Dungeon & Magic - Swords of Element (J) [b1] NES -f4b42da49b97bf4d93fde1016602087fe5c5b0cb B Dungeon & Magic - Swords of Element (J) [o1] NES +04295f33c9555d4694c57aa6423dbe1466b98836 G Dungeon & Magic - Swords of Element (J) [!] NES +d8054f63f849e6b01497450d763867ba43423a26 B Dungeon & Magic - Swords of Element (J) [b1] NES +f4b42da49b97bf4d93fde1016602087fe5c5b0cb B Dungeon & Magic - Swords of Element (J) [o1] NES 427506826bf9cf2ef144100be2e3f98d9e979798 G Dungeon Kid (J) [!] NES 602ca2cada36025c04562dc174f7ceca284885b3 B Dungeon Kid (J) [b1] NES d8519092cf52b7a4f0fc94a9829ada12681c0279 C Dungeon Kid (J) [t1] NES @@ -6219,8 +6219,8 @@ c4085b7a4aabd8ac27fdc2b647715d451a2bc04a B Eliminator Boat Duel (U) [b1] NES d0ef1150ab6cdcb076a528cf2b18a780864d4bb3 B Eliminator Boat Duel (U) [o1] NES 00009ecaf75344e39cc9a94805f5113c10f270a2 B Eliminator Boat Duel (U) [o2] NES 02b277caef0970078dfb3f2dbb7ced731380ecfd G Elite (E) [!] NES -aa3b7bbb929efd9c2b364e63000ccb1cc107c2a0 B Elite (E) [f1] (NTSC by Ian Bell & David Braben) [o1] NES -17c4f91469931ea309bfff4faba3f3c34deed3c7 H Elite (E) [f1] (NTSC by Ian Bell & David Braben) NES +aa3b7bbb929efd9c2b364e63000ccb1cc107c2a0 B Elite (E) [f1] (NTSC by Ian Bell & David Braben) [o1] NES +17c4f91469931ea309bfff4faba3f3c34deed3c7 H Elite (E) [f1] (NTSC by Ian Bell & David Braben) NES 092849f8d75ac1206f63bb82e43c4f670fb8eed1 H Elite Tecmo League (Tecmo Super Bowl Hack) NES 4d4faac62a455dfa8ada73480e6c67906b3957e1 H Elite Tecmo League Clock (Tecmo Super Bowl Hack) NES 8bb770863ccded715de87dbccbf26e36c8363572 H Elite Tecmo League S1 Week 03 (Tecmo Super Bowl Hack) NES @@ -6261,7 +6261,7 @@ f59d7b0cf20d9abaf6a7b7f1b66744ea55f9d2fa G Erika to Satoru no Yume Bouken (J) [! c42a1191d0292f208873e0e1ab122d7354c7925e H Erika to Satoru no Yume Bouken (J) [f1] NES 222ac701664930f295da954393e8eb9376017f33 B Erika to Satoru no Yume Bouken (J) [f1][o1] NES bc59e706bc0cda456e496b2403a41df61eebfdbb B Erika to Satoru no Yume Bouken (J) [hM04][b1] NES -00222d1ea57c7ee4bb614536642d03f02cbca769 H Ernie & The Muppets Take It All Off (Sesame Street ABC Hack) NES +00222d1ea57c7ee4bb614536642d03f02cbca769 H Ernie & The Muppets Take It All Off (Sesame Street ABC Hack) NES 4f4355afcfde87e651c32eda7610d67c02396ff8 G Erunaaku no Zaihou (J) [!] NES aff3198813f2e25c9684b63354f1da6bdf2d7c6d B Erunaaku no Zaihou (J) [b1] NES 8d68935e94134eec22a4259080b3ce5590e4f7a3 B Erunaaku no Zaihou (J) [b2] NES @@ -6419,7 +6419,7 @@ a0375e7e0da9093417a9d081b7606ed9f5c71ac3 B F-15 Strike Eagle (U) [o1] NES 96ab957763051c6b8d952567450469c9af99e3d4 B F22 (Ch) [b1] NES 63c23c5bb78d256a0361e7a7a0ffb24d8c87cc11 T Facemaker (Dr. PC Jr.) (Ch) [T+Rus_Cool-Spot] NES dc8fde977a5a06d579f80d0861b235014b678a53 U Facemaker (Dr. PC Jr.) (Ch) NES -ea97d054a53c65428d1c1ee27c2fc5c945944843 U Fade to Black by Frederik Schultz & Morgan Johansson (PD) NES +ea97d054a53c65428d1c1ee27c2fc5c945944843 U Fade to Black by Frederik Schultz & Morgan Johansson (PD) NES 9f3d83c3b6e620d9e67cf5cd49428c3f88a71ca4 H Fall of the Moon v1.0 (Zelda Hack) NES 508dfa36b062dfd1a465301ada3a876acc402582 U Falldown by Sivak (2008) (PD) NES 45543a0aed48f5d0943a8ee33ea8a9709c3bfa3d H Falling Mario by WA (SMB1 Hack) NES @@ -6441,7 +6441,7 @@ f07d48f7355480f855a60d0e8c65621f4e4c643d H Famicom Jump II - Saikyou no 7 Nin (J 9c5381325383bf6c074b2c3cdcc825e138615a19 G Famicom Meijin Sen (J) [!] NES 44c1d079b75deeb3e858240a0d4a10d5d7add87c U Famicom Meijin Sen (J) [a1] NES aaf74b17bfe8c18fd672fcae18741956d1c3380e B Famicom Meijin Sen (J) [a1][o1] NES -6992f115820264ceaaff988cb4bfbe3c5e35ecc9 U Famicom Pro Action Rocky Encoder-Decoder by Chris Covell, ReaperSMS & Jamethiel (PD) NES +6992f115820264ceaaff988cb4bfbe3c5e35ecc9 U Famicom Pro Action Rocky Encoder-Decoder by Chris Covell, ReaperSMS & Jamethiel (PD) NES 21727912fe4ae683da2c7aadb029f355079964fd U Famicom Sequencer V0.5 (PD) NES 052e6915a4b6c15982d5b134fce7581210c7d8de U Famicom Shougi - Ryuuousen (J) (Prototype) NES e4cc5f8e013fae686d97f3901c261b5abfcc9d5b B Famicom Shougi - Ryuuousen (J) [o1] NES @@ -6580,10 +6580,10 @@ a3d852930db34bb76c1ac1531311dd5552b8e7be G Fantasy Zone (Tengen) [!] NES 96aca644fb0450542d35573e99afdd1534f8191f H Fantasy Zone 2 - The Teardrop of Opa-Opa (J) [hFFE] NES 7b7b333f5f4da08f523256518b5244006c994090 B Fantasy Zone 2 - The Teardrop of Opa-Opa (J) [o1] NES 808cc9050dcee35fa499d601e8567166bda4493a C Fantasy Zone 2 - The Teardrop of Opa-Opa (J) [t1] NES -2841d46704680033b183c7c07945dbbcb68427ed G Faria - A World of Mystery & Danger! (U) [!] NES -b9350d2ca19c4185b8cb32ffa5e51b114a5702fc B Faria - A World of Mystery & Danger! (U) [b1] NES -6129ba26219de2586562234e8f16a29ad6c586db B Faria - A World of Mystery & Danger! (U) [o1] NES -24027380173f2004a44870c8fee3eb9dd1027d76 C Faria - A World of Mystery & Danger! (U) [t1] NES +2841d46704680033b183c7c07945dbbcb68427ed G Faria - A World of Mystery & Danger! (U) [!] NES +b9350d2ca19c4185b8cb32ffa5e51b114a5702fc B Faria - A World of Mystery & Danger! (U) [b1] NES +6129ba26219de2586562234e8f16a29ad6c586db B Faria - A World of Mystery & Danger! (U) [o1] NES +24027380173f2004a44870c8fee3eb9dd1027d76 C Faria - A World of Mystery & Danger! (U) [t1] NES e7fdd7976a9c834f171b3ac39ab69259e05a0afa G Faria - Fuuin no Tsurugi (J) [!] NES d87116e7aee1b8fac894b30b4aaa50539aaedab9 B Faria - Fuuin no Tsurugi (J) [b1] NES 2235a01f54223dd2609cef3dc3dc82b7775b9bfb B Faria - Fuuin no Tsurugi (J) [b2] NES @@ -6631,7 +6631,7 @@ e86add4e0badb9396c18bbc2b786b08a044dd83d H Faxanadu Uncensored Edition by Safari 0db354cc152ff3413e401160d5f51871326628aa C FC Genjin - Freakthoropus Computerus (J) [t1] NES 99e513dba565f5b4f648bc0a1a0f52aff5a48946 U FC Genjin - Freakthoropus Computerus (J) NES 99d5f61fc8fda02db984308368277a326c123977 U FC Intro by emumax (PD) NES -416b236dd5babc127555185e15a22f70e718186e U FC WIN2000 (for Infrared Mouse & Keyboard) (Ch) NES +416b236dd5babc127555185e15a22f70e718186e U FC WIN2000 (for Infrared Mouse & Keyboard) (Ch) NES 07252ffa0df0f65d681e79ab2ba38250ec85c08b U FC-Subor V3.0 Music Demo (Unl) NES e0d0eaaf0523d3442072134667198ea5ee342934 H Fedsvd MLB (R.B.I. Baseball Hack) [a1] NES 6411512f09c63c6679c258b9c8cbd87791581f1f H Fedsvd MLB (R.B.I. Baseball Hack) NES @@ -6664,7 +6664,7 @@ c2add8e26655ba9b6774197dc1a6e730f0a92c0b U Feng Se Huan Xiang (ES-1138) (Ch) NES 083793f71533db327cbcbe0ae27d4a1483733777 U Feng Yun (Ch) (Decrypted) NES 1a0ced71e62f11bccb4b2de3fe0433240e75357b U Feng Yun (Ch) (Wxn) NES ea0d9f0df87a2c5b518642bb793d67b544ae5165 U Feng Yun (Ch) NES -8008cd3ff792a2c7e5e34c34543394d6ffbf48b5 U Fengli Dance 12-in-1 & 24-in-1 (Ch) NES +8008cd3ff792a2c7e5e34c34543394d6ffbf48b5 U Fengli Dance 12-in-1 & 24-in-1 (Ch) NES 1f3c590a05e3897f4266302f744dd65e70e501b0 G Ferrari - Grand Prix Challenge (E) [!] NES 146e39e962c6fff24724fe55d632ba4217cc3b67 G Ferrari - Grand Prix Challenge (J) [!] NES bee319db995fc25dd6ee88217e10420aab7310ca G Ferrari - Grand Prix Challenge (U) [!] NES @@ -6829,13 +6829,13 @@ b0f164556d8cb71b2c04bd7d9d306c0e7c026772 H Final Fantasy Epica V2.0 by Clomax Do edafdca67ae322a086386b219d67c526de592f73 H Final Fantasy Gaiden (FF1 Hack) NES 083294dfaa5238c750110ce0d95b57ebcd9c9ce6 H Final Fantasy Hard Type by Red Wizard (FF1 Hack) NES 5b46b541851eefc0954bd7f15ef860dc43bf1fac H Final Fantasy Hardtype V1.1 (FF1 Hack) NES -4b22c2c88fc71eacf270ea51ef218944bb4c536a G Final Fantasy I & II (J) [!] NES -b3c2be46b4118df618a90969aec3836c36213187 B Final Fantasy I & II (J) [b1] NES -f68f71e3475a0d2a3455eb4ea55aa7c6b4989329 B Final Fantasy I & II (J) [b2] NES -e0a971450a7907f8e5ac1749638d03800c371cce B Final Fantasy I & II (J) [o1] NES -5c86afaee19c4d564be583d19639af9e3308a6c6 B Final Fantasy I & II (J) [o1][T+Eng1.00_Demiforce] NES -704d46eb311a7d07268ea57de26cdacc3a83711a T Final Fantasy I & II (J) [T+Eng1.00_Demiforce,Grond] NES -ff5a216e3da57ee7133449a4ac6b0e8957a23595 T Final Fantasy I & II (J) [T+Eng1.00_Demiforce] NES +4b22c2c88fc71eacf270ea51ef218944bb4c536a G Final Fantasy I & II (J) [!] NES +b3c2be46b4118df618a90969aec3836c36213187 B Final Fantasy I & II (J) [b1] NES +f68f71e3475a0d2a3455eb4ea55aa7c6b4989329 B Final Fantasy I & II (J) [b2] NES +e0a971450a7907f8e5ac1749638d03800c371cce B Final Fantasy I & II (J) [o1] NES +5c86afaee19c4d564be583d19639af9e3308a6c6 B Final Fantasy I & II (J) [o1][T+Eng1.00_Demiforce] NES +704d46eb311a7d07268ea57de26cdacc3a83711a T Final Fantasy I & II (J) [T+Eng1.00_Demiforce,Grond] NES +ff5a216e3da57ee7133449a4ac6b0e8957a23595 T Final Fantasy I & II (J) [T+Eng1.00_Demiforce] NES ae373debd5a1d787eec28214c221fa4590c20844 U Final Fantasy II (J) (VC) NES 1a9e01a29472f1161bd16e1b4d76994346a505f6 G Final Fantasy II (J) [!] NES de129faa757050a925e5060f65bdc390d3978eb4 H Final Fantasy II (J) [hM02] NES @@ -6876,7 +6876,7 @@ ddc7b6b85ab0eaf26586d5a97aaa04c3620c2d1e H Final Fantasy II (J) [hM02][T-Eng1.0] 20079a629ff38fb2e76cf3a6e78c782588c890ef T Final Fantasy II (J) [T+Bra100%_Thirteen Traducoes] NES 90a5ccc3119aa91947f086c3c9fc069a7f80ef09 T Final Fantasy II (J) [T+Eng0.36_Toma,AlanMidas] NES 62ed16088e5293a9f238161c12fe59eaa196f1f8 T Final Fantasy II (J) [T+Eng1.03_Demiforce] NES -b7a849df213b59cd43066d15eeec4df983c0b5f5 T Final Fantasy II (J) [T+Eng1.03_Demiforce][f1] (Title & Weapon-Magic Exploit by Parasyte) NES +b7a849df213b59cd43066d15eeec4df983c0b5f5 T Final Fantasy II (J) [T+Eng1.03_Demiforce][f1] (Title & Weapon-Magic Exploit by Parasyte) NES de7fecb42947a24fbf632e2ccfccbdba69a857fb T Final Fantasy II (J) [T+Eng1.03_Demiforce][f1] (Title by Parasyte v1.0) NES 73f8436f78cec36f4d205a2dc5cc25fe949efc22 T Final Fantasy II (J) [T+Eng1.03PasoFami_Demiforce] NES 4e68ee5da3dbe2ed7348be072825364c87d2ab6a T Final Fantasy II (J) [T+Ita0.99a_Weapon Hunter] NES @@ -7085,7 +7085,7 @@ b7b3054034234ffaea975e4158f32f0f6bd12721 B Fire Emblem Gaiden (J) [T+Eng97b2_J2E de04536e3fa70d9dbccf62e0dc2e58bf02ac94f4 H Fire Emblem Gaiden by jibo818 (070502) (Hack) NES ead6701e3998cd7f81c8e8fccd1bb12a0bd90169 H Fire Emblem Gaiden by Lewis GT (070806) (Hack) NES d0c52c96c29dd6144215e63047b39972982894d1 H Fire Emblem Gaiden by scorpioywk v3.0a (Hack) NES -44b79228f44efc9acf9f878a08e8d8493c311ca7 H Fire Emblem Map & Enemy by One Talent (Hack) NES +44b79228f44efc9acf9f878a08e8d8493c311ca7 H Fire Emblem Map & Enemy by One Talent (Hack) NES 209f7ca3f4f9e179881aa9387dc6ad5dea4f4575 B Fire Emblem Two Dragon Edition (Hack) [b1] NES efa0e83b2bcb0f02fc81fc7b434ffe56209d3d67 H Fire Emblem Two Dragon Edition (Hack) NES 85438df235e84b38452282aa2f96624f31986b59 B Fire Flight Z (Formation Z Hack) [o1] NES @@ -7127,17 +7127,17 @@ c212375ac4a48de955e608af2ccc9cd36cc040fe T Fleet Commander (J) [T+Rus_Chief-Net] 18e4116d04aa688a8a8629f3b6770ec8436d2778 G Flight of the Intruder (U) [!] NES 425d371df518c142c9dfc9764e02ac53ada94d0e B Flight of the Intruder (U) [b1] NES b823ee04d31bdf6937ddfc3a1e81f2fa8ea3cf2f B Flight of the Intruder (U) [o1] NES -9695b227545fca9cd6c95abf348ff51b175634f6 G Flintstones, The - The Rescue of Dino & Hoppy (E) [!] NES -66b701bcf13ea261cf459058d141f078fc66652c C Flintstones, The - The Rescue of Dino & Hoppy (E) [t1] NES -9d1ba8a9cb5afe378bf4cdf94dee5eecd80ccf6b U Flintstones, The - The Rescue of Dino & Hoppy (J) NES -549de66388ff02e33a40bf7ef83e207f98a50888 G Flintstones, The - The Rescue of Dino & Hoppy (U) [!] NES -db9f7f37cac7a00752beffe5a14c295f1722823e B Flintstones, The - The Rescue of Dino & Hoppy (U) [b1] NES -c0a6a7cbf5de4451aed7f5f8fe6b67df97c4c11b B Flintstones, The - The Rescue of Dino & Hoppy (U) [b2] NES -18c335127d0338318ac04d43b6ee434623db761c B Flintstones, The - The Rescue of Dino & Hoppy (U) [o1] NES -805737b473814baeeaf98bdacd2de810dae5c8e5 G Flintstones, The - The Rescue of Dino & Hoppy (U) [p1][!] NES -ad651e65a9e7333a415f1071f0783a3f4ea53218 B Flintstones, The - The Rescue of Dino & Hoppy (U) [p2] NES -deb230107c87863a7226d4466470aa5b824d6d0c C Flintstones, The - The Rescue of Dino & Hoppy (U) [t1] NES -4c2199ab578faf2cb1f244e5a562ecc0918f27ca C Flintstones, The - The Rescue of Dino & Hoppy (U) [t2] NES +9695b227545fca9cd6c95abf348ff51b175634f6 G Flintstones, The - The Rescue of Dino & Hoppy (E) [!] NES +66b701bcf13ea261cf459058d141f078fc66652c C Flintstones, The - The Rescue of Dino & Hoppy (E) [t1] NES +9d1ba8a9cb5afe378bf4cdf94dee5eecd80ccf6b U Flintstones, The - The Rescue of Dino & Hoppy (J) NES +549de66388ff02e33a40bf7ef83e207f98a50888 G Flintstones, The - The Rescue of Dino & Hoppy (U) [!] NES +db9f7f37cac7a00752beffe5a14c295f1722823e B Flintstones, The - The Rescue of Dino & Hoppy (U) [b1] NES +c0a6a7cbf5de4451aed7f5f8fe6b67df97c4c11b B Flintstones, The - The Rescue of Dino & Hoppy (U) [b2] NES +18c335127d0338318ac04d43b6ee434623db761c B Flintstones, The - The Rescue of Dino & Hoppy (U) [o1] NES +805737b473814baeeaf98bdacd2de810dae5c8e5 G Flintstones, The - The Rescue of Dino & Hoppy (U) [p1][!] NES +ad651e65a9e7333a415f1071f0783a3f4ea53218 B Flintstones, The - The Rescue of Dino & Hoppy (U) [p2] NES +deb230107c87863a7226d4466470aa5b824d6d0c C Flintstones, The - The Rescue of Dino & Hoppy (U) [t1] NES +4c2199ab578faf2cb1f244e5a562ecc0918f27ca C Flintstones, The - The Rescue of Dino & Hoppy (U) [t2] NES 354415e5472c4cbf4978744c97a9a53c6b61cb49 G Flintstones, The - The Surprise at Dinosaur Peak! (E) [!] NES 5a6ae3e6897414758a8791783f3a482e5a2dd0fb G Flintstones, The - The Surprise at Dinosaur Peak! (U) [!] NES a3bdfaa4d67de0f1468d9fe701a8988e2e732744 B Flintstones, The - The Surprise at Dinosaur Peak! (U) [o1] NES @@ -7284,9 +7284,9 @@ ff9ba69080f51331a10df9c2f7531ab5a9a34e58 B Front Line (J) [T-Chi][b1] NES 2b257fa8049678600b4db8461b56bfceee1056aa H Front Line 2 Hardcore (Front Line Hack) NES a9966b9065b29defc48a2566136b634f74dd31e7 U FS Demo by KZ-S (PD) NES 3759f6d43be742defb5b52117e5378645332c816 H Fucked Up Bros 2 (SMB2 Hack) NES -0bc48f6ceee853de3535bb49227415e5d817ba0e H Fucked Up North & South (Hack) NES +0bc48f6ceee853de3535bb49227415e5d817ba0e H Fucked Up North & South (Hack) NES 794d30faa4ba81046405f3c6599b73c3a297b2ad H Fucker's Quest by Shitdic (Fester's Quest Hack) NES -b346af0a6ef44db9e251ed18a3925f8396868496 H Fudan Mario by DU-6&Hi (SMB1 Hack) NES +b346af0a6ef44db9e251ed18a3925f8396868496 H Fudan Mario by DU-6&Hi (SMB1 Hack) NES 1ae0646964ad522f78427d5f29401b197020a4df G Fudou Myouou Den (J) [!] NES 54f3061ca2ccc87342d44cec098a4c07d530d6ce B Fudou Myouou Den (J) [hFFE][b1] NES 056280af7a109617d1f0d21e228dcb9dbe394693 H Fudou Myouou Den (J) [hM80] NES @@ -7525,8 +7525,8 @@ c6954c8d5030bd3f446644e2a02b3135d3bbff93 B Garou Densetsu Special (Unl) [hM04][b fe0d1d3f7662bcba4c550440696d6fb24b3181a9 B Garou Densetsu Special (Unl) [hM04][b5] NES aec04b867e7de8dc7ace8563bd693b9199c4a33a H Garou Densetsu Special (Unl) [hM04][f1] NES de38a34367495ff5e899b574e15495f78a5e5678 U Garou Densetsu Special (Unl) NES -7f95489c35713f1befb5bfbfc6a51b523eaa1b50 T Gary's Nuts (J) (Nuts & Milk Hack) [T+Rus_Cool-Spot] NES -468e874670c5b8e7db979db02d5eb5d4bae256a4 H Gary's Nuts (J) (Nuts & Milk Hack) NES +7f95489c35713f1befb5bfbfc6a51b523eaa1b50 T Gary's Nuts (J) (Nuts & Milk Hack) [T+Rus_Cool-Spot] NES +468e874670c5b8e7db979db02d5eb5d4bae256a4 H Gary's Nuts (J) (Nuts & Milk Hack) NES b5a669ea96249a23ca3b868ac1c7555e611ee83b U Gauntlet (PC10) NES d3a2ad975e2e955e39fb3fd64e93ff983af81e0d G Gauntlet (Tengen) [!] NES debb19b46939a296bad008cffbb3bb0f8d6608d3 B Gauntlet (Tengen) [b1] NES @@ -7978,7 +7978,7 @@ bc39a2546b530fc84e90052d4077676da97ed679 T Grand Master (J) [T-Eng_Stardust Crus aa0fb9dd052ee687ff02ed2713ed92a3887e76f0 U Grand Master (J) NES 0f01b092ce5d02d5c6e3ea553290a06c8281ee24 U Grandia (Ch) (Wxn) NES 8bcdc14b93f52cd4a657c18fee21cdc4ed6298a1 H Graros (Seicross Hack) NES -f5d968639bb462819500cb33a3644487f177740b U Grave Digger by Tarnow, Hollis, Gillotti & Subramanian (PD) NES +f5d968639bb462819500cb33a3644487f177740b U Grave Digger by Tarnow, Hollis, Gillotti & Subramanian (PD) NES d0da677def74b64e1b2d25748e2bce691566c4b0 B Great Adventures of Weiny, The (Mario Bros Hack) [o1] NES b0b0a350e4360fb03cf536c961f2f4fa68f98dbf H Great Adventures of Weiny, The (Mario Bros Hack) NES a55e9323d89d855672dcb20dc29efd2f53ded972 G Great Battle Cyber (J) [!] NES @@ -8019,9 +8019,9 @@ e327e3e3814f0ea008d347eeee1b72e378abb857 B Gremlins 2 - The New Batch (U) [b1] N abc3dfd1cc1fab09eb5edb6223570a26f974c9e8 C Gremlins 2 - The New Batch (U) [t1] NES 34eea8840f666fca69d85f6dfa5fdf77a297b3b3 U Greys Demo by Chris Covell (PD) NES 3b3dea215ac51563b049f9f5a643bc1e5e88c8aa H Grond's Final Fantasy (FF1 Hack) NES -3d1098ccc2250e8e007170d2143112d61f348a31 H Grond's Final Fantasy Bugfix & Balancing (FF1 Hack) [a1] NES -076003fdac7b73059f8e45c9d9f8ae5a04af5c9c H Grond's Final Fantasy Bugfix & Balancing (FF1 Hack) NES -1e18667e99767f3ab6acf54b685986b230696722 H Grond's Final Fantasy Bugfix & Balancing (v1.1) (FF1 Hack) NES +3d1098ccc2250e8e007170d2143112d61f348a31 H Grond's Final Fantasy Bugfix & Balancing (FF1 Hack) [a1] NES +076003fdac7b73059f8e45c9d9f8ae5a04af5c9c H Grond's Final Fantasy Bugfix & Balancing (FF1 Hack) NES +1e18667e99767f3ab6acf54b685986b230696722 H Grond's Final Fantasy Bugfix & Balancing (v1.1) (FF1 Hack) NES 0828f94fedee148987ac3cfa4a270d26306bc6b0 U GSD Super Student Computer Cartridge (Ch) NES f8229677bfad4050a24bfb9a78521a6e36d3cac4 G Gu Ba Zhan Shi Xi Hua (Ch) [!] NES bd147f4eeafe37d73524a0d0a6735a422376e482 U Gu Ba Zhan Shi Xi Hua (Ch) [a1] NES @@ -8203,7 +8203,7 @@ e545041ff87271f56f975d73d7b772d37f06d2bb H Hanjuku Eiyuu (J) [hM02] NES 810a86d04016eeba01cdc826f80babb86619b8d7 H Hanjuku Eiyuu (J) [hM02][a1] NES e7305030fe0261de587b16c85a0acab9386bc858 B Hanjuku Eiyuu (J) [o1] NES 11777a01cdb2d242233742d4a302c1af51f759e4 H Hanjuku Eiyuu by fenglianxilin (070808) (Hack) NES -fbb406a103e79df26ac4ef208b7f9df16006ee44 H Hansel & Gretel (SMB1 Hack) NES +fbb406a103e79df26ac4ef208b7f9df16006ee44 H Hansel & Gretel (SMB1 Hack) NES 9be59e3c120046c2b9e68bb5f25d21f1b2dc8386 U Happy Angel Legend (Unl) NES 9a07441300f5f13898f777020fe8cb04361d3ca6 H Happy Birthday - BMF x 28 (SMB1 Hack) NES 65855650819327782bce279dbaea220090deeb6e G Happy Birthday Bugs (J) [!] NES @@ -9118,10 +9118,10 @@ af45f13c326ce6e8b5e29eb583faf5d9a74349b7 B Iron Tank - The Invasion of Normandy 3b4a5cb92fc0df0cb8e6fb4528a5414004005116 B Iron Tank - The Invasion of Normandy (U) [o2] NES f745f07efda10a0c685f693df47ed8b15b3aa458 C Iron Tank - The Invasion of Normandy (U) [t1] NES c8c011ab830e9aefd2c6335a40857fda48186356 C Iron Tank - The Invasion of Normandy (U) [t2] NES -bf7b26e28cecc6a46131971210bfb10123ab9dab G Ironsword - Wizards & Warriors II (E) [!] NES -97b79e432f62403fb9f877090850c41112a9a168 G Ironsword - Wizards & Warriors II (U) [!] NES -cdc3da09fdd4478b5c8f1640ea26604cdf096a62 B Ironsword - Wizards & Warriors II (U) [b1] NES -84f6af51c04d27e877480bc9136d4c0401bb2461 B Ironsword - Wizards & Warriors II (U) [o1] NES +bf7b26e28cecc6a46131971210bfb10123ab9dab G Ironsword - Wizards & Warriors II (E) [!] NES +97b79e432f62403fb9f877090850c41112a9a168 G Ironsword - Wizards & Warriors II (U) [!] NES +cdc3da09fdd4478b5c8f1640ea26604cdf096a62 B Ironsword - Wizards & Warriors II (U) [b1] NES +84f6af51c04d27e877480bc9136d4c0401bb2461 B Ironsword - Wizards & Warriors II (U) [o1] NES 5d9402702b33d226e822dd4a39b9004dcd90b787 U IRQ Flag Operation Test by Shay Green (30 Jun 2005) (PD) NES 7fbd5c094f63d8d0ad9cfb0730e809875bcdace6 U IRQ Flag Timing Test by Shay Green (30 Jun 2005) (PD) NES 5b87d2e908ae68348ccb306764ac7ec9067395e3 U IRQ Handler Test by Shay Green (30 Jun 2005) (PD) NES @@ -9390,15 +9390,15 @@ e54091563b9f39863a93f8c0260b3b5518628576 T JJ - Tobidase Daisakusen Part 2 (J) [ f19a702eefcb6467176916a6f612974dcba0fb19 T JJ - Tobidase Daisakusen Part 2 (J) [T+Rus] NES 6c2aee3bfe22bdbcab6f707720b3675c2d439c42 T JJ - Tobidase Daisakusen Part 2 (J) [T+Rus][t1] NES 90dd8e45ade16e684489d34343856b6a0b8dac26 C JJ - Tobidase Daisakusen Part 2 (J) [t1] NES -935a56567d1e8516c104ead5e9ecbc6d8e9b0a1f G Joe & Mac - Caveman Ninja (E) [!] NES -36bafdf6f8d531fecb3553c1923eeafac4a05c28 G Joe & Mac - Caveman Ninja (U) [!] NES -79a02ad09b776734e9e341d91137e989ea482f8e B Joe & Mac - Caveman Ninja (U) [b1] NES -6edbe6c00f8246a1f8c1a6fa543e9e2e83ea666e B Joe & Mac - Caveman Ninja (U) [o1] NES -e3b06ee583b47c55b5a1c9354482a27ad2cfbfde G Joe & Mac - Caveman Ninja (U) [p1][!] NES -bcf23b47befc698b9c8e1c2e1aa48529ac6ecf06 B Joe & Mac - Caveman Ninja (U) [p2] NES -ef454083c6720b6f0a541257eb9a41758f27746c B Joe & Mac - Caveman Ninja (U) [p3] NES -f8139f01b7c3ca2b14cefec784ae64781c8f956d C Joe & Mac - Caveman Ninja (U) [t1] (No Time) NES -9031b847c51320960655849c750f027b20d05a80 C Joe & Mac - Caveman Ninja (U) [t2] NES +935a56567d1e8516c104ead5e9ecbc6d8e9b0a1f G Joe & Mac - Caveman Ninja (E) [!] NES +36bafdf6f8d531fecb3553c1923eeafac4a05c28 G Joe & Mac - Caveman Ninja (U) [!] NES +79a02ad09b776734e9e341d91137e989ea482f8e B Joe & Mac - Caveman Ninja (U) [b1] NES +6edbe6c00f8246a1f8c1a6fa543e9e2e83ea666e B Joe & Mac - Caveman Ninja (U) [o1] NES +e3b06ee583b47c55b5a1c9354482a27ad2cfbfde G Joe & Mac - Caveman Ninja (U) [p1][!] NES +bcf23b47befc698b9c8e1c2e1aa48529ac6ecf06 B Joe & Mac - Caveman Ninja (U) [p2] NES +ef454083c6720b6f0a541257eb9a41758f27746c B Joe & Mac - Caveman Ninja (U) [p3] NES +f8139f01b7c3ca2b14cefec784ae64781c8f956d C Joe & Mac - Caveman Ninja (U) [t1] (No Time) NES +9031b847c51320960655849c750f027b20d05a80 C Joe & Mac - Caveman Ninja (U) [t2] NES 5e44cea620e33e3c7c04c67163b0a9c612939c47 G John Elway's Quarterback (U) [!] NES d0e8588498ff005c311492c221b3c67721b8d42d B John Elway's Quarterback (U) [o1] NES f67733b11991cc1c2301bf9d97df7c2b25a6bfdf B John Elway's Quarterback (U) [o2] NES @@ -9413,11 +9413,11 @@ e53a42ac93b757541e853695dd0c7ae50b437874 B Jongbou (J) [f1][o1] NES 1c07244a8b98dde1f4ecb176097ca6aacd8c785d B Jongbou (J) [f1][o3] NES ce8415b6a7585a752d1979ef87d4227591789e97 G Jordan Vs Bird - One On One (U) [!] NES 538668aaa59db38e072cd1f499dead9236bbe13f B Jordan Vs Bird - One On One (U) [o1] NES -011a7ce0c86929a5788a67ed49c5dc587c53f991 U Joshua & the Battle of Jericho (Wisdom Tree) (V5.0 CHR 6.0) NES -4d838a393823b2ab2fcca48b6cda6292f2992880 G Joshua & the Battle of Jericho (Wisdom Tree) (V6.0) [!] NES -4856a12ba4f01e0ca41bfa6c95039fc302a60724 B Joshua & the Battle of Jericho (Wisdom Tree) (V6.0) [b1] NES -e598d9753a823d39fda3cddc486a56ffb0ebee33 B Joshua & the Battle of Jericho (Wisdom Tree) (V6.0) [b2] NES -eb320ad334f8f26044eb1084b070003bafc4e7d1 B Joshua & the Battle of Jericho (Wisdom Tree) (V6.0) [o1] NES +011a7ce0c86929a5788a67ed49c5dc587c53f991 U Joshua & the Battle of Jericho (Wisdom Tree) (V5.0 CHR 6.0) NES +4d838a393823b2ab2fcca48b6cda6292f2992880 G Joshua & the Battle of Jericho (Wisdom Tree) (V6.0) [!] NES +4856a12ba4f01e0ca41bfa6c95039fc302a60724 B Joshua & the Battle of Jericho (Wisdom Tree) (V6.0) [b1] NES +e598d9753a823d39fda3cddc486a56ffb0ebee33 B Joshua & the Battle of Jericho (Wisdom Tree) (V6.0) [b2] NES +eb320ad334f8f26044eb1084b070003bafc4e7d1 B Joshua & the Battle of Jericho (Wisdom Tree) (V6.0) [o1] NES 85f64db051e8c173a18905066052d412a8eb1d6c G Journey to Silius (E) [!] NES 275244538589393b552b159ab1d380090c8e8996 G Journey to Silius (U) [!] NES 08c67ce185d2a4230d6c954bd90587192d2e34d2 B Journey to Silius (U) [b1] NES @@ -9990,10 +9990,10 @@ f324e7c8c3ad102ecdcca011ecc494f6f345d768 G Kirby's Adventure (U) (PRG1) [!] NES 455a81e5644317409d6047a7dccff56cb07cde89 H Kirby's Adventure 2 (SMB1 Hack) NES c6f778708182114b4f58093575cf51b5de9926b7 H Kirby's Adventure FUCKED (Hack) NES 15175dfe4b255b3ffc1003e7ffc3d87888fd3acc U Kirby's Dreamland 3 Title Screen Demake by Macbee v1.0 (PD) NES -c445072c3362fa3fb2cc481706d5b1b96b368798 B Kirby's Nuts (Nuts & Milk Hack) [o1] NES -67c1d833caa09444555711fdb32e7f16dfe61389 T Kirby's Nuts (Nuts & Milk Hack) [T+Rus_Cool-Spot] NES -d875bd8977d6486ac3c5c874d9d4f2cdcdc0841a T Kirby's Nuts by Kidwhatever (Nuts & Milk Hack) [T+Rus_Multisoft] NES -046d3a72942639a1a0c8a6eaa8c0a049051ea113 H Kirby's Nuts by Kidwhatever (Nuts & Milk Hack) NES +c445072c3362fa3fb2cc481706d5b1b96b368798 B Kirby's Nuts (Nuts & Milk Hack) [o1] NES +67c1d833caa09444555711fdb32e7f16dfe61389 T Kirby's Nuts (Nuts & Milk Hack) [T+Rus_Cool-Spot] NES +d875bd8977d6486ac3c5c874d9d4f2cdcdc0841a T Kirby's Nuts by Kidwhatever (Nuts & Milk Hack) [T+Rus_Multisoft] NES +046d3a72942639a1a0c8a6eaa8c0a049051ea113 H Kirby's Nuts by Kidwhatever (Nuts & Milk Hack) NES 576b13815dbcfdb621b2654ab14b30a8080a8a4a H Kiri5 Star (SMB1 Hack) [a1] NES 58f4d00498313f5179fd5749e9c15efeef0b5910 H Kiri5 Star (SMB1 Hack) NES 226da664994cee80f3af52fe98f77b92df291766 H Kiri7 (SMB1 Hack) NES @@ -10182,7 +10182,7 @@ b338354bf584e2abccb625d88f543d27d5d9e542 H Kunio-kun no Nekketsu Soccer League - 340c0dc4d29883152e31a79aa5477b851dbdfeb2 H Kunio-kun no Nekketsu Soccer League - Striker (Hack) NES d39199f9c1550add08c12d5a13bbb59fcb6b3b2c H Kunio-kun no Nekketsu Soccer League - Super Maltreatment Edition (Hack) NES 4f78b071b96bf1b2c5e8098bf1529b1b333e246d H Kunio-kun no Nekketsu Soccer League - Super Striker (Hack) NES -f407cdd3308b4dd5ab48c74db33a8879e880f588 H Kunio-kun no Nekketsu Soccer League - To Change Skill & Hit Keeper (Hack) NES +f407cdd3308b4dd5ab48c74db33a8879e880f588 H Kunio-kun no Nekketsu Soccer League - To Change Skill & Hit Keeper (Hack) NES 3ca8ef95f367374000aa14223b7c0fd746a7f584 H Kunio-kun no Nekketsu Soccer League - TT (Hack) NES d64b96f6171876119a5af8bf0ead7e879ed8770d H Kunio-kun no Nekketsu Soccer League - Twin Shot by altinfener38 (Hack) NES e45275579fd75471bd6c2f8ce8980c7bd6b907ab H Kunio-kun no Nekketsu Soccer League by oktucu (110806) (Hack) NES @@ -10272,7 +10272,7 @@ e6226a1bdf7c304438f4444df242f5ab5b4a1f67 B Lagrange Point (J) [b1][o1] NES ab6818c5e75516264d3a285ecbec5a4884683612 B Lagrange Point (J) [b1][t1] NES 65557407307ca0313775510120b9e8b09f08e860 C Lagrange Point (J) [t1] NES cc44c4f1b8f8075e428389cde3b2c3ee583942e2 U Lair's Secret (Unl) NES -bce119365efcbcab4bc03f7dc4f6dae5514ac172 H Lam by darkdata (Milk & Nuts Hack) NES +bce119365efcbcab4bc03f7dc4f6dae5514ac172 H Lam by darkdata (Milk & Nuts Hack) NES 6a0005e1bfd16f99cc79766e543dc624248d6cf8 U LAN Master bu shiru (PD) (2011-06-10) NES 81763892417f2b2a89bfbac83b240ef5da322369 U LAN Master by shiru (PD) NES 62fac07016d534852c9da61c060e8bd19ba5e6f0 G Laser Invasion (U) [!] NES @@ -10339,7 +10339,7 @@ a86fb55799df29a70132e35ba305dad820068022 T Legend of Kage, The (U) [T+Rus_Shedev f2755fe982e51a7f31a237aee03b91d364795629 H Legend of Prince Valiant, The (E) [hM04] NES 773fefddc1a15ab045bc0e23151bf5d157e98bc5 C Legend of Prince Valiant, The (E) [t1] NES 60bf4889b5b99b7441b91b4c9f4e8820bc4d0c7a U Legend of Robin Hood, The (U) (Prototype) NES -961e2890880a2185fd21ca25b6874c5d6ffcc6b8 H Legend of Sean, The (Master Chu & The Drunkard Hu Hack) NES +961e2890880a2185fd21ca25b6874c5d6ffcc6b8 H Legend of Sean, The (Master Chu & The Drunkard Hu Hack) NES ee3a7feabc22fa45256416681496626493b7a2e9 H Legend of Super Pikachu Bros 3 (SMB3 Hack) NES 2cc6cc45fa63f9354acd4f6b9d9deadfa88900c8 U Legend of the Black Shawarma Medley (Music Demo) by Snowbro (PD) NES 1d195beeb4b3edbf8d1d53df8f7b756ad77890cf H Legend of the Blob Bros. 2 V1.0 by BMF54123 (SMB2 Hack) NES @@ -10700,7 +10700,7 @@ e1308b338c2b75bb5674547312d445cadcafa40c U Luan Shi San Guo (Ch) NES 7ed2f88638929b7e81a93510e19560ce0f4decf5 H Luigi and the Christmas Quest (Final) (SMB1 Hack) NES f880b618845829fe41d313d7386bea4545a97246 H Luigi and the Christmas Quest (SMB1 Hack) [a1] NES fcd6b2a1d32aca07ff8a1caa4a7e7ab09f8f243d H Luigi and the Christmas Quest (SMB1 Hack) NES -8fc67b2f8613c711def655519a390b41f5614ce0 H Luigi and the New Quest (Level & Graphics Patch) (SMB1 Hack) NES +8fc67b2f8613c711def655519a390b41f5614ce0 H Luigi and the New Quest (Level & Graphics Patch) (SMB1 Hack) NES 76515328e14754247618e9aed6cac87a49a2e494 H Luigi and the New Quest (New Level Patch) (SMB1 Hack) NES 56bd3d597f4024ed558e34c5fa1e7dbee4c7f63d H Luigi and the New Quest (Partial Levels Patch) (SMB1 Hack) NES b38c3b1d8bddf46e382ebfc8b13248214ba081a8 H Luigi and the New Quest (SMB1 Hack) [a1] NES @@ -10751,10 +10751,10 @@ c8e128a54bf9aba9d9dd0f28a45f34e443ff0cdc T Lupin Sansei - Pandora no Isan (J) [T 1d1f04e0bed7113be71d78eedc4cbd2a92bad32e C Lupin Sansei - Pandora no Isan (J) [t1] NES 18d0afcb194f5a7eca06efac29473fa22a499014 C Lupin Sansei - Pandora no Isan (J) [t2] NES 96edd908d86043c856d189c3db7a95998771aae6 H M Mario (SMB1 Hack) NES -e0064546070f426da5fdc9d05a1affa74d955882 U M&M Heroes (Ch) (Wxn) NES -7bc4d849ea854df4ec39bc632d38ab888cfa30a0 H M&M Heroes (Unl) [f1] NES -f63e163ed15f5bd977c0132679cb5f5a7f23f45a T M&M Heroes (Unl) [T+Rus_FedX IV] NES -a7ab98cadb51b86837fc9a71e72619c0d27a9a9d U M&M Heroes (Unl) NES +e0064546070f426da5fdc9d05a1affa74d955882 U M&M Heroes (Ch) (Wxn) NES +7bc4d849ea854df4ec39bc632d38ab888cfa30a0 H M&M Heroes (Unl) [f1] NES +f63e163ed15f5bd977c0132679cb5f5a7f23f45a T M&M Heroes (Unl) [T+Rus_FedX IV] NES +a7ab98cadb51b86837fc9a71e72619c0d27a9a9d U M&M Heroes (Unl) NES 9f026896275121d4cfb8ac34bd9e0cba96372508 U M-Day (Ch) (Wxn) NES afac4a56c2cf511e3cf983e16890adbf2f896bfd G M.C Kids (U) (Prototype) [!] NES 0fabf7ee8ed5bdc855daa5b16c49efc4b94497ba G M.C Kids (U) [!] NES @@ -10778,7 +10778,7 @@ deade5ae2b4f0948763b7e77b6561dfed5fdc8ff B M.U.S.C.L.E. (U) [o3] NES 0579081f3d7c4b5b756351bff82fd42f9e1eb54e B M.U.S.C.L.E. (U) [o4] NES 0414719a4ad314926d8d9b9fc8461d7303501ba0 B M.U.S.C.L.E. (U) [o5] NES 4d7786106e6e550d993f20319428f27cae6ba998 U M82 Game Selectable Working Product Display (E) NES -a58de11d0f58995d642fc3d556b3b554c3cb6493 U Ma Bu Mi Zhen & Qu Wei Cheng Yu Wu (Ch) NES +a58de11d0f58995d642fc3d556b3b554c3cb6493 U Ma Bu Mi Zhen & Qu Wei Cheng Yu Wu (Ch) NES 6b1d4795428ca175d83abcf06b4d6def3d7b9e11 B Ma Li 12 (Yoshi no Cookie) [p1] NES 7c9daf77487a885367666c4f9dbc7714b0ce1439 B Ma Li 12 (Yoshi no Cookie) [p1][o1] NES 39fcdb90ab5fe745eeebef591127dae761b02e81 U Mac OS Demo (Large) by Chris Covell (PD) NES @@ -10994,9 +10994,9 @@ b8eabd4dfe1710ea8d74a990a2701ccda27d07d2 B Making Love (Battle City Hack) [o1] N 0792c8302caf2641f3644146500d669bd21ef0d1 T Making Love (Battle City Hack) [T+Rus_Cool-Spot][a1] NES 6efde8835d2f8c34875e24de8cdc353452d9f9b5 H Making Love (Battle City Hack) NES e5c0edeec0c4c45e4cfcf0ff0d48304ee90c215c H Male Lover Eon Man (Time Diver Eon Man Hack) NES -f76c5b3598b7869e57f438b861b6a198ef59a80e B Maluex (Nuts & Milk Hack) [o1] NES -544a5ed93d8ec8c34822f827126961377087e58d B Maluex (Nuts & Milk Hack) [o2] NES -4f26475c03365c125f9f9590bced09e3158f6a9a H Maluex (Nuts & Milk Hack) NES +f76c5b3598b7869e57f438b861b6a198ef59a80e B Maluex (Nuts & Milk Hack) [o1] NES +544a5ed93d8ec8c34822f827126961377087e58d B Maluex (Nuts & Milk Hack) [o2] NES +4f26475c03365c125f9f9590bced09e3158f6a9a H Maluex (Nuts & Milk Hack) NES 76edf6482110b1dcfebb2c57e00993ad80cc7878 U Mandelbrot (PD) NES 3764bbd627f1a6b5790712019e06efa3a011d4e4 U Manhole by KZ-S (PD) [a1] NES b01b5adc58b6b81cae093e3ad43ad6fc4065237a U Manhole by KZ-S (PD) NES @@ -11072,8 +11072,8 @@ fca0c2983073ae17f1034077b0769e64dc33e179 B Marble Madness (U) [o1] NES 14565b90be871acba746be154cdfc254c9c79193 H Maria's Golf (Golf Hack) NES 038103f080bd837c11b8e82d03a57909006e2d4f H Marilunker (Spelunker Hack) NES a86de28534e8d6b80a4e193a34073a6a58c30626 H Marilunker by Tsurumidou (Spelunker Hack) NES -9ca35258a3637b43c45ef7f17a75c7b32ea969a8 G Mario & Yoshi (E) [!] NES -5f69d6fe6299cd09e359f0db360495a40f8359fa H Mario + Toad (Nuts & Milk Hack) NES +9ca35258a3637b43c45ef7f17a75c7b32ea969a8 G Mario & Yoshi (E) [!] NES +5f69d6fe6299cd09e359f0db360495a40f8359fa H Mario + Toad (Nuts & Milk Hack) NES 0c2494b25620c81cf4a514ed9659429e59b4c6ef H Mario 1337 (SMB1 Hack) NES ff70fcbdf643b0c71cb2f8c170f315a4af755531 B Mario 16 (1993) (Unl) [b1] NES 3a6f026690bbf5f13b1066e5b100f783a6928c8b B Mario 16 (1993) (Unl) [o1] NES @@ -11096,8 +11096,8 @@ e972a5ee5b0f8f68a08106bce39ae1c82d34e1d2 H Mario a la Caza del Tesoro V1.0 Spani 69b006cd318393e610e77ee22fd29ee4f10f0fda H Mario Adventure Island (Takahashi Meijin no Bouken Shima Hack) NES 34edbd53301273a8a31f1fade92003bf197d2926 T Mario and Goombas by Cool-Spot (Mappy Hack) [T+Rus_Cool-Spot] NES bc2eafe7d8c3b63595ecb75f19760e4ab5634e56 H Mario and Goombas by Cool-Spot (Mappy Hack) NES -fdd6a65ea316ec531c0f96804bd02941add01b44 T Mario and Luigi (Nuts & Milk Hack) [T+Rus_Cool-Spot] NES -01b81f8e7ba17db3298822035435cd0c1ab87de6 H Mario and Luigi (Nuts & Milk Hack) NES +fdd6a65ea316ec531c0f96804bd02941add01b44 T Mario and Luigi (Nuts & Milk Hack) [T+Rus_Cool-Spot] NES +01b81f8e7ba17db3298822035435cd0c1ab87de6 H Mario and Luigi (Nuts & Milk Hack) NES e9bd0d304d265fa5a25c47cfed2d847605d3de76 H Mario Bomb Jack (Mighty Bomb Jack Hack) NES ef30e7d464a79dd4482b0da82c41504f46e477d2 H Mario Bros in the Clouds (SMB1 Hack) NES 1bf3152946f6b697dd80aa9ba5b16bddab8ac0c2 G Mario Bros. (E) (PRG1) [!] NES @@ -11235,7 +11235,7 @@ c90404b3c08265dfbc0677e7eb8a91eda8cf9a19 H Mario Runner by Y.Project (Championsh 441f1355cc8d159de0f82bd5471b5e25efac9448 H Mario Satanic Freak Bros 2 (SMB2 Hack) NES 35cc22c2861cb67e3feee8bb10bcc22bf1c611e3 H Mario Spy vs Spy (Spy vs Spy Hack) NES 38550a3ca3fc7f3263b26758ed37a9e3ba7e87fe B Mario Tails (SMB1 Hack) [b1] NES -fcd488c8f40e2956b1030d2b0e9ca4565694a5be H Mario Tank & Sub (SMB1 Hack) NES +fcd488c8f40e2956b1030d2b0e9ca4565694a5be H Mario Tank & Sub (SMB1 Hack) NES 764d9f6c2d2f9130c8de46fe9a0a408d3e96b13e H Mario Tokes A Doobie (SMB1 Hack) NES 2b5135b41e78505abf5489a2ab52faefee4a65fa H Mario Tower (SMB1 Hack) NES 48b8f691f3d73d8d2aa35c2f1e9c869c97d8b97b H Mario vs Monkey by Hax0r Kyo (Mario Bros Hack) NES @@ -11310,11 +11310,11 @@ a2b6008b8c2a65cd6e2312614505c463e1f4615f B Mashou (J) [hM02][b1] NES 1f1b2f43de9c29e41a9514a6019978529a9bfac8 C Mashou (J) [t1] NES 1d9757ab82c6e1095bc88765e3ff012d0ad7375a U Masmix v0.06, The by Wojciech Andralojc (PD) NES 2a493dcfeeb0d7f928cb8862b8e8be295ed3c685 U Master Chess (Ch) (Wxn) NES -62918362f30e4840ed4e7719339520cfefc92a2a G Master Chu & The Drunkard Hu (Color Dreams) [!] NES -569065844ea9f5c29fb80becef94190358dc9fe3 B Master Chu & The Drunkard Hu (Color Dreams) [o1] NES -de04b54e6bb4bcfc3cb8a40669cf52499c51ff89 U Master Chu & The Drunkard Hu (Joy Van) NES -9c98deede6eaa1c352d75c9cd8d1ca67ba16f77a G Master Chu & The Drunkard Hu (Sachen) [!] NES -08a2fbefe2e5543b9ef3e8342009456d67500884 G Master Chu & The Drunkard Hu (Sachen) [U][!].unf NES +62918362f30e4840ed4e7719339520cfefc92a2a G Master Chu & The Drunkard Hu (Color Dreams) [!] NES +569065844ea9f5c29fb80becef94190358dc9fe3 B Master Chu & The Drunkard Hu (Color Dreams) [o1] NES +de04b54e6bb4bcfc3cb8a40669cf52499c51ff89 U Master Chu & The Drunkard Hu (Joy Van) NES +9c98deede6eaa1c352d75c9cd8d1ca67ba16f77a G Master Chu & The Drunkard Hu (Sachen) [!] NES +08a2fbefe2e5543b9ef3e8342009456d67500884 G Master Chu & The Drunkard Hu (Sachen) [U][!].unf NES 00e58c05c1ddc011418b762e203283ba61510549 U Master Fighter 3 (Unl) [a1] NES 0aeb922bd4bfe12fde656729e0ee0058276b7a95 U Master Fighter 3 (Unl) NES 89ec66a8c33722a5bd1120bc69393b237e72de03 G Master Fighter II (Unl) (UT1374 PCB) [!] NES @@ -11785,11 +11785,11 @@ b64e5757c43c4270c7ec4656823b3dd7f506a31c U Metal Max (J) (VC) NES 9a9401b7e009d560978053035ba854484258453f H Metal Max - Shining Strengthened Edition (Hack) NES f0ded676241e773791a3209281b6290ca6c2a115 H Metal Max by ZTOUYIA (090214) (Hack) NES 7af64b80c8857dba498a520298ab438b92a27a0d H Metal Max Night Edition by MISAKA KEN (Hack) NES -491f6a151cb43c794f1e0984e3645e946b5f5600 G Metal Mech - Man & Machine (U) [!] NES -c46b547aaa2295d6e6daa978b971a47a1ea12906 B Metal Mech - Man & Machine (U) [b1] NES -b5806e8504f79d790fc67bc31e6d2ccca2990011 B Metal Mech - Man & Machine (U) [o1] NES -3e06e7b5db6da401ec312ab490b7069e8624a62f B Metal Mech - Man & Machine (U) [o2] NES -079f970b54f70e2144b5c9f197331f08a46b9aa2 B Metal Mech - Man & Machine (U) [o3] NES +491f6a151cb43c794f1e0984e3645e946b5f5600 G Metal Mech - Man & Machine (U) [!] NES +c46b547aaa2295d6e6daa978b971a47a1ea12906 B Metal Mech - Man & Machine (U) [b1] NES +b5806e8504f79d790fc67bc31e6d2ccca2990011 B Metal Mech - Man & Machine (U) [o1] NES +3e06e7b5db6da401ec312ab490b7069e8624a62f B Metal Mech - Man & Machine (U) [o2] NES +079f970b54f70e2144b5c9f197331f08a46b9aa2 B Metal Mech - Man & Machine (U) [o3] NES 5aa98fc076e38002f08bfb3130cca0fbbe03058f U Metal Slader Glory (J) (VC) NES a62908e4873cf88f4a3c571c2b06d3d7c51e7450 G Metal Slader Glory (J) [!] NES c62cc944e7cfac05ac9b99170dadfe1d8b5a3965 B Metal Slader Glory (J) [b1] NES @@ -11828,7 +11828,7 @@ b0e1e0cd36b40aab2f9fecf057098abdad718cd3 T Metroid (U) [T+Fre_Terminus] NES 6170e1db74b46a77ad701c0ec87bd129adccd037 T Metroid (U) [T+Spa050_PaladinKnights] NES 574117fa7c66279a1373e25d792a40f45286fce2 T Metroid (U) [T+Spa100b_ereza] NES 0d589c18ee0e59b7c7d17d7b6a698dcd968eb56e T Metroid (U) [T+Swe1.0_TheTranslator] NES -180d37be77a6bcbb5a572364ab214defe84ca0b8 H Metroid - Unused GFX Tiles & 99 Energy Units by Grond (Metroid Hack) NES +180d37be77a6bcbb5a572364ab214defe84ca0b8 H Metroid - Unused GFX Tiles & 99 Energy Units by Grond (Metroid Hack) NES e7980c189177ab863b254a2a7a9683440557e3c0 H Metroid - Wart's Invasion (Metroid Hack) NES fe72d83deeb11b4579f7b07fb2e231137af396f0 H Metroid - Zebian Illusion (Metroid Hack) NES 0be24e45e1ef766d67701aae299e1315c66e0979 H Metroid 2000 (Metroid Hack) NES @@ -11994,7 +11994,7 @@ b47d159f82fe0ec2b458ead44337255f387f5179 C Mighty Final Fight (U) [t1] NES 855f819f6745c64532be84cb771dcda43bed5abc C Mighty Final Fight (U) [t4] NES c54abb5f91ff22e164510adb94be037661ffe0ee C Mighty Final Fight (U) [t5] NES b63f9117a0d864ecf028c79cf0b759d02ca12dc7 H Mighty Final Fight - Rock (Hack) NES -da6b671f63e0884a06edc4ffab18e80ef3815e5c H Mighty Final Fight - Skill & Enemies Changed (Hack) NES +da6b671f63e0884a06edc4ffab18e80ef3815e5c H Mighty Final Fight - Skill & Enemies Changed (Hack) NES 706a4d92a6f892f50768216222deb0943cf1c8fb H Mikamari 1 (SMB1 Hack) NES 291ecdfa63678f47489874c3b68bdbfe47a8651c H Mikamari 2 (SMB1 Hack) NES 4eaa8f7c55b779ffd5310062d0f6012b77fcb0d2 H Mikamari 3 (SMB1 Hack) NES @@ -12469,7 +12469,7 @@ e9ebfd1a44a8b62ab774e421770f0caee34c34d4 U Mr Brownstone by Snowbro (PD) NES 363c095b7d6b0b035365d55bbcd822c911adecf2 H Mr. Happyface (Ms. Pac-Man Hack) [a1] NES 141991d10b5c2424d44bc2e8dfd62cd528e710ae H Mr. Happyface (Ms. Pac-Man Hack) NES b5bf9531fe5900dc946e92114f7983088bfe232f H Mr. Men (Dig Dug II Hack) NES -141f8ddc64afb5f28a51b7265268ef76c1f11f4a H Mr. Pac-Man by Dave Augusta & Googie (v1.0) (Ms. Pac-Man Hack) NES +141f8ddc64afb5f28a51b7265268ef76c1f11f4a H Mr. Pac-Man by Dave Augusta & Googie (v1.0) (Ms. Pac-Man Hack) NES 7893f168fd56adad3546b5db267b286ff659a349 H Mr. Sandman! by The Eadernator (SMB1 Hack) NES 697d523d2db7f1ebdcf91bf501422c6a033fbd44 B Mr. Saturn's Dragon Quest v1.21 (Dragon Warrior PRG0 Hack) [o1] NES 93c5f1cb016f46ba5e1033997a8cd8bfdfa43e89 H Mr. Saturn's Dragon Quest v1.21 (Dragon Warrior PRG0 Hack) NES @@ -12682,7 +12682,7 @@ cecd61c0a2321d44500bee546e04e382259b93f7 T Nekketsu! Street Basket - Ganbare Dun 13e673bd83bff5923729e259c42fed0995d989be T Nekketsu! Street Basket - Ganbare Dunk Heroes (J) [T-Eng.50] NES 7e129fa870424cbc23f274f373ae0e389c7d127f U Nekketsu! Street Basket - Ganbare Dunk Heroes (J) NES ffd1705e5919b87d5a26d49a8f48d35d57497796 H Nekketsu! Street Basket - Ganbare Dunk Heroes - Spirit Edition (Hack) NES -f5f295588ef93bb1ac44d16df184ac67ab678167 H Nekketsu! Street Basket - Ganbare Dunk Heroes by AXI&AHE (v0.9) (Hack) NES +f5f295588ef93bb1ac44d16df184ac67ab678167 H Nekketsu! Street Basket - Ganbare Dunk Heroes by AXI&AHE (v0.9) (Hack) NES 6a50ac4d84116cd39b57531a44f6509ef151829a H Nekketsu! Street Basket - Ganbare Dunk Heroes by D.S.ghtMaster+KRIZAL (Hack) NES fbfa57623728465fd3c2582c8fc5930430502da9 H Nekketsu! Street Basket - Ganbare Dunk Heroes by PU (100426) (Hack) NES fb0a992bc148de44d82277b5cf4e3aba40ad6e38 G Nemo - Pajama Hero (J) [!] NES @@ -13233,20 +13233,20 @@ ca1f630cfcf80e817e6e395b5bd52497f1604e63 B Nobunaga's Ambition 2 (U) [o1] NES a8fd3c5c20777b94d1204145104f72a93f83d225 U Nomolos - Storming the Catsle Demo (PD) NES 9c5d4c2654998e874b3eda5e3f0af8b5e353575e U Nong Chang Xiao Jing Ling (NJ025) (Ch) NES 4e48b65b60f94a054b865f9e1cb3fd47cf9b4949 H Normal (Lolo1 Hack) NES -766a602e239895343819c2980ecd296da14613e1 G North & South (E) [!] NES -3c1f1f3ba8ce62899c2153116c3bd73ae058e554 T North & South (E) [T+FreFinal_Generation IX] NES -023b6b9ac517453541324e3cca279588b94d5016 G North & South (J) [!] NES -2a7f6052219e8ed69f307b8eb3d724fdded74ae1 G North & South (U) [!] NES -da1d5fb3d856cee918a57e510a93d32e33af2843 B North & South (U) [b1] NES -f2f1257a99f9fe3788851e62577798b7cb400cfb B North & South (U) [b1][o1] NES -58346ef19200fce9be100cc21284f31b6a1dad61 B North & South (U) [b1][o2] NES -2342eec6311f597ea24bf418a9ff26030b5edd43 B North & South (U) [b2] NES -7df0cc39d279659e4df9319aa74e24152a4db884 B North & South (U) [b3] NES -2a08ba115a2ee1b6a7f07829bde5049dde11ec6c B North & South (U) [b4] NES -7dee9233fc66d18c92ac477965ba3f15892bda78 B North & South (U) [b5] NES -f7ab568fd4b65dfcc89aeba81e7b127740967700 B North & South (U) [b6] NES -1a38e957fc2953c987ea4f129f17edc6adc133f6 B North & South (U) [b7] NES -53cbaf5517f6aba9a5eeba311ddfa03680898ac0 T North & South (U) [T+Swe1.0_TheTranslator] NES +766a602e239895343819c2980ecd296da14613e1 G North & South (E) [!] NES +3c1f1f3ba8ce62899c2153116c3bd73ae058e554 T North & South (E) [T+FreFinal_Generation IX] NES +023b6b9ac517453541324e3cca279588b94d5016 G North & South (J) [!] NES +2a7f6052219e8ed69f307b8eb3d724fdded74ae1 G North & South (U) [!] NES +da1d5fb3d856cee918a57e510a93d32e33af2843 B North & South (U) [b1] NES +f2f1257a99f9fe3788851e62577798b7cb400cfb B North & South (U) [b1][o1] NES +58346ef19200fce9be100cc21284f31b6a1dad61 B North & South (U) [b1][o2] NES +2342eec6311f597ea24bf418a9ff26030b5edd43 B North & South (U) [b2] NES +7df0cc39d279659e4df9319aa74e24152a4db884 B North & South (U) [b3] NES +2a08ba115a2ee1b6a7f07829bde5049dde11ec6c B North & South (U) [b4] NES +7dee9233fc66d18c92ac477965ba3f15892bda78 B North & South (U) [b5] NES +f7ab568fd4b65dfcc89aeba81e7b127740967700 B North & South (U) [b6] NES +1a38e957fc2953c987ea4f129f17edc6adc133f6 B North & South (U) [b7] NES +53cbaf5517f6aba9a5eeba311ddfa03680898ac0 T North & South (U) [T+Swe1.0_TheTranslator] NES f25301c5586eaf0bd53f95cbf264a0e4207731e2 U Nothing Demo (PD) NES 7b3ff58b8684313b775fcffcdd24347060be5d38 G Novel Diamond 999999-in-1 [U][p1][!].unf NES 077c8e387d2c605e4a1fb3b7a3b8e743feaffc64 U NROM Template 0.01 by Damian Yerrick (2011) (PD) NES @@ -13278,28 +13278,28 @@ f67c0b6e6386ab3672759b7e1edbca7cfeecf4d5 H Nude Punch Out (Punch-Out!! Hack) NES 9072be68ee2eaa942c474a7eba228640d7693ba9 U Nuevo Tipo de Computadora (Game Star) NES 44b74d6a242b6446fa5a937884fb5a01da15a1cb U Nullsleep - Kuribos Requiem (PD) NES 15bb5ad31ef26025bb744e53e238f9880c90b9bd U NumberGuess by Vincent van der Leun (PD) NES -cca97fba72ca56809dd216618f5962eb6ea2f1aa G Nuts & Milk (J) [!] NES -38ad30d95aaa4376b282f98efd89df92846bb940 B Nuts & Milk (J) [o1] NES -50ce8cec6085dd639292ae274bb5e913c9e1fc24 B Nuts & Milk (J) [o2] NES -73b1aeb8c794ae7c1f662411c34d7ff11b362369 B Nuts & Milk (J) [p1] NES -c01df7f32a0724e2258786a114f948e5d5ec7963 B Nuts & Milk (J) [p1][o1] NES -e5a0ad38498935f360997c0925b539014618aa8a T Nuts & Milk (J) [T+Bra_JM-trad] NES -8a5022c666bab63216563f76ca202125af6cb0ba T Nuts & Milk (J) [T+Chi_MS emumax] NES -f8c39e1b575a1ff6775329bbca4b723059b42ed0 T Nuts & Milk (J) [T+FreFinal_ks151] NES -7b84df69272bc4e29327c037ffd2d3d129df39be T Nuts & Milk (J) [T+Rus_CARI] NES -4a7726cbad59730bf05715e6549ddd0616637a1b T Nuts & Milk (J) [T+Rus_Cool-Spot] NES -4929bc380983b6b5cd0602c45b1964381e8ac170 T Nuts & Milk (J) [T+Rus_Mario Soft] NES -bcff20a94a6d026ac3d061e90599a1c881ef0a1c T Nuts & Milk (J) [T+Rus_Multisoft] NES -5a93e79325dd52cceb312ad84ced5b0c055cd9b6 T Nuts & Milk (J) [T-Chi_MS emumax] NES -5cccfd9cd3b6ab918003e46c8faf210255d5736a T Nuts & Milk (J) [T-Chi_MS emumax][a1] NES -b3d5d4f11b7d68d82c8ca5240f8239f930b1c688 T Nuts & Milk (J) [T-Chi_MS emumax][a2] NES -e878b5c62b83cc13acf466480bc037c5d99b77e7 T Nuts & Milk (J) [t1][T+Rus_Cool-Spot] NES -9a229b126f0573659448bba903a13048dd21c99a C Nuts & Milk (J) [t2] (9 Lives) NES -d8289a152855628af82aafefe5e3e9ed765d6523 C Nuts & Milk (J) [t3] (50 Lives) NES -573df023388af04977b8ffd787987e66ea16efc6 C Nuts & Milk (J) [t4] (100 Lives) NES -0b00c2eef9ed256599f9584b0ba366f838065fec B Nuts & Milk by PE (Hack) [o1] NES -bcff4b0d1d7dfea58018434e6a9aca29568a7844 T Nuts & Milk by PE (Hack) [T+Rus_Cool-Spot] NES -8cdde663a326c50ab9d8cb434628dcd5490f3797 H Nuts & Milk by PE (Hack) NES +cca97fba72ca56809dd216618f5962eb6ea2f1aa G Nuts & Milk (J) [!] NES +38ad30d95aaa4376b282f98efd89df92846bb940 B Nuts & Milk (J) [o1] NES +50ce8cec6085dd639292ae274bb5e913c9e1fc24 B Nuts & Milk (J) [o2] NES +73b1aeb8c794ae7c1f662411c34d7ff11b362369 B Nuts & Milk (J) [p1] NES +c01df7f32a0724e2258786a114f948e5d5ec7963 B Nuts & Milk (J) [p1][o1] NES +e5a0ad38498935f360997c0925b539014618aa8a T Nuts & Milk (J) [T+Bra_JM-trad] NES +8a5022c666bab63216563f76ca202125af6cb0ba T Nuts & Milk (J) [T+Chi_MS emumax] NES +f8c39e1b575a1ff6775329bbca4b723059b42ed0 T Nuts & Milk (J) [T+FreFinal_ks151] NES +7b84df69272bc4e29327c037ffd2d3d129df39be T Nuts & Milk (J) [T+Rus_CARI] NES +4a7726cbad59730bf05715e6549ddd0616637a1b T Nuts & Milk (J) [T+Rus_Cool-Spot] NES +4929bc380983b6b5cd0602c45b1964381e8ac170 T Nuts & Milk (J) [T+Rus_Mario Soft] NES +bcff20a94a6d026ac3d061e90599a1c881ef0a1c T Nuts & Milk (J) [T+Rus_Multisoft] NES +5a93e79325dd52cceb312ad84ced5b0c055cd9b6 T Nuts & Milk (J) [T-Chi_MS emumax] NES +5cccfd9cd3b6ab918003e46c8faf210255d5736a T Nuts & Milk (J) [T-Chi_MS emumax][a1] NES +b3d5d4f11b7d68d82c8ca5240f8239f930b1c688 T Nuts & Milk (J) [T-Chi_MS emumax][a2] NES +e878b5c62b83cc13acf466480bc037c5d99b77e7 T Nuts & Milk (J) [t1][T+Rus_Cool-Spot] NES +9a229b126f0573659448bba903a13048dd21c99a C Nuts & Milk (J) [t2] (9 Lives) NES +d8289a152855628af82aafefe5e3e9ed765d6523 C Nuts & Milk (J) [t3] (50 Lives) NES +573df023388af04977b8ffd787987e66ea16efc6 C Nuts & Milk (J) [t4] (100 Lives) NES +0b00c2eef9ed256599f9584b0ba366f838065fec B Nuts & Milk by PE (Hack) [o1] NES +bcff4b0d1d7dfea58018434e6a9aca29568a7844 T Nuts & Milk by PE (Hack) [T+Rus_Cool-Spot] NES +8cdde663a326c50ab9d8cb434628dcd5490f3797 H Nuts & Milk by PE (Hack) NES 4381f42f7b69e00e4d44ba643331f0b8d4d6af12 U Nyancat V1 by DerekB (PD) NES 486b47656c93db07fae5a8749278414531efb6ce U Nyancat V2 by DerekB (PD) NES ab7e39224ff304c4619329c026cf9c079002921e H Oaty Invaders by Pope Hentai (Space Invaders Hack) NES @@ -14127,14 +14127,14 @@ fad06695ceb4520547470a3df1a7b5c561d056ca U Pattern Table Pixel-Flickering Demo F f052c4486726c3abac420bd6f411fbecd551d4ab H PCGC Tank Chinese (Battle City Hack) NES c1df3c306ed45974b45c4832f72e93382f38a0e8 U PCM Demo (PD) [a1] NES 72f4b89acfb66e7abeafc894507b8c8b8f3d4225 U PCM Demo (PD) NES -9d75e5dcaa20e302b0820331d0995d1cb9b4c50d H Peach & Daisy - The Royal Quest (Alpha) (SMB1 Hack) [a1] NES -83e35177b4c0cbcb92d6ab975a2d876964eba303 H Peach & Daisy - The Royal Quest (Alpha) (SMB1 Hack) NES -84701b4567b09170bdb5dd7eb0a0fd54afa64a50 H Peach & Daisy and The Royal Games (SMB1 Hack) NES -8559c0dc7d22d61b77306d0f270e0bb3e27ca620 H Peach & Daisy and The Royal Games with Hacked Music (SMB1 Hack) NES -2488999a27d64decba8545ad41b6884cf8b02fac H Peach & Daisy in The Ultimate Quest (SMB3 PRG0 Hack) NES -91ffa269fa5ffb549e9a12cc14bf7574b95b2226 H Peach & Daisy in The Ultimate Quest (SMB3 PRG1 Hack) [a1] NES -6ac4ce8f754326ce7d6e1bc33f90528eeebd82cd H Peach & Daisy in The Ultimate Quest (SMB3 PRG1 Hack) NES -1218041ff94ed80d91b5b83f760bd78645791233 H Peach & Daisy in The Ultimate Quest V2b (SMB3 PRG1 Hack) NES +9d75e5dcaa20e302b0820331d0995d1cb9b4c50d H Peach & Daisy - The Royal Quest (Alpha) (SMB1 Hack) [a1] NES +83e35177b4c0cbcb92d6ab975a2d876964eba303 H Peach & Daisy - The Royal Quest (Alpha) (SMB1 Hack) NES +84701b4567b09170bdb5dd7eb0a0fd54afa64a50 H Peach & Daisy and The Royal Games (SMB1 Hack) NES +8559c0dc7d22d61b77306d0f270e0bb3e27ca620 H Peach & Daisy and The Royal Games with Hacked Music (SMB1 Hack) NES +2488999a27d64decba8545ad41b6884cf8b02fac H Peach & Daisy in The Ultimate Quest (SMB3 PRG0 Hack) NES +91ffa269fa5ffb549e9a12cc14bf7574b95b2226 H Peach & Daisy in The Ultimate Quest (SMB3 PRG1 Hack) [a1] NES +6ac4ce8f754326ce7d6e1bc33f90528eeebd82cd H Peach & Daisy in The Ultimate Quest (SMB3 PRG1 Hack) NES +1218041ff94ed80d91b5b83f760bd78645791233 H Peach & Daisy in The Ultimate Quest V2b (SMB3 PRG1 Hack) NES a3714d4067896c3eafdc820fb75d72b2e9a44600 H Peach's Nightmare - No Mercy (Beta) (SMB1 Hack) NES 9485ea0fca9c569c50b12c1bbdaf58d188ebca3f H Peach's Nightmare - No Mercy (SMB1 Hack) NES c2f75c845b3ed54285153bf66cfa649ff9525931 H Peachy Mario by Mana (SMB1 Hack) NES @@ -14151,12 +14151,12 @@ f8d094394bb036ffb0d7f4c6572c876d481eaaec U Pegasus 5-in-1 (Golden Five) (Unl) NE 8bb6485cafa110f01e60da35ce5d537b886c5cc3 U Pegs by Sly Dog Studios (PD) NES 4d3d00d774ee6153d55878112c3aeeb48189b819 U Penalty Kick (Ch) (Wxn) NES cee202c3fbcc89608d6e333bdc290bd6224cc53e H Pencilvania (CV Hack) NES -f828bba945c4291586c9843a7bcff4400125cc88 U Penguin & Seal, The (Dung Dung No 1) (Sachen) (Ch) NES -eac74d9de2001baa8fa76e740f9866d612612e33 G Penguin & Seal, The (Sachen-HES) [!] NES -dab87920067b13c1252b47673ff078c882651ed0 B Penguin & Seal, The (Sachen-HES) [o1] NES -41994a3c8f15bfbba09fe48ce2f98b9691fbfd7b G Penguin & Seal, The (Sachen-HES) [U][!].unf NES +f828bba945c4291586c9843a7bcff4400125cc88 U Penguin & Seal, The (Dung Dung No 1) (Sachen) (Ch) NES +eac74d9de2001baa8fa76e740f9866d612612e33 G Penguin & Seal, The (Sachen-HES) [!] NES +dab87920067b13c1252b47673ff078c882651ed0 B Penguin & Seal, The (Sachen-HES) [o1] NES +41994a3c8f15bfbba09fe48ce2f98b9691fbfd7b G Penguin & Seal, The (Sachen-HES) [U][!].unf NES 74a1ae73ec743bc20f9959c3f4434b8c2a9b3cd5 U Penguin (Ch) (Wxn) NES -84e0889f31db8949d9e4281a6dc84350d5caef19 H Penguin (Nuts & Milk Hack) NES +84e0889f31db8949d9e4281a6dc84350d5caef19 H Penguin (Nuts & Milk Hack) NES 8226578f38034a45a2023d7340115149ed2d96bf H Penguin Shoot (Battle City Hack) NES 19f3aa482f2ed6f46d81fcb55960c9e56c039cf2 B Penguin-kun Wars (J) [b1] NES f04547d268c367e4bf42c47b2c15a7fa41a60ee7 B Penguin-kun Wars (J) [p1] NES @@ -14178,15 +14178,15 @@ ed96ab727ba734cda8f619ff171f5eeaf100c0f1 B Perfect Bowling (J) [o1] NES e2798f1b0f34fb4177b032ad37c6117632a2b8f7 G Pesterminator - The Western Exterminator (Color Dreams) [!] NES 6427975ec1a6c8eb2b44fbd23727ca4673dee6f1 B Pesterminator - The Western Exterminator (Color Dreams) [o1] NES ec5b7cea33ded1afa919a8e2d975ba25e7cb2d8e U Pet 4-in-1 (Unl) NES -faf1e63eaf03dba975d9f40cccbe446a71386ab2 G Peter Pan & The Pirates (U) [!] NES -bcf8aca930e0edfe72da7e836f121cce7ecfb0cd B Peter Pan & The Pirates (U) [b1] NES -0f71b02b1828d6fa3cf477b304e2e49c90333a40 B Peter Pan & The Pirates (U) [b2] NES -6f633431bcb0ec6a5d2883ea742c4281f6fe7351 B Peter Pan & The Pirates (U) [b3] NES -4596be40277f40d4c8c7546a25a08f912dbf7645 B Peter Pan & The Pirates (U) [o1] NES -acc8e6a5efee672e34b11ad2d699ba2adbe91770 B Peter Pan & The Pirates (U) [o2] NES -c51d1b51e599b5cf5743458ec7248c7653b461c2 B Peter Pan & The Pirates (U) [o3] NES -4eac15442ca9bc0ba7591e219e5d24176df1fa57 B Peter Pan & The Pirates (U) [o4] NES -93b0e1be6669692c19d51d35d4b8a31bdbf90573 C Peter Pan & The Pirates (U) [t1] NES +faf1e63eaf03dba975d9f40cccbe446a71386ab2 G Peter Pan & The Pirates (U) [!] NES +bcf8aca930e0edfe72da7e836f121cce7ecfb0cd B Peter Pan & The Pirates (U) [b1] NES +0f71b02b1828d6fa3cf477b304e2e49c90333a40 B Peter Pan & The Pirates (U) [b2] NES +6f633431bcb0ec6a5d2883ea742c4281f6fe7351 B Peter Pan & The Pirates (U) [b3] NES +4596be40277f40d4c8c7546a25a08f912dbf7645 B Peter Pan & The Pirates (U) [o1] NES +acc8e6a5efee672e34b11ad2d699ba2adbe91770 B Peter Pan & The Pirates (U) [o2] NES +c51d1b51e599b5cf5743458ec7248c7653b461c2 B Peter Pan & The Pirates (U) [o3] NES +4eac15442ca9bc0ba7591e219e5d24176df1fa57 B Peter Pan & The Pirates (U) [o4] NES +93b0e1be6669692c19d51d35d4b8a31bdbf90573 C Peter Pan & The Pirates (U) [t1] NES 1c6ebffde98f4afaba4032d68a6d2713d7ce6c01 H Phantasy Star The Hopeless (Air Fortress Hack) NES de763651d0d6ab670935b86f412e24d853f4a6d1 G Phantom Air Mission (E) [!] NES 373b6c4721e73142ea77be78439e741d6f86ad29 G Phantom Fighter (U) [!] NES @@ -14609,7 +14609,7 @@ e5c46255f9723358115d9a15142a1d2ed8e2123f U Powerpak Boot Loader V1.10 (PD) NES 99155590ec76d5541aff7e49ed3f998517130ac2 U Powerpak Boot Loader V1.11 (PD) NES 949f5a882611b0dd79333c5ba338e587d9fc986e U Powerpak NSF V1.20 (PD) NES 2e360a03a7b1e38dca4bf8d1153549b42a15bbf4 U Powerpak NSF V1.34 (PD) NES -9e470702ad1466d62245453dc8c6bb50b92c30c2 U PPU Palette RAM Access & Mirroring Test by Shay Green (15 Sep 2005) (PD) NES +9e470702ad1466d62245453dc8c6bb50b92c30c2 U PPU Palette RAM Access & Mirroring Test by Shay Green (15 Sep 2005) (PD) NES 4aad1a570833e0365592ac54ea13019dcd3d15e4 U PPU Timing V2 by Kevin Horton (PD) NES a376886d844d36e0a073d39fb343c3955fa908e5 U PR2_test (PD) NES 502923edd8e4efd7ff1b3c1eef302997ef3cff0b U PR8 NES Drum Synth v0.99 by Neil Baldwin (2011) (PD) NES @@ -14848,7 +14848,7 @@ d9492dd8f558b7db25e6fee6b95f008e9f7e6061 G Qix (U) [!] NES 84ef8209b0dc88bf9794e3373c35e64dd7bbf375 B Qix (U) [b2] NES 5411c6741a26912adcc0b5ec87813dca9cb77cce B Qix (U) [o1] NES 9440b56316739c25dd4a1470c36eb29fe41a7c11 H Quadruple Dragons (FF1 Hack) NES -05dbd91abd97b747b4470f1ea2109274714b6532 U Quadz by Michael Blain, Mark Schmit & Phil Yam (PD) NES +05dbd91abd97b747b4470f1ea2109274714b6532 U Quadz by Michael Blain, Mark Schmit & Phil Yam (PD) NES b053482f9ced7a1835fe961cc2373ff9521b74a2 U Quantum Disco Brothers by wAMMA (PD) (PAL) NES 93efdadedba42f4ec7a6cdf5634187ff38b66f91 G Quarter Back Scramble (J) [!] NES 10532a9c32080431fb5711ff42ef83187cf13639 G Quarth (J) [!] NES @@ -14941,7 +14941,7 @@ ecd19585722f8985b1e898dae23231aa2f75cdc5 H R.B.I. Baseball - Fantasy Baseball Le 949b63ad49546c59901f143d6331dcb0f290fdad H R.B.I. Baseball - Greats of College Baseball by fightonusc (Hack) NES 4599d3da7bf2968980000c6dc6ba9fc4a1bc67a0 H R.B.I. Baseball - Heaven Vs Hell by Britznoc (Hack) NES a9947effb0e21f56beb66b771dc8f62d06ac33ba H R.B.I. Baseball - Hunt for October '06 by Fryak (Hack) NES -da4bb9c9b18ff1e37c13852824b28ed5563dfb51 H R.B.I. Baseball - Japanese League & Negro League by DrNick (Hack) NES +da4bb9c9b18ff1e37c13852824b28ed5563dfb51 H R.B.I. Baseball - Japanese League & Negro League by DrNick (Hack) NES 2d94e410ca61c704bb319ea7e4fc8980765fe97e H R.B.I. Baseball - Mexican League 1979 - Northern Division by Cafetero (Hack) NES 79230b44c7a4429f96bba1bce5da3306d04cdbf0 H R.B.I. Baseball - Mexican League 1979 - Southern Division by Cafetero (Hack) NES cd415b9405d8ae4d52038ef086b017c498fdbc3d H R.B.I. Baseball - Same Team Fix (Hack) NES @@ -15037,7 +15037,7 @@ e875c71d507573f1c4559e7b8e797a5f05adc6d2 B Racket Attack (U) [b6] NES f55f2a192bc6d0927fedd445cb0515c5284467f2 B Racket Attack (U) [b8] NES 90716b3b6b4bb2bfb39f16248a257fe07557ba70 B Racket Attack (U) [o1] NES a2bc61169a2c21a68bc6d48441538e178bcb563b B Racket Attack (U) [o2] NES -b1197945728949126af2049e96d2433a7813a9da G Rackets & Rivals (E) [!] NES +b1197945728949126af2049e96d2433a7813a9da G Rackets & Rivals (E) [!] NES 66a0be81eb404220b2c519dcc3ca3432e883ac5a G Rad Racer (E) [!] NES cda80a93a5fa2622064056b5bc5e93eeb1c811de B Rad Racer (PC10) [b1] NES 7e0332479069fe729f44f61d8f337d228efc2a07 U Rad Racer (PC10) NES @@ -15202,12 +15202,12 @@ b00813ed6a0b4602b1384d6f7418052dc496dead G Reigen Doushi (J) [!] NES cb58b0109a4dc4c1f757035842da3b79744f4e9e B Remote Control (U) [o1] NES 068c2b2053974a7cad3e7a0637bc6354f32694e0 B Remote Control (U) [o2] NES 075b4a6af861726f45d0da61052769886a080e35 B Remote Control (U) [o3] NES -982f6bc24423ecc04199c8fa3f8d156c9af1a9b3 G Ren & Stimpy Show, The (U) [!] NES -07a8119abea8e83455f8aa45224418cc3af784a4 B Ren & Stimpy Show, The (U) [b1] NES -2476bf9fed478b6612c50be88448cd14cf694a17 B Ren & Stimpy Show, The (U) [b2] NES -ce765eceee5a44dbf2112f3e986c8cb0d11ac54d B Ren & Stimpy Show, The (U) [b3] NES -04b8201def7ae785ea69e592fa66f9a3f6838093 B Ren & Stimpy Show, The (U) [o1] NES -14c3f7970827f6f231f142396843966a0be4478f B Ren & Stimpy Show, The (U) [o2] NES +982f6bc24423ecc04199c8fa3f8d156c9af1a9b3 G Ren & Stimpy Show, The (U) [!] NES +07a8119abea8e83455f8aa45224418cc3af784a4 B Ren & Stimpy Show, The (U) [b1] NES +2476bf9fed478b6612c50be88448cd14cf694a17 B Ren & Stimpy Show, The (U) [b2] NES +ce765eceee5a44dbf2112f3e986c8cb0d11ac54d B Ren & Stimpy Show, The (U) [b3] NES +04b8201def7ae785ea69e592fa66f9a3f6838093 B Ren & Stimpy Show, The (U) [o1] NES +14c3f7970827f6f231f142396843966a0be4478f B Ren & Stimpy Show, The (U) [o2] NES c3e3e30408fda21ee2383e128b13e1b0f5650c32 U Renegade (U) (VC) NES bce48217b901a2bbd81fb89586661da6a442a179 G Renegade (U) [!] NES 3da61d5ef055b8fb8f0eb9605b7bb08f3cbbd21c B Renegade (U) [b1] NES @@ -15234,7 +15234,7 @@ ce9be360c843606897cba2878e8ad3bd57134369 H Retro Mario Bros 3 (Older) (SMB3 PRG1 47958c4b9b18116ffd4aafad43aeb4bfa3ec173d H Retro Mario Bros 3 (SMB3 PRG1 Hack) NES 85e5e4241d7fb3cb4bd03f2ec44c3439960e2f49 U Retrocoders' Demo for Y2Kode (PD) NES 5e4eb9f1a8b2a9dc60308c380659aa040d164545 U Retrocoders' Music ROMS - Years Behind (PD) NES -482360d347ba7c0deb945f93d43cc85377fc3654 H Return BC by Bishop & Multisoft (Battle City Hack) NES +482360d347ba7c0deb945f93d43cc85377fc3654 H Return BC by Bishop & Multisoft (Battle City Hack) NES 4be8bc2dfd966d52c3dc27042813eaaadf4217e3 H Return BC by Bishop (Battle City Hack) NES caa8da6dcf9d28028dfd6d2e6e86537fd0be3eb1 B Return of the Black Mage by Redrum (Warpman Hack) [o1] NES 717c53d094d0d7f01358568a92e938934a82960c H Return of the Black Mage by Redrum (Warpman Hack) NES @@ -16117,8 +16117,8 @@ c1332faaa9e40f1953a8f470b851f2a1f869715c H Sansuu 3 Nen - Keisan Game (J) [hM03] a9ce58ea73e0f63d264d0f79f23a077797fd52ff B Sansuu 3 Nen - Keisan Game (J) [hM03][o1] NES dafe0132cf7850ddbc50bc3a0f516d8a0b6049c6 G Sansuu 4 Nen - Keisan Game (J) (Prototype) [!] NES 7c5b6f8b54790e73d72088854253395360625d7f G Sansuu 4 Nen - Keisan Game (J) [!] NES -c6ac68e9dfaf87f774f8ff94a7a0eef3591e2d68 G Sansuu 5 & 6 Nen - Keisan Game (J) (Prototype) [!] NES -6020dc7df0e63dc00293d2fea63aef698f608942 U Sansuu 5 & 6 Nen - Keisan Game (J) NES +c6ac68e9dfaf87f774f8ff94a7a0eef3591e2d68 G Sansuu 5 & 6 Nen - Keisan Game (J) (Prototype) [!] NES +6020dc7df0e63dc00293d2fea63aef698f608942 U Sansuu 5 & 6 Nen - Keisan Game (J) NES 4631b718863e7e0819f8a5a20871df489667894f U Santa Claus (Ch) (Wxn) NES 4dd9861f9e77fd1d79058ec168d3659765f9b9a1 B SARS Kung Fu 2003 by Jeremiah Johnson (Kung Fu Hack) [o1] NES 5d2b88a9b421114ee9161a32a4a4be36e4d33c95 H SARS Kung Fu 2003 by Jeremiah Johnson (Kung Fu Hack) NES @@ -16151,8 +16151,8 @@ e0f27eda215acd60fd3333d971f353ade4022774 H Schneider (Captain Tsubasa II Hack) N e31b969724dc19ade8c2e82bd36b506653de7b58 U Screen Saver Demo by KZ-S (PD) NES 49735dfc8bcbb6a53b484832f6ee8a2b3379935e U Screen2NES Zelda Demo V2 by Afroman (PD) NES ac503144a0cf452f71a5ba3076f6c2ee130d58f0 U Scroll Demo by HollowOne11 (PD) NES -31f013891c2daa44cda80afc5fe9ed632823750a U ScrollNES 0.1 2010 by NO CARRIER & Batsly Adams (PD) [a1] NES -64a95d6b75ee8a90df670e3740980063289a81a5 U ScrollNES 0.1 2010 by NO CARRIER & Batsly Adams (PD) NES +31f013891c2daa44cda80afc5fe9ed632823750a U ScrollNES 0.1 2010 by NO CARRIER & Batsly Adams (PD) [a1] NES +64a95d6b75ee8a90df670e3740980063289a81a5 U ScrollNES 0.1 2010 by NO CARRIER & Batsly Adams (PD) NES 5ced0cb435fb8c3e28f3f3bbfe55b6ca196970ba G SD Battle Oozumou - Heisei Hero Basho (J) [!] NES 077c2d4b9ef42e915e13c40bf7e88fce098d0f14 G SD Gundam - Gachapon Senshi 2 - Capsule Senki (J) [!] NES 382496bc94169a2e13ddf946cdee66a8f15035f8 B SD Gundam - Gachapon Senshi 2 - Capsule Senki (J) [b1] NES @@ -16664,8 +16664,8 @@ dc06b62c59901190ad2f04f6a9b857c16c2400ec H Skinhead Fight (Nekketsu Kakutou Dens d25f42a6f677399c05e08b8c164dfd43cb6be2b5 H Skinhead on Ice (Nekketsu Hockey Hack) NES 1fd7896dfa2af88a0056fa712074b43f59c0e4da H Skinhead Racing (Downtown - Nekketsu Koushin Kyoku Hack) NES d383d346725ed66ea41d619daa311867c9dc5c58 G Sklad Nomer 18 (Unl) [!] NES -b191e5d30e31e1f8613c4b3fb40b770f97ae92ed G Skull & Crossbones (Tengen) [!] NES -6b05670da10c0ba5eb33c94fb931a5464741239e B Skull & Crossbones (Tengen) [o1] NES +b191e5d30e31e1f8613c4b3fb40b770f97ae92ed G Skull & Crossbones (Tengen) [!] NES +6b05670da10c0ba5eb33c94fb931a5464741239e B Skull & Crossbones (Tengen) [o1] NES 8427c83a22306c0ee376f782e948601985f49f5a B Skullanoid by Evan Lucore (Arkanoid Hack) [o1] NES 146cb857051c2fc6892e0a65b8246abf0bceabf3 H Skullanoid by Evan Lucore (Arkanoid Hack) NES 3fc678eae782f6337e6522285b9b78b0541067a9 G Sky Destroyer (J) [!] NES @@ -16974,11 +16974,11 @@ eb60b5015be750db9484d7f5a74fdd23ec22d150 G Solar Jetman - Hunt for the Golden Wa 65f10ecade7082e8cebd1e2cc9c18ba67746691c B Solar Jetman - Hunt for the Golden Warpship (U) [o1] NES 195959f8fc5daf5ed05dc8b7fd72a5e5a748a8bb T Solar Jetman - Hunt for the Golden Warpship (U) [T+Bra1.0_TraduROMS] NES a632ae12fec13637ee1824bad5e4f6e180add3d8 T Solar Jetman - Hunt for the Golden Warpship (U) [T+Rus_Chief-Net] NES -c05e8c0f26044ee2ed8873b9939f1a97e71fc29f U Solar Wars 2001 by Chris Covell, Joey Parsell & Michel Iwaniec (PD) NES -4d42ecc70c481f7fe68a8a2961ac27860fa97575 U Solar Wars by Chris Covell, Joey Parsell & Michel Iwaniec (PD) [a1] NES -da5ecfca8ee9f6a313039266fe0c705db84978d3 U Solar Wars by Chris Covell, Joey Parsell & Michel Iwaniec (PD) NES -ce8b4818719ecad6b35ce9ca4ef573467e160126 U Solar Wars Silent V.1 by Chris Covell, Joey Parsell & Michel Iwaniec (PD) NES -728e45acb68985ce8cc73c5f97ab226992ccfc09 U Solar Wars Silent V.2 by Chris Covell, Joey Parsell & Michel Iwaniec (PD) NES +c05e8c0f26044ee2ed8873b9939f1a97e71fc29f U Solar Wars 2001 by Chris Covell, Joey Parsell & Michel Iwaniec (PD) NES +4d42ecc70c481f7fe68a8a2961ac27860fa97575 U Solar Wars by Chris Covell, Joey Parsell & Michel Iwaniec (PD) [a1] NES +da5ecfca8ee9f6a313039266fe0c705db84978d3 U Solar Wars by Chris Covell, Joey Parsell & Michel Iwaniec (PD) NES +ce8b4818719ecad6b35ce9ca4ef573467e160126 U Solar Wars Silent V.1 by Chris Covell, Joey Parsell & Michel Iwaniec (PD) NES +728e45acb68985ce8cc73c5f97ab226992ccfc09 U Solar Wars Silent V.2 by Chris Covell, Joey Parsell & Michel Iwaniec (PD) NES dc50b0576187261030236687f37540cd429749ae H Soldier VS Mario (SMB1 Hack) NES 67bd42b43a2e0fc012569c02ab18bf7ec679443f T Solitair (from Nuevo Tipo de Computadora) (Unl) [T+Rus_Cool-Spot] NES b3fcfd458cb9ad4c69414b37b17b4c9cdd3d7abd T Solitair (from Nuevo Tipo de Computadora) (Unl) [T+Rus_Cool-Spot][a1] NES @@ -17245,7 +17245,7 @@ c9374202764fa52c749144b7ddcf26a9687a7d8a B Sqoon (U) [o3] NES 9bf0d67acdfde71eb391c7d35b6e45671c4fe35d U Square (Ch) (Wxn) NES 4072c52beeb14b128e0f1f497b4a72377fe59923 U Square Box by Quietust (PD) NES a864d3b913cefc885e01e0dacc53077ea7f5c727 U Square Box by Quietust [U] (PD).unf NES -7517bed4dbdc71c3184a9632e460f223b7a2191f U Square City by Mankeli, Zonzki & Bananmos (PD) NES +7517bed4dbdc71c3184a9632e460f223b7a2191f U Square City by Mankeli, Zonzki & Bananmos (PD) NES 90c1266a1bfc51c6a8fd5ae75a90bd9b6d491949 G Square Force (Unl) [!] NES f00d2feb353450bd6294bb431a54cee729e56689 G Square no Tom Sawyer (J) [!] NES af6443e035e95a7917b773fc2a32a9d7709caae5 B Square no Tom Sawyer (J) [b1] NES @@ -17566,11 +17566,11 @@ b3ed4ba03dba257229c68c4ea0173f8961bc00a2 B Strider (U) [o1] NES be18c598d75b1b8504952154938868723b045daa C Strider (U) [t1] NES a25bfd8f0cf77ee96f6b07deebe6313eb3787ea3 G Strike Wolf (MGC-014) (Unl) [!] NES 80cdb522e0d2adc41595c6dcec9fe330816b077e H Strip Aerobics (beta) by Golden Gun (Dance Aerobics Hack) NES -356fa145d802faa849c66b1c0e549de850cdffb1 U Stroke & Match Golf (Ladies) (VS) NES -53ed0cca26f766bbeb6d10bf90dd2891bda93ebe G Stroke & Match Golf (VS) [!] NES -c988eb9e17969812cd4d09896fd28da9ae3a6a13 U Stroke & Match Golf (VS) [a1] NES -6c756c8e4263a5b4dc8cc2502dc4e63fac6fab29 B Stroke & Match Golf (VS) [a1][b1] NES -7bbd19e207a78c833f8ae5ff535cbf974f299d73 B Stroke & Match Golf (VS) [a1][b2] NES +356fa145d802faa849c66b1c0e549de850cdffb1 U Stroke & Match Golf (Ladies) (VS) NES +53ed0cca26f766bbeb6d10bf90dd2891bda93ebe G Stroke & Match Golf (VS) [!] NES +c988eb9e17969812cd4d09896fd28da9ae3a6a13 U Stroke & Match Golf (VS) [a1] NES +6c756c8e4263a5b4dc8cc2502dc4e63fac6fab29 B Stroke & Match Golf (VS) [a1][b1] NES +7bbd19e207a78c833f8ae5ff535cbf974f299d73 B Stroke & Match Golf (VS) [a1][b2] NES 7bba18f6c4970a841fcca61cfa0c137fe4d79156 U Strong Pill (Ch) (Wxn) NES 8af29c451a88c37520a3ba67289b0ea984f1799a H Stronghold (SMB1 Hack) NES 0b1ff1e0010dfebe2e8a072df96ae1ce7af0595e H Stronghold, The (SMB1 Hack) NES @@ -17582,7 +17582,7 @@ b9a9a64cf606bba1fb70b3da70926ae2f22781f6 B Stunt Kids (Camerica) [o1] NES 75f1475b12ab45bd82aff0d46224dfec8b6ad663 H Subcon 2000 (Final) (SMB2 Hack) NES 13e7f2ca2c7ee1aea28245af364ce4fa6ac8b592 H Subcon 2000 (SMB2 Hack) NES 488d37154efc7611de0cded75aade267222777a6 U Submarine War (Ch) (Wxn) NES -8d24486170a3ffc5f36d89bae423a1d9fa173b60 U Subor Figure Ratiocination & IQ Puzzle (Ch) NES +8d24486170a3ffc5f36d89bae423a1d9fa173b60 U Subor Figure Ratiocination & IQ Puzzle (Ch) NES 88318d936361115b784f072ec7f1bddb0e6728ba U Subor V1.0 (R) [a1] NES 786f2da157861fd6db2aaf84fe95cc83244594fa U Subor V1.0 (R) NES 406a458af2f51a1b44ea18e1999781ca22b5b3c7 B Subor V3.0 (Ch) [b1] NES @@ -17649,8 +17649,8 @@ add98da0583a4a1cb6d5bfecf305fa64457d7b90 H SUP-Noid (Arkanoid Hack) NES 60081d0d62971348268c68f3c352c1da7cfc0d88 B Super 1997 4-in-1 [p1] NES 5e5ce5cbd73ea88ee012c88c0e7be30130f55ebd G Super 1998 3-in-1 (NT-008 PCB) [p1][!] NES fb947bf2f88e9cb8d33c0a7de8c243969bb54fdb G Super 1998 3-in-1 (VT-850, NT-008 PCB) [p1][!] NES -b103bd0b66e8ea798e64295e799fefe6b69cfd2b G Super 2-in-1 (Soccer Game & Crazy Dance) (Unl) [!] NES -3d580c1ce546b60664f2c6367d804a673478bc8d H Super 2-in-1 (Soccer Game & Crazy Dance) (Unl) [f1] NES +b103bd0b66e8ea798e64295e799fefe6b69cfd2b G Super 2-in-1 (Soccer Game & Crazy Dance) (Unl) [!] NES +3d580c1ce546b60664f2c6367d804a673478bc8d H Super 2-in-1 (Soccer Game & Crazy Dance) (Unl) [f1] NES a21a620a1eaed19ef52e8f184dec2872cee2005a U Super 2-in-1 (Unl) NES 997bbb9a3e52507fa488810ed90b613e5ba1f4cd B Super 22-in-1 [p1] NES 5830ff9449a0388450718d014a9034e32645bdec G Super 24-in-1 [U][p1][!].unf NES @@ -18009,7 +18009,7 @@ c48a6d63859327ffb4d7aac6ac4fb15f9d663c37 H Super Luigi - The Red Coin Quest Demo ea69228d23f05be1205ed891e558485069060736 H Super Mari 2 by Maikami (SMB1 Hack) NES 8301685fec5dc281b46b32acc1fadde588ca59bc H Super Mari by Maikami (SMB1 Hack) [a1] NES 749484a5d999730184edd0c5b1d234a841d08c63 H Super Mari by Maikami (SMB1 Hack) NES -9c2562be31541ef7df69e4133daaa3e2531cdedf U Super Mario & Sonic 2 (Ch) NES +9c2562be31541ef7df69e4133daaa3e2531cdedf U Super Mario & Sonic 2 (Ch) NES bf0ddfe1e564829c52d7aff0560721231994e786 U Super Mario 14 (Unl) NES 9f9f52fd92b660721b0ccccab1d99fc22729b289 H Super Mario 3 Challenge (SMB3 PAL Hack) NES 8a812f75451c88130424e39b4e38972dbbfa0b2a H Super Mario 4 (SMB1 Hack) [a1] NES @@ -18899,15 +18899,15 @@ fd7b1e21e33988714e0c6e5d881c40d11bc651cd B Swords and Serpents (U) [b1] NES a737d3984b88328a5d5f9709547b931f99e3f32d B Swords and Serpents (U) [b2] NES 297d50d7296544ab74ccf019aca1869424b99932 B Swords and Serpents (U) [o1] NES 77f4ea6ebcdd71a5dab45b014dd300458e625b19 B Swords and Serpents (U) [o2] NES -592c8b6be5816ba771b4fc18ec6a72cfee06d2c7 G T&C 2 - Thrilla's Surfari (U) [!] NES -55e8093bbbe53bd9d8d0d90952fcb6aeb9240b23 B T&C 2 - Thrilla's Surfari (U) [b1] NES -846b6b442ec5532c53d198da7c7d5909c97aff3c B T&C 2 - Thrilla's Surfari (U) [b2] NES -6a101fb054fbe93b6c6ca33245e3f8b8710e45a8 B T&C 2 - Thrilla's Surfari (U) [o1] NES -ec1ac46af157cbe49383402373ab04a483105980 B T&C 2 - Thrilla's Surfari (U) [p1] NES -7114bc8b0aad3094e59ccedba2845c1c032b15cc G T&C Surf Design (U) [!] NES -a8d63aa540cf74d966b465036f9a423136c8536b B T&C Surf Design (U) [b1] NES -006c8859d1ab3429daa1228cd6161af3cdabb236 B T&C Surf Design (U) [b2] NES -aff91bfb462c2aa10cc2d51ce93a04f050d7f84d B T&C Surf Design (U) [o1] NES +592c8b6be5816ba771b4fc18ec6a72cfee06d2c7 G T&C 2 - Thrilla's Surfari (U) [!] NES +55e8093bbbe53bd9d8d0d90952fcb6aeb9240b23 B T&C 2 - Thrilla's Surfari (U) [b1] NES +846b6b442ec5532c53d198da7c7d5909c97aff3c B T&C 2 - Thrilla's Surfari (U) [b2] NES +6a101fb054fbe93b6c6ca33245e3f8b8710e45a8 B T&C 2 - Thrilla's Surfari (U) [o1] NES +ec1ac46af157cbe49383402373ab04a483105980 B T&C 2 - Thrilla's Surfari (U) [p1] NES +7114bc8b0aad3094e59ccedba2845c1c032b15cc G T&C Surf Design (U) [!] NES +a8d63aa540cf74d966b465036f9a423136c8536b B T&C Surf Design (U) [b1] NES +006c8859d1ab3429daa1228cd6161af3cdabb236 B T&C Surf Design (U) [b2] NES +aff91bfb462c2aa10cc2d51ce93a04f050d7f84d B T&C Surf Design (U) [o1] NES fdbe721de58985fa9388e8dacaab2b9bbd2594bb G Taan Hak Fung Wan King Tank (Ch) [!] NES 07d463406d853ee92d196bedbf1c9d304fbfc442 T Taan Hak Fung Wan King Tank (Ch) [T+Rus_Cool-Spot] NES 09f2fc1c42469212c6867ae1a8049716f59e8773 U Table Tennis (Ch) (Wxn) NES @@ -19076,12 +19076,12 @@ cda500269bb162b0724f974b104cdc1573cd69dd C TaleSpin (U) [t4] NES ba0f38461b625da1b4d2d87ffe2d425e4300c7bc U Tall Pixel Demo by Damian Yerrick (PD) NES dab071f1829851c34483f02b1da737ee3ccd13b6 G Tamura Koushou Mahjong Seminar (J) [!] NES 21047b05fe5387b1c08834439f8fb153735da6ff B Tamura Koushou Mahjong Seminar (J) [b1] NES -4a6a524759ca64e2983cb188ff439178075e304c U Tanespot by Jonathan & Hans Knektar (PD) NES +4a6a524759ca64e2983cb188ff439178075e304c U Tanespot by Jonathan & Hans Knektar (PD) NES 74bb1012db87e69d6deb37de19446c668886049b U Tang Bo Hu Dian Qiu Xiang (NJ069) (Ch) NES 61c396d07aae17b391121f07cf9ba92bec0ca736 U Tang Mu Li Xian Ji (Ch) NES eac84b8189e3ec871f6974376e158737c2a376c7 G Tanigawa Kouji no Shougi Shinan II (J) [!] NES 9c3c6e0dd492ae7ea8f38224089a3f0b0b979880 G Tanigawa Kouji no Shougi Shinan III (J) [!] NES -d061ab6624edb4fdaf4d2a1df75499d1238eccf5 H Tank & Sub Mario (SMB1 Hack) NES +d061ab6624edb4fdaf4d2a1df75499d1238eccf5 H Tank & Sub Mario (SMB1 Hack) NES 459a8d83e8d0d992a2685ce6da135a2e691ed1a6 H Tank (Battle City Hack) NES 7f7888211e30b4dc296ee5addfbf8c62985bd9f9 U Tank (Ch) (Wxn) NES b5544d657fadef726ada69718407ab509dc69c47 U Tank 1990 (Ch) [a1] NES @@ -19112,8 +19112,8 @@ e30f43730fd9b74ebe5dc5c88e5bc0f72dc19fef H Tank Duel (Chi Title) (Battle City Ha e5f6c4aebfa1123554d4e3ef984f0a7e0bfdaef8 H Tank Duel 2 (Battle City Hack) NES 74ca37027c5e461fc88adc33fa428d832a5b225e B Tank Z by TOF (Battle City Hack) [o1] NES 007775f70b0726f7e20241484bf59e84cb35ce6f H Tank Z by TOF (Battle City Hack) NES -b5b01322bde1c061a76471fb544f90ecfbd0622b T Tanks & Milk (Nuts & Milk Hack) [T+Rus_Mitz] NES -832900808ad3add22e973fbb65408139abc0ed1a H Tanks & Milk (Nuts & Milk Hack) NES +b5b01322bde1c061a76471fb544f90ecfbd0622b T Tanks & Milk (Nuts & Milk Hack) [T+Rus_Mitz] NES +832900808ad3add22e973fbb65408139abc0ed1a H Tanks & Milk (Nuts & Milk Hack) NES b07bd06624f56133c87610a8bb722be10e495147 G Tantei Jinguuji Saburou - Toki no Sugiyuku Mama ni (J) [!] NES 2c0a885c049a4de54a31f51086cb20006e11beb8 U Tantei Jinguuji Saburou - Yokohamakou Renzoku Satsujin Jiken (J) (VC) NES be8ae507a738cc2059a598f2cfe68a0e848939c4 G Tantei Jinguuji Saburou - Yokohamakou Renzoku Satsujin Jiken (J) [!] NES @@ -19446,7 +19446,7 @@ f0a930d6451dd861698c153e2e4af341b506942a H Tecmo Rose Bowl 2002 1-AA College Foo b7d7e496ca9dfa023d79dcc973208c1c63477125 G Tecmo Super Bowl (U) [!] NES 09d7268535053f7ba16f94f4e4846a0d2705ee41 B Tecmo Super Bowl (U) [b1] NES 4f197e5d60df3bb0df051e46614b3de55edd0d7d B Tecmo Super Bowl (U) [o1] NES -ac3da734fa5eda62df44ecfb8912c18cb0f6623f H Tecmo Super Bowl 1962 Edit by Denny, Jstout & Elway7 (Hack) NES +ac3da734fa5eda62df44ecfb8912c18cb0f6623f H Tecmo Super Bowl 1962 Edit by Denny, Jstout & Elway7 (Hack) NES 761290f53aa1bfee1f9ddabbbdc70482dd415d1c H Tecmo Super Bowl 1968 by Carther (Hack) NES ea38b12e3cd3192d07637f32055ce1a3a82be32f H Tecmo Super Bowl 1968 Even Team - Online Tecmo Tourney Version (Hack) NES 6f4441535cc711207a204ee375bc7d0b535a9d19 H Tecmo Super Bowl 1983-1984 - BO FB Offtackle Left (Hack) NES @@ -19502,7 +19502,7 @@ cab90185c6f732f922f915cada0e9010a1330f6a H Tecmo Super Bowl 2006 - AFC Champions ce0e7ecec10a711a0e3afc31155ef920adc28cb9 H Tecmo Super Bowl 2006 by GRG (Hack) NES b75b315ca3c96ec8a2632a0373928979c4aefeab H Tecmo Super Bowl 2006 v.2 by RBPD5015 (Hack) NES 59783d5c20f9f046738532d7323f5c2dadaae333 H Tecmo Super Bowl 2006 v.final by mattjones18 (Hack) NES -9d2c88538919d6e1a2fc60215b721ff7d3e2b9b9 H Tecmo Super Bowl 2006 v.update - Title Screen by mattjones18&andrewmarsh13 (Hack) NES +9d2c88538919d6e1a2fc60215b721ff7d3e2b9b9 H Tecmo Super Bowl 2006 v.update - Title Screen by mattjones18&andrewmarsh13 (Hack) NES 40efbfe8bbb00f3db078fdcf522957653020fd4f H Tecmo Super Bowl 2006 v1 by drummer4god (Hack) NES bc25eaf09228d5a1c6a0f692898509b1de119534 H Tecmo Super Bowl 2006 v1 by mattjones18 (Hack) NES 95ddb60aaa75a8d2adb03c4f6d63dceca65dcadb H Tecmo Super Bowl 2006 v2 by drummer4god (Hack) NES @@ -19739,7 +19739,7 @@ bed34bf7c2bda653eda7a3eb1181c6a7c4cb0a65 H Tecmo Super Bowl X Globe Bowl (Hack) 10c4e09361a27a527dd4337ff62a49409670343c H Tecmo Super Bowl X IHSAA (Hack) NES 058e6dd332cc20282b87b001ee554f01666a939b H Tecmo Super Bowl X Mutant League (Hack) NES a2ddbeb71c07961cf875f0f01a3eca1b1dc7dd8f H Tecmo Super Bowl X Olympics (Hack) NES -3f5d28fe0591911ff8b60b59a80502572407af62 H Tecmo Super Bowl X World & USFL (Hack) NES +3f5d28fe0591911ff8b60b59a80502572407af62 H Tecmo Super Bowl X World & USFL (Hack) NES 07e33fb37a8ef1ef32582fc3ade1a1d42750c891 H Tecmo Super Bowl X World League (Hack) NES 1dccdc47be881eda06fc80bb6ee95b769177a814 H Tecmo Super Bowl X XFL (Hack) NES 30b6033e6ef01cbd8099beff41a10dfeda91436e H Tecmo Super Bowl XFL - Updated by GRG (Hack) NES @@ -20036,7 +20036,7 @@ d9e05cd3cb72d02352ce907f65137c161f000d51 H Tenchi wo Kurau II - Star and Rainbow 606b6c26886e37f674ba0b076825a0c18e51b838 H Tenchi wo Kurau II - Valiant General Edition by lmjny (Hack) NES 947659dcc3aa847b7abcd701e7328c13aff76941 H Tenchi wo Kurau II - Weiruwei's Final Edition (Hack) NES 7ce8f14c477da953cb66f7f0bfb89772de574e8f H Tenchi wo Kurau II - Woman Edition (Hack) NES -53bbb3a3def86ddf00d763c1ed171282d10dd29b H Tenchi wo Kurau II - Wu Jin & Guo Tai (Hack) NES +53bbb3a3def86ddf00d763c1ed171282d10dd29b H Tenchi wo Kurau II - Wu Jin & Guo Tai (Hack) NES 81be25d041c91f81e1b6df190b6baf886ee9a75c H Tenchi wo Kurau II - Yellow Turban Story (Hack) NES 17c71e03f6423c5f706e616182b1eea779913fd7 H Tenchi wo Kurau II - Yuan Luzhi Story (Hack) NES fa8396969fd18af4606f9a6d36cadc45eb747987 H Tenchi wo Kurau II - Yuan Shao Story (Hack) NES @@ -20252,16 +20252,16 @@ c697f7159f401fa736320a25a4f1b06233198f81 B Three Stooges (U) [o1] NES 2d2dd56f453715fc2fd8d0abf95bc2459f1d6082 B Three Stooges (U) [o2] NES 8c30cfc34cf89bae61591f599f6f24b3b255cb00 B Three Stooges (U) [o3] NES 1a618d99702421566c04e14096bf23ab25207f83 B Three Stooges (U) [o4] NES -5203dd2cbaafba9e5d4581a8252f2d47413902d8 G Thunder & Lightning (U) [!] NES -537819f97ddad1210614b59bffc81a6ef045a9ed B Thunder & Lightning (U) [b1] NES -cec96de01564f5bd14ace8668cd616f5f54094c8 B Thunder & Lightning (U) [b1][o1] NES -2eef9579430f9c00a59504715ebe3f4b3b4fbc4f B Thunder & Lightning (U) [b1][o2] NES -0a7c1edf9d2b26497de3aec1aa67a600795b72ca B Thunder & Lightning (U) [b2] NES -e6a90c84a3bd1e6c4e34d08df3ef4ff74c2206a3 B Thunder & Lightning (U) [b3] NES -2ea8b553bda94064f8142e8e2ea1d258db857da7 B Thunder & Lightning (U) [b4] NES -f04edfb835d9b14827f2e3359c81b7678b16b71b B Thunder & Lightning (U) [b5] NES -da657ecdd900b9b0d4ddc0473b9e9a92624d0659 B Thunder & Lightning (U) [b6] NES -468c6e236ddcab75bdc31e18f1731ffa52a62ade C Thunder & Lightning (U) [t1] NES +5203dd2cbaafba9e5d4581a8252f2d47413902d8 G Thunder & Lightning (U) [!] NES +537819f97ddad1210614b59bffc81a6ef045a9ed B Thunder & Lightning (U) [b1] NES +cec96de01564f5bd14ace8668cd616f5f54094c8 B Thunder & Lightning (U) [b1][o1] NES +2eef9579430f9c00a59504715ebe3f4b3b4fbc4f B Thunder & Lightning (U) [b1][o2] NES +0a7c1edf9d2b26497de3aec1aa67a600795b72ca B Thunder & Lightning (U) [b2] NES +e6a90c84a3bd1e6c4e34d08df3ef4ff74c2206a3 B Thunder & Lightning (U) [b3] NES +2ea8b553bda94064f8142e8e2ea1d258db857da7 B Thunder & Lightning (U) [b4] NES +f04edfb835d9b14827f2e3359c81b7678b16b71b B Thunder & Lightning (U) [b5] NES +da657ecdd900b9b0d4ddc0473b9e9a92624d0659 B Thunder & Lightning (U) [b6] NES +468c6e236ddcab75bdc31e18f1731ffa52a62ade C Thunder & Lightning (U) [t1] NES ff9a9dadbc051dba184bb2b75898d0b1e2003fa9 H Thunder Mario v0.1 (SMB1 Hack) [a1] NES ca34b25a91844a3553460f5c8a2c9c965aa2aa5c H Thunder Mario v0.1 (SMB1 Hack) NES e14b6ba27655313943a2bb440aa753bb6ca6fed5 U Thunder Warrior (Unl) NES @@ -20288,7 +20288,7 @@ cb0899ae2d9a0ad60edd0ada2b0a62c79be46893 U Thwaite V0.03 by Damian Yerrick (2011 276a18af8b307acd1edf98594e29710eeccf1c8c U Tian Long Ba Bu (NJ035) (Ch) NES cac9a7bb24890cc9cd7ab020581a5b609e1e1d0d U Tian Wang Xiang Mo Zhuan (Ch) (Decrypted) NES ab39d3fe1be075db59fe77abfb225249cfefcf90 U Tiao Wu Tan (Ch) NES -93e851e78f811175edb368d37dd7060c82fcfc3a T Tic & Tac 2 - Rangers du Risque (Chip 'n Dale 2 Hack) [T+Fre] NES +93e851e78f811175edb368d37dd7060c82fcfc3a T Tic & Tac 2 - Rangers du Risque (Chip 'n Dale 2 Hack) [T+Fre] NES 9bff3f91adf6fce47baae595be44fcd9c906884b U Tic-Tac by Sly Dog Studios (PD) NES 3bdb74f3a9f0620ca6581a7ad8a9864b810e3772 U Tic-Tac XO by Sly Dog Studios (PD) NES 15ac45742f1830dd6ba727cf41a4a9d9676a6d2a B Tie Fighter (Older) (SMB1 Hack) [b1] NES @@ -20430,7 +20430,7 @@ b4bc7b0867d9ecc88fe89bb6b4c564c495455363 H Toaster Bros (SMB1 Hack) NES 6e89817eb2531c4260120a609b89de354a5fd39d H Tobi (SMB1 Hack) NES b01ede8636ad9642476c09541b85ffb3d6bbb11a U Tobidase Daisakusen (FDS Conversion) NES c1307b51a96018211ef8105cbbbe90cd3e16a67b H Todos Contra TCHECO 2.0 by Macbee (Rockin' Kats Hack) NES -bf27c3c6ea6f06ff6d3071eb0e105608038e8052 U ToeJam & Earl Title Screen (PD) NES +bf27c3c6ea6f06ff6d3071eb0e105608038e8052 U ToeJam & Earl Title Screen (PD) NES 3d03d92a8f68a8d0619de48b710c9d514663b63e H Toilet Mario (SMB1 Hack) [a1] NES 8af0f78307042ecb8d938600b83daca6f76f004c H Toilet Mario (SMB1 Hack) NES f11c1240a664c5424a8c7eba7eeb42343c792350 U Toita Basketball (Unl) NES @@ -20464,30 +20464,30 @@ aef80dedb58085fc4b779e3747d69492f3b666bf G Tokoro San no Mamoru mo Semeru mo (J) b42120ffa11f8c809db4e6dd0ba11a8eebcd65bd H Tokoro San no Mamoru mo Semeru mo (Saitama Hack) NES ecf1fd4135beebe35c7ca8036e1a085dacdc4f5d U Tokumaru Raycaster 00 (PD) NES 2fca78b0d4a436579b3ed6c72dfe3888f3154644 U Tokumaru Raycaster 01 (PD) NES -d67f0beeb7603c224177264f13fc4b2d08ad679b G Tom & Jerry (E) [!] NES -7e1048cd8d868d1df56ed613f660b8513a6d71ea T Tom & Jerry (J) [T+Chi_MS emumax] NES -709016db8902eb4c6a99cd462fd1627babbbfbe4 U Tom & Jerry (J) NES -d6ebfe209995e8db14e82df952e8c5b10b025460 G Tom & Jerry (U) [!] NES -8620b79e4f0087a6a44ac3c31d2746292e573d49 B Tom & Jerry (U) [b1] NES -201867ffc992c4038021d8510fe8beea4f3e305a B Tom & Jerry (U) [b2] NES -936d84aafd680e4b52cfd006fd0f3ec8abfa2c24 B Tom & Jerry (U) [b3] NES -fe4ed3c8f29cbdb649a233b85e224f04f6a7f533 B Tom & Jerry (U) [o1] NES -6f8965f2e332e96a43de03ccca6a12b982f4a95a B Tom & Jerry (U) [p1] NES -7e984e9696e8d089ad870c68944ff2b95f053732 T Tom & Jerry (U) [p1][T+Rus_2R Team] NES -623f8b48b17e34653a0d9cd1db0b0facb8429b8f B Tom & Jerry (U) [p2] NES -8ecbe4a0a6b94542409c0990357de968e2e85f22 T Tom & Jerry (U) [T+Ara_Hisoka] NES -22c95df30f90c68b0d64b412029f9e905195bca1 T Tom & Jerry (U) [T+Pol] NES -28ceb78e1a2f2646bb47a8c5ed293605a7fa8a5f T Tom & Jerry (U) [T+Rus] NES -c3a972e3cd3f9832f7f46756d68744952e1585e9 C Tom & Jerry (U) [t1] NES -168e14e08574662823d6e4604540225205e29301 U Tom & Jerry 3 (Unl) NES +d67f0beeb7603c224177264f13fc4b2d08ad679b G Tom & Jerry (E) [!] NES +7e1048cd8d868d1df56ed613f660b8513a6d71ea T Tom & Jerry (J) [T+Chi_MS emumax] NES +709016db8902eb4c6a99cd462fd1627babbbfbe4 U Tom & Jerry (J) NES +d6ebfe209995e8db14e82df952e8c5b10b025460 G Tom & Jerry (U) [!] NES +8620b79e4f0087a6a44ac3c31d2746292e573d49 B Tom & Jerry (U) [b1] NES +201867ffc992c4038021d8510fe8beea4f3e305a B Tom & Jerry (U) [b2] NES +936d84aafd680e4b52cfd006fd0f3ec8abfa2c24 B Tom & Jerry (U) [b3] NES +fe4ed3c8f29cbdb649a233b85e224f04f6a7f533 B Tom & Jerry (U) [o1] NES +6f8965f2e332e96a43de03ccca6a12b982f4a95a B Tom & Jerry (U) [p1] NES +7e984e9696e8d089ad870c68944ff2b95f053732 T Tom & Jerry (U) [p1][T+Rus_2R Team] NES +623f8b48b17e34653a0d9cd1db0b0facb8429b8f B Tom & Jerry (U) [p2] NES +8ecbe4a0a6b94542409c0990357de968e2e85f22 T Tom & Jerry (U) [T+Ara_Hisoka] NES +22c95df30f90c68b0d64b412029f9e905195bca1 T Tom & Jerry (U) [T+Pol] NES +28ceb78e1a2f2646bb47a8c5ed293605a7fa8a5f T Tom & Jerry (U) [T+Rus] NES +c3a972e3cd3f9832f7f46756d68744952e1585e9 C Tom & Jerry (U) [t1] NES +168e14e08574662823d6e4604540225205e29301 U Tom & Jerry 3 (Unl) NES 67e2781b74c0771c377bfd11308662ab906e7a09 G Tom Sawyer no Bouken (J) [!] NES da0a506fda6aba44a56ac998b613176a7b8f8919 T Tom Sawyer no Bouken (J) [T+Rus_Guyver] NES a506f23a0f5905fe85051e14e9ad1e0e181163ed C Tom Sawyer no Bouken (J) [t1] NES 2ffc983e94e5ec9fc654052a442297c2b1ab24a1 H Tom Servo (Megaman III Hack) NES -9c1de5cd49641d025d75c4024ee303ed0135673e G Tombs & Treasure (U) [!] NES -582a21a4e41a0e844d66cd3c7e75bc75939c0cb5 B Tombs & Treasure (U) [o1] NES -2e819d9c061ab801c931ef547ce737de8f92403a B Tombs & Treasure (U) [o2] NES -6a1536f70666a52075e967ed24b1e48cbd7fa8a1 C Tombs & Treasure (U) [t1] NES +9c1de5cd49641d025d75c4024ee303ed0135673e G Tombs & Treasure (U) [!] NES +582a21a4e41a0e844d66cd3c7e75bc75939c0cb5 B Tombs & Treasure (U) [o1] NES +2e819d9c061ab801c931ef547ce737de8f92403a B Tombs & Treasure (U) [o2] NES +6a1536f70666a52075e967ed24b1e48cbd7fa8a1 C Tombs & Treasure (U) [t1] NES ea4f4ddf8d26245a0a16078f913d0074a080261c U Tommy T's Play Me Sound Editor (PD) NES 3b287cb938e58a77c6d5aefdfb47fe9027c17055 G Toobin' (Tengen) [!] NES df8f7e23d1cca410226951d89fd6d4cdbd8aaf4e B Toobin' (Tengen) [b1] NES @@ -20520,11 +20520,11 @@ ee7747f09f98e6fc1717652a7a485982f5b2d6d6 G Top Gun - The Second Mission (U) [!] 3dfdd953c496287d95c38a5e8653b6fdaadc0ede B Top Gun - The Second Mission (U) [o1] NES 9f92f4d56710b97b79525b7d055041a7ff302697 H Top Gun Altered (Hack) NES 334e4ff5070846b5db6f1f0d1eba80cb1a1141c8 U Top Gun III (Unl) NES -d3de04f554a5ae57750f12aedc810c0c3db3d2ea G Top Players' Tennis - Featuring Chris Evert & Ivan Lendl (U) [!] NES -1dc84f0db89649761867fb52711d31566ff26883 B Top Players' Tennis - Featuring Chris Evert & Ivan Lendl (U) [b1] NES -e42950f3b54f3368e3fdc54e03bfe9e728334561 B Top Players' Tennis - Featuring Chris Evert & Ivan Lendl (U) [b2] NES -ef32f202aa300422587ce967621b3a7afeb9065a B Top Players' Tennis - Featuring Chris Evert & Ivan Lendl (U) [b3] NES -50a9b1a803d4c5c55799657c340e942dc976e3f4 B Top Players' Tennis - Featuring Chris Evert & Ivan Lendl (U) [o1] NES +d3de04f554a5ae57750f12aedc810c0c3db3d2ea G Top Players' Tennis - Featuring Chris Evert & Ivan Lendl (U) [!] NES +1dc84f0db89649761867fb52711d31566ff26883 B Top Players' Tennis - Featuring Chris Evert & Ivan Lendl (U) [b1] NES +e42950f3b54f3368e3fdc54e03bfe9e728334561 B Top Players' Tennis - Featuring Chris Evert & Ivan Lendl (U) [b2] NES +ef32f202aa300422587ce967621b3a7afeb9065a B Top Players' Tennis - Featuring Chris Evert & Ivan Lendl (U) [b3] NES +50a9b1a803d4c5c55799657c340e942dc976e3f4 B Top Players' Tennis - Featuring Chris Evert & Ivan Lendl (U) [o1] NES d4d46dc4d99459c8dd57f30eeb16aa03358540f3 G Top Rider (J) [!] NES fd4d0f89989a257c35fc243eeb6f5c6d3f36b88a B Top Rider (J) [b1] NES cf633f8b8571bead545ed8d72da9b22771c1b255 H Top Rider (J) [hM04] NES @@ -20588,26 +20588,26 @@ d67238510c7f9b72eec13d5269a0158ffa975055 C Toxic Crusaders (U) [t1] NES aad697dda0e00fd508d0e9469660194701f25a2a H Toxic Crusaders Debug by dragon2snow (Hack) NES 7c748e5a83fb07905cadc427d1909a04af8c51ec H Toy Story (Unl) [hM219] NES e3a08bd0e03b4b395410ec1ccdd9c0f49400a410 U Toy Story (Unl) NES -f036a0ba914cac462525480fe583e2a7871d192c B Track & Field (PC10) [b1] NES -95f499762d567ca9c8373cff73253937529baeab U Track & Field (PC10) NES -df8425d96b3ac613eec604d66b32e91b001488d0 G Track & Field (U) [!] NES -ac29221519765ec4a10e5f6ef5549dd1393436c7 B Track & Field (U) [b1] NES -5a7c68d213dd96b2e4f4cedd3de4165c711ba945 B Track & Field (U) [o1] NES -c2d8a7573451d64681d2baa10b83e7d1e3c1c04a B Track & Field (U) [p1] NES -abee2b7e0513ba2e55a522a0105e461f2f5cb267 T Track & Field (U) [T+Bra100%_BRGames] NES -70b74fc1f7623f133a7f49f9e1b54418164f4056 G Track & Field II (E) [!] NES -29bd3871447df2ad02a5ab1ec2c9256e85a5c359 G Track & Field II (U) (PRG0) [!] NES -316a53f846cdbf55c021f8e9497f06e2b08245e4 B Track & Field II (U) (PRG0) [b1] NES -97e6822b57a61ed4f1f763582a1fb2f556f44632 B Track & Field II (U) (PRG0) [b2] NES -921d31753740408fe8b3cce41e36609ada225068 B Track & Field II (U) (PRG0) [b3] NES -817ca6d0d790458dfa248763170dd05b0408ab25 B Track & Field II (U) (PRG0) [b4] NES -16994d0c5085bc91e0768b39c462c8920fdfdb26 B Track & Field II (U) (PRG0) [o1] NES -dda552f0a6b95dbcc891cff98220fad2fd08eaad B Track & Field II (U) (PRG0) [o2] NES -62ce1b905f5bcf37d65c6126f962a8088c1ce171 T Track & Field II (U) (PRG0) [T+Bra1.0_ROMHackBR] NES -533cd4effd292961c38d5d3bec9bf4bab4acaa32 T Track & Field II (U) (PRG0) [T+Swe1.0_TheTranslator] NES -a3ca238ef9744175b1bdc70bcdb70aafe97239bc T Track & Field II (U) (PRG0) [T+Swe1.0_TheTranslator][a1] NES -768e8707b2af9167cfd2851c968988185d463f98 G Track & Field II (U) (REVA) [!] NES -830d9875c723a15fb322b4f12a750f618268e80b G Track & Field in Barcelona (E) [!] NES +f036a0ba914cac462525480fe583e2a7871d192c B Track & Field (PC10) [b1] NES +95f499762d567ca9c8373cff73253937529baeab U Track & Field (PC10) NES +df8425d96b3ac613eec604d66b32e91b001488d0 G Track & Field (U) [!] NES +ac29221519765ec4a10e5f6ef5549dd1393436c7 B Track & Field (U) [b1] NES +5a7c68d213dd96b2e4f4cedd3de4165c711ba945 B Track & Field (U) [o1] NES +c2d8a7573451d64681d2baa10b83e7d1e3c1c04a B Track & Field (U) [p1] NES +abee2b7e0513ba2e55a522a0105e461f2f5cb267 T Track & Field (U) [T+Bra100%_BRGames] NES +70b74fc1f7623f133a7f49f9e1b54418164f4056 G Track & Field II (E) [!] NES +29bd3871447df2ad02a5ab1ec2c9256e85a5c359 G Track & Field II (U) (PRG0) [!] NES +316a53f846cdbf55c021f8e9497f06e2b08245e4 B Track & Field II (U) (PRG0) [b1] NES +97e6822b57a61ed4f1f763582a1fb2f556f44632 B Track & Field II (U) (PRG0) [b2] NES +921d31753740408fe8b3cce41e36609ada225068 B Track & Field II (U) (PRG0) [b3] NES +817ca6d0d790458dfa248763170dd05b0408ab25 B Track & Field II (U) (PRG0) [b4] NES +16994d0c5085bc91e0768b39c462c8920fdfdb26 B Track & Field II (U) (PRG0) [o1] NES +dda552f0a6b95dbcc891cff98220fad2fd08eaad B Track & Field II (U) (PRG0) [o2] NES +62ce1b905f5bcf37d65c6126f962a8088c1ce171 T Track & Field II (U) (PRG0) [T+Bra1.0_ROMHackBR] NES +533cd4effd292961c38d5d3bec9bf4bab4acaa32 T Track & Field II (U) (PRG0) [T+Swe1.0_TheTranslator] NES +a3ca238ef9744175b1bdc70bcdb70aafe97239bc T Track & Field II (U) (PRG0) [T+Swe1.0_TheTranslator][a1] NES +768e8707b2af9167cfd2851c968988185d463f98 G Track & Field II (U) (REVA) [!] NES +830d9875c723a15fb322b4f12a750f618268e80b G Track & Field in Barcelona (E) [!] NES d974155c893375bdc5701e18b2feac774c4a59e5 B TradeMark Mario (SMB1 Hack) [o1] NES 1263a4459dfa4722581a46d94bf1429f1465f683 H TradeMark Mario (SMB1 Hack) NES c953cb58d25ed19b477779b81b1962bb25e06cdb H Tranny Tramps - The Family Jewels (Double Dragon III Hack) NES @@ -21002,7 +21002,7 @@ f6642a2ee4fd9cf1a8c4f991d9e427627fe5ea3b U Variable Width Font Demo v0.01 by Dam 8548c230871abaf39c965bc3f87488ec1ca13fff U Variable Width Font Demo v0.02 by Damian Yerrick+Blargg (PD) NES 582450682d233eb3b1279b1e11a0e0137602be6b U Variable Width Font Demo v0.03 by Damian Yerrick+Blargg (PD) NES afd24e18c113309cbc0917c73fdb2c7865511990 U VBL Flag Clearing Timing Test by Shay Green (6 Nov 2005) (PD) NES -6e1faa816c80462f5ee293c1847ee829683ea8a9 U VBL Flag Operation & PPU Timing Test by Shay Green (7 Nov 2005) (PD) NES +6e1faa816c80462f5ee293c1847ee829683ea8a9 U VBL Flag Operation & PPU Timing Test by Shay Green (7 Nov 2005) (PD) NES 3aef088d11ce1b6b8b2db07aba9aa79b6d8526e3 U VBL Timing Test by Shay Green (6 Nov 2005) (PD) NES 45585124fb0ba1b93995c4c15ec48382c90af165 U Vectest3 (PD) NES 2d55988a0e29604c90c844df15da34764688fbf0 U Vector Demo (PD) NES @@ -21094,7 +21094,7 @@ a99e0bc1b9087b3f2540c1b18425af6083e74f0e T Volleyball (UE) [T+FreBeta_ks151] NES 2b711242f71bdee2a9ec5045c4863b2b030bbbd8 T Volleyball (UE) [T+Ita1.0_ZombiKiller] NES 028bfd4d3228343a992cecf5fdd9d4805d8a3cc2 G Volshebnaya Palitra (R) [!] NES 58832f2ce7232a8e476b5376f533300eb6b702de U Vote for Oniken on Greenlight (PD) NES -c81a649f330e3de4784d94e5ea00b502a207716c U VRAM Access & Internal Read Buffer Operation Test by Shay Green (15 Sep 2005) (PD) NES +c81a649f330e3de4784d94e5ea00b502a207716c U VRAM Access & Internal Read Buffer Operation Test by Shay Green (15 Sep 2005) (PD) NES 475ec5c8f610793d2ec555021e18f9230b151d63 U VRC6 Sound Demo by Siudym (PD) (PAL) NES 3e6154c79f27c5c9b2d4eba11c78570c9c5425cb H VS. Airman (SMB1 Hack) NES f9db1a17425dcd34a7bc68c0f86d5c338e58e795 B VS. Blink (VS SMB1 Hack) [o1] NES @@ -21190,9 +21190,9 @@ abae2b3ed342bc069abee73137744e5b36b4b0ab B Wall Street Kid (U) [b1] NES 7aca04613ec4e14df9c954f3e08605b5d981fadc B Wall Street Kid (U) [o2] NES 3b07de583fdf353d0e78f46b161e1e0c955b45d1 B Wall Street Kid (U) [o3] NES 1f5b5b4552ad51bc07a8aa99345b25190527995e B Wall Street Kid (U) [o4] NES -7d60a48aa52afcdf64ea9b249ade7cc8e83301c6 U Wally Bear & the No Gang (AVE) (Prototype) NES -cd1ee26c0cef8c48b72cc4000ac7a577b8c4c0b5 G Wally Bear & the No Gang (AVE) [!] NES -6603d08ee41b39350184cdf03537eb36162e2f01 B Wally Bear & the No Gang (AVE) [o1] NES +7d60a48aa52afcdf64ea9b249ade7cc8e83301c6 U Wally Bear & the No Gang (AVE) (Prototype) NES +cd1ee26c0cef8c48b72cc4000ac7a577b8c4c0b5 G Wally Bear & the No Gang (AVE) [!] NES +6603d08ee41b39350184cdf03537eb36162e2f01 B Wally Bear & the No Gang (AVE) [o1] NES dd8c8a387158230df68e20bd90b6c729589a5116 H Waluigi's Adventure by Googie (SMB1 Hack) [a1] NES 0de42862be2fea4d569700db9a01ef7745e2d97a H Waluigi's Adventure by Googie (SMB1 Hack) [a2] NES a9c35c50a1a447728621fffbad42f32a521c09ed B Waluigi's Adventure by Googie (SMB1 Hack) [b1] NES @@ -21267,7 +21267,7 @@ ad680a185bed1fdb8f6f885deaad6ed3ae565ea1 H Waterboy, The (Harry's Legend Hack) N dc88673fb3defcf60fcbbc5b2968dab20a188ad8 U WAV2NES Sample (PD) NES 831595bf54bf5dc41031358b87c7a3f30b2da765 U Wavetable5 Demo by Blargg (PD) NES 0b8582204c535c3b9c7d1b89342f22efb455a757 U Wavetable6 4-Channel Music Demo by Blargg (PD) NES -f5391038938d1c8577e572f0480ebf600bfd6482 U Wavy & Stretch Demo V0.3 by Chris Covell (PD) NES +f5391038938d1c8577e572f0480ebf600bfd6482 U Wavy & Stretch Demo V0.3 by Chris Covell (PD) NES c3c8bc28a11c11e45d48bdb8dd6b03d9e1974c47 U Way Out (Ch) (Wxn) NES 2470ce28d144f6d1320a81e8f1faeabd07bed462 G Wayne Gretzky Hockey (U) [!] NES 2be91df36a683e1e09f3f897ba5170fff22f2ac7 B Wayne Gretzky Hockey (U) [b1] NES @@ -21385,14 +21385,14 @@ d3040b0e2e70f426236cf76e3dbc7bc23967eb28 T Willow (U) [T+Fre100] NES 5e108abf60f2f8467c5a7f962cf11f0702c370a5 T Willow (U) [T+Rus_arsen13,Tigran] NES c6639a7b826fc3c85167334d7e3902db896a4779 T Willow (U) [T-Fre010] NES 3352a0493d4d40de75b3036ee01133e2fbe8e602 C Willow (U) [t1] NES -d94557741ae526a0cc7b4a3be5aa4a825baf9a85 G Wily & Light no Rockboard - That's Paradise (J) [!] NES -be4507a270fb3406cd483f2fd4e34da74a22d7a7 B Wily & Light no Rockboard - That's Paradise (J) [b1] NES -f44c84c330d5d84ec5410ad81e4300e4be9578a9 B Wily & Light no Rockboard - That's Paradise (J) [b1][o1] NES -40bce9f07c099e021bc1a7c73e5cd81de026c630 T Wily & Light no Rockboard - That's Paradise (J) [T+Eng1.1(Megaman)_Interordi] NES -0cedcf804a8fce45e56ec7f4d8be454838589cc2 T Wily & Light no Rockboard - That's Paradise (J) [T+Eng1.1(Rockman)_Interordi] NES -8166ad98dc32344e803d662333bda1b2acc29035 T Wily & Light no Rockboard - That's Paradise (J) [T-Eng(Megaman)_Interordi] NES -479364d2a6bb8db8c3343ce813157a8024a2ab92 T Wily & Light no Rockboard - That's Paradise (J) [T-Eng(Rockman)_Interordi] NES -35993e347372d4496ccc387b5a29f71a1f0bdba2 T Wily & Light no Rockboard - That's Paradise (J) [T-Eng0.10_Interordi] NES +d94557741ae526a0cc7b4a3be5aa4a825baf9a85 G Wily & Light no Rockboard - That's Paradise (J) [!] NES +be4507a270fb3406cd483f2fd4e34da74a22d7a7 B Wily & Light no Rockboard - That's Paradise (J) [b1] NES +f44c84c330d5d84ec5410ad81e4300e4be9578a9 B Wily & Light no Rockboard - That's Paradise (J) [b1][o1] NES +40bce9f07c099e021bc1a7c73e5cd81de026c630 T Wily & Light no Rockboard - That's Paradise (J) [T+Eng1.1(Megaman)_Interordi] NES +0cedcf804a8fce45e56ec7f4d8be454838589cc2 T Wily & Light no Rockboard - That's Paradise (J) [T+Eng1.1(Rockman)_Interordi] NES +8166ad98dc32344e803d662333bda1b2acc29035 T Wily & Light no Rockboard - That's Paradise (J) [T-Eng(Megaman)_Interordi] NES +479364d2a6bb8db8c3343ce813157a8024a2ab92 T Wily & Light no Rockboard - That's Paradise (J) [T-Eng(Rockman)_Interordi] NES +35993e347372d4496ccc387b5a29f71a1f0bdba2 T Wily & Light no Rockboard - That's Paradise (J) [T-Eng0.10_Interordi] NES 49773466c4296d77f0697c073ed66d4fe3375459 G Win, Lose or Draw (U) [!] NES 8f37e6b4dbbfcbb1c9b4e1620f0dd459837e0e06 B Win, Lose or Draw (U) [b1] NES 8993dafeff608f9c2f9a4508ac9e334795ae87be B Win, Lose or Draw (U) [o1] NES @@ -21432,17 +21432,17 @@ f324f1977d4b7840c37821990247993c26fa46fc G Wizardry - Proving Grounds of the Mad 9a7adb06a54e7bccb74583a6217b47e5a9525520 B Wizardry II - Llylgamyn no Densetsu (J) [b1] NES 56fbae974686e83054fafe06e9d8a2b6bbb82ce9 B Wizardry II - Llylgamyn no Densetsu (J) [b2] NES 026ae09c426d6eb689270b384349f20890578a82 G Wizardry III - Diamond no Kishi (J) [!] NES -61ff5043afb71553b21f04378b0e9f3179b5ef81 G Wizards & Warriors (E) [!] NES -5c135a7971013cf6e3a2243bcdd6938cf5ba4b5b G Wizards & Warriors (U) (PRG0) [!] NES -5c8df2859ddc204537fd83cadcee540faacf175e B Wizards & Warriors (U) (PRG0) [o1] NES -59e36195a3fb2a3d5fd3db02cedb0e71b54bb3cd T Wizards & Warriors (U) (PRG0) [T+Rus_Guyver] NES -f1e061a739ed0a1963a357c8df3f19fffd9b77c3 G Wizards & Warriors (U) (PRG1) [!] NES -c6f1bed4cf59c155cd8e03109cefc0f451426450 G Wizards & Warriors III - Kuros - Visions of Power (E) [!] NES -9c04e7357e5b39cfd9d0a119c52102197b4a1be0 G Wizards & Warriors III - Kuros - Visions of Power (U) [!] NES -f4c54e865c9b76e7b96045d285a0b8a81a1e8095 B Wizards & Warriors III - Kuros - Visions of Power (U) [b1] NES -5a5063fa947b0755dfb5f8313e6b7cd0384bb424 B Wizards & Warriors III - Kuros - Visions of Power (U) [b2] NES -7f2093ea1e427e54b42ef0e607f64c0cc4bce2d7 B Wizards & Warriors III - Kuros - Visions of Power (U) [o1] NES -f12e91ee96a101aad014bda73933a053219a33c3 C Wizards & Warriors III - Kuros - Visions of Power (U) [t1] NES +61ff5043afb71553b21f04378b0e9f3179b5ef81 G Wizards & Warriors (E) [!] NES +5c135a7971013cf6e3a2243bcdd6938cf5ba4b5b G Wizards & Warriors (U) (PRG0) [!] NES +5c8df2859ddc204537fd83cadcee540faacf175e B Wizards & Warriors (U) (PRG0) [o1] NES +59e36195a3fb2a3d5fd3db02cedb0e71b54bb3cd T Wizards & Warriors (U) (PRG0) [T+Rus_Guyver] NES +f1e061a739ed0a1963a357c8df3f19fffd9b77c3 G Wizards & Warriors (U) (PRG1) [!] NES +c6f1bed4cf59c155cd8e03109cefc0f451426450 G Wizards & Warriors III - Kuros - Visions of Power (E) [!] NES +9c04e7357e5b39cfd9d0a119c52102197b4a1be0 G Wizards & Warriors III - Kuros - Visions of Power (U) [!] NES +f4c54e865c9b76e7b96045d285a0b8a81a1e8095 B Wizards & Warriors III - Kuros - Visions of Power (U) [b1] NES +5a5063fa947b0755dfb5f8313e6b7cd0384bb424 B Wizards & Warriors III - Kuros - Visions of Power (U) [b2] NES +7f2093ea1e427e54b42ef0e607f64c0cc4bce2d7 B Wizards & Warriors III - Kuros - Visions of Power (U) [o1] NES +f12e91ee96a101aad014bda73933a053219a33c3 C Wizards & Warriors III - Kuros - Visions of Power (U) [t1] NES 175b452b31adac390d5a36c654aaf4de49ec19c9 B Wizzy (Formation Z Hack) [o1] NES eae3e42bc9b02382207f39edfd71b77b5228c4d4 B Wizzy (Formation Z Hack) [o2] NES 2f416726d94f7541709b61a1f1e8a4ae8d2ef14d B Wizzy (Formation Z Hack) [o3] NES @@ -21993,7 +21993,7 @@ f52a4b77d37156db3d470b7a2acf1625d041520c U Zero Pong V3.0 by Zero-Soul (PD) NES 9119581a22ac8fe03a546f0088132eaa55692abd U Zhan Guo Qun Xiong Chuan (Ch) NES 349e2e47a59a14151c190fd687de973f82ea8c69 B Zhan Guo Qun Xiong Zhuan (Ch) [b1] NES 9680484cd6a1aba6164bb07a7b556c1a90b1d9d7 U Zhan Guo Qun Xiong Zhuan (Ch) NES -54b371871d45aad6219e6394ed379dd9db24b6b8 U Zhan Guo Si Chuan Sheng (C&E) (Unl) NES +54b371871d45aad6219e6394ed379dd9db24b6b8 U Zhan Guo Si Chuan Sheng (C&E) (Unl) NES be6140cc9fb99c7ab5388dfe5c7c13fa4cfe2a3f G Zhen Ben Xi You Ji (Asder) [!] NES 902dd1345e1440b4297b1046ce0c2db26fbbca5e C Zhen Jia Hou Wang (ES-1061) (Ch) (Decrypted) [t1] NES af9e06787f450260f9810c3d4a54674f24adea1b U Zhen Jia Hou Wang (ES-1061) (Ch) (Decrypted) NES From 952609eeaa906ee955a0328b9c9aedf8b3ca7c2a Mon Sep 17 00:00:00 2001 From: "J.D. Purcell" Date: Sun, 20 Oct 2019 23:36:00 -0400 Subject: [PATCH 095/166] Factor out some common stuff in rom load/close. --- BizHawk.Client.Common/SaveSlotManager.cs | 6 --- BizHawk.Client.EmuHawk/MainForm.cs | 50 ++++++++++-------------- 2 files changed, 21 insertions(+), 35 deletions(-) diff --git a/BizHawk.Client.Common/SaveSlotManager.cs b/BizHawk.Client.Common/SaveSlotManager.cs index 8584312e7e..7ec9588a22 100644 --- a/BizHawk.Client.Common/SaveSlotManager.cs +++ b/BizHawk.Client.Common/SaveSlotManager.cs @@ -97,12 +97,6 @@ namespace BizHawk.Client.Common return _redo[slot]; } - public void Clear() - { - ClearRedoList(); - Update(); - } - public void SwapBackupSavestate(string path) { // Takes the .state and .bak files and swaps them diff --git a/BizHawk.Client.EmuHawk/MainForm.cs b/BizHawk.Client.EmuHawk/MainForm.cs index 978ac86acf..01ecb89b7e 100644 --- a/BizHawk.Client.EmuHawk/MainForm.cs +++ b/BizHawk.Client.EmuHawk/MainForm.cs @@ -3819,14 +3819,9 @@ namespace BizHawk.Client.EmuHawk } } - SetWindowText(); CurrentlyOpenRom = oa_openrom?.Path ?? openAdvancedArgs; CurrentlyOpenRomArgs = args; - HandlePlatformMenus(); - _stateSlots.Clear(); - UpdateCoreStatusBarButton(); - UpdateDumpIcon(); - SetMainformMovieInfo(); + OnRomChanged(); GlobalWin.DisplayManager.Blank(); Global.Rewinder.Initialize(); @@ -3854,26 +3849,17 @@ namespace BizHawk.Client.EmuHawk ClientApi.OnRomLoaded(Emulator); return true; } + else if (!(Emulator is NullEmulator)) + { + // The ROM has been loaded by a recursive invocation of the LoadROM method. + ClientApi.OnRomLoaded(Emulator); + return true; + } else { // This shows up if there's a problem - // TODO: put all these in a single method or something - - // The ROM has been loaded by a recursive invocation of the LoadROM method. - if (!(Emulator is NullEmulator)) - { - ClientApi.OnRomLoaded(Emulator); - return true; - } - ClientApi.UpdateEmulatorAndVP(Emulator); - HandlePlatformMenus(); - _stateSlots.Clear(); - UpdateStatusSlots(); - UpdateCoreStatusBarButton(); - UpdateDumpIcon(); - SetMainformMovieInfo(); - SetWindowText(); + OnRomChanged(); return false; } } @@ -3886,6 +3872,17 @@ namespace BizHawk.Client.EmuHawk } } + private void OnRomChanged() + { + SetWindowText(); + HandlePlatformMenus(); + _stateSlots.ClearRedoList(); + UpdateStatusSlots(); + UpdateCoreStatusBarButton(); + UpdateDumpIcon(); + SetMainformMovieInfo(); + } + private void CommitCoreSettingsToConfig() { // save settings object @@ -3979,17 +3976,12 @@ namespace BizHawk.Client.EmuHawk GlobalWin.Tools.Restart(); ApiManager.Restart(Emulator.ServiceProvider); RewireSound(); - Text = $"BizHawk{(VersionInfo.DeveloperBuild ? " (interim) " : "")}"; - HandlePlatformMenus(); - _stateSlots.Clear(); - UpdateDumpIcon(); - UpdateCoreStatusBarButton(); ClearHolds(); - PauseOnFrame = null; ToolFormBase.UpdateCheatRelatedTools(null, null); - UpdateStatusSlots(); + PauseOnFrame = null; CurrentlyOpenRom = null; CurrentlyOpenRomArgs = null; + OnRomChanged(); } } From c956b5993b5fdb956d7c9601530f38f59fe1bc31 Mon Sep 17 00:00:00 2001 From: "J.D. Purcell" Date: Mon, 21 Oct 2019 00:10:28 -0400 Subject: [PATCH 096/166] Small FFT change I had stashed. --- BizHawk.Emulation.Cores/Computers/Commodore64/FFT.cs | 7 ++++--- BizHawk.Emulation.Cores/Computers/Commodore64/MOS/Sid.cs | 2 +- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/BizHawk.Emulation.Cores/Computers/Commodore64/FFT.cs b/BizHawk.Emulation.Cores/Computers/Commodore64/FFT.cs index 1948acbf60..b87c8f5b38 100644 --- a/BizHawk.Emulation.Cores/Computers/Commodore64/FFT.cs +++ b/BizHawk.Emulation.Cores/Computers/Commodore64/FFT.cs @@ -6,7 +6,6 @@ namespace BizHawk.Emulation.Cores.Computers.Commodore64 { - public class RealFFT { private readonly int _length; @@ -15,12 +14,13 @@ namespace BizHawk.Emulation.Cores.Computers.Commodore64 public readonly double ForwardScaleFactor; public readonly double ReverseScaleFactor; + public readonly double CorrectionScaleFactor; public RealFFT(int length) { if (length < 2 || (length & (length - 1)) != 0) { - throw new ArgumentException("length", "FFT length must be at least 2 and a power of 2."); + throw new ArgumentException("FFT length must be at least 2 and a power of 2.", nameof(length)); } _length = length; @@ -29,6 +29,7 @@ namespace BizHawk.Emulation.Cores.Computers.Commodore64 ForwardScaleFactor = length; ReverseScaleFactor = 0.5; + CorrectionScaleFactor = 1.0 / (ForwardScaleFactor * ReverseScaleFactor); } public void ComputeForward(double[] buff) @@ -45,7 +46,7 @@ namespace BizHawk.Emulation.Cores.Computers.Commodore64 { if (buff.Length < _length) { - throw new ArgumentException("buff", "Buffer length must be greater than or equal to the FFT length."); + throw new ArgumentException("Buffer length must be greater than or equal to the FFT length.", nameof(buff)); } rdft(_length, reverse, buff, _ip, _w); diff --git a/BizHawk.Emulation.Cores/Computers/Commodore64/MOS/Sid.cs b/BizHawk.Emulation.Cores/Computers/Commodore64/MOS/Sid.cs index b96573b995..f3f3a56e5c 100644 --- a/BizHawk.Emulation.Cores/Computers/Commodore64/MOS/Sid.cs +++ b/BizHawk.Emulation.Cores/Computers/Commodore64/MOS/Sid.cs @@ -324,7 +324,7 @@ namespace BizHawk.Emulation.Cores.Computers.Commodore64.MOS //re-sample back down to the original number of samples for (double i = 0; i < nsamp; i++) { - _outputBufferFiltered[(int)i + _filterIndex] = (int)(_fftBuffer[(int)Math.Ceiling((i / (nsamp - 1) * (nsamp_2 - 1)))]/(nsamp_2/2)); + _outputBufferFiltered[(int)i + _filterIndex] = (int)(_fftBuffer[(int)Math.Ceiling((i / (nsamp - 1) * (nsamp_2 - 1)))] * _fft.CorrectionScaleFactor); if (_outputBufferFiltered[(int)i + _filterIndex] < 0) { From 3f216fb4a4f5fca9d63f156c87252ef1c2c76bf8 Mon Sep 17 00:00:00 2001 From: alyosha-tas Date: Mon, 21 Oct 2019 14:18:25 -0400 Subject: [PATCH 097/166] Disable cheats hotkey --- BizHawk.Client.EmuHawk/tools/Cheats/Cheats.Designer.cs | 2 ++ BizHawk.Client.EmuHawk/tools/Cheats/Cheats.cs | 5 +++-- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/BizHawk.Client.EmuHawk/tools/Cheats/Cheats.Designer.cs b/BizHawk.Client.EmuHawk/tools/Cheats/Cheats.Designer.cs index f5d56cbd24..10fa9bdabe 100644 --- a/BizHawk.Client.EmuHawk/tools/Cheats/Cheats.Designer.cs +++ b/BizHawk.Client.EmuHawk/tools/Cheats/Cheats.Designer.cs @@ -348,6 +348,8 @@ // this.DisableAllCheatsMenuItem.Image = global::BizHawk.Client.EmuHawk.Properties.Resources.Stop; this.DisableAllCheatsMenuItem.Name = "DisableAllCheatsMenuItem"; + this.DisableAllCheatsMenuItem.ShortcutKeys = ((System.Windows.Forms.Keys)((System.Windows.Forms.Keys.Control | System.Windows.Forms.Keys.Back))); + this.DisableAllCheatsMenuItem.ShortcutKeyDisplayString = "Ctrl + Backspace"; this.DisableAllCheatsMenuItem.Size = new System.Drawing.Size(233, 22); this.DisableAllCheatsMenuItem.Text = "Disable all"; this.DisableAllCheatsMenuItem.Click += new System.EventHandler(this.DisableAllCheatsMenuItem_Click); diff --git a/BizHawk.Client.EmuHawk/tools/Cheats/Cheats.cs b/BizHawk.Client.EmuHawk/tools/Cheats/Cheats.cs index afb412e6f0..c53d2c9e8b 100644 --- a/BizHawk.Client.EmuHawk/tools/Cheats/Cheats.cs +++ b/BizHawk.Client.EmuHawk/tools/Cheats/Cheats.cs @@ -446,7 +446,8 @@ namespace BizHawk.Client.EmuHawk ToggleMenuItem.Enabled = SelectedIndices.Any(); - DisableAllCheatsMenuItem.Enabled = Global.CheatList.ActiveCount > 0; + // Always leave enabled even if no cheats enabled. This way the hotkey will always work however a new cheat is enabled + // DisableAllCheatsMenuItem.Enabled = Global.CheatList.ActiveCount > 0; GameGenieSeparator.Visible = OpenGameGenieEncoderDecoderMenuItem.Visible = @@ -553,7 +554,7 @@ namespace BizHawk.Client.EmuHawk } private void DisableAllCheatsMenuItem_Click(object sender, EventArgs e) - { + { Global.CheatList.DisableAll(); } From bc76a4a040bac1f95eb82d701b77e74e4388e48d Mon Sep 17 00:00:00 2001 From: alyosha-tas Date: Mon, 21 Oct 2019 14:30:34 -0400 Subject: [PATCH 098/166] Cheats: typo fix --- .../tools/Cheats/CheatEdit.Designer.cs | 20 +++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/BizHawk.Client.EmuHawk/tools/Cheats/CheatEdit.Designer.cs b/BizHawk.Client.EmuHawk/tools/Cheats/CheatEdit.Designer.cs index 1e115271d4..9707bb5bb5 100644 --- a/BizHawk.Client.EmuHawk/tools/Cheats/CheatEdit.Designer.cs +++ b/BizHawk.Client.EmuHawk/tools/Cheats/CheatEdit.Designer.cs @@ -41,7 +41,7 @@ this.DomainDropDown = new System.Windows.Forms.ComboBox(); this.SizeLabel = new System.Windows.Forms.Label(); this.SizeDropDown = new System.Windows.Forms.ComboBox(); - this.DisplayTypeLael = new System.Windows.Forms.Label(); + this.DisplayTypeLabel = new System.Windows.Forms.Label(); this.DisplayTypeDropDown = new System.Windows.Forms.ComboBox(); this.BigEndianCheckBox = new System.Windows.Forms.CheckBox(); this.AddButton = new System.Windows.Forms.Button(); @@ -174,14 +174,14 @@ this.SizeDropDown.TabIndex = 19; this.SizeDropDown.SelectedIndexChanged += new System.EventHandler(this.SizeDropDown_SelectedIndexChanged); // - // DisplayTypeLael + // DisplayTypeLabel // - this.DisplayTypeLael.AutoSize = true; - this.DisplayTypeLael.Location = new System.Drawing.Point(11, 219); - this.DisplayTypeLael.Name = "DisplayTypeLael"; - this.DisplayTypeLael.Size = new System.Drawing.Size(114, 25); - this.DisplayTypeLael.TabIndex = 20; - this.DisplayTypeLael.Text = "Display As"; + this.DisplayTypeLabel.AutoSize = true; + this.DisplayTypeLabel.Location = new System.Drawing.Point(11, 219); + this.DisplayTypeLabel.Name = "DisplayTypeLabel"; + this.DisplayTypeLabel.Size = new System.Drawing.Size(114, 25); + this.DisplayTypeLabel.TabIndex = 20; + this.DisplayTypeLabel.Text = "Display As"; // // DisplayTypeDropDown // @@ -289,7 +289,7 @@ this.Controls.Add(this.AddButton); this.Controls.Add(this.BigEndianCheckBox); this.Controls.Add(this.DisplayTypeDropDown); - this.Controls.Add(this.DisplayTypeLael); + this.Controls.Add(this.DisplayTypeLabel); this.Controls.Add(this.SizeDropDown); this.Controls.Add(this.SizeLabel); this.Controls.Add(this.DomainDropDown); @@ -330,7 +330,7 @@ private System.Windows.Forms.ComboBox DomainDropDown; private System.Windows.Forms.Label SizeLabel; private System.Windows.Forms.ComboBox SizeDropDown; - private System.Windows.Forms.Label DisplayTypeLael; + private System.Windows.Forms.Label DisplayTypeLabel; private System.Windows.Forms.ComboBox DisplayTypeDropDown; private System.Windows.Forms.CheckBox BigEndianCheckBox; private System.Windows.Forms.Button AddButton; From 09dc1df9aeeb6385c9beeb34c1ef45619f8286e0 Mon Sep 17 00:00:00 2001 From: "J.D. Purcell" Date: Mon, 21 Oct 2019 20:09:55 -0400 Subject: [PATCH 099/166] Fix NullReferenceException when loading SNES MSU-1 XML file (MSU-1 still doesn't work for me though). --- BizHawk.Client.EmuHawk/MainForm.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/BizHawk.Client.EmuHawk/MainForm.cs b/BizHawk.Client.EmuHawk/MainForm.cs index 01ecb89b7e..65e7ee8fd2 100644 --- a/BizHawk.Client.EmuHawk/MainForm.cs +++ b/BizHawk.Client.EmuHawk/MainForm.cs @@ -3704,7 +3704,7 @@ namespace BizHawk.Client.EmuHawk CoreFileProvider.SyncCoreCommInputSignals(nextComm); InputManager.SyncControls(); - if (oa_openrom != null && Path.GetExtension(oa_openrom.Path.Replace("|","")).ToLower() == ".xml") + if (oa_openrom != null && Path.GetExtension(oa_openrom.Path.Replace("|","")).ToLowerInvariant() == ".xml" && !(Emulator is LibsnesCore)) { // this is a multi-disk bundler file // determine the xml assets and create RomStatusDetails for all of them @@ -3714,7 +3714,7 @@ namespace BizHawk.Client.EmuHawk for (int xg = 0; xg < xmlGame.Assets.Count; xg++) { - var ext = Path.GetExtension(xmlGame.AssetFullPaths[xg]).ToLower(); + var ext = Path.GetExtension(xmlGame.AssetFullPaths[xg]).ToLowerInvariant(); if (ext == ".cue" || ext == ".ccd" || ext == ".toc" || ext == ".mds") { From 1aadff8ca1bad27c9f2491276753a67977c19e57 Mon Sep 17 00:00:00 2001 From: "J.D. Purcell" Date: Mon, 21 Oct 2019 22:13:48 -0400 Subject: [PATCH 100/166] Cleanup speed increase/decrease. --- BizHawk.Client.EmuHawk/MainForm.cs | 128 +++-------------------------- 1 file changed, 12 insertions(+), 116 deletions(-) diff --git a/BizHawk.Client.EmuHawk/MainForm.cs b/BizHawk.Client.EmuHawk/MainForm.cs index 65e7ee8fd2..ff20280884 100644 --- a/BizHawk.Client.EmuHawk/MainForm.cs +++ b/BizHawk.Client.EmuHawk/MainForm.cs @@ -2490,6 +2490,8 @@ namespace BizHawk.Client.EmuHawk FrameBufferResized(); } + private static readonly int[] _speedPercents = { 1, 3, 6, 12, 25, 50, 75, 100, 150, 200, 300, 400, 800, 1600, 3200, 6400 }; + private void IncreaseSpeed() { if (!Global.Config.ClockThrottle) @@ -2501,66 +2503,13 @@ namespace BizHawk.Client.EmuHawk var oldp = Global.Config.SpeedPercent; int newp; - if (oldp < 3) + int i = 0; + do { - newp = 3; - } - else if (oldp < 6) - { - newp = 6; - } - else if (oldp < 12) - { - newp = 12; - } - else if (oldp < 25) - { - newp = 25; - } - else if (oldp < 50) - { - newp = 50; - } - else if (oldp < 75) - { - newp = 75; - } - else if (oldp < 100) - { - newp = 100; - } - else if (oldp < 150) - { - newp = 150; - } - else if (oldp < 200) - { - newp = 200; - } - else if (oldp < 300) - { - newp = 300; - } - else if (oldp < 400) - { - newp = 400; - } - else if (oldp < 800) - { - newp = 800; - } - else if (oldp < 1600) - { - newp = 1600; - } - else if (oldp < 3200) - { - newp = 3200; - } - else - { - newp = 6400; + i++; + newp = _speedPercents[i]; } + while (newp <= oldp && i < _speedPercents.Length - 1); SetSpeedPercent(newp); } @@ -2576,66 +2525,13 @@ namespace BizHawk.Client.EmuHawk var oldp = Global.Config.SpeedPercent; int newp; - if (oldp > 3200) + int i = _speedPercents.Length - 1; + do { - newp = 3200; - } - else if (oldp > 1600) - { - newp = 1600; - } - else if (oldp > 800) - { - newp = 800; - } - else if (oldp > 400) - { - newp = 400; - } - else if (oldp > 300) - { - newp = 300; - } - else if (oldp > 200) - { - newp = 200; - } - else if (oldp > 150) - { - newp = 150; - } - else if (oldp > 100) - { - newp = 100; - } - else if (oldp > 75) - { - newp = 75; - } - else if (oldp > 50) - { - newp = 50; - } - else if (oldp > 25) - { - newp = 25; - } - else if (oldp > 12) - { - newp = 12; - } - else if (oldp > 6) - { - newp = 6; - } - else if (oldp > 3) - { - newp = 3; - } - else - { - newp = 1; + i--; + newp = _speedPercents[i]; } + while (newp >= oldp && i > 0); SetSpeedPercent(newp); } From 1df41efc0d04999e83ffaaffcd5abc2d3fa872ce Mon Sep 17 00:00:00 2001 From: "J.D. Purcell" Date: Mon, 21 Oct 2019 23:54:16 -0400 Subject: [PATCH 101/166] Consolidate core accuracy warning dialog. --- .../BizHawk.Client.EmuHawk.csproj | 1 + BizHawk.Client.EmuHawk/EmuHawkUtil.cs | 54 ++++++++++++++++++ BizHawk.Client.EmuHawk/MainForm.Events.cs | 51 +---------------- .../tools/TAStudio/TAStudio.cs | 55 +------------------ 4 files changed, 61 insertions(+), 100 deletions(-) create mode 100644 BizHawk.Client.EmuHawk/EmuHawkUtil.cs diff --git a/BizHawk.Client.EmuHawk/BizHawk.Client.EmuHawk.csproj b/BizHawk.Client.EmuHawk/BizHawk.Client.EmuHawk.csproj index 1b30776f00..6623c8199c 100644 --- a/BizHawk.Client.EmuHawk/BizHawk.Client.EmuHawk.csproj +++ b/BizHawk.Client.EmuHawk/BizHawk.Client.EmuHawk.csproj @@ -649,6 +649,7 @@ + diff --git a/BizHawk.Client.EmuHawk/EmuHawkUtil.cs b/BizHawk.Client.EmuHawk/EmuHawkUtil.cs new file mode 100644 index 0000000000..41ed03e16f --- /dev/null +++ b/BizHawk.Client.EmuHawk/EmuHawkUtil.cs @@ -0,0 +1,54 @@ +using System; +using System.Drawing; +using System.Windows.Forms; +using BizHawk.Client.Common; +using BizHawk.Client.EmuHawk.CustomControls; +using BizHawk.Emulation.Common; +using Cores = BizHawk.Emulation.Cores; + +namespace BizHawk.Client.EmuHawk +{ + public static class EmuHawkUtil + { + public static bool EnsureCoreIsAccurate(IEmulator emulator) + { + bool PromptToSwitchCore(string currentCore, string recommendedCore, Action disableCurrentCore) + { + var box = new MsgBox( + $"While the {currentCore} core is faster, it is not nearly as accurate as {recommendedCore}.{Environment.NewLine}It is recommended that you switch to the {recommendedCore} core for movie recording. {Environment.NewLine}Switch to {recommendedCore}?", + "Accuracy Warning", + MessageBoxIcon.Warning); + + box.SetButtons( + new[] { "Switch", "Continue" }, + new[] { DialogResult.Yes, DialogResult.Cancel }); + + box.MaximumSize = UIHelper.Scale(new Size(575, 175)); + box.SetMessageToAutoSize(); + + var result = box.ShowDialog(); + box.Dispose(); + + if (result != DialogResult.Yes) + { + return false; + } + + disableCurrentCore(); + GlobalWin.MainForm.RebootCore(); + return true; + } + + if (emulator is Cores.Nintendo.SNES9X.Snes9x) + { + return PromptToSwitchCore("Snes9x", "bsnes", () => Global.Config.SNES_InSnes9x = false); + } + if (emulator is Cores.Consoles.Nintendo.QuickNES.QuickNES) + { + return PromptToSwitchCore("QuickNes", "NesHawk", () => Global.Config.NES_InQuickNES = false); + } + + return true; + } + } +} diff --git a/BizHawk.Client.EmuHawk/MainForm.Events.cs b/BizHawk.Client.EmuHawk/MainForm.Events.cs index 3a6f38a98a..1f704cf7b6 100644 --- a/BizHawk.Client.EmuHawk/MainForm.Events.cs +++ b/BizHawk.Client.EmuHawk/MainForm.Events.cs @@ -478,55 +478,10 @@ namespace BizHawk.Client.EmuHawk return; } } - else if (Emulator is Snes9x) + + if (!EmuHawkUtil.EnsureCoreIsAccurate(Emulator)) { - var box = new MsgBox( - "While the Snes9x core is faster, it is not nearly as accurate as bsnes. \nIt is recommended that you switch to the bsnes core for movie recording\nSwitch to bsnes?", - "Accuracy Warning", - MessageBoxIcon.Warning); - - box.SetButtons( - new[] { "Switch", "Continue" }, - new[] { DialogResult.Yes, DialogResult.Cancel }); - - box.MaximumSize = UIHelper.Scale(new Size(475, 350)); - box.SetMessageToAutoSize(); - var result = box.ShowDialog(); - - if (result == DialogResult.Yes) - { - Global.Config.SNES_InSnes9x = false; - RebootCore(); - } - else if (result == DialogResult.Cancel) - { - // Do nothing and allow the user to continue to record the movie - } - } - else if (Emulator is QuickNES) // This is unsustainable :( But mixing the logic together is even worse, this needs to be rethought - { - var box = new MsgBox( - "While the QuickNes core is faster, it is not nearly as accurate as NesHawk. \nIt is recommended that you switch to the NesHawk core for movie recording\nSwitch to NesHawk?", - "Accuracy Warning", - MessageBoxIcon.Warning); - - box.SetButtons( - new[] { "Switch", "Continue" }, - new[] { DialogResult.Yes, DialogResult.Cancel }); - - box.MaximumSize = UIHelper.Scale(new Size(475, 350)); - box.SetMessageToAutoSize(); - var result = box.ShowDialog(); - - if (result == DialogResult.Yes) - { - Global.Config.NES_InQuickNES = false; - RebootCore(); - } - else if (result == DialogResult.Cancel) - { - // Do nothing and allow the user to continue to record the movie - } + // Inaccurate core but allow the user to continue anyway } new RecordMovie(Emulator).ShowDialog(); diff --git a/BizHawk.Client.EmuHawk/tools/TAStudio/TAStudio.cs b/BizHawk.Client.EmuHawk/tools/TAStudio/TAStudio.cs index 183b37df89..72eae81252 100644 --- a/BizHawk.Client.EmuHawk/tools/TAStudio/TAStudio.cs +++ b/BizHawk.Client.EmuHawk/tools/TAStudio/TAStudio.cs @@ -1,6 +1,5 @@ using System; using System.Collections.Generic; -using System.Drawing; using System.IO; using System.Linq; using System.Windows.Forms; @@ -8,14 +7,12 @@ using System.ComponentModel; using BizHawk.Emulation.Common; using BizHawk.Emulation.Common.IEmulatorExtensions; -using BizHawk.Emulation.Cores.Nintendo.SNES9X; using BizHawk.Client.Common; using BizHawk.Client.Common.MovieConversionExtensions; using BizHawk.Client.EmuHawk.WinFormExtensions; using BizHawk.Client.EmuHawk.ToolExtensions; -using BizHawk.Emulation.Cores.Consoles.Nintendo.QuickNES; namespace BizHawk.Client.EmuHawk { @@ -320,56 +317,10 @@ namespace BizHawk.Client.EmuHawk Mainform.PauseOnFrame = null; Mainform.PauseEmulator(); - // Start Scenario 0: snes9x needs a nag (copied from RecordMovieMenuItem_Click()) - if (Emulator is Snes9x) + // Start Scenario 0: core needs a nag + if (!EmuHawkUtil.EnsureCoreIsAccurate(Emulator)) { - var box = new CustomControls.MsgBox( - "While the Snes9x core is faster, it is not nearly as accurate as bsnes. \nIt is recommended that you switch to the bsnes core for movie recording\nSwitch to bsnes?", - "Accuracy Warning", - MessageBoxIcon.Warning); - - box.SetButtons( - new[] { "Switch", "Continue" }, - new[] { DialogResult.Yes, DialogResult.Cancel }); - - box.MaximumSize = UIHelper.Scale(new Size(475, 350)); - box.SetMessageToAutoSize(); - var result = box.ShowDialog(); - - if (result == DialogResult.Yes) - { - Global.Config.SNES_InSnes9x = false; - Mainform.RebootCore(); - } - else if (result == DialogResult.Cancel) - { - //return false; - } - } - else if (Emulator is QuickNES) // Copy pasta of unsustainable logic, even better - { - var box = new CustomControls.MsgBox( - "While the QuickNes core is faster, it is not nearly as accurate as NesHawk. \nIt is recommended that you switch to the NesHawk core for movie recording\nSwitch to NesHawk?", - "Accuracy Warning", - MessageBoxIcon.Warning); - - box.SetButtons( - new[] { "Switch", "Continue" }, - new[] { DialogResult.Yes, DialogResult.Cancel }); - - box.MaximumSize = UIHelper.Scale(new Size(475, 350)); - box.SetMessageToAutoSize(); - var result = box.ShowDialog(); - - if (result == DialogResult.Yes) - { - Global.Config.NES_InQuickNES = false; - Mainform.RebootCore(); - } - else if (result == DialogResult.Cancel) - { - //return false; - } + // Inaccurate core but allow the user to continue anyway } // Start Scenario 1: A regular movie is active From 219d0d2e8dbe0ea10e6915e0aa41ffb5c17eebd6 Mon Sep 17 00:00:00 2001 From: "J.D. Purcell" Date: Tue, 22 Oct 2019 09:44:22 -0400 Subject: [PATCH 102/166] Remove old commented code (it got moved to FileLoader 3+ years ago). --- BizHawk.Client.EmuHawk/MainForm.Events.cs | 109 +--------------------- 1 file changed, 1 insertion(+), 108 deletions(-) diff --git a/BizHawk.Client.EmuHawk/MainForm.Events.cs b/BizHawk.Client.EmuHawk/MainForm.Events.cs index 1f704cf7b6..32be86ad9e 100644 --- a/BizHawk.Client.EmuHawk/MainForm.Events.cs +++ b/BizHawk.Client.EmuHawk/MainForm.Events.cs @@ -3252,7 +3252,7 @@ namespace BizHawk.Client.EmuHawk { try { - FormDragDrop_Internal(sender, e); + _FormDragDrop_internal(sender, e); } catch (Exception ex) { @@ -3260,113 +3260,6 @@ namespace BizHawk.Client.EmuHawk } } - private void FormDragDrop_Internal(object sender, DragEventArgs e) - { - _FormDragDrop_internal(sender, e); -/* - var filePaths = (string[])e.Data.GetData(DataFormats.FileDrop); - var isLua = false; - foreach (var path in filePaths) - { - var extension = Path.GetExtension(path); - if (extension != null && extension.ToUpper() == ".LUA") - { - OpenLuaConsole(); - if (GlobalWin.Tools.Has()) - { - GlobalWin.Tools.LuaConsole.LoadLuaFile(path); - } - isLua = true; - } - } - if (isLua) - { - return; - } - - var ext = Path.GetExtension(filePaths[0]) ?? ""; - if (ext.ToUpper() == ".LUASES") - { - OpenLuaConsole(); - if (GlobalWin.Tools.Has()) - { - GlobalWin.Tools.LuaConsole.LoadLuaSession(filePaths[0]); - } - } - else if (MovieService.IsValidMovieExtension(ext)) - { - if (Emulator.IsNull()) - { - OpenRom(); - } - - if (Emulator.IsNull()) - { - return; - } - - StartNewMovie(MovieService.Get(filePaths[0]), false); - } - else if (ext.ToUpper() == ".STATE") - { - LoadState(filePaths[0], Path.GetFileName(filePaths[0])); - } - else if (ext.ToUpper() == ".CHT") - { - Global.CheatList.Load(filePaths[0], false); - GlobalWin.Tools.Load(); - } - else if (ext.ToUpper() == ".WCH") - { - GlobalWin.Tools.LoadRamWatch(true); - (GlobalWin.Tools.Get() as RamWatch).LoadWatchFile(new FileInfo(filePaths[0]), false); - } - - else if (ext.ToUpper() == ".CDL" && Emulator is PCEngine) - { - GlobalWin.Tools.Load(); - (GlobalWin.Tools.Get() as CDL).LoadFile(filePaths[0]); - } - - else if (MovieImport.IsValidMovieExtension(Path.GetExtension(filePaths[0]))) - { - if (Emulator.IsNull()) - { - OpenRom(); - } - - if (Emulator.IsNull()) - { - return; - } - - // tries to open a legacy movie format by importing it - string errorMsg; - string warningMsg; - var movie = MovieImport.ImportFile(filePaths[0], out errorMsg, out warningMsg); - if (!string.IsNullOrEmpty(errorMsg)) - { - MessageBox.Show(errorMsg, "Conversion error", MessageBoxButtons.OK, MessageBoxIcon.Error); - } - else - { - // fix movie extension to something palatable for these purposes. - // for instance, something which doesnt clobber movies you already may have had. - // i'm evenly torn between this, and a file in %TEMP%, but since we dont really have a way to clean up this tempfile, i choose this: - StartNewMovie(movie, false); - } - - GlobalWin.OSD.AddMessage(warningMsg); - } - else - { - var args = new LoadRomArgs(); - args.OpenAdvanced = new OpenAdvanced_OpenRom { Path = filePaths[0] }; - LoadRom(filePaths[0], args); - } - */ - } - #endregion } } From 2054a6b905de2ae1f0d4fd245efb3c3ff6b5c9ee Mon Sep 17 00:00:00 2001 From: "J.D. Purcell" Date: Tue, 22 Oct 2019 11:54:42 -0400 Subject: [PATCH 103/166] RomFilter cleanup. --- .../BizHawk.Client.EmuHawk.csproj | 1 + BizHawk.Client.EmuHawk/FileFilterEntry.cs | 33 ++++++ BizHawk.Client.EmuHawk/FileLoader.cs | 30 +---- BizHawk.Client.EmuHawk/MainForm.cs | 112 ++++++++---------- 4 files changed, 87 insertions(+), 89 deletions(-) create mode 100644 BizHawk.Client.EmuHawk/FileFilterEntry.cs diff --git a/BizHawk.Client.EmuHawk/BizHawk.Client.EmuHawk.csproj b/BizHawk.Client.EmuHawk/BizHawk.Client.EmuHawk.csproj index 6623c8199c..d323d5241f 100644 --- a/BizHawk.Client.EmuHawk/BizHawk.Client.EmuHawk.csproj +++ b/BizHawk.Client.EmuHawk/BizHawk.Client.EmuHawk.csproj @@ -653,6 +653,7 @@ + Form diff --git a/BizHawk.Client.EmuHawk/FileFilterEntry.cs b/BizHawk.Client.EmuHawk/FileFilterEntry.cs new file mode 100644 index 0000000000..9465b9b940 --- /dev/null +++ b/BizHawk.Client.EmuHawk/FileFilterEntry.cs @@ -0,0 +1,33 @@ +using System; +using System.Collections.Generic; +using System.Linq; + +namespace BizHawk.Client.EmuHawk +{ + public class FileFilterEntry + { + public string Description { get; } + public string[] Filters { get; } + public string[] DeveloperFilters { get; } + + public FileFilterEntry(string description, string filters, string developerFilters = null) + { + Description = description; + Filters = filters?.Split(';') ?? Array.Empty(); + DeveloperFilters = developerFilters?.Split(';') ?? Array.Empty(); + } + + public IEnumerable EffectiveFilters + { + get + { + IEnumerable effectiveFilters = Filters; + if (VersionInfo.DeveloperBuild) + { + effectiveFilters = effectiveFilters.Concat(DeveloperFilters); + } + return effectiveFilters; + } + } + } +} diff --git a/BizHawk.Client.EmuHawk/FileLoader.cs b/BizHawk.Client.EmuHawk/FileLoader.cs index 3d49dd87a1..d08f5c693d 100644 --- a/BizHawk.Client.EmuHawk/FileLoader.cs +++ b/BizHawk.Client.EmuHawk/FileLoader.cs @@ -6,7 +6,6 @@ using System.Collections.Generic; using BizHawk.Common; using BizHawk.Emulation.Common.IEmulatorExtensions; -using BizHawk.Emulation.Cores.PCEngine; using BizHawk.Client.Common; namespace BizHawk.Client.EmuHawk @@ -40,31 +39,8 @@ namespace BizHawk.Client.EmuHawk } } - // This is the list from MainForm->RomFilter()'s non-developer build. It needs to be kept up-to-date when new cores are added. - // adelikat: This is annoying and bad. Maybe we could generate RomFilter from this property? - private string[] KnownRomExtensions - { - get - { - if (VersionInfo.DeveloperBuild) - { - return new[] - { - ".NES", ".FDS", ".UNF", ".SMS", ".GG", ".SG", ".GB", ".GBC", ".GBA", ".PCE", ".SGX", ".BIN", ".SMD", ".GEN", ".MD", ".SMC", - ".SFC", ".A26", ".A78", ".LNX", ".COL", ".ROM", ".M3U", ".CUE", ".CCD", ".SGB", ".Z64", ".V64", ".N64", ".WS", ".WSC", ".XML", - ".DSK", ".DO", ".PO", ".PSF", ".MINIPSF", ".NSF", ".EXE", ".PRG", ".D64", ".G64", ".CRT", ".TAP", ".32X", ".MDS", ".TZX", - ".PZX", ".CSW", ".WAV", ".CDT" - }; - } - - return new[] - { - ".NES", ".FDS", ".UNF", ".SMS", ".GG", ".SG", ".GB", ".GBC", ".GBA", ".PCE", ".SGX", ".BIN", ".SMD", ".GEN", ".MD", ".SMC", - ".SFC", ".A26", ".A78", ".LNX", ".COL", ".ROM", ".M3U", ".CUE", ".CCD", ".SGB", ".Z64", ".V64", ".N64", ".WS", ".WSC", ".XML", - ".DSK", ".DO", ".PO", ".PSF", ".MINIPSF", ".NSF", ".PRG", ".D64", ".G64", ".CRT", ".TAP", ".32X", ".MDS", ".TZX", ".PZX", ".CSW", ".WAV" - }; - } - } + private IEnumerable KnownRomExtensions => + RomFilterEntries.SelectMany(f => f.EffectiveFilters.Where(s => s.StartsWith("*.", StringComparison.Ordinal)).Select(s => s.Substring(1).ToUpperInvariant())); private readonly string[] _nonArchive = { ".ISO", ".CUE", ".CCD" }; @@ -173,7 +149,7 @@ namespace BizHawk.Client.EmuHawk { foreach (string file in fileList) { - var ext = Path.GetExtension(file).ToUpper() ?? ""; + var ext = Path.GetExtension(file).ToUpperInvariant() ?? ""; FileInformation fileInformation = new FileInformation(Path.GetDirectoryName(file), Path.GetFileName(file), archive); switch (ext) diff --git a/BizHawk.Client.EmuHawk/MainForm.cs b/BizHawk.Client.EmuHawk/MainForm.cs index ff20280884..d199a789df 100644 --- a/BizHawk.Client.EmuHawk/MainForm.cs +++ b/BizHawk.Client.EmuHawk/MainForm.cs @@ -2120,79 +2120,67 @@ namespace BizHawk.Client.EmuHawk } } - var str = sb.ToString().Replace("%ARCH%", "*.zip;*.rar;*.7z;*.gz"); + var str = sb.ToString().Replace("%ARCH%", ArchiveFilters); str = str.Replace(";", "; "); return str; } + public static FileFilterEntry[] RomFilterEntries { get; } = + { + new FileFilterEntry("Music Files", null, developerFilters: "*.psf;*.minipsf;*.sid;*.nsf"), + new FileFilterEntry("Disc Images", "*.cue;*.ccd;*.mds;*.m3u"), + new FileFilterEntry("NES", "*.nes;*.fds;*.unf;*.nsf;%ARCH%"), + new FileFilterEntry("Super NES", "*.smc;*.sfc;*.xml;%ARCH%"), + new FileFilterEntry("PlayStation", "*.cue;*.ccd;*.mds;*.m3u"), + new FileFilterEntry("PSX Executables (experimental)", null, developerFilters: "*.exe"), + new FileFilterEntry("PSF Playstation Sound File", "*.psf;*.minipsf"), + new FileFilterEntry("Nintendo 64", "*.z64;*.v64;*.n64"), + new FileFilterEntry("Gameboy", "*.gb;*.gbc;*.sgb;%ARCH%"), + new FileFilterEntry("Gameboy Advance", "*.gba;%ARCH%"), + new FileFilterEntry("Master System", "*.sms;*.gg;*.sg;%ARCH%"), + new FileFilterEntry("PC Engine", "*.pce;*.sgx;*.cue;*.ccd;*.mds;%ARCH%"), + new FileFilterEntry("Atari 2600", "*.a26;%ARCH%", developerFilters: "*.bin"), + new FileFilterEntry("Atari 7800", "*.a78;%ARCH%", developerFilters: "*.bin"), + new FileFilterEntry("Atari Lynx", "*.lnx;%ARCH%"), + new FileFilterEntry("Colecovision", "*.col;%ARCH%"), + new FileFilterEntry("Intellivision", "*.int;*.bin;*.rom;%ARCH%"), + new FileFilterEntry("TI-83", "*.rom;%ARCH%"), + new FileFilterEntry("Archive Files", "%ARCH%"), + new FileFilterEntry("Genesis", "*.gen;*.md;*.smd;*.32x;*.bin;*.cue;*.ccd;%ARCH%"), + new FileFilterEntry("SID Commodore 64 Music File", null, developerFilters: "*.sid;%ARCH%"), + new FileFilterEntry("WonderSwan", "*.ws;*.wsc;%ARCH%"), + new FileFilterEntry("Apple II", "*.dsk;*.do;*.po;%ARCH%"), + new FileFilterEntry("Virtual Boy", "*.vb;%ARCH%"), + new FileFilterEntry("Neo Geo Pocket", "*.ngp;*.ngc;%ARCH%"), + new FileFilterEntry("Commodore 64", "*.prg;*.d64;*.g64;*.crt;*.tap;%ARCH%"), + new FileFilterEntry("Amstrad CPC", null, developerFilters: "*.cdt;*.dsk;%ARCH%"), + new FileFilterEntry("Sinclair ZX Spectrum", "*.tzx;*.tap;*.dsk;*.pzx;*.csw;*.wav;%ARCH%") + }; + + public const string ArchiveFilters = "*.zip;*.rar;*.7z;*.gz"; + public static string RomFilter { get { - if (VersionInfo.DeveloperBuild) + string GetRomFilterStrings() { - return FormatFilter( - "Rom Files", "*.nes;*.fds;*.unf;*.sms;*.gg;*.sg;*.pce;*.sgx;*.bin;*.smd;*.rom;*.a26;*.a78;*.lnx;*.m3u;*.cue;*.ccd;*.mds;*.exe;*.gb;*.gbc;*.gba;*.gen;*.md;*.32x;*.col;*.int;*.smc;*.sfc;*.prg;*.d64;*.g64;*.crt;*.tap;*.sgb;*.xml;*.z64;*.v64;*.n64;*.ws;*.wsc;*.dsk;*.do;*.po;*.vb;*.ngp;*.ngc;*.psf;*.minipsf;*.nsf;*.tzx;*.pzx;*.csw;*.wav;*.cdt;%ARCH%", - "Music Files", "*.psf;*.minipsf;*.sid;*.nsf", - "Disc Images", "*.cue;*.ccd;*.mds;*.m3u", - "NES", "*.nes;*.fds;*.unf;*.nsf;%ARCH%", - "Super NES", "*.smc;*.sfc;*.xml;%ARCH%", - "Master System", "*.sms;*.gg;*.sg;%ARCH%", - "PC Engine", "*.pce;*.sgx;*.cue;*.ccd;*.mds;%ARCH%", - "TI-83", "*.rom;%ARCH%", - "Archive Files", "%ARCH%", - "Savestate", "*.state", - "Atari 2600", "*.a26;*.bin;%ARCH%", - "Atari 7800", "*.a78;*.bin;%ARCH%", - "Atari Lynx", "*.lnx;%ARCH%", - "Genesis", "*.gen;*.smd;*.bin;*.md;*.32x;*.cue;*.ccd;%ARCH%", - "Gameboy", "*.gb;*.gbc;*.sgb;%ARCH%", - "Gameboy Advance", "*.gba;%ARCH%", - "Colecovision", "*.col;%ARCH%", - "Intellivision", "*.int;*.bin;*.rom;%ARCH%", - "PlayStation", "*.cue;*.ccd;*.mds;*.m3u", - "PSX Executables (experimental)", "*.exe", - "PSF Playstation Sound File", "*.psf;*.minipsf", - "Commodore 64", "*.prg;*.d64;*.g64;*.crt;*.tap;%ARCH%", - "SID Commodore 64 Music File", "*.sid;%ARCH%", - "Nintendo 64", "*.z64;*.v64;*.n64", - "WonderSwan", "*.ws;*.wsc;%ARCH%", - "Apple II", "*.dsk;*.do;*.po;%ARCH%", - "Virtual Boy", "*.vb;%ARCH%", - "Neo Geo Pocket", "*.ngp;*.ngc;%ARCH%", - "Sinclair ZX Spectrum", "*.tzx;*.tap;*.dsk;*.pzx;*.csw;*.wav;%ARCH%", - "Amstrad CPC", "*.cdt;*.dsk;%ARCH%", - "All Files", "*.*"); + var values = new HashSet(RomFilterEntries.SelectMany(f => f.EffectiveFilters)); + if (values.Remove("%ARCH%")) + { + values.UnionWith(ArchiveFilters.Split(';')); + } + return string.Join(";", values.OrderBy(n => n)); } - return FormatFilter( - "Rom Files", "*.nes;*.fds;*.unf;*.sms;*.gg;*.sg;*.gb;*.gbc;*.gba;*.pce;*.sgx;*.bin;*.smd;*.gen;*.md;*.32x;*.smc;*.sfc;*.a26;*.a78;*.lnx;*.col;*.int;*.rom;*.m3u;*.cue;*.ccd;*.mds;*.sgb;*.z64;*.v64;*.n64;*.ws;*.wsc;*.xml;*.dsk;*.do;*.po;*.psf;*.ngp;*.ngc;*.prg;*.d64;*.g64;*.minipsf;*.nsf;*.tzx;*.pzx;*.csw;*.wav;%ARCH%", - "Disc Images", "*.cue;*.ccd;*.mds;*.m3u", - "NES", "*.nes;*.fds;*.unf;*.nsf;%ARCH%", - "Super NES", "*.smc;*.sfc;*.xml;%ARCH%", - "PlayStation", "*.cue;*.ccd;*.mds;*.m3u", - "PSF Playstation Sound File", "*.psf;*.minipsf", - "Nintendo 64", "*.z64;*.v64;*.n64", - "Gameboy", "*.gb;*.gbc;*.sgb;%ARCH%", - "Gameboy Advance", "*.gba;%ARCH%", - "Master System", "*.sms;*.gg;*.sg;%ARCH%", - "PC Engine", "*.pce;*.sgx;*.cue;*.ccd;*.mds;%ARCH%", - "Atari 2600", "*.a26;%ARCH%", - "Atari 7800", "*.a78;%ARCH%", - "Atari Lynx", "*.lnx;%ARCH%", - "Colecovision", "*.col;%ARCH%", - "Intellivision", "*.int;*.bin;*.rom;%ARCH%", - "TI-83", "*.rom;%ARCH%", - "Archive Files", "%ARCH%", - "Savestate", "*.state", - "Genesis", "*.gen;*.md;*.smd;*.32x;*.bin;*.cue;*.ccd;%ARCH%", - "WonderSwan", "*.ws;*.wsc;%ARCH%", - "Apple II", "*.dsk;*.do;*.po;%ARCH%", - "Virtual Boy", "*.vb;%ARCH%", - "Neo Geo Pocket", "*.ngp;*.ngc;%ARCH%", - "Commodore 64", "*.prg;*.d64;*.g64;*.crt;*.tap;%ARCH%", - "Sinclair ZX Spectrum", "*.tzx;*.tap;*.dsk;*.pzx;*.csw;*.wav;%ARCH%", - "All Files", "*.*"); + var allFilters = new List(); + + allFilters.Add(new FileFilterEntry("Rom Files", GetRomFilterStrings())); + allFilters.AddRange(RomFilterEntries.Where(f => f.EffectiveFilters.Any())); + allFilters.Add(new FileFilterEntry("Savestate", "*.state")); + allFilters.Add(new FileFilterEntry("All Files", "*.*")); + + return FormatFilter(allFilters.SelectMany(f => new[] { f.Description, string.Join(";", f.EffectiveFilters) }).ToArray()); } } From c0e2529b20deaf473f14c2630c06289d56e58c17 Mon Sep 17 00:00:00 2001 From: adelikat Date: Thu, 24 Oct 2019 15:49:23 -0500 Subject: [PATCH 104/166] tastudio - don't nag about inaccurate cores if autoloading a file --- BizHawk.Client.EmuHawk/tools/TAStudio/TAStudio.cs | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/BizHawk.Client.EmuHawk/tools/TAStudio/TAStudio.cs b/BizHawk.Client.EmuHawk/tools/TAStudio/TAStudio.cs index 72eae81252..45c08457ac 100644 --- a/BizHawk.Client.EmuHawk/tools/TAStudio/TAStudio.cs +++ b/BizHawk.Client.EmuHawk/tools/TAStudio/TAStudio.cs @@ -312,13 +312,16 @@ namespace BizHawk.Client.EmuHawk _initialized = true; } + private bool CanAutoload => Settings.RecentTas.AutoLoad && !string.IsNullOrEmpty(Settings.RecentTas.MostRecent); + private bool InitializeOnLoad() { Mainform.PauseOnFrame = null; Mainform.PauseEmulator(); // Start Scenario 0: core needs a nag - if (!EmuHawkUtil.EnsureCoreIsAccurate(Emulator)) + // But do not nag if auto-loading + if (!CanAutoload && !EmuHawkUtil.EnsureCoreIsAccurate(Emulator)) { // Inaccurate core but allow the user to continue anyway } @@ -351,7 +354,7 @@ namespace BizHawk.Client.EmuHawk } // Start Scenario 3: No movie, but user wants to autoload their last project - else if (Settings.RecentTas.AutoLoad && !string.IsNullOrEmpty(Settings.RecentTas.MostRecent)) + else if (CanAutoload) { bool result = LoadFile(new FileInfo(Settings.RecentTas.MostRecent)); if (!result) From 74450ee0a6b1704b3027b38c973bca5c09ac761c Mon Sep 17 00:00:00 2001 From: adelikat Date: Sat, 19 Oct 2019 21:12:29 -0500 Subject: [PATCH 105/166] create an interface for GDIRenderer --- .../BizHawk.Client.EmuHawk.csproj | 3 +- .../{ => ControlRenderer}/GDIRenderer.cs | 1538 ++++++++--------- .../ControlRenderer/IControlRenderer.cs | 28 + .../CustomControls/InputRoll.cs | 2 +- 4 files changed, 800 insertions(+), 771 deletions(-) rename BizHawk.Client.EmuHawk/CustomControls/{ => ControlRenderer}/GDIRenderer.cs (96%) create mode 100644 BizHawk.Client.EmuHawk/CustomControls/ControlRenderer/IControlRenderer.cs diff --git a/BizHawk.Client.EmuHawk/BizHawk.Client.EmuHawk.csproj b/BizHawk.Client.EmuHawk/BizHawk.Client.EmuHawk.csproj index d323d5241f..ff5c3580d8 100644 --- a/BizHawk.Client.EmuHawk/BizHawk.Client.EmuHawk.csproj +++ b/BizHawk.Client.EmuHawk/BizHawk.Client.EmuHawk.csproj @@ -566,6 +566,7 @@ CoreFeatureAnalysis.cs + Form @@ -575,7 +576,7 @@ Component - + Component diff --git a/BizHawk.Client.EmuHawk/CustomControls/GDIRenderer.cs b/BizHawk.Client.EmuHawk/CustomControls/ControlRenderer/GDIRenderer.cs similarity index 96% rename from BizHawk.Client.EmuHawk/CustomControls/GDIRenderer.cs rename to BizHawk.Client.EmuHawk/CustomControls/ControlRenderer/GDIRenderer.cs index 92ef9d86c0..e4548f4cca 100644 --- a/BizHawk.Client.EmuHawk/CustomControls/GDIRenderer.cs +++ b/BizHawk.Client.EmuHawk/CustomControls/ControlRenderer/GDIRenderer.cs @@ -1,769 +1,769 @@ -using System; -using System.Text; -using System.Collections.Generic; -using System.Drawing; -using System.Runtime.InteropServices; - -namespace BizHawk.Client.EmuHawk.CustomControls -{ - ///

- /// Wrapper for GDI rendering functions - /// This class is not thread-safe as GDI functions should be called from the UI thread - /// - public sealed class GDIRenderer : IDisposable - { - /// - /// used for calculation. - /// - private static readonly int[] CharFit = new int[1]; - - /// - /// used for calculation - /// - private static readonly int[] CharFitWidth = new int[1000]; - - /// - /// Cache of all the HFONTs used, rather than create them again and again - /// - private readonly Dictionary FontsCache = new Dictionary(); - - class FontCacheEntry - { - public IntPtr HFont; - } - - /// - /// Cache of all the brushes used, rather than create them again and again - /// - private readonly Dictionary BrushCache = new Dictionary(); - - private Graphics _g; - private IntPtr _hdc; - private IntPtr _currentBrush = IntPtr.Zero; - - #region Construct and Destroy - - public GDIRenderer() - { - //zero 04-16-2016 : this can't be legal, theres no HDC yet - //SetBkMode(_hdc, BkModes.OPAQUE); - } - - public void Dispose() - { - foreach (var brush in BrushCache) - { - if (brush.Value != IntPtr.Zero) - { - DeleteObject(brush.Value); - } - } - - foreach (var fc in FontsCache) - DeleteObject(fc.Value.HFont); - - EndOffScreenBitmap(); - - System.Diagnostics.Debug.Assert(_hdc == IntPtr.Zero, "Disposed a GDIRenderer while it held an HDC"); - System.Diagnostics.Debug.Assert(_g == null, "Disposed a GDIRenderer while it held a Graphics"); - } - - #endregion - - #region Api - - /// - /// Draw a bitmap object at the given position - /// - public void DrawBitmap(Bitmap bitmap, Point point, bool blend = false) - { - IntPtr hbmp = bitmap.GetHbitmap(); - var bitHDC = CreateCompatibleDC(CurrentHDC); - IntPtr old = SelectObject(bitHDC, hbmp); - if (blend) - { - AlphaBlend(CurrentHDC, point.X, point.Y, bitmap.Width, bitmap.Height, bitHDC, 0, 0, bitmap.Width, bitmap.Height, new BLENDFUNCTION(AC_SRC_OVER, 0, 0xff, AC_SRC_ALPHA)); - } - else - { - BitBlt(CurrentHDC, point.X, point.Y, bitmap.Width, bitmap.Height, bitHDC, 0, 0, 0xCC0020); - } - SelectObject(bitHDC, old); - DeleteDC(bitHDC); - DeleteObject(hbmp); - } - - /// - /// Required to use before calling drawing methods - /// - public GdiGraphicsLock LockGraphics(Graphics g) - { - _g = g; - _hdc = g.GetHdc(); - SetBkMode(_hdc, BkModes.TRANSPARENT); - return new GdiGraphicsLock(this); - } - - /// - /// Measure the width and height of string when drawn on device context HDC - /// using the given font - /// - public Size MeasureString(string str, Font font) - { - SetFont(font); - - var size = new Size(); - GetTextExtentPoint32(CurrentHDC, str, str.Length, ref size); - return size; - } - - /// - /// Measure the width and height of string when drawn on device context HDC - /// using the given font - /// Restrict the width of the string and get the number of characters able to fit in the restriction and - /// the width those characters take - /// - /// the max width to render the string in - /// the number of characters that will fit under restriction - public Size MeasureString(string str, Font font, float maxWidth, out int charFit, out int charFitWidth) - { - SetFont(font); - - var size = new Size(); - GetTextExtentExPoint(CurrentHDC, str, str.Length, (int)Math.Round(maxWidth), CharFit, CharFitWidth, ref size); - charFit = CharFit[0]; - charFitWidth = charFit > 0 ? CharFitWidth[charFit - 1] : 0; - return size; - } - - public void DrawString(string str, Point point) - { - TextOut(CurrentHDC, point.X, point.Y, str, str.Length); - } - - public static IntPtr CreateNormalHFont(Font font, int width) - { - LOGFONT logf = new LOGFONT(); - font.ToLogFont(logf); - logf.lfWidth = width; - logf.lfOutPrecision = (byte)FontPrecision.OUT_TT_ONLY_PRECIS; - var ret = CreateFontIndirect(logf); - return ret; - } - - //this returns an IntPtr HFONT because .net's Font class will erase the relevant properties when using its Font.FromLogFont() - //note that whether this is rotated clockwise or CCW might affect how you have to position the text (right-aligned sometimes?, up or down by the height of the font?) - public static IntPtr CreateRotatedHFont(Font font, bool CW) - { - LOGFONT logf = new LOGFONT(); - font.ToLogFont(logf); - logf.lfEscapement = CW ? 2700 : 900; - logf.lfOrientation = logf.lfEscapement; - logf.lfOutPrecision = (byte)FontPrecision.OUT_TT_ONLY_PRECIS; - - //this doesnt work! .net erases the relevant propreties.. it seems? - //return Font.FromLogFont(logf); - - var ret = CreateFontIndirect(logf); - return ret; - } - - public static void DestroyHFont(IntPtr hfont) - { - DeleteObject(hfont); - } - - public void PrepDrawString(IntPtr hfont, Color color) - { - SetGraphicsMode(CurrentHDC, 2); //shouldnt be necessary.. cant hurt - SelectObject(CurrentHDC, hfont); - SetTextColor(color); - } - - public void PrepDrawString(Font font, Color color) - { - SetFont(font); - SetTextColor(color); - } - - - /// - /// Draw the given string using the given font and foreground color at given location - /// See [http://msdn.microsoft.com/en-us/library/windows/desktop/dd162498(v=vs.85).aspx][15] - /// - public void DrawString(string str, Font font, Color color, Rectangle rect, TextFormatFlags flags) - { - SetFont(font); - SetTextColor(color); - - var rect2 = new Rect(rect); - DrawText(CurrentHDC, str, str.Length, ref rect2, (uint)flags); - } - - - /// - /// Set the text color of the device context - /// - public void SetTextColor(Color color) - { - int rgb = (color.B & 0xFF) << 16 | (color.G & 0xFF) << 8 | color.R; - SetTextColor(CurrentHDC, rgb); - } - - public void SetBackgroundColor(Color color) - { - int rgb = (color.B & 0xFF) << 16 | (color.G & 0xFF) << 8 | color.R; - SetBkColor(CurrentHDC, rgb); - } - - public void DrawRectangle(int nLeftRect, int nTopRect, int nRightRect, int nBottomRect) - { - Rectangle(CurrentHDC, nLeftRect, nTopRect, nRightRect, nBottomRect); - } - - public void SetBrush(Color color) - { - if (BrushCache.ContainsKey(color)) - { - _currentBrush = BrushCache[color]; - } - else - { - int rgb = (color.B & 0xFF) << 16 | (color.G & 0xFF) << 8 | color.R; - var newBrush = CreateSolidBrush(rgb); - BrushCache.Add(color, newBrush); - _currentBrush = newBrush; - } - } - - public void FillRectangle(int x, int y, int w, int h) - { - var r = new GDIRect(new Rectangle(x, y, w, h)); - FillRect(CurrentHDC, ref r, _currentBrush); - } - - public void SetPenPosition(int x, int y) - { - MoveToEx(CurrentHDC, x, y, IntPtr.Zero); - } - - public void SetSolidPen(Color color) - { - int rgb = (color.B & 0xFF) << 16 | (color.G & 0xFF) << 8 | color.R; - SelectObject(CurrentHDC, GetStockObject((int)PaintObjects.DC_PEN)); - SetDCPenColor(CurrentHDC, rgb); - } - - public void Line(int x1, int y1, int x2, int y2) - { - MoveToEx(CurrentHDC, x1, y1, IntPtr.Zero); - LineTo(CurrentHDC, x2, y2); - } - - private IntPtr CurrentHDC - { - get { return _bitHDC != IntPtr.Zero ? _bitHDC : _hdc; } - } - - private IntPtr _bitMap = IntPtr.Zero; - private IntPtr _bitHDC = IntPtr.Zero; - private int _bitW; - private int _bitH; - - public void StartOffScreenBitmap(int width, int height) - { - _bitW = width; - _bitH = height; - - _bitHDC = CreateCompatibleDC(_hdc); - _bitMap = CreateCompatibleBitmap(_hdc, width, height); - SelectObject(_bitHDC, _bitMap); - SetBkMode(_bitHDC, BkModes.TRANSPARENT); - } - - public void EndOffScreenBitmap() - { - _bitW = 0; - _bitH = 0; - - DeleteObject(_bitMap); - DeleteObject(_bitHDC); - - _bitHDC = IntPtr.Zero; - _bitMap = IntPtr.Zero; - } - - public void CopyToScreen() - { - BitBlt(_hdc, 0, 0, _bitW, _bitH, _bitHDC, 0, 0, 0x00CC0020); - } - - #endregion - - #region Helpers - - /// - /// Set a resource (e.g. a font) for the specified device context. - /// - private void SetFont(Font font) - { - SelectObject(CurrentHDC, GetCachedHFont(font)); - } - - private IntPtr GetCachedHFont(Font font) - { - //the original code struck me as bad. attempting to ID fonts by picking a subset of their fields is not gonna work. - //don't call this.Font in InputRoll.cs, it is probably slow. - //consider Fonts to be a jealously guarded resource (they need to be disposed, after all) and manage them carefully. - //this cache maintains the HFONTs only. - FontCacheEntry ce; - if (!FontsCache.TryGetValue(font, out ce)) - { - FontsCache[font] = ce = new FontCacheEntry(); - ce.HFont = font.ToHfont(); - } - return ce.HFont; - } - - #endregion - - #region Imports - - [DllImport("user32.dll")] - private static extern int ReleaseDC(IntPtr hWnd, IntPtr hDC); - - [DllImport("user32.dll")] - private static extern IntPtr GetDC(IntPtr hWnd); - - [DllImport("user32.dll")] - private static extern IntPtr BeginPaint(IntPtr hWnd, ref IntPtr lpPaint); - - [DllImport("user32.dll")] - private static extern IntPtr EndPaint(IntPtr hWnd, IntPtr lpPaint); - - [DllImport("gdi32.dll", CharSet = CharSet.Auto)] - private static extern IntPtr CreateFontIndirect( - [In, MarshalAs(UnmanagedType.LPStruct)]LOGFONT lplf - ); - - [DllImport("gdi32.dll")] - private static extern int Rectangle(IntPtr hdc, int nLeftRect, int nTopRect, int nRightRect, int nBottomRect); - - [DllImport("user32.dll")] - private static extern int FillRect(IntPtr hdc, [In] ref GDIRect lprc, IntPtr hbr); - - [DllImport("gdi32.dll")] - private static extern int SetBkMode(IntPtr hdc, BkModes mode); - - [DllImport("gdi32.dll")] - private static extern IntPtr SelectObject(IntPtr hdc, IntPtr hgdiObj); - - [DllImport("gdi32.dll")] - private static extern int SetTextColor(IntPtr hdc, int color); - - [DllImport("gdi32.dll")] - private static extern int SetBkColor(IntPtr hdc, int color); - - [DllImport("gdi32.dll", EntryPoint = "GetTextExtentPoint32W")] - private static extern int GetTextExtentPoint32(IntPtr hdc, [MarshalAs(UnmanagedType.LPWStr)] string str, int len, ref Size size); - - [DllImport("gdi32.dll", EntryPoint = "GetTextExtentExPointW")] - private static extern bool GetTextExtentExPoint(IntPtr hDc, [MarshalAs(UnmanagedType.LPWStr)]string str, int nLength, int nMaxExtent, int[] lpnFit, int[] alpDx, ref Size size); - - [DllImport("gdi32.dll", EntryPoint = "TextOutW")] - private static extern bool TextOut(IntPtr hdc, int x, int y, [MarshalAs(UnmanagedType.LPWStr)] string str, int len); - - [DllImport("gdi32.dll")] - public static extern int SetGraphicsMode(IntPtr hdc, int iMode); - - [DllImport("user32.dll", EntryPoint = "DrawTextW")] - private static extern int DrawText(IntPtr hdc, [MarshalAs(UnmanagedType.LPWStr)] string str, int len, ref Rect rect, uint uFormat); - - [DllImport("gdi32.dll", EntryPoint = "ExtTextOutW")] - private static extern bool ExtTextOut(IntPtr hdc, int X, int Y, uint fuOptions, uint cbCount, [In] IntPtr lpDx); - - [DllImport("gdi32.dll")] - static extern bool SetWorldTransform(IntPtr hdc, [In] ref XFORM lpXform); - - [DllImport("gdi32.dll")] - private static extern int SelectClipRgn(IntPtr hdc, IntPtr hrgn); - - [DllImport("gdi32.dll")] - private static extern bool DeleteObject(IntPtr hObject); - - [DllImport("gdi32.dll")] - private static extern IntPtr CreateSolidBrush(int color); - - [DllImport("gdi32.dll")] - private static extern IntPtr CreatePen(int fnPenStyle, int nWidth, int color); - - [DllImport("gdi32.dll")] - private static extern IntPtr MoveToEx(IntPtr hdc, int x, int y, IntPtr point); - - [DllImport("gdi32.dll")] - private static extern IntPtr LineTo(IntPtr hdc, int nXEnd, int nYEnd); - - [DllImport("gdi32.dll")] - private static extern IntPtr GetStockObject(int fnObject); - - [DllImport("gdi32.dll")] - private static extern IntPtr SetDCPenColor(IntPtr hdc, int crColor); - - [DllImport("gdi32.dll")] - private static extern IntPtr CreateCompatibleDC(IntPtr hdc); - - [DllImport("gdi32.dll", EntryPoint = "DeleteDC")] - public static extern bool DeleteDC([In] IntPtr hdc); - - [DllImport("gdi32.dll")] - private static extern IntPtr CreateCompatibleBitmap(IntPtr hdc, int width, int height); - - [DllImport("gdi32.dll", EntryPoint = "BitBlt", SetLastError = true)] - [return: MarshalAs(UnmanagedType.Bool)] - static extern bool BitBlt([In] IntPtr hdc, int nXDest, int nYDest, int nWidth, int nHeight, [In] IntPtr hdcSrc, int nXSrc, int nYSrc, int dwRop); - - [DllImport("gdi32.dll", EntryPoint = "GdiAlphaBlend")] - static extern bool AlphaBlend(IntPtr hdcDest, int nXOriginDest, int nYOriginDest, int nWidthDest, int nHeightDest, IntPtr hdcSrc, int nXOriginSrc, int nYOriginSrc, int nWidthSrc, int nHeightSrc, BLENDFUNCTION blendFunction); - - public enum FontWeight : int - { - FW_DONTCARE = 0, - FW_THIN = 100, - FW_EXTRALIGHT = 200, - FW_LIGHT = 300, - FW_NORMAL = 400, - FW_MEDIUM = 500, - FW_SEMIBOLD = 600, - FW_BOLD = 700, - FW_EXTRABOLD = 800, - FW_HEAVY = 900, - } - public enum FontCharSet : byte - { - ANSI_CHARSET = 0, - DEFAULT_CHARSET = 1, - SYMBOL_CHARSET = 2, - SHIFTJIS_CHARSET = 128, - HANGEUL_CHARSET = 129, - HANGUL_CHARSET = 129, - GB2312_CHARSET = 134, - CHINESEBIG5_CHARSET = 136, - OEM_CHARSET = 255, - JOHAB_CHARSET = 130, - HEBREW_CHARSET = 177, - ARABIC_CHARSET = 178, - GREEK_CHARSET = 161, - TURKISH_CHARSET = 162, - VIETNAMESE_CHARSET = 163, - THAI_CHARSET = 222, - EASTEUROPE_CHARSET = 238, - RUSSIAN_CHARSET = 204, - MAC_CHARSET = 77, - BALTIC_CHARSET = 186, - } - public enum FontPrecision : byte - { - OUT_DEFAULT_PRECIS = 0, - OUT_STRING_PRECIS = 1, - OUT_CHARACTER_PRECIS = 2, - OUT_STROKE_PRECIS = 3, - OUT_TT_PRECIS = 4, - OUT_DEVICE_PRECIS = 5, - OUT_RASTER_PRECIS = 6, - OUT_TT_ONLY_PRECIS = 7, - OUT_OUTLINE_PRECIS = 8, - OUT_SCREEN_OUTLINE_PRECIS = 9, - OUT_PS_ONLY_PRECIS = 10, - } - public enum FontClipPrecision : byte - { - CLIP_DEFAULT_PRECIS = 0, - CLIP_CHARACTER_PRECIS = 1, - CLIP_STROKE_PRECIS = 2, - CLIP_MASK = 0xf, - CLIP_LH_ANGLES = (1 << 4), - CLIP_TT_ALWAYS = (2 << 4), - CLIP_DFA_DISABLE = (4 << 4), - CLIP_EMBEDDED = (8 << 4), - } - public enum FontQuality : byte - { - DEFAULT_QUALITY = 0, - DRAFT_QUALITY = 1, - PROOF_QUALITY = 2, - NONANTIALIASED_QUALITY = 3, - ANTIALIASED_QUALITY = 4, - CLEARTYPE_QUALITY = 5, - CLEARTYPE_NATURAL_QUALITY = 6, - } - [Flags] - public enum FontPitchAndFamily : byte - { - DEFAULT_PITCH = 0, - FIXED_PITCH = 1, - VARIABLE_PITCH = 2, - FF_DONTCARE = (0 << 4), - FF_ROMAN = (1 << 4), - FF_SWISS = (2 << 4), - FF_MODERN = (3 << 4), - FF_SCRIPT = (4 << 4), - FF_DECORATIVE = (5 << 4), - } - - //it is important for this to be the right declaration - //see more here http://www.tech-archive.net/Archive/DotNet/microsoft.public.dotnet.framework.drawing/2004-04/0319.html - //if it's wrong (I had a wrong one from pinvoke.net) then ToLogFont will fail mysteriously - [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)] - class LOGFONT - { - public int lfHeight = 0; - public int lfWidth = 0; - public int lfEscapement = 0; - public int lfOrientation = 0; - public int lfWeight = 0; - public byte lfItalic = 0; - public byte lfUnderline = 0; - public byte lfStrikeOut = 0; - public byte lfCharSet = 0; - public byte lfOutPrecision = 0; - public byte lfClipPrecision = 0; - public byte lfQuality = 0; - public byte lfPitchAndFamily = 0; - [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 32)] - public string lfFaceName = null; - } - - /// - /// The graphics mode that can be set by SetGraphicsMode. - /// - public enum GraphicsMode : int - { - /// - /// Sets the graphics mode that is compatible with 16-bit Windows. This is the default mode. If - /// this value is specified, the application can only modify the world-to-device transform by - /// calling functions that set window and viewport extents and origins, but not by using - /// SetWorldTransform or ModifyWorldTransform; calls to those functions will fail. - /// Examples of functions that set window and viewport extents and origins are SetViewportExtEx - /// and SetWindowExtEx. - /// - GM_COMPATIBLE = 1, - /// - /// Sets the advanced graphics mode that allows world transformations. This value must be - /// specified if the application will set or modify the world transformation for the specified - /// device context. In this mode all graphics, including text output, fully conform to the - /// world-to-device transformation specified in the device context. - /// - GM_ADVANCED = 2, - } - - /// - /// The XFORM structure specifies a world-space to page-space transformation. - /// - [StructLayout(LayoutKind.Sequential)] - public struct XFORM - { - public float eM11; - public float eM12; - public float eM21; - public float eM22; - public float eDx; - public float eDy; - - public XFORM(float eM11, float eM12, float eM21, float eM22, float eDx, float eDy) - { - this.eM11 = eM11; - this.eM12 = eM12; - this.eM21 = eM21; - this.eM22 = eM22; - this.eDx = eDx; - this.eDy = eDy; - } - - /// - /// Allows implicit converstion to a managed transformation matrix. - /// - public static implicit operator System.Drawing.Drawing2D.Matrix(XFORM xf) - { - return new System.Drawing.Drawing2D.Matrix(xf.eM11, xf.eM12, xf.eM21, xf.eM22, xf.eDx, xf.eDy); - } - - /// - /// Allows implicit converstion from a managed transformation matrix. - /// - public static implicit operator XFORM(System.Drawing.Drawing2D.Matrix m) - { - float[] elems = m.Elements; - return new XFORM(elems[0], elems[1], elems[2], elems[3], elems[4], elems[5]); - } - } - - [StructLayout(LayoutKind.Sequential)] - public struct BLENDFUNCTION - { - byte BlendOp; - byte BlendFlags; - byte SourceConstantAlpha; - byte AlphaFormat; - - public BLENDFUNCTION(byte op, byte flags, byte alpha, byte format) - { - BlendOp = op; - BlendFlags = flags; - SourceConstantAlpha = alpha; - AlphaFormat = format; - } - } - - const byte AC_SRC_OVER = 0x00; - const byte AC_SRC_ALPHA = 0x01; - - [DllImport("gdi32.dll")] - static extern int SetBitmapBits(IntPtr hbmp, uint cBytes, byte[] lpBits); - - #endregion - - #region Classes, Structs, and Enums - - public class GdiGraphicsLock : IDisposable - { - private readonly GDIRenderer Gdi; - - public GdiGraphicsLock(GDIRenderer gdi) - { - this.Gdi = gdi; - } - - public void Dispose() - { - Gdi._g.ReleaseHdc(Gdi._hdc); - Gdi._hdc = IntPtr.Zero; - Gdi._g = null; - } - } - - private struct Rect - { - private int _left; - private int _top; - private int _right; - private int _bottom; - - public Rect(Rectangle r) - { - _left = r.Left; - _top = r.Top; - _bottom = r.Bottom; - _right = r.Right; - } - } - - private struct GDIRect - { - private int left; - private int top; - private int right; - private int bottom; - - public GDIRect(Rectangle r) - { - left = r.Left; - top = r.Top; - bottom = r.Bottom; - right = r.Right; - } - } - - private struct GDIPoint - { - private int x; - private int y; - - private GDIPoint(int x, int y) - { - this.x = x; - this.y = y; - } - } - - [Flags] - public enum ETOOptions : uint - { - CLIPPED = 0x4, - GLYPH_INDEX = 0x10, - IGNORELANGUAGE = 0x1000, - NUMERICSLATIN = 0x800, - NUMERICSLOCAL = 0x400, - OPAQUE = 0x2, - PDY = 0x2000, - RTLREADING = 0x800, - } - - /// - /// See [http://msdn.microsoft.com/en-us/library/windows/desktop/dd162498(v=vs.85).aspx][15] - /// - [Flags] - public enum TextFormatFlags : uint - { - Default = 0x00000000, - Center = 0x00000001, - Right = 0x00000002, - VCenter = 0x00000004, - Bottom = 0x00000008, - WordBreak = 0x00000010, - SingleLine = 0x00000020, - ExpandTabs = 0x00000040, - TabStop = 0x00000080, - NoClip = 0x00000100, - ExternalLeading = 0x00000200, - CalcRect = 0x00000400, - NoPrefix = 0x00000800, - Internal = 0x00001000, - EditControl = 0x00002000, - PathEllipsis = 0x00004000, - EndEllipsis = 0x00008000, - ModifyString = 0x00010000, - RtlReading = 0x00020000, - WordEllipsis = 0x00040000, - NoFullWidthCharBreak = 0x00080000, - HidePrefix = 0x00100000, - ProfixOnly = 0x00200000, - } - - [Flags] - public enum PenStyles - { - PS_SOLID = 0x00000000 - // TODO - } - - public enum PaintObjects - { - WHITE_BRUSH = 0, - LTGRAY_BRUSH = 1, - GRAY_BRUSH = 2, - DKGRAY_BRUSH = 3, - BLACK_BRUSH = 4, - NULL_BRUSH = 5, - WHITE_PEN = 6, - BLACK_PEN = 7, - NULL_PEN = 8, - OEM_FIXED_FONT = 10, - ANSI_FIXED_FONT = 11, - ANSI_VAR_FONT = 12, - SYSTEM_FONT = 13, - DEVICE_DEFAULT_FONT = 14, - DEFAULT_PALETTE = 15, - SYSTEM_FIXED_FONT = 16, - DC_BRUSH = 18, - DC_PEN = 19, - } - - public enum BkModes : int - { - TRANSPARENT = 1, - OPAQUE = 2 - } - - #endregion - } -} +using System; +using System.Text; +using System.Collections.Generic; +using System.Drawing; +using System.Runtime.InteropServices; + +namespace BizHawk.Client.EmuHawk.CustomControls +{ + /// + /// Wrapper for GDI rendering functions + /// This class is not thread-safe as GDI functions should be called from the UI thread + /// + public sealed class GDIRenderer : IControlRenderer + { + /// + /// used for calculation. + /// + private static readonly int[] CharFit = new int[1]; + + /// + /// used for calculation + /// + private static readonly int[] CharFitWidth = new int[1000]; + + /// + /// Cache of all the HFONTs used, rather than create them again and again + /// + private readonly Dictionary FontsCache = new Dictionary(); + + class FontCacheEntry + { + public IntPtr HFont; + } + + /// + /// Cache of all the brushes used, rather than create them again and again + /// + private readonly Dictionary BrushCache = new Dictionary(); + + private Graphics _g; + private IntPtr _hdc; + private IntPtr _currentBrush = IntPtr.Zero; + + #region Construct and Destroy + + public GDIRenderer() + { + //zero 04-16-2016 : this can't be legal, theres no HDC yet + //SetBkMode(_hdc, BkModes.OPAQUE); + } + + public void Dispose() + { + foreach (var brush in BrushCache) + { + if (brush.Value != IntPtr.Zero) + { + DeleteObject(brush.Value); + } + } + + foreach (var fc in FontsCache) + DeleteObject(fc.Value.HFont); + + EndOffScreenBitmap(); + + System.Diagnostics.Debug.Assert(_hdc == IntPtr.Zero, "Disposed a GDIRenderer while it held an HDC"); + System.Diagnostics.Debug.Assert(_g == null, "Disposed a GDIRenderer while it held a Graphics"); + } + + #endregion + + #region Api + + /// + /// Draw a bitmap object at the given position + /// + public void DrawBitmap(Bitmap bitmap, Point point, bool blend = false) + { + IntPtr hbmp = bitmap.GetHbitmap(); + var bitHDC = CreateCompatibleDC(CurrentHDC); + IntPtr old = SelectObject(bitHDC, hbmp); + if (blend) + { + AlphaBlend(CurrentHDC, point.X, point.Y, bitmap.Width, bitmap.Height, bitHDC, 0, 0, bitmap.Width, bitmap.Height, new BLENDFUNCTION(AC_SRC_OVER, 0, 0xff, AC_SRC_ALPHA)); + } + else + { + BitBlt(CurrentHDC, point.X, point.Y, bitmap.Width, bitmap.Height, bitHDC, 0, 0, 0xCC0020); + } + SelectObject(bitHDC, old); + DeleteDC(bitHDC); + DeleteObject(hbmp); + } + + /// + /// Required to use before calling drawing methods + /// + public IDisposable LockGraphics(Graphics g) + { + _g = g; + _hdc = g.GetHdc(); + SetBkMode(_hdc, BkModes.TRANSPARENT); + return new GdiGraphicsLock(this); + } + + /// + /// Measure the width and height of string when drawn on device context HDC + /// using the given font + /// + public Size MeasureString(string str, Font font) + { + SetFont(font); + + var size = new Size(); + GetTextExtentPoint32(CurrentHDC, str, str.Length, ref size); + return size; + } + + /// + /// Measure the width and height of string when drawn on device context HDC + /// using the given font + /// Restrict the width of the string and get the number of characters able to fit in the restriction and + /// the width those characters take + /// + /// the max width to render the string in + /// the number of characters that will fit under restriction + public Size MeasureString(string str, Font font, float maxWidth, out int charFit, out int charFitWidth) + { + SetFont(font); + + var size = new Size(); + GetTextExtentExPoint(CurrentHDC, str, str.Length, (int)Math.Round(maxWidth), CharFit, CharFitWidth, ref size); + charFit = CharFit[0]; + charFitWidth = charFit > 0 ? CharFitWidth[charFit - 1] : 0; + return size; + } + + public void DrawString(string str, Point point) + { + TextOut(CurrentHDC, point.X, point.Y, str, str.Length); + } + + public static IntPtr CreateNormalHFont(Font font, int width) + { + LOGFONT logf = new LOGFONT(); + font.ToLogFont(logf); + logf.lfWidth = width; + logf.lfOutPrecision = (byte)FontPrecision.OUT_TT_ONLY_PRECIS; + var ret = CreateFontIndirect(logf); + return ret; + } + + //this returns an IntPtr HFONT because .net's Font class will erase the relevant properties when using its Font.FromLogFont() + //note that whether this is rotated clockwise or CCW might affect how you have to position the text (right-aligned sometimes?, up or down by the height of the font?) + public static IntPtr CreateRotatedHFont(Font font, bool CW) + { + LOGFONT logf = new LOGFONT(); + font.ToLogFont(logf); + logf.lfEscapement = CW ? 2700 : 900; + logf.lfOrientation = logf.lfEscapement; + logf.lfOutPrecision = (byte)FontPrecision.OUT_TT_ONLY_PRECIS; + + //this doesnt work! .net erases the relevant propreties.. it seems? + //return Font.FromLogFont(logf); + + var ret = CreateFontIndirect(logf); + return ret; + } + + public static void DestroyHFont(IntPtr hfont) + { + DeleteObject(hfont); + } + + public void PrepDrawString(IntPtr hfont, Color color) + { + SetGraphicsMode(CurrentHDC, 2); //shouldnt be necessary.. cant hurt + SelectObject(CurrentHDC, hfont); + SetTextColor(color); + } + + public void PrepDrawString(Font font, Color color) + { + SetFont(font); + SetTextColor(color); + } + + + /// + /// Draw the given string using the given font and foreground color at given location + /// See [http://msdn.microsoft.com/en-us/library/windows/desktop/dd162498(v=vs.85).aspx][15] + /// + public void DrawString(string str, Font font, Color color, Rectangle rect, TextFormatFlags flags) + { + SetFont(font); + SetTextColor(color); + + var rect2 = new Rect(rect); + DrawText(CurrentHDC, str, str.Length, ref rect2, (uint)flags); + } + + + /// + /// Set the text color of the device context + /// + public void SetTextColor(Color color) + { + int rgb = (color.B & 0xFF) << 16 | (color.G & 0xFF) << 8 | color.R; + SetTextColor(CurrentHDC, rgb); + } + + public void SetBackgroundColor(Color color) + { + int rgb = (color.B & 0xFF) << 16 | (color.G & 0xFF) << 8 | color.R; + SetBkColor(CurrentHDC, rgb); + } + + public void DrawRectangle(int nLeftRect, int nTopRect, int nRightRect, int nBottomRect) + { + Rectangle(CurrentHDC, nLeftRect, nTopRect, nRightRect, nBottomRect); + } + + public void SetBrush(Color color) + { + if (BrushCache.ContainsKey(color)) + { + _currentBrush = BrushCache[color]; + } + else + { + int rgb = (color.B & 0xFF) << 16 | (color.G & 0xFF) << 8 | color.R; + var newBrush = CreateSolidBrush(rgb); + BrushCache.Add(color, newBrush); + _currentBrush = newBrush; + } + } + + public void FillRectangle(int x, int y, int w, int h) + { + var r = new GDIRect(new Rectangle(x, y, w, h)); + FillRect(CurrentHDC, ref r, _currentBrush); + } + + public void SetPenPosition(int x, int y) + { + MoveToEx(CurrentHDC, x, y, IntPtr.Zero); + } + + public void SetSolidPen(Color color) + { + int rgb = (color.B & 0xFF) << 16 | (color.G & 0xFF) << 8 | color.R; + SelectObject(CurrentHDC, GetStockObject((int)PaintObjects.DC_PEN)); + SetDCPenColor(CurrentHDC, rgb); + } + + public void Line(int x1, int y1, int x2, int y2) + { + MoveToEx(CurrentHDC, x1, y1, IntPtr.Zero); + LineTo(CurrentHDC, x2, y2); + } + + private IntPtr CurrentHDC + { + get { return _bitHDC != IntPtr.Zero ? _bitHDC : _hdc; } + } + + private IntPtr _bitMap = IntPtr.Zero; + private IntPtr _bitHDC = IntPtr.Zero; + private int _bitW; + private int _bitH; + + public void StartOffScreenBitmap(int width, int height) + { + _bitW = width; + _bitH = height; + + _bitHDC = CreateCompatibleDC(_hdc); + _bitMap = CreateCompatibleBitmap(_hdc, width, height); + SelectObject(_bitHDC, _bitMap); + SetBkMode(_bitHDC, BkModes.TRANSPARENT); + } + + public void EndOffScreenBitmap() + { + _bitW = 0; + _bitH = 0; + + DeleteObject(_bitMap); + DeleteObject(_bitHDC); + + _bitHDC = IntPtr.Zero; + _bitMap = IntPtr.Zero; + } + + public void CopyToScreen() + { + BitBlt(_hdc, 0, 0, _bitW, _bitH, _bitHDC, 0, 0, 0x00CC0020); + } + + #endregion + + #region Helpers + + /// + /// Set a resource (e.g. a font) for the specified device context. + /// + private void SetFont(Font font) + { + SelectObject(CurrentHDC, GetCachedHFont(font)); + } + + private IntPtr GetCachedHFont(Font font) + { + //the original code struck me as bad. attempting to ID fonts by picking a subset of their fields is not gonna work. + //don't call this.Font in InputRoll.cs, it is probably slow. + //consider Fonts to be a jealously guarded resource (they need to be disposed, after all) and manage them carefully. + //this cache maintains the HFONTs only. + FontCacheEntry ce; + if (!FontsCache.TryGetValue(font, out ce)) + { + FontsCache[font] = ce = new FontCacheEntry(); + ce.HFont = font.ToHfont(); + } + return ce.HFont; + } + + #endregion + + #region Imports + + [DllImport("user32.dll")] + private static extern int ReleaseDC(IntPtr hWnd, IntPtr hDC); + + [DllImport("user32.dll")] + private static extern IntPtr GetDC(IntPtr hWnd); + + [DllImport("user32.dll")] + private static extern IntPtr BeginPaint(IntPtr hWnd, ref IntPtr lpPaint); + + [DllImport("user32.dll")] + private static extern IntPtr EndPaint(IntPtr hWnd, IntPtr lpPaint); + + [DllImport("gdi32.dll", CharSet = CharSet.Auto)] + private static extern IntPtr CreateFontIndirect( + [In, MarshalAs(UnmanagedType.LPStruct)]LOGFONT lplf + ); + + [DllImport("gdi32.dll")] + private static extern int Rectangle(IntPtr hdc, int nLeftRect, int nTopRect, int nRightRect, int nBottomRect); + + [DllImport("user32.dll")] + private static extern int FillRect(IntPtr hdc, [In] ref GDIRect lprc, IntPtr hbr); + + [DllImport("gdi32.dll")] + private static extern int SetBkMode(IntPtr hdc, BkModes mode); + + [DllImport("gdi32.dll")] + private static extern IntPtr SelectObject(IntPtr hdc, IntPtr hgdiObj); + + [DllImport("gdi32.dll")] + private static extern int SetTextColor(IntPtr hdc, int color); + + [DllImport("gdi32.dll")] + private static extern int SetBkColor(IntPtr hdc, int color); + + [DllImport("gdi32.dll", EntryPoint = "GetTextExtentPoint32W")] + private static extern int GetTextExtentPoint32(IntPtr hdc, [MarshalAs(UnmanagedType.LPWStr)] string str, int len, ref Size size); + + [DllImport("gdi32.dll", EntryPoint = "GetTextExtentExPointW")] + private static extern bool GetTextExtentExPoint(IntPtr hDc, [MarshalAs(UnmanagedType.LPWStr)]string str, int nLength, int nMaxExtent, int[] lpnFit, int[] alpDx, ref Size size); + + [DllImport("gdi32.dll", EntryPoint = "TextOutW")] + private static extern bool TextOut(IntPtr hdc, int x, int y, [MarshalAs(UnmanagedType.LPWStr)] string str, int len); + + [DllImport("gdi32.dll")] + public static extern int SetGraphicsMode(IntPtr hdc, int iMode); + + [DllImport("user32.dll", EntryPoint = "DrawTextW")] + private static extern int DrawText(IntPtr hdc, [MarshalAs(UnmanagedType.LPWStr)] string str, int len, ref Rect rect, uint uFormat); + + [DllImport("gdi32.dll", EntryPoint = "ExtTextOutW")] + private static extern bool ExtTextOut(IntPtr hdc, int X, int Y, uint fuOptions, uint cbCount, [In] IntPtr lpDx); + + [DllImport("gdi32.dll")] + static extern bool SetWorldTransform(IntPtr hdc, [In] ref XFORM lpXform); + + [DllImport("gdi32.dll")] + private static extern int SelectClipRgn(IntPtr hdc, IntPtr hrgn); + + [DllImport("gdi32.dll")] + private static extern bool DeleteObject(IntPtr hObject); + + [DllImport("gdi32.dll")] + private static extern IntPtr CreateSolidBrush(int color); + + [DllImport("gdi32.dll")] + private static extern IntPtr CreatePen(int fnPenStyle, int nWidth, int color); + + [DllImport("gdi32.dll")] + private static extern IntPtr MoveToEx(IntPtr hdc, int x, int y, IntPtr point); + + [DllImport("gdi32.dll")] + private static extern IntPtr LineTo(IntPtr hdc, int nXEnd, int nYEnd); + + [DllImport("gdi32.dll")] + private static extern IntPtr GetStockObject(int fnObject); + + [DllImport("gdi32.dll")] + private static extern IntPtr SetDCPenColor(IntPtr hdc, int crColor); + + [DllImport("gdi32.dll")] + private static extern IntPtr CreateCompatibleDC(IntPtr hdc); + + [DllImport("gdi32.dll", EntryPoint = "DeleteDC")] + public static extern bool DeleteDC([In] IntPtr hdc); + + [DllImport("gdi32.dll")] + private static extern IntPtr CreateCompatibleBitmap(IntPtr hdc, int width, int height); + + [DllImport("gdi32.dll", EntryPoint = "BitBlt", SetLastError = true)] + [return: MarshalAs(UnmanagedType.Bool)] + static extern bool BitBlt([In] IntPtr hdc, int nXDest, int nYDest, int nWidth, int nHeight, [In] IntPtr hdcSrc, int nXSrc, int nYSrc, int dwRop); + + [DllImport("gdi32.dll", EntryPoint = "GdiAlphaBlend")] + static extern bool AlphaBlend(IntPtr hdcDest, int nXOriginDest, int nYOriginDest, int nWidthDest, int nHeightDest, IntPtr hdcSrc, int nXOriginSrc, int nYOriginSrc, int nWidthSrc, int nHeightSrc, BLENDFUNCTION blendFunction); + + public enum FontWeight : int + { + FW_DONTCARE = 0, + FW_THIN = 100, + FW_EXTRALIGHT = 200, + FW_LIGHT = 300, + FW_NORMAL = 400, + FW_MEDIUM = 500, + FW_SEMIBOLD = 600, + FW_BOLD = 700, + FW_EXTRABOLD = 800, + FW_HEAVY = 900, + } + public enum FontCharSet : byte + { + ANSI_CHARSET = 0, + DEFAULT_CHARSET = 1, + SYMBOL_CHARSET = 2, + SHIFTJIS_CHARSET = 128, + HANGEUL_CHARSET = 129, + HANGUL_CHARSET = 129, + GB2312_CHARSET = 134, + CHINESEBIG5_CHARSET = 136, + OEM_CHARSET = 255, + JOHAB_CHARSET = 130, + HEBREW_CHARSET = 177, + ARABIC_CHARSET = 178, + GREEK_CHARSET = 161, + TURKISH_CHARSET = 162, + VIETNAMESE_CHARSET = 163, + THAI_CHARSET = 222, + EASTEUROPE_CHARSET = 238, + RUSSIAN_CHARSET = 204, + MAC_CHARSET = 77, + BALTIC_CHARSET = 186, + } + public enum FontPrecision : byte + { + OUT_DEFAULT_PRECIS = 0, + OUT_STRING_PRECIS = 1, + OUT_CHARACTER_PRECIS = 2, + OUT_STROKE_PRECIS = 3, + OUT_TT_PRECIS = 4, + OUT_DEVICE_PRECIS = 5, + OUT_RASTER_PRECIS = 6, + OUT_TT_ONLY_PRECIS = 7, + OUT_OUTLINE_PRECIS = 8, + OUT_SCREEN_OUTLINE_PRECIS = 9, + OUT_PS_ONLY_PRECIS = 10, + } + public enum FontClipPrecision : byte + { + CLIP_DEFAULT_PRECIS = 0, + CLIP_CHARACTER_PRECIS = 1, + CLIP_STROKE_PRECIS = 2, + CLIP_MASK = 0xf, + CLIP_LH_ANGLES = (1 << 4), + CLIP_TT_ALWAYS = (2 << 4), + CLIP_DFA_DISABLE = (4 << 4), + CLIP_EMBEDDED = (8 << 4), + } + public enum FontQuality : byte + { + DEFAULT_QUALITY = 0, + DRAFT_QUALITY = 1, + PROOF_QUALITY = 2, + NONANTIALIASED_QUALITY = 3, + ANTIALIASED_QUALITY = 4, + CLEARTYPE_QUALITY = 5, + CLEARTYPE_NATURAL_QUALITY = 6, + } + [Flags] + public enum FontPitchAndFamily : byte + { + DEFAULT_PITCH = 0, + FIXED_PITCH = 1, + VARIABLE_PITCH = 2, + FF_DONTCARE = (0 << 4), + FF_ROMAN = (1 << 4), + FF_SWISS = (2 << 4), + FF_MODERN = (3 << 4), + FF_SCRIPT = (4 << 4), + FF_DECORATIVE = (5 << 4), + } + + //it is important for this to be the right declaration + //see more here http://www.tech-archive.net/Archive/DotNet/microsoft.public.dotnet.framework.drawing/2004-04/0319.html + //if it's wrong (I had a wrong one from pinvoke.net) then ToLogFont will fail mysteriously + [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)] + class LOGFONT + { + public int lfHeight = 0; + public int lfWidth = 0; + public int lfEscapement = 0; + public int lfOrientation = 0; + public int lfWeight = 0; + public byte lfItalic = 0; + public byte lfUnderline = 0; + public byte lfStrikeOut = 0; + public byte lfCharSet = 0; + public byte lfOutPrecision = 0; + public byte lfClipPrecision = 0; + public byte lfQuality = 0; + public byte lfPitchAndFamily = 0; + [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 32)] + public string lfFaceName = null; + } + + /// + /// The graphics mode that can be set by SetGraphicsMode. + /// + public enum GraphicsMode : int + { + /// + /// Sets the graphics mode that is compatible with 16-bit Windows. This is the default mode. If + /// this value is specified, the application can only modify the world-to-device transform by + /// calling functions that set window and viewport extents and origins, but not by using + /// SetWorldTransform or ModifyWorldTransform; calls to those functions will fail. + /// Examples of functions that set window and viewport extents and origins are SetViewportExtEx + /// and SetWindowExtEx. + /// + GM_COMPATIBLE = 1, + /// + /// Sets the advanced graphics mode that allows world transformations. This value must be + /// specified if the application will set or modify the world transformation for the specified + /// device context. In this mode all graphics, including text output, fully conform to the + /// world-to-device transformation specified in the device context. + /// + GM_ADVANCED = 2, + } + + /// + /// The XFORM structure specifies a world-space to page-space transformation. + /// + [StructLayout(LayoutKind.Sequential)] + public struct XFORM + { + public float eM11; + public float eM12; + public float eM21; + public float eM22; + public float eDx; + public float eDy; + + public XFORM(float eM11, float eM12, float eM21, float eM22, float eDx, float eDy) + { + this.eM11 = eM11; + this.eM12 = eM12; + this.eM21 = eM21; + this.eM22 = eM22; + this.eDx = eDx; + this.eDy = eDy; + } + + /// + /// Allows implicit converstion to a managed transformation matrix. + /// + public static implicit operator System.Drawing.Drawing2D.Matrix(XFORM xf) + { + return new System.Drawing.Drawing2D.Matrix(xf.eM11, xf.eM12, xf.eM21, xf.eM22, xf.eDx, xf.eDy); + } + + /// + /// Allows implicit converstion from a managed transformation matrix. + /// + public static implicit operator XFORM(System.Drawing.Drawing2D.Matrix m) + { + float[] elems = m.Elements; + return new XFORM(elems[0], elems[1], elems[2], elems[3], elems[4], elems[5]); + } + } + + [StructLayout(LayoutKind.Sequential)] + public struct BLENDFUNCTION + { + byte BlendOp; + byte BlendFlags; + byte SourceConstantAlpha; + byte AlphaFormat; + + public BLENDFUNCTION(byte op, byte flags, byte alpha, byte format) + { + BlendOp = op; + BlendFlags = flags; + SourceConstantAlpha = alpha; + AlphaFormat = format; + } + } + + const byte AC_SRC_OVER = 0x00; + const byte AC_SRC_ALPHA = 0x01; + + [DllImport("gdi32.dll")] + static extern int SetBitmapBits(IntPtr hbmp, uint cBytes, byte[] lpBits); + + #endregion + + #region Classes, Structs, and Enums + + public class GdiGraphicsLock : IDisposable + { + private readonly GDIRenderer Gdi; + + public GdiGraphicsLock(GDIRenderer gdi) + { + this.Gdi = gdi; + } + + public void Dispose() + { + Gdi._g.ReleaseHdc(Gdi._hdc); + Gdi._hdc = IntPtr.Zero; + Gdi._g = null; + } + } + + private struct Rect + { + private int _left; + private int _top; + private int _right; + private int _bottom; + + public Rect(Rectangle r) + { + _left = r.Left; + _top = r.Top; + _bottom = r.Bottom; + _right = r.Right; + } + } + + private struct GDIRect + { + private int left; + private int top; + private int right; + private int bottom; + + public GDIRect(Rectangle r) + { + left = r.Left; + top = r.Top; + bottom = r.Bottom; + right = r.Right; + } + } + + private struct GDIPoint + { + private int x; + private int y; + + private GDIPoint(int x, int y) + { + this.x = x; + this.y = y; + } + } + + [Flags] + public enum ETOOptions : uint + { + CLIPPED = 0x4, + GLYPH_INDEX = 0x10, + IGNORELANGUAGE = 0x1000, + NUMERICSLATIN = 0x800, + NUMERICSLOCAL = 0x400, + OPAQUE = 0x2, + PDY = 0x2000, + RTLREADING = 0x800, + } + + /// + /// See [http://msdn.microsoft.com/en-us/library/windows/desktop/dd162498(v=vs.85).aspx][15] + /// + [Flags] + public enum TextFormatFlags : uint + { + Default = 0x00000000, + Center = 0x00000001, + Right = 0x00000002, + VCenter = 0x00000004, + Bottom = 0x00000008, + WordBreak = 0x00000010, + SingleLine = 0x00000020, + ExpandTabs = 0x00000040, + TabStop = 0x00000080, + NoClip = 0x00000100, + ExternalLeading = 0x00000200, + CalcRect = 0x00000400, + NoPrefix = 0x00000800, + Internal = 0x00001000, + EditControl = 0x00002000, + PathEllipsis = 0x00004000, + EndEllipsis = 0x00008000, + ModifyString = 0x00010000, + RtlReading = 0x00020000, + WordEllipsis = 0x00040000, + NoFullWidthCharBreak = 0x00080000, + HidePrefix = 0x00100000, + ProfixOnly = 0x00200000, + } + + [Flags] + public enum PenStyles + { + PS_SOLID = 0x00000000 + // TODO + } + + public enum PaintObjects + { + WHITE_BRUSH = 0, + LTGRAY_BRUSH = 1, + GRAY_BRUSH = 2, + DKGRAY_BRUSH = 3, + BLACK_BRUSH = 4, + NULL_BRUSH = 5, + WHITE_PEN = 6, + BLACK_PEN = 7, + NULL_PEN = 8, + OEM_FIXED_FONT = 10, + ANSI_FIXED_FONT = 11, + ANSI_VAR_FONT = 12, + SYSTEM_FONT = 13, + DEVICE_DEFAULT_FONT = 14, + DEFAULT_PALETTE = 15, + SYSTEM_FIXED_FONT = 16, + DC_BRUSH = 18, + DC_PEN = 19, + } + + public enum BkModes : int + { + TRANSPARENT = 1, + OPAQUE = 2 + } + + #endregion + } +} diff --git a/BizHawk.Client.EmuHawk/CustomControls/ControlRenderer/IControlRenderer.cs b/BizHawk.Client.EmuHawk/CustomControls/ControlRenderer/IControlRenderer.cs new file mode 100644 index 0000000000..e3c232113c --- /dev/null +++ b/BizHawk.Client.EmuHawk/CustomControls/ControlRenderer/IControlRenderer.cs @@ -0,0 +1,28 @@ +using System; +using System.Drawing; + +namespace BizHawk.Client.EmuHawk.CustomControls +{ + public interface IControlRenderer : IDisposable + { + IDisposable LockGraphics(Graphics g); + + void StartOffScreenBitmap(int width, int height); + void EndOffScreenBitmap(); + void CopyToScreen(); + + Size MeasureString(string str, Font font); + + void SetBrush(Color color); + void SetSolidPen(Color color); + + // TODO: use the Font version + void PrepDrawString(IntPtr hFont, Color color); + void DrawString(string str, Point point); + + void DrawRectangle(int nLeftRect, int nTopRect, int nRightRect, int nBottomRect); + void FillRectangle(int x, int y, int w, int h); + void DrawBitmap(Bitmap bitmap, Point point, bool blend = false); + void Line(int x1, int y1, int x2, int y2); + } +} diff --git a/BizHawk.Client.EmuHawk/CustomControls/InputRoll.cs b/BizHawk.Client.EmuHawk/CustomControls/InputRoll.cs index fabf42d68e..9525cbb9ea 100644 --- a/BizHawk.Client.EmuHawk/CustomControls/InputRoll.cs +++ b/BizHawk.Client.EmuHawk/CustomControls/InputRoll.cs @@ -15,7 +15,7 @@ namespace BizHawk.Client.EmuHawk // Row width is specified for horizontal orientation public partial class InputRoll : Control { - private readonly GDIRenderer _gdi; + private readonly IControlRenderer _gdi; private readonly SortedSet _selectedItems = new SortedSet(new SortCell()); private readonly VScrollBar _vBar; From 0a7db2ad4dd251fbe9f58bd13e325ea8b7bf5f91 Mon Sep 17 00:00:00 2001 From: adelikat Date: Sat, 19 Oct 2019 21:38:30 -0500 Subject: [PATCH 106/166] cleanup GDI Renderer --- .../ControlRenderer/GDIRenderer.cs | 446 ++++-------------- .../ControlRenderer/IControlRenderer.cs | 15 + .../CustomControls/HexView.cs | 4 +- .../CustomControls/InputRoll.cs | 10 +- 4 files changed, 112 insertions(+), 363 deletions(-) diff --git a/BizHawk.Client.EmuHawk/CustomControls/ControlRenderer/GDIRenderer.cs b/BizHawk.Client.EmuHawk/CustomControls/ControlRenderer/GDIRenderer.cs index e4548f4cca..b2cef5ad9f 100644 --- a/BizHawk.Client.EmuHawk/CustomControls/ControlRenderer/GDIRenderer.cs +++ b/BizHawk.Client.EmuHawk/CustomControls/ControlRenderer/GDIRenderer.cs @@ -1,5 +1,4 @@ using System; -using System.Text; using System.Collections.Generic; using System.Drawing; using System.Runtime.InteropServices; @@ -10,32 +9,18 @@ namespace BizHawk.Client.EmuHawk.CustomControls /// Wrapper for GDI rendering functions /// This class is not thread-safe as GDI functions should be called from the UI thread /// - public sealed class GDIRenderer : IControlRenderer + public sealed class GdiRenderer : IControlRenderer { - /// - /// used for calculation. - /// - private static readonly int[] CharFit = new int[1]; + // Cache of all the Fonts used, rather than create them again and again + private readonly Dictionary _fontsCache = new Dictionary(); - /// - /// used for calculation - /// - private static readonly int[] CharFitWidth = new int[1000]; - - /// - /// Cache of all the HFONTs used, rather than create them again and again - /// - private readonly Dictionary FontsCache = new Dictionary(); - - class FontCacheEntry + private class FontCacheEntry { public IntPtr HFont; } - /// - /// Cache of all the brushes used, rather than create them again and again - /// - private readonly Dictionary BrushCache = new Dictionary(); + // Cache of all the brushes used, rather than create them again and again + private readonly Dictionary _brushCache = new Dictionary(); private Graphics _g; private IntPtr _hdc; @@ -43,15 +28,9 @@ namespace BizHawk.Client.EmuHawk.CustomControls #region Construct and Destroy - public GDIRenderer() - { - //zero 04-16-2016 : this can't be legal, theres no HDC yet - //SetBkMode(_hdc, BkModes.OPAQUE); - } - public void Dispose() { - foreach (var brush in BrushCache) + foreach (var brush in _brushCache) { if (brush.Value != IntPtr.Zero) { @@ -59,8 +38,10 @@ namespace BizHawk.Client.EmuHawk.CustomControls } } - foreach (var fc in FontsCache) + foreach (var fc in _fontsCache) + { DeleteObject(fc.Value.HFont); + } EndOffScreenBitmap(); @@ -72,30 +53,24 @@ namespace BizHawk.Client.EmuHawk.CustomControls #region Api - /// - /// Draw a bitmap object at the given position - /// public void DrawBitmap(Bitmap bitmap, Point point, bool blend = false) { - IntPtr hbmp = bitmap.GetHbitmap(); - var bitHDC = CreateCompatibleDC(CurrentHDC); - IntPtr old = SelectObject(bitHDC, hbmp); + IntPtr hBmp = bitmap.GetHbitmap(); + var bitHdc = CreateCompatibleDC(CurrentHdc); + IntPtr old = SelectObject(bitHdc, hBmp); if (blend) { - AlphaBlend(CurrentHDC, point.X, point.Y, bitmap.Width, bitmap.Height, bitHDC, 0, 0, bitmap.Width, bitmap.Height, new BLENDFUNCTION(AC_SRC_OVER, 0, 0xff, AC_SRC_ALPHA)); + AlphaBlend(CurrentHdc, point.X, point.Y, bitmap.Width, bitmap.Height, bitHdc, 0, 0, bitmap.Width, bitmap.Height, new BLENDFUNCTION(AC_SRC_OVER, 0, 0xff, AC_SRC_ALPHA)); } else { - BitBlt(CurrentHDC, point.X, point.Y, bitmap.Width, bitmap.Height, bitHDC, 0, 0, 0xCC0020); + BitBlt(CurrentHdc, point.X, point.Y, bitmap.Width, bitmap.Height, bitHdc, 0, 0, 0xCC0020); } - SelectObject(bitHDC, old); - DeleteDC(bitHDC); - DeleteObject(hbmp); + SelectObject(bitHdc, old); + DeleteDC(bitHdc); + DeleteObject(hBmp); } - /// - /// Required to use before calling drawing methods - /// public IDisposable LockGraphics(Graphics g) { _g = g; @@ -103,135 +78,81 @@ namespace BizHawk.Client.EmuHawk.CustomControls SetBkMode(_hdc, BkModes.TRANSPARENT); return new GdiGraphicsLock(this); } - - /// - /// Measure the width and height of string when drawn on device context HDC - /// using the given font - /// + public Size MeasureString(string str, Font font) { SetFont(font); var size = new Size(); - GetTextExtentPoint32(CurrentHDC, str, str.Length, ref size); - return size; - } - - /// - /// Measure the width and height of string when drawn on device context HDC - /// using the given font - /// Restrict the width of the string and get the number of characters able to fit in the restriction and - /// the width those characters take - /// - /// the max width to render the string in - /// the number of characters that will fit under restriction - public Size MeasureString(string str, Font font, float maxWidth, out int charFit, out int charFitWidth) - { - SetFont(font); - - var size = new Size(); - GetTextExtentExPoint(CurrentHDC, str, str.Length, (int)Math.Round(maxWidth), CharFit, CharFitWidth, ref size); - charFit = CharFit[0]; - charFitWidth = charFit > 0 ? CharFitWidth[charFit - 1] : 0; + GetTextExtentPoint32(CurrentHdc, str, str.Length, ref size); return size; } public void DrawString(string str, Point point) { - TextOut(CurrentHDC, point.X, point.Y, str, str.Length); + TextOut(CurrentHdc, point.X, point.Y, str, str.Length); } public static IntPtr CreateNormalHFont(Font font, int width) { - LOGFONT logf = new LOGFONT(); - font.ToLogFont(logf); - logf.lfWidth = width; - logf.lfOutPrecision = (byte)FontPrecision.OUT_TT_ONLY_PRECIS; - var ret = CreateFontIndirect(logf); + var logFont = new LOGFONT(); + font.ToLogFont(logFont); + logFont.lfWidth = width; + logFont.lfOutPrecision = (byte)FontPrecision.OUT_TT_ONLY_PRECIS; + var ret = CreateFontIndirect(logFont); return ret; } - //this returns an IntPtr HFONT because .net's Font class will erase the relevant properties when using its Font.FromLogFont() + //this returns an IntPtr font because .net's Font class will erase the relevant properties when using its Font.FromLogFont() //note that whether this is rotated clockwise or CCW might affect how you have to position the text (right-aligned sometimes?, up or down by the height of the font?) - public static IntPtr CreateRotatedHFont(Font font, bool CW) + public static IntPtr CreateRotatedHFont(Font font, bool cw) { - LOGFONT logf = new LOGFONT(); - font.ToLogFont(logf); - logf.lfEscapement = CW ? 2700 : 900; - logf.lfOrientation = logf.lfEscapement; - logf.lfOutPrecision = (byte)FontPrecision.OUT_TT_ONLY_PRECIS; + LOGFONT logF = new LOGFONT(); + font.ToLogFont(logF); + logF.lfEscapement = cw ? 2700 : 900; + logF.lfOrientation = logF.lfEscapement; + logF.lfOutPrecision = (byte)FontPrecision.OUT_TT_ONLY_PRECIS; - //this doesnt work! .net erases the relevant propreties.. it seems? - //return Font.FromLogFont(logf); - - var ret = CreateFontIndirect(logf); + var ret = CreateFontIndirect(logF); return ret; } - public static void DestroyHFont(IntPtr hfont) + // TODO: this should go away and be abstracted internally + public static void DestroyHFont(IntPtr hFont) { - DeleteObject(hfont); + DeleteObject(hFont); } - public void PrepDrawString(IntPtr hfont, Color color) + public void PrepDrawString(IntPtr hFont, Color color) { - SetGraphicsMode(CurrentHDC, 2); //shouldnt be necessary.. cant hurt - SelectObject(CurrentHDC, hfont); + SetGraphicsMode(CurrentHdc, 2); // shouldn't be necessary.. cant hurt + SelectObject(CurrentHdc, hFont); SetTextColor(color); } - public void PrepDrawString(Font font, Color color) - { - SetFont(font); - SetTextColor(color); - } - - - /// - /// Draw the given string using the given font and foreground color at given location - /// See [http://msdn.microsoft.com/en-us/library/windows/desktop/dd162498(v=vs.85).aspx][15] - /// - public void DrawString(string str, Font font, Color color, Rectangle rect, TextFormatFlags flags) - { - SetFont(font); - SetTextColor(color); - - var rect2 = new Rect(rect); - DrawText(CurrentHDC, str, str.Length, ref rect2, (uint)flags); - } - - - /// - /// Set the text color of the device context - /// - public void SetTextColor(Color color) + // Set the text color of the device context + private void SetTextColor(Color color) { int rgb = (color.B & 0xFF) << 16 | (color.G & 0xFF) << 8 | color.R; - SetTextColor(CurrentHDC, rgb); - } - - public void SetBackgroundColor(Color color) - { - int rgb = (color.B & 0xFF) << 16 | (color.G & 0xFF) << 8 | color.R; - SetBkColor(CurrentHDC, rgb); + SetTextColor(CurrentHdc, rgb); } public void DrawRectangle(int nLeftRect, int nTopRect, int nRightRect, int nBottomRect) { - Rectangle(CurrentHDC, nLeftRect, nTopRect, nRightRect, nBottomRect); + Rectangle(CurrentHdc, nLeftRect, nTopRect, nRightRect, nBottomRect); } public void SetBrush(Color color) { - if (BrushCache.ContainsKey(color)) + if (_brushCache.ContainsKey(color)) { - _currentBrush = BrushCache[color]; + _currentBrush = _brushCache[color]; } else { int rgb = (color.B & 0xFF) << 16 | (color.G & 0xFF) << 8 | color.R; var newBrush = CreateSolidBrush(rgb); - BrushCache.Add(color, newBrush); + _brushCache.Add(color, newBrush); _currentBrush = newBrush; } } @@ -239,34 +160,26 @@ namespace BizHawk.Client.EmuHawk.CustomControls public void FillRectangle(int x, int y, int w, int h) { var r = new GDIRect(new Rectangle(x, y, w, h)); - FillRect(CurrentHDC, ref r, _currentBrush); - } - - public void SetPenPosition(int x, int y) - { - MoveToEx(CurrentHDC, x, y, IntPtr.Zero); + FillRect(CurrentHdc, ref r, _currentBrush); } public void SetSolidPen(Color color) { int rgb = (color.B & 0xFF) << 16 | (color.G & 0xFF) << 8 | color.R; - SelectObject(CurrentHDC, GetStockObject((int)PaintObjects.DC_PEN)); - SetDCPenColor(CurrentHDC, rgb); + SelectObject(CurrentHdc, GetStockObject((int)PaintObjects.DC_PEN)); + SetDCPenColor(CurrentHdc, rgb); } public void Line(int x1, int y1, int x2, int y2) { - MoveToEx(CurrentHDC, x1, y1, IntPtr.Zero); - LineTo(CurrentHDC, x2, y2); + MoveToEx(CurrentHdc, x1, y1, IntPtr.Zero); + LineTo(CurrentHdc, x2, y2); } - private IntPtr CurrentHDC - { - get { return _bitHDC != IntPtr.Zero ? _bitHDC : _hdc; } - } + private IntPtr CurrentHdc => _bitHdc != IntPtr.Zero ? _bitHdc : _hdc; private IntPtr _bitMap = IntPtr.Zero; - private IntPtr _bitHDC = IntPtr.Zero; + private IntPtr _bitHdc = IntPtr.Zero; private int _bitW; private int _bitH; @@ -275,10 +188,10 @@ namespace BizHawk.Client.EmuHawk.CustomControls _bitW = width; _bitH = height; - _bitHDC = CreateCompatibleDC(_hdc); + _bitHdc = CreateCompatibleDC(_hdc); _bitMap = CreateCompatibleBitmap(_hdc, width, height); - SelectObject(_bitHDC, _bitMap); - SetBkMode(_bitHDC, BkModes.TRANSPARENT); + SelectObject(_bitHdc, _bitMap); + SetBkMode(_bitHdc, BkModes.TRANSPARENT); } public void EndOffScreenBitmap() @@ -287,39 +200,37 @@ namespace BizHawk.Client.EmuHawk.CustomControls _bitH = 0; DeleteObject(_bitMap); - DeleteObject(_bitHDC); + DeleteObject(_bitHdc); - _bitHDC = IntPtr.Zero; + _bitHdc = IntPtr.Zero; _bitMap = IntPtr.Zero; } public void CopyToScreen() { - BitBlt(_hdc, 0, 0, _bitW, _bitH, _bitHDC, 0, 0, 0x00CC0020); + BitBlt(_hdc, 0, 0, _bitW, _bitH, _bitHdc, 0, 0, 0x00CC0020); } #endregion #region Helpers - /// - /// Set a resource (e.g. a font) for the specified device context. - /// + // Set a resource (e.g. a font) for the current device context. private void SetFont(Font font) { - SelectObject(CurrentHDC, GetCachedHFont(font)); + SelectObject(CurrentHdc, GetCachedHFont(font)); } private IntPtr GetCachedHFont(Font font) { - //the original code struck me as bad. attempting to ID fonts by picking a subset of their fields is not gonna work. - //don't call this.Font in InputRoll.cs, it is probably slow. - //consider Fonts to be a jealously guarded resource (they need to be disposed, after all) and manage them carefully. - //this cache maintains the HFONTs only. + // the original code struck me as bad. attempting to ID fonts by picking a subset of their fields is not gonna work. + // don't call this.Font in InputRoll.cs, it is probably slow. + // consider Fonts to be a jealously guarded resource (they need to be disposed, after all) and manage them carefully. + // this cache maintains the hFonts only. FontCacheEntry ce; - if (!FontsCache.TryGetValue(font, out ce)) + if (!_fontsCache.TryGetValue(font, out ce)) { - FontsCache[font] = ce = new FontCacheEntry(); + _fontsCache[font] = ce = new FontCacheEntry(); ce.HFont = font.ToHfont(); } return ce.HFont; @@ -329,18 +240,7 @@ namespace BizHawk.Client.EmuHawk.CustomControls #region Imports - [DllImport("user32.dll")] - private static extern int ReleaseDC(IntPtr hWnd, IntPtr hDC); - - [DllImport("user32.dll")] - private static extern IntPtr GetDC(IntPtr hWnd); - - [DllImport("user32.dll")] - private static extern IntPtr BeginPaint(IntPtr hWnd, ref IntPtr lpPaint); - - [DllImport("user32.dll")] - private static extern IntPtr EndPaint(IntPtr hWnd, IntPtr lpPaint); - + // ReSharper disable IdentifierTypo [DllImport("gdi32.dll", CharSet = CharSet.Auto)] private static extern IntPtr CreateFontIndirect( [In, MarshalAs(UnmanagedType.LPStruct)]LOGFONT lplf @@ -356,47 +256,27 @@ namespace BizHawk.Client.EmuHawk.CustomControls private static extern int SetBkMode(IntPtr hdc, BkModes mode); [DllImport("gdi32.dll")] + private static extern IntPtr SelectObject(IntPtr hdc, IntPtr hgdiObj); [DllImport("gdi32.dll")] private static extern int SetTextColor(IntPtr hdc, int color); - [DllImport("gdi32.dll")] - private static extern int SetBkColor(IntPtr hdc, int color); - [DllImport("gdi32.dll", EntryPoint = "GetTextExtentPoint32W")] private static extern int GetTextExtentPoint32(IntPtr hdc, [MarshalAs(UnmanagedType.LPWStr)] string str, int len, ref Size size); - [DllImport("gdi32.dll", EntryPoint = "GetTextExtentExPointW")] - private static extern bool GetTextExtentExPoint(IntPtr hDc, [MarshalAs(UnmanagedType.LPWStr)]string str, int nLength, int nMaxExtent, int[] lpnFit, int[] alpDx, ref Size size); - [DllImport("gdi32.dll", EntryPoint = "TextOutW")] private static extern bool TextOut(IntPtr hdc, int x, int y, [MarshalAs(UnmanagedType.LPWStr)] string str, int len); [DllImport("gdi32.dll")] public static extern int SetGraphicsMode(IntPtr hdc, int iMode); - [DllImport("user32.dll", EntryPoint = "DrawTextW")] - private static extern int DrawText(IntPtr hdc, [MarshalAs(UnmanagedType.LPWStr)] string str, int len, ref Rect rect, uint uFormat); - - [DllImport("gdi32.dll", EntryPoint = "ExtTextOutW")] - private static extern bool ExtTextOut(IntPtr hdc, int X, int Y, uint fuOptions, uint cbCount, [In] IntPtr lpDx); - - [DllImport("gdi32.dll")] - static extern bool SetWorldTransform(IntPtr hdc, [In] ref XFORM lpXform); - - [DllImport("gdi32.dll")] - private static extern int SelectClipRgn(IntPtr hdc, IntPtr hrgn); - [DllImport("gdi32.dll")] private static extern bool DeleteObject(IntPtr hObject); [DllImport("gdi32.dll")] private static extern IntPtr CreateSolidBrush(int color); - [DllImport("gdi32.dll")] - private static extern IntPtr CreatePen(int fnPenStyle, int nWidth, int color); - [DllImport("gdi32.dll")] private static extern IntPtr MoveToEx(IntPtr hdc, int x, int y, IntPtr point); @@ -425,44 +305,14 @@ namespace BizHawk.Client.EmuHawk.CustomControls [DllImport("gdi32.dll", EntryPoint = "GdiAlphaBlend")] static extern bool AlphaBlend(IntPtr hdcDest, int nXOriginDest, int nYOriginDest, int nWidthDest, int nHeightDest, IntPtr hdcSrc, int nXOriginSrc, int nYOriginSrc, int nWidthSrc, int nHeightSrc, BLENDFUNCTION blendFunction); - public enum FontWeight : int - { - FW_DONTCARE = 0, - FW_THIN = 100, - FW_EXTRALIGHT = 200, - FW_LIGHT = 300, - FW_NORMAL = 400, - FW_MEDIUM = 500, - FW_SEMIBOLD = 600, - FW_BOLD = 700, - FW_EXTRABOLD = 800, - FW_HEAVY = 900, - } - public enum FontCharSet : byte - { - ANSI_CHARSET = 0, - DEFAULT_CHARSET = 1, - SYMBOL_CHARSET = 2, - SHIFTJIS_CHARSET = 128, - HANGEUL_CHARSET = 129, - HANGUL_CHARSET = 129, - GB2312_CHARSET = 134, - CHINESEBIG5_CHARSET = 136, - OEM_CHARSET = 255, - JOHAB_CHARSET = 130, - HEBREW_CHARSET = 177, - ARABIC_CHARSET = 178, - GREEK_CHARSET = 161, - TURKISH_CHARSET = 162, - VIETNAMESE_CHARSET = 163, - THAI_CHARSET = 222, - EASTEUROPE_CHARSET = 238, - RUSSIAN_CHARSET = 204, - MAC_CHARSET = 77, - BALTIC_CHARSET = 186, - } + // ReSharper disable InconsistentNaming + // ReSharper disable UnusedMember.Global + // ReSharper disable UnusedMember.Local + // ReSharper disable NotAccessedField.Local + // ReSharper disable ArrangeTypeMemberModifiers public enum FontPrecision : byte { + OUT_DEFAULT_PRECIS = 0, OUT_STRING_PRECIS = 1, OUT_CHARACTER_PRECIS = 2, @@ -475,44 +325,10 @@ namespace BizHawk.Client.EmuHawk.CustomControls OUT_SCREEN_OUTLINE_PRECIS = 9, OUT_PS_ONLY_PRECIS = 10, } - public enum FontClipPrecision : byte - { - CLIP_DEFAULT_PRECIS = 0, - CLIP_CHARACTER_PRECIS = 1, - CLIP_STROKE_PRECIS = 2, - CLIP_MASK = 0xf, - CLIP_LH_ANGLES = (1 << 4), - CLIP_TT_ALWAYS = (2 << 4), - CLIP_DFA_DISABLE = (4 << 4), - CLIP_EMBEDDED = (8 << 4), - } - public enum FontQuality : byte - { - DEFAULT_QUALITY = 0, - DRAFT_QUALITY = 1, - PROOF_QUALITY = 2, - NONANTIALIASED_QUALITY = 3, - ANTIALIASED_QUALITY = 4, - CLEARTYPE_QUALITY = 5, - CLEARTYPE_NATURAL_QUALITY = 6, - } - [Flags] - public enum FontPitchAndFamily : byte - { - DEFAULT_PITCH = 0, - FIXED_PITCH = 1, - VARIABLE_PITCH = 2, - FF_DONTCARE = (0 << 4), - FF_ROMAN = (1 << 4), - FF_SWISS = (2 << 4), - FF_MODERN = (3 << 4), - FF_SCRIPT = (4 << 4), - FF_DECORATIVE = (5 << 4), - } - //it is important for this to be the right declaration - //see more here http://www.tech-archive.net/Archive/DotNet/microsoft.public.dotnet.framework.drawing/2004-04/0319.html - //if it's wrong (I had a wrong one from pinvoke.net) then ToLogFont will fail mysteriously + // It is important for this to be the right declaration + // See more here http://www.tech-archive.net/Archive/DotNet/microsoft.public.dotnet.framework.drawing/2004-04/0319.html + // If it's wrong (I had a wrong one from pinvoke.net) then ToLogFont will fail mysteriously [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)] class LOGFONT { @@ -580,7 +396,7 @@ namespace BizHawk.Client.EmuHawk.CustomControls } /// - /// Allows implicit converstion to a managed transformation matrix. + /// Allows implicit conversion to a managed transformation matrix. /// public static implicit operator System.Drawing.Drawing2D.Matrix(XFORM xf) { @@ -588,7 +404,7 @@ namespace BizHawk.Client.EmuHawk.CustomControls } /// - /// Allows implicit converstion from a managed transformation matrix. + /// Allows implicit conversion from a managed transformation matrix. /// public static implicit operator XFORM(System.Drawing.Drawing2D.Matrix m) { @@ -617,43 +433,24 @@ namespace BizHawk.Client.EmuHawk.CustomControls const byte AC_SRC_OVER = 0x00; const byte AC_SRC_ALPHA = 0x01; - [DllImport("gdi32.dll")] - static extern int SetBitmapBits(IntPtr hbmp, uint cBytes, byte[] lpBits); - #endregion #region Classes, Structs, and Enums - public class GdiGraphicsLock : IDisposable + private class GdiGraphicsLock : IDisposable { - private readonly GDIRenderer Gdi; + private readonly GdiRenderer _gdi; - public GdiGraphicsLock(GDIRenderer gdi) + public GdiGraphicsLock(GdiRenderer gdi) { - this.Gdi = gdi; + _gdi = gdi; } public void Dispose() { - Gdi._g.ReleaseHdc(Gdi._hdc); - Gdi._hdc = IntPtr.Zero; - Gdi._g = null; - } - } - - private struct Rect - { - private int _left; - private int _top; - private int _right; - private int _bottom; - - public Rect(Rectangle r) - { - _left = r.Left; - _top = r.Top; - _bottom = r.Bottom; - _right = r.Right; + _gdi._g.ReleaseHdc(_gdi._hdc); + _gdi._hdc = IntPtr.Zero; + _gdi._g = null; } } @@ -673,70 +470,7 @@ namespace BizHawk.Client.EmuHawk.CustomControls } } - private struct GDIPoint - { - private int x; - private int y; - - private GDIPoint(int x, int y) - { - this.x = x; - this.y = y; - } - } - - [Flags] - public enum ETOOptions : uint - { - CLIPPED = 0x4, - GLYPH_INDEX = 0x10, - IGNORELANGUAGE = 0x1000, - NUMERICSLATIN = 0x800, - NUMERICSLOCAL = 0x400, - OPAQUE = 0x2, - PDY = 0x2000, - RTLREADING = 0x800, - } - - /// - /// See [http://msdn.microsoft.com/en-us/library/windows/desktop/dd162498(v=vs.85).aspx][15] - /// - [Flags] - public enum TextFormatFlags : uint - { - Default = 0x00000000, - Center = 0x00000001, - Right = 0x00000002, - VCenter = 0x00000004, - Bottom = 0x00000008, - WordBreak = 0x00000010, - SingleLine = 0x00000020, - ExpandTabs = 0x00000040, - TabStop = 0x00000080, - NoClip = 0x00000100, - ExternalLeading = 0x00000200, - CalcRect = 0x00000400, - NoPrefix = 0x00000800, - Internal = 0x00001000, - EditControl = 0x00002000, - PathEllipsis = 0x00004000, - EndEllipsis = 0x00008000, - ModifyString = 0x00010000, - RtlReading = 0x00020000, - WordEllipsis = 0x00040000, - NoFullWidthCharBreak = 0x00080000, - HidePrefix = 0x00100000, - ProfixOnly = 0x00200000, - } - - [Flags] - public enum PenStyles - { - PS_SOLID = 0x00000000 - // TODO - } - - public enum PaintObjects + private enum PaintObjects { WHITE_BRUSH = 0, LTGRAY_BRUSH = 1, @@ -758,7 +492,7 @@ namespace BizHawk.Client.EmuHawk.CustomControls DC_PEN = 19, } - public enum BkModes : int + private enum BkModes : int { TRANSPARENT = 1, OPAQUE = 2 diff --git a/BizHawk.Client.EmuHawk/CustomControls/ControlRenderer/IControlRenderer.cs b/BizHawk.Client.EmuHawk/CustomControls/ControlRenderer/IControlRenderer.cs index e3c232113c..fd89ba0180 100644 --- a/BizHawk.Client.EmuHawk/CustomControls/ControlRenderer/IControlRenderer.cs +++ b/BizHawk.Client.EmuHawk/CustomControls/ControlRenderer/IControlRenderer.cs @@ -5,12 +5,19 @@ namespace BizHawk.Client.EmuHawk.CustomControls { public interface IControlRenderer : IDisposable { + /// + /// Required to use before calling drawing methods + /// IDisposable LockGraphics(Graphics g); void StartOffScreenBitmap(int width, int height); void EndOffScreenBitmap(); void CopyToScreen(); + /// + /// Measure the width and height of string when drawn on device context HDC + /// using the given font + /// Size MeasureString(string str, Font font); void SetBrush(Color color); @@ -18,10 +25,18 @@ namespace BizHawk.Client.EmuHawk.CustomControls // TODO: use the Font version void PrepDrawString(IntPtr hFont, Color color); + + /// + /// Draw the given string using the given font and foreground color at given location + /// void DrawString(string str, Point point); void DrawRectangle(int nLeftRect, int nTopRect, int nRightRect, int nBottomRect); void FillRectangle(int x, int y, int w, int h); + + /// + /// Draw a bitmap object at the given position + /// void DrawBitmap(Bitmap bitmap, Point point, bool blend = false); void Line(int x1, int y1, int x2, int y2); } diff --git a/BizHawk.Client.EmuHawk/CustomControls/HexView.cs b/BizHawk.Client.EmuHawk/CustomControls/HexView.cs index 30faae953b..13035ca5f6 100644 --- a/BizHawk.Client.EmuHawk/CustomControls/HexView.cs +++ b/BizHawk.Client.EmuHawk/CustomControls/HexView.cs @@ -12,7 +12,7 @@ namespace BizHawk.Client.EmuHawk { public class HexView : Control { - private readonly GDIRenderer Gdi; + private readonly GdiRenderer Gdi; private readonly Font NormalFont; private Size _charSize; @@ -27,7 +27,7 @@ namespace BizHawk.Client.EmuHawk SetStyle(ControlStyles.SupportsTransparentBackColor, true); SetStyle(ControlStyles.Opaque, true); - Gdi = new GDIRenderer(); + Gdi = new GdiRenderer(); using (var g = CreateGraphics()) using (var LCK = Gdi.LockGraphics(g)) diff --git a/BizHawk.Client.EmuHawk/CustomControls/InputRoll.cs b/BizHawk.Client.EmuHawk/CustomControls/InputRoll.cs index 9525cbb9ea..6262f78a9c 100644 --- a/BizHawk.Client.EmuHawk/CustomControls/InputRoll.cs +++ b/BizHawk.Client.EmuHawk/CustomControls/InputRoll.cs @@ -61,18 +61,18 @@ namespace BizHawk.Client.EmuHawk ScrollMethod = "near"; var commonFont = new Font("Arial", 8, FontStyle.Bold); - _normalFont = GDIRenderer.CreateNormalHFont(commonFont, 6); + _normalFont = GdiRenderer.CreateNormalHFont(commonFont, 6); // PrepDrawString doesn't actually set the font, so this is rather useless. // I'm leaving this stuff as-is so it will be a bit easier to fix up with another rendering method. - _rotatedFont = GDIRenderer.CreateRotatedHFont(commonFont, true); + _rotatedFont = GdiRenderer.CreateRotatedHFont(commonFont, true); SetStyle(ControlStyles.AllPaintingInWmPaint, true); SetStyle(ControlStyles.UserPaint, true); SetStyle(ControlStyles.SupportsTransparentBackColor, true); SetStyle(ControlStyles.Opaque, true); - _gdi = new GDIRenderer(); + _gdi = new GdiRenderer(); using (var g = CreateGraphics()) using (_gdi.LockGraphics(g)) @@ -129,8 +129,8 @@ namespace BizHawk.Client.EmuHawk { _gdi.Dispose(); - GDIRenderer.DestroyHFont(_normalFont); - GDIRenderer.DestroyHFont(_rotatedFont); + GdiRenderer.DestroyHFont(_normalFont); + GdiRenderer.DestroyHFont(_rotatedFont); base.Dispose(disposing); } From 92d6769b0679b4f751ded46dc42d04d3b915cbf9 Mon Sep 17 00:00:00 2001 From: adelikat Date: Sat, 19 Oct 2019 21:39:37 -0500 Subject: [PATCH 107/166] inputroll - rename renderer variable --- .../CustomControls/InputRoll.Drawing.cs | 120 +++++++++--------- .../CustomControls/InputRoll.cs | 10 +- 2 files changed, 65 insertions(+), 65 deletions(-) diff --git a/BizHawk.Client.EmuHawk/CustomControls/InputRoll.Drawing.cs b/BizHawk.Client.EmuHawk/CustomControls/InputRoll.Drawing.cs index 9c453c76e5..95e250d2d7 100644 --- a/BizHawk.Client.EmuHawk/CustomControls/InputRoll.Drawing.cs +++ b/BizHawk.Client.EmuHawk/CustomControls/InputRoll.Drawing.cs @@ -10,14 +10,14 @@ namespace BizHawk.Client.EmuHawk { protected override void OnPaint(PaintEventArgs e) { - using (_gdi.LockGraphics(e.Graphics)) + using (_renderer.LockGraphics(e.Graphics)) { - _gdi.StartOffScreenBitmap(Width, Height); + _renderer.StartOffScreenBitmap(Width, Height); // White Background - _gdi.SetBrush(Color.White); - _gdi.SetSolidPen(Color.White); - _gdi.FillRectangle(0, 0, Width, Height); + _renderer.SetBrush(Color.White); + _renderer.SetSolidPen(Color.White); + _renderer.FillRectangle(0, 0, Width, Height); // Lag frame calculations SetLagFramesArray(); @@ -39,8 +39,8 @@ namespace BizHawk.Client.EmuHawk DrawColumnDrag(e); DrawCellDrag(e); - _gdi.CopyToScreen(); - _gdi.EndOffScreenBitmap(); + _renderer.CopyToScreen(); + _renderer.EndOffScreenBitmap(); } } @@ -60,7 +60,7 @@ namespace BizHawk.Client.EmuHawk } } - _gdi.DrawString(text, point); + _renderer.DrawString(text, point); } protected override void OnPaintBackground(PaintEventArgs pevent) @@ -77,10 +77,10 @@ namespace BizHawk.Client.EmuHawk int x2 = x1 + _columnDown.Width.Value; int y2 = y1 + CellHeight; - _gdi.SetSolidPen(_backColor); - _gdi.DrawRectangle(x1, y1, x2, y2); - _gdi.PrepDrawString(_normalFont, _foreColor); - _gdi.DrawString(_columnDown.Text, new Point(x1 + CellWidthPadding, y1 + CellHeightPadding)); + _renderer.SetSolidPen(_backColor); + _renderer.DrawRectangle(x1, y1, x2, y2); + _renderer.PrepDrawString(_normalFont, _foreColor); + _renderer.DrawString(_columnDown.Text, new Point(x1 + CellWidthPadding, y1 + CellHeightPadding)); } } @@ -102,10 +102,10 @@ namespace BizHawk.Client.EmuHawk int y2 = y1 + CellHeight; - _gdi.SetBrush(bgColor); - _gdi.FillRectangle(x1, y1, x2 - x1, y2 - y1); - _gdi.PrepDrawString(_normalFont, _foreColor); - _gdi.DrawString(text, new Point(x1 + CellWidthPadding + offsetX, y1 + CellHeightPadding + offsetY)); + _renderer.SetBrush(bgColor); + _renderer.FillRectangle(x1, y1, x2 - x1, y2 - y1); + _renderer.PrepDrawString(_normalFont, _foreColor); + _renderer.DrawString(text, new Point(x1 + CellWidthPadding + offsetX, y1 + CellHeightPadding + offsetY)); } } @@ -115,7 +115,7 @@ namespace BizHawk.Client.EmuHawk { int start = -_vBar.Value; - _gdi.PrepDrawString(_normalFont, _foreColor); + _renderer.PrepDrawString(_normalFont, _foreColor); foreach (var column in visibleColumns) { @@ -123,9 +123,9 @@ namespace BizHawk.Client.EmuHawk if (IsHoveringOnColumnCell && column == CurrentCell.Column) { - _gdi.PrepDrawString(_normalFont, SystemColors.HighlightText); + _renderer.PrepDrawString(_normalFont, SystemColors.HighlightText); DrawString(column.Text, column.Width, point); - _gdi.PrepDrawString(_normalFont, _foreColor); + _renderer.PrepDrawString(_normalFont, _foreColor); } else { @@ -137,7 +137,7 @@ namespace BizHawk.Client.EmuHawk } else { - _gdi.PrepDrawString(_normalFont, _foreColor); + _renderer.PrepDrawString(_normalFont, _foreColor); foreach (var column in visibleColumns) { @@ -145,9 +145,9 @@ namespace BizHawk.Client.EmuHawk if (IsHoveringOnColumnCell && column == CurrentCell.Column) { - _gdi.PrepDrawString(_normalFont, SystemColors.HighlightText); + _renderer.PrepDrawString(_normalFont, SystemColors.HighlightText); DrawString(column.Text, column.Width, point); - _gdi.PrepDrawString(_normalFont, _foreColor); + _renderer.PrepDrawString(_normalFont, _foreColor); } else { @@ -171,7 +171,7 @@ namespace BizHawk.Client.EmuHawk int startRow = FirstVisibleRow; int range = Math.Min(LastVisibleRow, RowCount - 1) - startRow + 1; - _gdi.PrepDrawString(_normalFont, _foreColor); + _renderer.PrepDrawString(_normalFont, _foreColor); for (int i = 0, f = 0; f < range; i++, f++) { f += _lagFrames[i]; @@ -190,7 +190,7 @@ namespace BizHawk.Client.EmuHawk { x = RowsToPixels(i) + CellWidthPadding + bitmapOffsetX; y = (j * CellHeight) + (CellHeightPadding * 2) + bitmapOffsetY; - _gdi.DrawBitmap(image, new Point(x, y), true); + _renderer.DrawBitmap(image, new Point(x, y), true); } string text; @@ -207,21 +207,21 @@ namespace BizHawk.Client.EmuHawk if (j == 1) if (_selectedItems.Contains(new Cell { Column = visibleColumns[j], RowIndex = i + startRow })) { - _gdi.PrepDrawString(_rotatedFont, SystemColors.HighlightText); + _renderer.PrepDrawString(_rotatedFont, SystemColors.HighlightText); rePrep = true; } else if (j == 1) { // 1. not sure about this; 2. repreps may be excess, but if we render one column at a time, we do need to change back after rendering the header rePrep = true; - _gdi.PrepDrawString(_rotatedFont, _foreColor); + _renderer.PrepDrawString(_rotatedFont, _foreColor); } DrawString(text, ColumnWidth, point); if (rePrep) { - _gdi.PrepDrawString(_normalFont, _foreColor); + _renderer.PrepDrawString(_normalFont, _foreColor); } } } @@ -231,7 +231,7 @@ namespace BizHawk.Client.EmuHawk int startRow = FirstVisibleRow; int range = Math.Min(LastVisibleRow, RowCount - 1) - startRow + 1; - _gdi.PrepDrawString(_normalFont, _foreColor); + _renderer.PrepDrawString(_normalFont, _foreColor); int xPadding = CellWidthPadding + 1 - _hBar.Value; for (int i = 0, f = 0; f < range; i++, f++) // Vertical { @@ -254,7 +254,7 @@ namespace BizHawk.Client.EmuHawk if (image != null) { - _gdi.DrawBitmap(image, new Point(point.X + bitmapOffsetX, point.Y + bitmapOffsetY + CellHeightPadding), true); + _renderer.DrawBitmap(image, new Point(point.X + bitmapOffsetX, point.Y + bitmapOffsetY + CellHeightPadding), true); } QueryItemText(f + startRow, visibleColumns[j], out text, ref strOffsetX, ref strOffsetY); @@ -262,7 +262,7 @@ namespace BizHawk.Client.EmuHawk bool rePrep = false; if (_selectedItems.Contains(new Cell { Column = visibleColumns[j], RowIndex = f + startRow })) { - _gdi.PrepDrawString(_normalFont, SystemColors.HighlightText); + _renderer.PrepDrawString(_normalFont, SystemColors.HighlightText); rePrep = true; } @@ -270,7 +270,7 @@ namespace BizHawk.Client.EmuHawk if (rePrep) { - _gdi.PrepDrawString(_normalFont, _foreColor); + _renderer.PrepDrawString(_normalFont, _foreColor); } } } @@ -280,25 +280,25 @@ namespace BizHawk.Client.EmuHawk private void DrawColumnBg(PaintEventArgs e, List visibleColumns) { - _gdi.SetBrush(SystemColors.ControlLight); - _gdi.SetSolidPen(Color.Black); + _renderer.SetBrush(SystemColors.ControlLight); + _renderer.SetSolidPen(Color.Black); if (HorizontalOrientation) { - _gdi.FillRectangle(0, 0, ColumnWidth + 1, DrawHeight + 1); - _gdi.Line(0, 0, 0, visibleColumns.Count * CellHeight + 1); - _gdi.Line(ColumnWidth, 0, ColumnWidth, visibleColumns.Count * CellHeight + 1); + _renderer.FillRectangle(0, 0, ColumnWidth + 1, DrawHeight + 1); + _renderer.Line(0, 0, 0, visibleColumns.Count * CellHeight + 1); + _renderer.Line(ColumnWidth, 0, ColumnWidth, visibleColumns.Count * CellHeight + 1); int start = -_vBar.Value; foreach (var column in visibleColumns) { - _gdi.Line(1, start, ColumnWidth, start); + _renderer.Line(1, start, ColumnWidth, start); start += CellHeight; } if (visibleColumns.Any()) { - _gdi.Line(1, start, ColumnWidth, start); + _renderer.Line(1, start, ColumnWidth, start); } } else @@ -306,36 +306,36 @@ namespace BizHawk.Client.EmuHawk int bottomEdge = RowsToPixels(0); // Gray column box and black line underneath - _gdi.FillRectangle(0, 0, Width + 1, bottomEdge + 1); - _gdi.Line(0, 0, TotalColWidth.Value + 1, 0); - _gdi.Line(0, bottomEdge, TotalColWidth.Value + 1, bottomEdge); + _renderer.FillRectangle(0, 0, Width + 1, bottomEdge + 1); + _renderer.Line(0, 0, TotalColWidth.Value + 1, 0); + _renderer.Line(0, bottomEdge, TotalColWidth.Value + 1, bottomEdge); // Vertical black seperators for (int i = 0; i < visibleColumns.Count; i++) { int pos = visibleColumns[i].Left.Value - _hBar.Value; - _gdi.Line(pos, 0, pos, bottomEdge); + _renderer.Line(pos, 0, pos, bottomEdge); } // Draw right most line if (visibleColumns.Any()) { int right = TotalColWidth.Value - _hBar.Value; - _gdi.Line(right, 0, right, bottomEdge); + _renderer.Line(right, 0, right, bottomEdge); } } // Emphasis foreach (var column in visibleColumns.Where(c => c.Emphasis)) { - _gdi.SetBrush(SystemColors.ActiveBorder); + _renderer.SetBrush(SystemColors.ActiveBorder); if (HorizontalOrientation) { - _gdi.FillRectangle(1, visibleColumns.IndexOf(column) * CellHeight + 1, ColumnWidth - 1, ColumnHeight - 1); + _renderer.FillRectangle(1, visibleColumns.IndexOf(column) * CellHeight + 1, ColumnWidth - 1, ColumnHeight - 1); } else { - _gdi.FillRectangle(column.Left.Value + 1 - _hBar.Value, 1, column.Width.Value - 1, ColumnHeight - 1); + _renderer.FillRectangle(column.Left.Value + 1 - _hBar.Value, 1, column.Width.Value - 1, ColumnHeight - 1); } } @@ -353,14 +353,14 @@ namespace BizHawk.Client.EmuHawk if (CurrentCell.Column.Emphasis) { - _gdi.SetBrush(Add(SystemColors.Highlight, 0x00222222)); + _renderer.SetBrush(Add(SystemColors.Highlight, 0x00222222)); } else { - _gdi.SetBrush(SystemColors.Highlight); + _renderer.SetBrush(SystemColors.Highlight); } - _gdi.FillRectangle(1, i * CellHeight + 1, ColumnWidth - 1, ColumnHeight - 1); + _renderer.FillRectangle(1, i * CellHeight + 1, ColumnWidth - 1, ColumnHeight - 1); } } else @@ -381,14 +381,14 @@ namespace BizHawk.Client.EmuHawk if (CurrentCell.Column.Emphasis) { - _gdi.SetBrush(Add(SystemColors.Highlight, 0x00550000)); + _renderer.SetBrush(Add(SystemColors.Highlight, 0x00550000)); } else { - _gdi.SetBrush(SystemColors.Highlight); + _renderer.SetBrush(SystemColors.Highlight); } - _gdi.FillRectangle(left + 1, 1, width - 1, ColumnHeight - 1); + _renderer.FillRectangle(left + 1, 1, width - 1, ColumnHeight - 1); } } } @@ -408,20 +408,20 @@ namespace BizHawk.Client.EmuHawk if (GridLines) { - _gdi.SetSolidPen(SystemColors.ControlLight); + _renderer.SetSolidPen(SystemColors.ControlLight); if (HorizontalOrientation) { // Columns for (int i = 1; i < VisibleRows + 1; i++) { int x = RowsToPixels(i); - _gdi.Line(x, 1, x, DrawHeight); + _renderer.Line(x, 1, x, DrawHeight); } // Rows for (int i = 0; i < visibleColumns.Count + 1; i++) { - _gdi.Line(RowsToPixels(0) + 1, i * CellHeight - _vBar.Value, DrawWidth, i * CellHeight - _vBar.Value); + _renderer.Line(RowsToPixels(0) + 1, i * CellHeight - _vBar.Value, DrawWidth, i * CellHeight - _vBar.Value); } } else @@ -432,18 +432,18 @@ namespace BizHawk.Client.EmuHawk foreach (var column in visibleColumns) { int x = column.Left.Value - _hBar.Value; - _gdi.Line(x, y, x, Height - 1); + _renderer.Line(x, y, x, Height - 1); } if (visibleColumns.Any()) { - _gdi.Line(totalColWidth.Value - _hBar.Value, y, totalColWidth.Value - _hBar.Value, Height - 1); + _renderer.Line(totalColWidth.Value - _hBar.Value, y, totalColWidth.Value - _hBar.Value, Height - 1); } // Rows for (int i = 1; i < VisibleRows + 1; i++) { - _gdi.Line(0, RowsToPixels(i), Width + 1, RowsToPixels(i)); + _renderer.Line(0, RowsToPixels(i), Width + 1, RowsToPixels(i)); } } } @@ -536,8 +536,8 @@ namespace BizHawk.Client.EmuHawk return; } // Don't draw if off screen. - _gdi.SetBrush(color); - _gdi.FillRectangle(x, y, w, h); + _renderer.SetBrush(color); + _renderer.FillRectangle(x, y, w, h); } /// diff --git a/BizHawk.Client.EmuHawk/CustomControls/InputRoll.cs b/BizHawk.Client.EmuHawk/CustomControls/InputRoll.cs index 6262f78a9c..fd6fb2d545 100644 --- a/BizHawk.Client.EmuHawk/CustomControls/InputRoll.cs +++ b/BizHawk.Client.EmuHawk/CustomControls/InputRoll.cs @@ -15,7 +15,7 @@ namespace BizHawk.Client.EmuHawk // Row width is specified for horizontal orientation public partial class InputRoll : Control { - private readonly IControlRenderer _gdi; + private readonly IControlRenderer _renderer; private readonly SortedSet _selectedItems = new SortedSet(new SortCell()); private readonly VScrollBar _vBar; @@ -72,12 +72,12 @@ namespace BizHawk.Client.EmuHawk SetStyle(ControlStyles.SupportsTransparentBackColor, true); SetStyle(ControlStyles.Opaque, true); - _gdi = new GdiRenderer(); + _renderer = new GdiRenderer(); using (var g = CreateGraphics()) - using (_gdi.LockGraphics(g)) + using (_renderer.LockGraphics(g)) { - _charSize = _gdi.MeasureString("A", commonFont); // TODO make this a property so changing it updates other values. + _charSize = _renderer.MeasureString("A", commonFont); // TODO make this a property so changing it updates other values. } UpdateCellSize(); @@ -127,7 +127,7 @@ namespace BizHawk.Client.EmuHawk protected override void Dispose(bool disposing) { - _gdi.Dispose(); + _renderer.Dispose(); GdiRenderer.DestroyHFont(_normalFont); GdiRenderer.DestroyHFont(_rotatedFont); From ca2767c536d1fc16b65d4489b09f61140b82917b Mon Sep 17 00:00:00 2001 From: adelikat Date: Sun, 20 Oct 2019 08:44:26 -0500 Subject: [PATCH 108/166] HexView - cleanup and comment out GDIREnderer for now --- .../CustomControls/HexView.cs | 38 +++++++++---------- 1 file changed, 19 insertions(+), 19 deletions(-) diff --git a/BizHawk.Client.EmuHawk/CustomControls/HexView.cs b/BizHawk.Client.EmuHawk/CustomControls/HexView.cs index 13035ca5f6..446c41950f 100644 --- a/BizHawk.Client.EmuHawk/CustomControls/HexView.cs +++ b/BizHawk.Client.EmuHawk/CustomControls/HexView.cs @@ -12,7 +12,7 @@ namespace BizHawk.Client.EmuHawk { public class HexView : Control { - private readonly GdiRenderer Gdi; + //private readonly IControlRenderer _renderer; private readonly Font NormalFont; private Size _charSize; @@ -27,18 +27,18 @@ namespace BizHawk.Client.EmuHawk SetStyle(ControlStyles.SupportsTransparentBackColor, true); SetStyle(ControlStyles.Opaque, true); - Gdi = new GdiRenderer(); + //_renderer = new GdiRenderer(); - using (var g = CreateGraphics()) - using (var LCK = Gdi.LockGraphics(g)) - { - _charSize = Gdi.MeasureString("A", NormalFont); // TODO make this a property so changing it updates other values. - } + //using (var g = CreateGraphics()) + //using (var LCK = _renderer.LockGraphics(g)) + //{ + // _charSize = _renderer.MeasureString("A", NormalFont); // TODO make this a property so changing it updates other values. + //} } protected override void Dispose(bool disposing) { - Gdi.Dispose(); + //_renderer.Dispose(); NormalFont.Dispose(); @@ -49,21 +49,21 @@ namespace BizHawk.Client.EmuHawk protected override void OnPaint(PaintEventArgs e) { - using (var LCK = Gdi.LockGraphics(e.Graphics)) - { - Gdi.StartOffScreenBitmap(Width, Height); + //using (var lck = _renderer.LockGraphics(e.Graphics)) + //{ + // _renderer.StartOffScreenBitmap(Width, Height); - // White Background - Gdi.SetBrush(Color.White); - Gdi.SetSolidPen(Color.White); - Gdi.FillRectangle(0, 0, Width, Height); + // // White Background + // _renderer.SetBrush(Color.White); + // _renderer.SetSolidPen(Color.White); + // _renderer.FillRectangle(0, 0, Width, Height); - Gdi.DrawString("Hello World", new Point(10, 10)); + // _renderer.DrawString("Hello World", new Point(10, 10)); - Gdi.CopyToScreen(); - Gdi.EndOffScreenBitmap(); - } + // _renderer.CopyToScreen(); + // _renderer.EndOffScreenBitmap(); + //} } #endregion From 9dc91e508ee1fe803f62fdb4089444e18bda40ee Mon Sep 17 00:00:00 2001 From: adelikat Date: Sun, 20 Oct 2019 09:24:50 -0500 Subject: [PATCH 109/166] simplify renderer api --- .../ControlRenderer/GDIRenderer.cs | 16 +++++++++------- .../ControlRenderer/IControlRenderer.cs | 6 +----- .../CustomControls/InputRoll.Drawing.cs | 7 +------ .../CustomControls/InputRoll.cs | 2 +- 4 files changed, 12 insertions(+), 19 deletions(-) diff --git a/BizHawk.Client.EmuHawk/CustomControls/ControlRenderer/GDIRenderer.cs b/BizHawk.Client.EmuHawk/CustomControls/ControlRenderer/GDIRenderer.cs index b2cef5ad9f..a29b8f9f54 100644 --- a/BizHawk.Client.EmuHawk/CustomControls/ControlRenderer/GDIRenderer.cs +++ b/BizHawk.Client.EmuHawk/CustomControls/ControlRenderer/GDIRenderer.cs @@ -43,8 +43,6 @@ namespace BizHawk.Client.EmuHawk.CustomControls DeleteObject(fc.Value.HFont); } - EndOffScreenBitmap(); - System.Diagnostics.Debug.Assert(_hdc == IntPtr.Zero, "Disposed a GDIRenderer while it held an HDC"); System.Diagnostics.Debug.Assert(_g == null, "Disposed a GDIRenderer while it held a Graphics"); } @@ -71,12 +69,14 @@ namespace BizHawk.Client.EmuHawk.CustomControls DeleteObject(hBmp); } - public IDisposable LockGraphics(Graphics g) + public IDisposable LockGraphics(Graphics g, int width, int height) { _g = g; _hdc = g.GetHdc(); SetBkMode(_hdc, BkModes.TRANSPARENT); - return new GdiGraphicsLock(this); + var l = new GdiGraphicsLock(this); + StartOffScreenBitmap(width, height); + return l; } public Size MeasureString(string str, Font font) @@ -183,7 +183,7 @@ namespace BizHawk.Client.EmuHawk.CustomControls private int _bitW; private int _bitH; - public void StartOffScreenBitmap(int width, int height) + private void StartOffScreenBitmap(int width, int height) { _bitW = width; _bitH = height; @@ -194,7 +194,7 @@ namespace BizHawk.Client.EmuHawk.CustomControls SetBkMode(_bitHdc, BkModes.TRANSPARENT); } - public void EndOffScreenBitmap() + private void EndOffScreenBitmap() { _bitW = 0; _bitH = 0; @@ -206,7 +206,7 @@ namespace BizHawk.Client.EmuHawk.CustomControls _bitMap = IntPtr.Zero; } - public void CopyToScreen() + private void CopyToScreen() { BitBlt(_hdc, 0, 0, _bitW, _bitH, _bitHdc, 0, 0, 0x00CC0020); } @@ -448,6 +448,8 @@ namespace BizHawk.Client.EmuHawk.CustomControls public void Dispose() { + _gdi.CopyToScreen(); + _gdi.EndOffScreenBitmap(); _gdi._g.ReleaseHdc(_gdi._hdc); _gdi._hdc = IntPtr.Zero; _gdi._g = null; diff --git a/BizHawk.Client.EmuHawk/CustomControls/ControlRenderer/IControlRenderer.cs b/BizHawk.Client.EmuHawk/CustomControls/ControlRenderer/IControlRenderer.cs index fd89ba0180..f31924c211 100644 --- a/BizHawk.Client.EmuHawk/CustomControls/ControlRenderer/IControlRenderer.cs +++ b/BizHawk.Client.EmuHawk/CustomControls/ControlRenderer/IControlRenderer.cs @@ -8,11 +8,7 @@ namespace BizHawk.Client.EmuHawk.CustomControls /// /// Required to use before calling drawing methods /// - IDisposable LockGraphics(Graphics g); - - void StartOffScreenBitmap(int width, int height); - void EndOffScreenBitmap(); - void CopyToScreen(); + IDisposable LockGraphics(Graphics g, int width, int height); /// /// Measure the width and height of string when drawn on device context HDC diff --git a/BizHawk.Client.EmuHawk/CustomControls/InputRoll.Drawing.cs b/BizHawk.Client.EmuHawk/CustomControls/InputRoll.Drawing.cs index 95e250d2d7..79d01dcd28 100644 --- a/BizHawk.Client.EmuHawk/CustomControls/InputRoll.Drawing.cs +++ b/BizHawk.Client.EmuHawk/CustomControls/InputRoll.Drawing.cs @@ -10,10 +10,8 @@ namespace BizHawk.Client.EmuHawk { protected override void OnPaint(PaintEventArgs e) { - using (_renderer.LockGraphics(e.Graphics)) + using (_renderer.LockGraphics(e.Graphics, Width, Height)) { - _renderer.StartOffScreenBitmap(Width, Height); - // White Background _renderer.SetBrush(Color.White); _renderer.SetSolidPen(Color.White); @@ -38,9 +36,6 @@ namespace BizHawk.Client.EmuHawk DrawColumnDrag(e); DrawCellDrag(e); - - _renderer.CopyToScreen(); - _renderer.EndOffScreenBitmap(); } } diff --git a/BizHawk.Client.EmuHawk/CustomControls/InputRoll.cs b/BizHawk.Client.EmuHawk/CustomControls/InputRoll.cs index fd6fb2d545..791d0b2ee0 100644 --- a/BizHawk.Client.EmuHawk/CustomControls/InputRoll.cs +++ b/BizHawk.Client.EmuHawk/CustomControls/InputRoll.cs @@ -75,7 +75,7 @@ namespace BizHawk.Client.EmuHawk _renderer = new GdiRenderer(); using (var g = CreateGraphics()) - using (_renderer.LockGraphics(g)) + using (_renderer.LockGraphics(g, Width, Height)) { _charSize = _renderer.MeasureString("A", commonFont); // TODO make this a property so changing it updates other values. } From f86b21811124bf47d4ec43c3de71c9aa937b3243 Mon Sep 17 00:00:00 2001 From: adelikat Date: Sun, 20 Oct 2019 09:27:22 -0500 Subject: [PATCH 110/166] Renderer doc fix --- .../CustomControls/ControlRenderer/IControlRenderer.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/BizHawk.Client.EmuHawk/CustomControls/ControlRenderer/IControlRenderer.cs b/BizHawk.Client.EmuHawk/CustomControls/ControlRenderer/IControlRenderer.cs index f31924c211..8026c85d1c 100644 --- a/BizHawk.Client.EmuHawk/CustomControls/ControlRenderer/IControlRenderer.cs +++ b/BizHawk.Client.EmuHawk/CustomControls/ControlRenderer/IControlRenderer.cs @@ -11,7 +11,7 @@ namespace BizHawk.Client.EmuHawk.CustomControls IDisposable LockGraphics(Graphics g, int width, int height); /// - /// Measure the width and height of string when drawn on device context HDC + /// Measure the width and height of string when drawn /// using the given font /// Size MeasureString(string str, Font font); From b4a38597a60333a4eaeffb8873c5b587cb190707 Mon Sep 17 00:00:00 2001 From: adelikat Date: Sun, 20 Oct 2019 13:01:34 -0500 Subject: [PATCH 111/166] remove unnecessary hack --- BizHawk.Client.EmuHawk/CustomControls/InputRoll.cs | 1 - 1 file changed, 1 deletion(-) diff --git a/BizHawk.Client.EmuHawk/CustomControls/InputRoll.cs b/BizHawk.Client.EmuHawk/CustomControls/InputRoll.cs index 791d0b2ee0..7c98201bf3 100644 --- a/BizHawk.Client.EmuHawk/CustomControls/InputRoll.cs +++ b/BizHawk.Client.EmuHawk/CustomControls/InputRoll.cs @@ -106,7 +106,6 @@ namespace BizHawk.Client.EmuHawk _vBar.ValueChanged += VerticalBar_ValueChanged; _hBar.ValueChanged += HorizontalBar_ValueChanged; - HorizontalOrientation = false; RecalculateScrollBars(); _columns.ChangedCallback = ColumnChangedCallback; From b7f8f830e0af11adb684318f57852665fd639b21 Mon Sep 17 00:00:00 2001 From: adelikat Date: Sun, 20 Oct 2019 13:20:20 -0500 Subject: [PATCH 112/166] move some font shenanigans into GDI Renderer instead of input roll --- .../ControlRenderer/GDIRenderer.cs | 18 +++++++++-- .../ControlRenderer/IControlRenderer.cs | 3 +- .../CustomControls/InputRoll.Drawing.cs | 30 +++++++++---------- .../CustomControls/InputRoll.cs | 17 ++--------- 4 files changed, 35 insertions(+), 33 deletions(-) diff --git a/BizHawk.Client.EmuHawk/CustomControls/ControlRenderer/GDIRenderer.cs b/BizHawk.Client.EmuHawk/CustomControls/ControlRenderer/GDIRenderer.cs index a29b8f9f54..45c4a1c316 100644 --- a/BizHawk.Client.EmuHawk/CustomControls/ControlRenderer/GDIRenderer.cs +++ b/BizHawk.Client.EmuHawk/CustomControls/ControlRenderer/GDIRenderer.cs @@ -17,6 +17,7 @@ namespace BizHawk.Client.EmuHawk.CustomControls private class FontCacheEntry { public IntPtr HFont; + public IntPtr RotatedHFont; } // Cache of all the brushes used, rather than create them again and again @@ -41,6 +42,7 @@ namespace BizHawk.Client.EmuHawk.CustomControls foreach (var fc in _fontsCache) { DeleteObject(fc.Value.HFont); + DeleteObject(fc.Value.RotatedHFont); } System.Diagnostics.Debug.Assert(_hdc == IntPtr.Zero, "Disposed a GDIRenderer while it held an HDC"); @@ -123,10 +125,22 @@ namespace BizHawk.Client.EmuHawk.CustomControls DeleteObject(hFont); } - public void PrepDrawString(IntPtr hFont, Color color) + public void PrepDrawString(Font font, Color color, bool rotate = false) { + FontCacheEntry fontEntry; + var result = _fontsCache.TryGetValue(font, out fontEntry); + if (!result) + { + // Hack! The 6 is hardcoded to make tastudio look like taseditor, because taseditor is so perfect and wonderful + _fontsCache.Add(font, new FontCacheEntry + { + HFont = CreateNormalHFont(font, 6), + RotatedHFont = CreateRotatedHFont(font, true) + }); + } + SetGraphicsMode(CurrentHdc, 2); // shouldn't be necessary.. cant hurt - SelectObject(CurrentHdc, hFont); + SelectObject(CurrentHdc, rotate ? fontEntry.RotatedHFont : fontEntry.HFont); SetTextColor(color); } diff --git a/BizHawk.Client.EmuHawk/CustomControls/ControlRenderer/IControlRenderer.cs b/BizHawk.Client.EmuHawk/CustomControls/ControlRenderer/IControlRenderer.cs index 8026c85d1c..6bef52e7fa 100644 --- a/BizHawk.Client.EmuHawk/CustomControls/ControlRenderer/IControlRenderer.cs +++ b/BizHawk.Client.EmuHawk/CustomControls/ControlRenderer/IControlRenderer.cs @@ -19,8 +19,7 @@ namespace BizHawk.Client.EmuHawk.CustomControls void SetBrush(Color color); void SetSolidPen(Color color); - // TODO: use the Font version - void PrepDrawString(IntPtr hFont, Color color); + void PrepDrawString(Font font, Color color, bool rotate = false); /// /// Draw the given string using the given font and foreground color at given location diff --git a/BizHawk.Client.EmuHawk/CustomControls/InputRoll.Drawing.cs b/BizHawk.Client.EmuHawk/CustomControls/InputRoll.Drawing.cs index 79d01dcd28..24ce6d181d 100644 --- a/BizHawk.Client.EmuHawk/CustomControls/InputRoll.Drawing.cs +++ b/BizHawk.Client.EmuHawk/CustomControls/InputRoll.Drawing.cs @@ -74,7 +74,7 @@ namespace BizHawk.Client.EmuHawk _renderer.SetSolidPen(_backColor); _renderer.DrawRectangle(x1, y1, x2, y2); - _renderer.PrepDrawString(_normalFont, _foreColor); + _renderer.PrepDrawString(_font, _foreColor); _renderer.DrawString(_columnDown.Text, new Point(x1 + CellWidthPadding, y1 + CellHeightPadding)); } } @@ -99,7 +99,7 @@ namespace BizHawk.Client.EmuHawk _renderer.SetBrush(bgColor); _renderer.FillRectangle(x1, y1, x2 - x1, y2 - y1); - _renderer.PrepDrawString(_normalFont, _foreColor); + _renderer.PrepDrawString(_font, _foreColor); _renderer.DrawString(text, new Point(x1 + CellWidthPadding + offsetX, y1 + CellHeightPadding + offsetY)); } } @@ -110,7 +110,7 @@ namespace BizHawk.Client.EmuHawk { int start = -_vBar.Value; - _renderer.PrepDrawString(_normalFont, _foreColor); + _renderer.PrepDrawString(_font, _foreColor); foreach (var column in visibleColumns) { @@ -118,9 +118,9 @@ namespace BizHawk.Client.EmuHawk if (IsHoveringOnColumnCell && column == CurrentCell.Column) { - _renderer.PrepDrawString(_normalFont, SystemColors.HighlightText); + _renderer.PrepDrawString(_font, SystemColors.HighlightText); DrawString(column.Text, column.Width, point); - _renderer.PrepDrawString(_normalFont, _foreColor); + _renderer.PrepDrawString(_font, _foreColor); } else { @@ -132,7 +132,7 @@ namespace BizHawk.Client.EmuHawk } else { - _renderer.PrepDrawString(_normalFont, _foreColor); + _renderer.PrepDrawString(_font, _foreColor); foreach (var column in visibleColumns) { @@ -140,9 +140,9 @@ namespace BizHawk.Client.EmuHawk if (IsHoveringOnColumnCell && column == CurrentCell.Column) { - _renderer.PrepDrawString(_normalFont, SystemColors.HighlightText); + _renderer.PrepDrawString(_font, SystemColors.HighlightText); DrawString(column.Text, column.Width, point); - _renderer.PrepDrawString(_normalFont, _foreColor); + _renderer.PrepDrawString(_font, _foreColor); } else { @@ -166,7 +166,7 @@ namespace BizHawk.Client.EmuHawk int startRow = FirstVisibleRow; int range = Math.Min(LastVisibleRow, RowCount - 1) - startRow + 1; - _renderer.PrepDrawString(_normalFont, _foreColor); + _renderer.PrepDrawString(_font, _foreColor); for (int i = 0, f = 0; f < range; i++, f++) { f += _lagFrames[i]; @@ -202,21 +202,21 @@ namespace BizHawk.Client.EmuHawk if (j == 1) if (_selectedItems.Contains(new Cell { Column = visibleColumns[j], RowIndex = i + startRow })) { - _renderer.PrepDrawString(_rotatedFont, SystemColors.HighlightText); + _renderer.PrepDrawString(_font, SystemColors.HighlightText, rotate: true); rePrep = true; } else if (j == 1) { // 1. not sure about this; 2. repreps may be excess, but if we render one column at a time, we do need to change back after rendering the header rePrep = true; - _renderer.PrepDrawString(_rotatedFont, _foreColor); + _renderer.PrepDrawString(_font, _foreColor, rotate: true); } DrawString(text, ColumnWidth, point); if (rePrep) { - _renderer.PrepDrawString(_normalFont, _foreColor); + _renderer.PrepDrawString(_font, _foreColor); } } } @@ -226,7 +226,7 @@ namespace BizHawk.Client.EmuHawk int startRow = FirstVisibleRow; int range = Math.Min(LastVisibleRow, RowCount - 1) - startRow + 1; - _renderer.PrepDrawString(_normalFont, _foreColor); + _renderer.PrepDrawString(_font, _foreColor); int xPadding = CellWidthPadding + 1 - _hBar.Value; for (int i = 0, f = 0; f < range; i++, f++) // Vertical { @@ -257,7 +257,7 @@ namespace BizHawk.Client.EmuHawk bool rePrep = false; if (_selectedItems.Contains(new Cell { Column = visibleColumns[j], RowIndex = f + startRow })) { - _renderer.PrepDrawString(_normalFont, SystemColors.HighlightText); + _renderer.PrepDrawString(_font, SystemColors.HighlightText); rePrep = true; } @@ -265,7 +265,7 @@ namespace BizHawk.Client.EmuHawk if (rePrep) { - _renderer.PrepDrawString(_normalFont, _foreColor); + _renderer.PrepDrawString(_font, _foreColor); } } } diff --git a/BizHawk.Client.EmuHawk/CustomControls/InputRoll.cs b/BizHawk.Client.EmuHawk/CustomControls/InputRoll.cs index 7c98201bf3..a1b9d6f345 100644 --- a/BizHawk.Client.EmuHawk/CustomControls/InputRoll.cs +++ b/BizHawk.Client.EmuHawk/CustomControls/InputRoll.cs @@ -24,8 +24,6 @@ namespace BizHawk.Client.EmuHawk private readonly Timer _hoverTimer = new Timer(); private readonly byte[] _lagFrames = new byte[256]; // Large enough value that it shouldn't ever need resizing. // apparently not large enough for 4K - private readonly IntPtr _rotatedFont; - private readonly IntPtr _normalFont; private readonly Color _foreColor; private readonly Color _backColor; @@ -51,6 +49,8 @@ namespace BizHawk.Client.EmuHawk public bool LetKeysModifySelection { get; set; } public bool SuspendHotkeys { get; set; } + private Font _font = new Font("Arial", 8, FontStyle.Bold); + public InputRoll() { UseCustomBackground = true; @@ -60,13 +60,6 @@ namespace BizHawk.Client.EmuHawk CurrentCell = null; ScrollMethod = "near"; - var commonFont = new Font("Arial", 8, FontStyle.Bold); - _normalFont = GdiRenderer.CreateNormalHFont(commonFont, 6); - - // PrepDrawString doesn't actually set the font, so this is rather useless. - // I'm leaving this stuff as-is so it will be a bit easier to fix up with another rendering method. - _rotatedFont = GdiRenderer.CreateRotatedHFont(commonFont, true); - SetStyle(ControlStyles.AllPaintingInWmPaint, true); SetStyle(ControlStyles.UserPaint, true); SetStyle(ControlStyles.SupportsTransparentBackColor, true); @@ -77,7 +70,7 @@ namespace BizHawk.Client.EmuHawk using (var g = CreateGraphics()) using (_renderer.LockGraphics(g, Width, Height)) { - _charSize = _renderer.MeasureString("A", commonFont); // TODO make this a property so changing it updates other values. + _charSize = _renderer.MeasureString("A", _font); // TODO make this a property so changing it updates other values. } UpdateCellSize(); @@ -127,10 +120,6 @@ namespace BizHawk.Client.EmuHawk protected override void Dispose(bool disposing) { _renderer.Dispose(); - - GdiRenderer.DestroyHFont(_normalFont); - GdiRenderer.DestroyHFont(_rotatedFont); - base.Dispose(disposing); } From 7b7e9a269ae096e04a1d779da1b25e324b4a37e7 Mon Sep 17 00:00:00 2001 From: adelikat Date: Sun, 20 Oct 2019 14:15:33 -0500 Subject: [PATCH 113/166] Rough in of a GDI+ Renderer implementation --- .../BizHawk.Client.EmuHawk.csproj | 1 + .../ControlRenderer/GdiPlusRenderer.cs | 134 ++++++++++++++++++ .../ControlRenderer/IControlRenderer.cs | 1 + .../CustomControls/InputRoll.cs | 3 +- 4 files changed, 138 insertions(+), 1 deletion(-) create mode 100644 BizHawk.Client.EmuHawk/CustomControls/ControlRenderer/GdiPlusRenderer.cs diff --git a/BizHawk.Client.EmuHawk/BizHawk.Client.EmuHawk.csproj b/BizHawk.Client.EmuHawk/BizHawk.Client.EmuHawk.csproj index ff5c3580d8..70a0bf936e 100644 --- a/BizHawk.Client.EmuHawk/BizHawk.Client.EmuHawk.csproj +++ b/BizHawk.Client.EmuHawk/BizHawk.Client.EmuHawk.csproj @@ -566,6 +566,7 @@ CoreFeatureAnalysis.cs + Form diff --git a/BizHawk.Client.EmuHawk/CustomControls/ControlRenderer/GdiPlusRenderer.cs b/BizHawk.Client.EmuHawk/CustomControls/ControlRenderer/GdiPlusRenderer.cs new file mode 100644 index 0000000000..3080dc55fd --- /dev/null +++ b/BizHawk.Client.EmuHawk/CustomControls/ControlRenderer/GdiPlusRenderer.cs @@ -0,0 +1,134 @@ +using System; +using System.Collections.Generic; +using System.Drawing; +using System.Linq; + +namespace BizHawk.Client.EmuHawk.CustomControls +{ + public class GdiPlusRenderer : IControlRenderer + { + private Graphics _graphics; + private int _width; + private int _height; + + // TODO: see if caching has any benefit + private readonly Dictionary _penCache = new Dictionary(); + private Pen _currentPen; + + private readonly Dictionary _brushCache = new Dictionary(); + private Brush _currentBrush; + + private Font _currentFont = new Font("Arial", 8, FontStyle.Bold); + // TODO: cache this? + private Brush _currentStringBrush = new SolidBrush(Color.Black); + + public GdiPlusRenderer() + { + _currentPen = new Pen(Color.Black); + _penCache.Add(Color.Black, _currentPen); + + _currentBrush = new SolidBrush(Color.Black); + _brushCache.Add(Color.Black, _currentBrush); + } + + private class GdiPlusGraphicsLock : IDisposable + { + private readonly GdiPlusRenderer _renderer; + + public GdiPlusGraphicsLock(GdiPlusRenderer renderer) + { + _renderer = renderer; + } + + public void Dispose() + { + // TODO + } + } + + public void Dispose() + { + // TODO + } + + public void DrawBitmap(Bitmap bitmap, Point point, bool blend = false) + { + // TODO: implement blend + _graphics.DrawImage(bitmap, point); + } + + public void DrawRectangle(int nLeftRect, int nTopRect, int nRightRect, int nBottomRect) + { + _graphics.DrawRectangle( + _currentPen, + new Rectangle(nLeftRect, nTopRect, nRightRect - nLeftRect, nBottomRect - nTopRect)); + } + + public void DrawString(string str, Point point) + { + _graphics.DrawString(str, _currentFont, _currentStringBrush, point); + } + + public void FillRectangle(int x, int y, int w, int h) + { + _graphics.FillRectangle( + _currentBrush, + new Rectangle(x, y, w, h)); + } + + public void Line(int x1, int y1, int x2, int y2) + { + _graphics.DrawLine(_currentPen, x1, y1, x2, y2); + } + + public IDisposable LockGraphics(Graphics g, int width, int height) + { + _graphics = g; + _width = width; + _height = height; + return new GdiPlusGraphicsLock(this); + } + + public Size MeasureString(string str, Font font) + { + var size = _graphics.MeasureString(str, font); + return new Size((int)(size.Width + 0.5), (int)(size.Height + 0.5)); + } + + public void PrepDrawString(Font font, Color color, bool rotate = false) + { + // Implement TODO + if (rotate) + { + throw new NotImplementedException("rotate not implemented yet!"); + } + + _currentFont = font; + _currentStringBrush = new SolidBrush(color); + } + + public void SetBrush(Color color) + { + var result = _brushCache.TryGetValue(color, out Brush brush); + if (!result) + { + brush = new SolidBrush(color); + _brushCache.Add(color, brush); + } + + _currentBrush = brush; + } + + public void SetSolidPen(Color color) + { + var result = _penCache.TryGetValue(color, out Pen pen); + if (!result) + { + pen = new Pen(color); + _penCache.Add(color, pen); + } + + _currentPen = pen; + } + } +} diff --git a/BizHawk.Client.EmuHawk/CustomControls/ControlRenderer/IControlRenderer.cs b/BizHawk.Client.EmuHawk/CustomControls/ControlRenderer/IControlRenderer.cs index 6bef52e7fa..a0d222c0ef 100644 --- a/BizHawk.Client.EmuHawk/CustomControls/ControlRenderer/IControlRenderer.cs +++ b/BizHawk.Client.EmuHawk/CustomControls/ControlRenderer/IControlRenderer.cs @@ -26,6 +26,7 @@ namespace BizHawk.Client.EmuHawk.CustomControls /// void DrawString(string str, Point point); + void DrawRectangle(int nLeftRect, int nTopRect, int nRightRect, int nBottomRect); void FillRectangle(int x, int y, int w, int h); diff --git a/BizHawk.Client.EmuHawk/CustomControls/InputRoll.cs b/BizHawk.Client.EmuHawk/CustomControls/InputRoll.cs index a1b9d6f345..cd83bf34b6 100644 --- a/BizHawk.Client.EmuHawk/CustomControls/InputRoll.cs +++ b/BizHawk.Client.EmuHawk/CustomControls/InputRoll.cs @@ -65,7 +65,8 @@ namespace BizHawk.Client.EmuHawk SetStyle(ControlStyles.SupportsTransparentBackColor, true); SetStyle(ControlStyles.Opaque, true); - _renderer = new GdiRenderer(); + //_renderer = new GdiRenderer(); + _renderer = new GdiPlusRenderer(); using (var g = CreateGraphics()) using (_renderer.LockGraphics(g, Width, Height)) From 2e8d7346c3d931cd772d997fbaf4f4b88b27c054 Mon Sep 17 00:00:00 2001 From: Asnivor Date: Mon, 21 Oct 2019 10:04:23 +0100 Subject: [PATCH 114/166] InputRoll: Implement proper double buffering (improves gdi+ inputroll performance by a factor of 8 or 9 on my machine) --- BizHawk.Client.EmuHawk/CustomControls/InputRoll.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/BizHawk.Client.EmuHawk/CustomControls/InputRoll.cs b/BizHawk.Client.EmuHawk/CustomControls/InputRoll.cs index cd83bf34b6..c83b5fd2a9 100644 --- a/BizHawk.Client.EmuHawk/CustomControls/InputRoll.cs +++ b/BizHawk.Client.EmuHawk/CustomControls/InputRoll.cs @@ -64,6 +64,7 @@ namespace BizHawk.Client.EmuHawk SetStyle(ControlStyles.UserPaint, true); SetStyle(ControlStyles.SupportsTransparentBackColor, true); SetStyle(ControlStyles.Opaque, true); + SetStyle(ControlStyles.OptimizedDoubleBuffer, true); //_renderer = new GdiRenderer(); _renderer = new GdiPlusRenderer(); From 28dcae6c8b78ab242e316c13f674d64e915f0cff Mon Sep 17 00:00:00 2001 From: adelikat Date: Thu, 24 Oct 2019 16:35:07 -0500 Subject: [PATCH 115/166] GDIPlus renderer - use brush cache for text drawing --- .../ControlRenderer/GdiPlusRenderer.cs | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/BizHawk.Client.EmuHawk/CustomControls/ControlRenderer/GdiPlusRenderer.cs b/BizHawk.Client.EmuHawk/CustomControls/ControlRenderer/GdiPlusRenderer.cs index 3080dc55fd..0218329bd0 100644 --- a/BizHawk.Client.EmuHawk/CustomControls/ControlRenderer/GdiPlusRenderer.cs +++ b/BizHawk.Client.EmuHawk/CustomControls/ControlRenderer/GdiPlusRenderer.cs @@ -11,16 +11,14 @@ namespace BizHawk.Client.EmuHawk.CustomControls private int _width; private int _height; - // TODO: see if caching has any benefit private readonly Dictionary _penCache = new Dictionary(); private Pen _currentPen; private readonly Dictionary _brushCache = new Dictionary(); private Brush _currentBrush; + private Brush _currentStringBrush = new SolidBrush(Color.Black); private Font _currentFont = new Font("Arial", 8, FontStyle.Bold); - // TODO: cache this? - private Brush _currentStringBrush = new SolidBrush(Color.Black); public GdiPlusRenderer() { @@ -104,7 +102,15 @@ namespace BizHawk.Client.EmuHawk.CustomControls } _currentFont = font; - _currentStringBrush = new SolidBrush(color); + + var result = _brushCache.TryGetValue(color, out Brush brush); + if (!result) + { + brush = new SolidBrush(color); + _brushCache.Add(color, brush); + } + + _currentStringBrush = brush; } public void SetBrush(Color color) From 6395089a9c6d5f3273c7de149dc542f7ea65d3f6 Mon Sep 17 00:00:00 2001 From: "J.D. Purcell" Date: Fri, 25 Oct 2019 18:02:13 -0400 Subject: [PATCH 116/166] TAStudio.ListView.cs: Fix missing alpha values. --- .../tools/TAStudio/TAStudio.ListView.cs | 34 +++++++++---------- 1 file changed, 17 insertions(+), 17 deletions(-) diff --git a/BizHawk.Client.EmuHawk/tools/TAStudio/TAStudio.ListView.cs b/BizHawk.Client.EmuHawk/tools/TAStudio/TAStudio.ListView.cs index e8dbe1376d..f5cf9410a4 100644 --- a/BizHawk.Client.EmuHawk/tools/TAStudio/TAStudio.ListView.cs +++ b/BizHawk.Client.EmuHawk/tools/TAStudio/TAStudio.ListView.cs @@ -129,22 +129,22 @@ namespace BizHawk.Client.EmuHawk #region Query callbacks - // public static Color CurrentFrame_FrameCol = Color.FromArgb(0xCFEDFC); Why? - public static Color CurrentFrame_InputLog => Color.FromArgb(0x00B5E7F7); - public static Color SeekFrame_InputLog => Color.FromArgb(0x70B5E7F7); + // public static Color CurrentFrame_FrameCol = Color.FromArgb(0xCF, 0xED, 0xFC); Why? + public static Color CurrentFrame_InputLog => Color.FromArgb(0xB5, 0xE7, 0xF7); + public static Color SeekFrame_InputLog => Color.FromArgb(0x70, 0xB5, 0xE7, 0xF7); - public static Color GreenZone_FrameCol => Color.FromArgb(0xDDFFDD); - public static Color GreenZone_InputLog => Color.FromArgb(0xD2F9D3); - public static Color GreenZone_InputLog_Stated => Color.FromArgb(0xC4F7C8); - public static Color GreenZone_InputLog_Invalidated => Color.FromArgb(0xE0FBE0); + public static Color GreenZone_FrameCol => Color.FromArgb(0xDD, 0xFF, 0xDD); + public static Color GreenZone_InputLog => Color.FromArgb(0xD2, 0xF9, 0xD3); + public static Color GreenZone_InputLog_Stated => Color.FromArgb(0xC4, 0xF7, 0xC8); + public static Color GreenZone_InputLog_Invalidated => Color.FromArgb(0xE0, 0xFB, 0xE0); - public static Color LagZone_FrameCol => Color.FromArgb(0xFFDCDD); - public static Color LagZone_InputLog => Color.FromArgb(0xF4DADA); - public static Color LagZone_InputLog_Stated => Color.FromArgb(0xF0D0D2); - public static Color LagZone_InputLog_Invalidated => Color.FromArgb(0xF7E5E5); + public static Color LagZone_FrameCol => Color.FromArgb(0xFF, 0xDC, 0xDD); + public static Color LagZone_InputLog => Color.FromArgb(0xF4, 0xDA, 0xDA); + public static Color LagZone_InputLog_Stated => Color.FromArgb(0xF0, 0xD0, 0xD2); + public static Color LagZone_InputLog_Invalidated => Color.FromArgb(0xF7, 0xE5, 0xE5); - public static Color Marker_FrameCol => Color.FromArgb(0xF7FFC9); - public static Color AnalogEdit_Col => Color.FromArgb(0x909070); // SuuperW: When editing an analog value, it will be a gray color. + public static Color Marker_FrameCol => Color.FromArgb(0xF7, 0xFF, 0xC9); + public static Color AnalogEdit_Col => Color.FromArgb(0x90, 0x90, 0x70); // SuuperW: When editing an analog value, it will be a gray color. private Bitmap ts_v_arrow_green_blue => Properties.Resources.ts_v_arrow_green_blue; private Bitmap ts_h_arrow_green_blue => Properties.Resources.ts_h_arrow_green_blue; @@ -228,7 +228,7 @@ namespace BizHawk.Client.EmuHawk if (columnName == CursorColumnName) { - color = Color.FromArgb(0xFEFFFF); + color = Color.FromArgb(0xFE, 0xFF, 0xFF); } if (columnName == FrameColumnName) @@ -239,7 +239,7 @@ namespace BizHawk.Client.EmuHawk } else { - color = Color.FromArgb(0x60FFFFFF); + color = Color.FromArgb(0x60, 0xFF, 0xFF, 0xFF); } } else if (FloatEditingMode && @@ -253,7 +253,7 @@ namespace BizHawk.Client.EmuHawk int player = Emulator.ControllerDefinition.PlayerNumber(columnName); if (player != 0 && player % 2 == 0) { - color = Color.FromArgb(0x0D000000); + color = Color.FromArgb(0x0D, 0x00, 0x00, 0x00); } } @@ -292,7 +292,7 @@ namespace BizHawk.Client.EmuHawk } else { - color = Color.FromArgb(0xFFFEEE); + color = Color.FromArgb(0xFF, 0xFE, 0xEE); } } From 2e489763b98d15f0b311ed3917a1ca4ce5f604ee Mon Sep 17 00:00:00 2001 From: adelikat Date: Fri, 25 Oct 2019 18:20:13 -0500 Subject: [PATCH 117/166] use OSTailoredCode class to decide GDI vs GDIPlus renderering --- BizHawk.Client.EmuHawk/CustomControls/InputRoll.cs | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/BizHawk.Client.EmuHawk/CustomControls/InputRoll.cs b/BizHawk.Client.EmuHawk/CustomControls/InputRoll.cs index c83b5fd2a9..4ecd4aad7a 100644 --- a/BizHawk.Client.EmuHawk/CustomControls/InputRoll.cs +++ b/BizHawk.Client.EmuHawk/CustomControls/InputRoll.cs @@ -7,6 +7,7 @@ using System.Windows.Forms; using BizHawk.Client.Common; using BizHawk.Client.EmuHawk.CustomControls; +using BizHawk.Common; namespace BizHawk.Client.EmuHawk { @@ -66,8 +67,14 @@ namespace BizHawk.Client.EmuHawk SetStyle(ControlStyles.Opaque, true); SetStyle(ControlStyles.OptimizedDoubleBuffer, true); - //_renderer = new GdiRenderer(); - _renderer = new GdiPlusRenderer(); + if (OSTailoredCode.CurrentOS == OSTailoredCode.DistinctOS.Windows) + { + _renderer = new GdiRenderer(); + } + else + { + _renderer = new GdiPlusRenderer(); + } using (var g = CreateGraphics()) using (_renderer.LockGraphics(g, Width, Height)) From 8977137e84dd48b103879d38267ffbd9c125e005 Mon Sep 17 00:00:00 2001 From: adelikat Date: Sat, 26 Oct 2019 11:11:38 -0500 Subject: [PATCH 118/166] GDIPlusRenderer - cleanup --- .../ControlRenderer/GdiPlusRenderer.cs | 29 ++++++------------- 1 file changed, 9 insertions(+), 20 deletions(-) diff --git a/BizHawk.Client.EmuHawk/CustomControls/ControlRenderer/GdiPlusRenderer.cs b/BizHawk.Client.EmuHawk/CustomControls/ControlRenderer/GdiPlusRenderer.cs index 0218329bd0..0a2f1bee04 100644 --- a/BizHawk.Client.EmuHawk/CustomControls/ControlRenderer/GdiPlusRenderer.cs +++ b/BizHawk.Client.EmuHawk/CustomControls/ControlRenderer/GdiPlusRenderer.cs @@ -1,23 +1,19 @@ using System; using System.Collections.Generic; using System.Drawing; -using System.Linq; namespace BizHawk.Client.EmuHawk.CustomControls { public class GdiPlusRenderer : IControlRenderer { - private Graphics _graphics; - private int _width; - private int _height; - private readonly Dictionary _penCache = new Dictionary(); - private Pen _currentPen; - private readonly Dictionary _brushCache = new Dictionary(); - private Brush _currentBrush; - private Brush _currentStringBrush = new SolidBrush(Color.Black); + + private Graphics _graphics; + private Pen _currentPen = new Pen(Color.Black); + private Brush _currentBrush = new SolidBrush(Color.Black); + private Brush _currentStringBrush = new SolidBrush(Color.Black); private Font _currentFont = new Font("Arial", 8, FontStyle.Bold); public GdiPlusRenderer() @@ -31,16 +27,11 @@ namespace BizHawk.Client.EmuHawk.CustomControls private class GdiPlusGraphicsLock : IDisposable { - private readonly GdiPlusRenderer _renderer; - - public GdiPlusGraphicsLock(GdiPlusRenderer renderer) - { - _renderer = renderer; - } - public void Dispose() { - // TODO + // Nothing to do + // Other drawing methods need a way to dispose on demand, hence the need for + // this dummy class } } @@ -82,9 +73,7 @@ namespace BizHawk.Client.EmuHawk.CustomControls public IDisposable LockGraphics(Graphics g, int width, int height) { _graphics = g; - _width = width; - _height = height; - return new GdiPlusGraphicsLock(this); + return new GdiPlusGraphicsLock(); } public Size MeasureString(string str, Font font) From 9bbfb995b8a667d82a682e4c74e2b36e8c2e4d7a Mon Sep 17 00:00:00 2001 From: adelikat Date: Sat, 26 Oct 2019 11:26:12 -0500 Subject: [PATCH 119/166] GDIPlusRenderer - put off rotate text, for now --- .../CustomControls/ControlRenderer/GdiPlusRenderer.cs | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/BizHawk.Client.EmuHawk/CustomControls/ControlRenderer/GdiPlusRenderer.cs b/BizHawk.Client.EmuHawk/CustomControls/ControlRenderer/GdiPlusRenderer.cs index 0a2f1bee04..e9ed3b2d42 100644 --- a/BizHawk.Client.EmuHawk/CustomControls/ControlRenderer/GdiPlusRenderer.cs +++ b/BizHawk.Client.EmuHawk/CustomControls/ControlRenderer/GdiPlusRenderer.cs @@ -84,12 +84,11 @@ namespace BizHawk.Client.EmuHawk.CustomControls public void PrepDrawString(Font font, Color color, bool rotate = false) { - // Implement TODO if (rotate) { - throw new NotImplementedException("rotate not implemented yet!"); + // TODO } - + _currentFont = font; var result = _brushCache.TryGetValue(color, out Brush brush); From 437c2f067ac5d330577b9053d37a59670c92fb21 Mon Sep 17 00:00:00 2001 From: adelikat Date: Sat, 26 Oct 2019 11:40:04 -0500 Subject: [PATCH 120/166] TAStudio - Consolidate the two restore defaults menu items. Restore splitter positions when restoring defaults --- .../tools/TAStudio/TAStudio.MenuItems.cs | 35 ++++++++++++------- .../tools/TAStudio/TAStudio.cs | 6 ++++ 2 files changed, 29 insertions(+), 12 deletions(-) diff --git a/BizHawk.Client.EmuHawk/tools/TAStudio/TAStudio.MenuItems.cs b/BizHawk.Client.EmuHawk/tools/TAStudio/TAStudio.MenuItems.cs index fce1725c9d..a4f90146ae 100644 --- a/BizHawk.Client.EmuHawk/tools/TAStudio/TAStudio.MenuItems.cs +++ b/BizHawk.Client.EmuHawk/tools/TAStudio/TAStudio.MenuItems.cs @@ -1392,23 +1392,34 @@ namespace BizHawk.Client.EmuHawk } } - ColumnsSubMenu.DropDownItems.Add(new ToolStripSeparator()); - var defaults = new ToolStripMenuItem - { - Name = "RestoreDefaultColumnConfiguration", - Text = "Restore defaults" - }; + TasView.AllColumns.ColumnsChanged(); + } - defaults.Click += (o, ev) => - { - TasView.AllColumns.Clear(); + [RestoreDefaults] + private void RestoreDefaults() + { + TasView.AllColumns.Clear(); SetUpColumns(); RefreshTasView(); CurrentTasMovie.FlagChanges(); - }; - ColumnsSubMenu.DropDownItems.Add(defaults); - TasView.AllColumns.ColumnsChanged(); + try + { + MainVertialSplit.SplitterDistance = Settings.MainVerticalSplitDistance; + } + catch (Exception) + { + MainVertialSplit.SplitterDistance = _defaultMainSplitDistance; + } + + try + { + BranchesMarkersSplit.SplitterDistance = Settings.BranchMarkerSplitDistance; + } + catch (Exception) + { + BranchesMarkersSplit.SplitterDistance = _defaultBranchMarkerSplitDistance; + } } #endregion diff --git a/BizHawk.Client.EmuHawk/tools/TAStudio/TAStudio.cs b/BizHawk.Client.EmuHawk/tools/TAStudio/TAStudio.cs index 45c08457ac..97375fdf25 100644 --- a/BizHawk.Client.EmuHawk/tools/TAStudio/TAStudio.cs +++ b/BizHawk.Client.EmuHawk/tools/TAStudio/TAStudio.cs @@ -33,6 +33,9 @@ namespace BizHawk.Client.EmuHawk private UndoHistoryForm _undoForm; private Timer _autosaveTimer; + private int _defaultMainSplitDistance; + private int _defaultBranchMarkerSplitDistance; + /// /// Gets a value that separates "restore last position" logic from seeking caused by navigation. /// TASEditor never kills LastPositionFrame, and it only pauses on it, if it hasn't been greenzoned beforehand and middle mouse button was pressed. @@ -113,6 +116,9 @@ namespace BizHawk.Client.EmuHawk InitializeComponent(); InitializeSeekWorker(); + _defaultMainSplitDistance = MainVertialSplit.SplitterDistance; + _defaultBranchMarkerSplitDistance = BranchesMarkersSplit.SplitterDistance; + // TODO: show this at all times or hide it when saving is done? SavingProgressBar.Visible = false; From 5e5f69f07e90ff6ffb6bf88ce7e25fea4bd5d229 Mon Sep 17 00:00:00 2001 From: YoshiRulz Date: Sun, 27 Oct 2019 03:38:30 +1000 Subject: [PATCH 121/166] Move _vBar/_hVar init out of ctor, init CellHeight to non-zero CellHeight/_vBar/_hBar were being read *while the ctor was running* due to unexplained Mono magic (and hence their values were 0/null/null, respectively) --- .../CustomControls/InputRoll.cs | 25 ++++++------------- 1 file changed, 8 insertions(+), 17 deletions(-) diff --git a/BizHawk.Client.EmuHawk/CustomControls/InputRoll.cs b/BizHawk.Client.EmuHawk/CustomControls/InputRoll.cs index 4ecd4aad7a..a28826ca48 100644 --- a/BizHawk.Client.EmuHawk/CustomControls/InputRoll.cs +++ b/BizHawk.Client.EmuHawk/CustomControls/InputRoll.cs @@ -19,8 +19,9 @@ namespace BizHawk.Client.EmuHawk private readonly IControlRenderer _renderer; private readonly SortedSet _selectedItems = new SortedSet(new SortCell()); - private readonly VScrollBar _vBar; - private readonly HScrollBar _hBar; + // scrollbar location(s) are calculated later (e.g. on resize) + private readonly VScrollBar _vBar = new VScrollBar { Visible = false }; + private readonly HScrollBar _hBar = new HScrollBar { Visible = false }; private readonly Timer _hoverTimer = new Timer(); private readonly byte[] _lagFrames = new byte[256]; // Large enough value that it shouldn't ever need resizing. // apparently not large enough for 4K @@ -86,21 +87,11 @@ namespace BizHawk.Client.EmuHawk ColumnWidth = CellWidth; ColumnHeight = CellHeight + 2; - _vBar = new VScrollBar - { - // Location gets calculated later (e.g. on resize) - Visible = false, - SmallChange = CellHeight, - LargeChange = CellHeight * 20 - }; + _vBar.SmallChange = CellHeight; + _vBar.LargeChange = CellHeight * 20; - _hBar = new HScrollBar - { - // Location gets calculated later (e.g. on resize) - Visible = false, - SmallChange = CellWidth, - LargeChange = 20 - }; + _hBar.SmallChange = CellWidth; + _hBar.LargeChange = 20; Controls.Add(_vBar); Controls.Add(_hBar); @@ -1941,7 +1932,7 @@ namespace BizHawk.Client.EmuHawk /// /// Gets or sets a value indicating the height of a cell in Vertical Orientation. Only can be changed by changing the Font or CellPadding. /// - private int CellHeight { get; set; } + private int CellHeight { get; set; } = 8; /// /// Call when _charSize, MaxCharactersInHorizontal, or CellPadding is changed. From 4e2818222de85d538dc8f9cfd2378b211ce7b9b9 Mon Sep 17 00:00:00 2001 From: "J.D. Purcell" Date: Sat, 26 Oct 2019 13:40:20 -0400 Subject: [PATCH 122/166] GdiPlusRenderer: Remove caches, implement Dispose. --- .../ControlRenderer/GdiPlusRenderer.cs | 52 +++++-------------- 1 file changed, 13 insertions(+), 39 deletions(-) diff --git a/BizHawk.Client.EmuHawk/CustomControls/ControlRenderer/GdiPlusRenderer.cs b/BizHawk.Client.EmuHawk/CustomControls/ControlRenderer/GdiPlusRenderer.cs index e9ed3b2d42..ef23e7b98a 100644 --- a/BizHawk.Client.EmuHawk/CustomControls/ControlRenderer/GdiPlusRenderer.cs +++ b/BizHawk.Client.EmuHawk/CustomControls/ControlRenderer/GdiPlusRenderer.cs @@ -1,28 +1,21 @@ using System; -using System.Collections.Generic; using System.Drawing; namespace BizHawk.Client.EmuHawk.CustomControls { public class GdiPlusRenderer : IControlRenderer { - private readonly Dictionary _penCache = new Dictionary(); - private readonly Dictionary _brushCache = new Dictionary(); - private Graphics _graphics; - private Pen _currentPen = new Pen(Color.Black); - private Brush _currentBrush = new SolidBrush(Color.Black); - private Brush _currentStringBrush = new SolidBrush(Color.Black); - private Font _currentFont = new Font("Arial", 8, FontStyle.Bold); + private readonly Pen _currentPen = new Pen(Color.Black); + private readonly SolidBrush _currentBrush = new SolidBrush(Color.Black); + private readonly SolidBrush _currentStringBrush = new SolidBrush(Color.Black); + private readonly Font _defaultFont = new Font("Arial", 8, FontStyle.Bold); + private Font _currentFont; public GdiPlusRenderer() { - _currentPen = new Pen(Color.Black); - _penCache.Add(Color.Black, _currentPen); - - _currentBrush = new SolidBrush(Color.Black); - _brushCache.Add(Color.Black, _currentBrush); + _currentFont = _defaultFont; } private class GdiPlusGraphicsLock : IDisposable @@ -37,7 +30,10 @@ namespace BizHawk.Client.EmuHawk.CustomControls public void Dispose() { - // TODO + _currentPen.Dispose(); + _currentBrush.Dispose(); + _currentStringBrush.Dispose(); + _defaultFont.Dispose(); } public void DrawBitmap(Bitmap bitmap, Point point, bool blend = false) @@ -90,39 +86,17 @@ namespace BizHawk.Client.EmuHawk.CustomControls } _currentFont = font; - - var result = _brushCache.TryGetValue(color, out Brush brush); - if (!result) - { - brush = new SolidBrush(color); - _brushCache.Add(color, brush); - } - - _currentStringBrush = brush; + _currentStringBrush.Color = color; } public void SetBrush(Color color) { - var result = _brushCache.TryGetValue(color, out Brush brush); - if (!result) - { - brush = new SolidBrush(color); - _brushCache.Add(color, brush); - } - - _currentBrush = brush; + _currentBrush.Color = color; } public void SetSolidPen(Color color) { - var result = _penCache.TryGetValue(color, out Pen pen); - if (!result) - { - pen = new Pen(color); - _penCache.Add(color, pen); - } - - _currentPen = pen; + _currentPen.Color = color; } } } From f6b0fa15505f734f3d1019a2567fbf10733b5459 Mon Sep 17 00:00:00 2001 From: adelikat Date: Sat, 26 Oct 2019 12:59:30 -0500 Subject: [PATCH 123/166] GdiRenderer - cleanup font caching logic and fix rotated text --- .../ControlRenderer/GDIRenderer.cs | 39 ++++++++----------- 1 file changed, 16 insertions(+), 23 deletions(-) diff --git a/BizHawk.Client.EmuHawk/CustomControls/ControlRenderer/GDIRenderer.cs b/BizHawk.Client.EmuHawk/CustomControls/ControlRenderer/GDIRenderer.cs index 45c4a1c316..679b8b3b53 100644 --- a/BizHawk.Client.EmuHawk/CustomControls/ControlRenderer/GDIRenderer.cs +++ b/BizHawk.Client.EmuHawk/CustomControls/ControlRenderer/GDIRenderer.cs @@ -127,18 +127,7 @@ namespace BizHawk.Client.EmuHawk.CustomControls public void PrepDrawString(Font font, Color color, bool rotate = false) { - FontCacheEntry fontEntry; - var result = _fontsCache.TryGetValue(font, out fontEntry); - if (!result) - { - // Hack! The 6 is hardcoded to make tastudio look like taseditor, because taseditor is so perfect and wonderful - _fontsCache.Add(font, new FontCacheEntry - { - HFont = CreateNormalHFont(font, 6), - RotatedHFont = CreateRotatedHFont(font, true) - }); - } - + var fontEntry = GetCachedHFont(font); SetGraphicsMode(CurrentHdc, 2); // shouldn't be necessary.. cant hurt SelectObject(CurrentHdc, rotate ? fontEntry.RotatedHFont : fontEntry.HFont); SetTextColor(color); @@ -232,22 +221,26 @@ namespace BizHawk.Client.EmuHawk.CustomControls // Set a resource (e.g. a font) for the current device context. private void SetFont(Font font) { - SelectObject(CurrentHdc, GetCachedHFont(font)); + var blah = GetCachedHFont(font); + SelectObject(CurrentHdc, blah.HFont); } - private IntPtr GetCachedHFont(Font font) + private FontCacheEntry GetCachedHFont(Font font) { - // the original code struck me as bad. attempting to ID fonts by picking a subset of their fields is not gonna work. - // don't call this.Font in InputRoll.cs, it is probably slow. - // consider Fonts to be a jealously guarded resource (they need to be disposed, after all) and manage them carefully. - // this cache maintains the hFonts only. - FontCacheEntry ce; - if (!_fontsCache.TryGetValue(font, out ce)) + FontCacheEntry fontEntry; + var result = _fontsCache.TryGetValue(font, out fontEntry); + if (!result) { - _fontsCache[font] = ce = new FontCacheEntry(); - ce.HFont = font.ToHfont(); + // Hack! The 6 is hardcoded to make tastudio look like taseditor, because taseditor is so perfect and wonderful + fontEntry = new FontCacheEntry + { + HFont = CreateNormalHFont(font, 6), + RotatedHFont = CreateRotatedHFont(font, true) + }; + _fontsCache.Add(font, fontEntry); } - return ce.HFont; + + return fontEntry; } #endregion From e21e861e992045fff2d0a28716ba596ad4010a8b Mon Sep 17 00:00:00 2001 From: adelikat Date: Sat, 26 Oct 2019 14:22:19 -0500 Subject: [PATCH 124/166] temp hack to force tastudio to draw the frame column rotated in horizontal orientation --- .../CustomControls/InputRoll.Drawing.cs | 25 ++++++++++++------- 1 file changed, 16 insertions(+), 9 deletions(-) diff --git a/BizHawk.Client.EmuHawk/CustomControls/InputRoll.Drawing.cs b/BizHawk.Client.EmuHawk/CustomControls/InputRoll.Drawing.cs index 24ce6d181d..08dd3eb36c 100644 --- a/BizHawk.Client.EmuHawk/CustomControls/InputRoll.Drawing.cs +++ b/BizHawk.Client.EmuHawk/CustomControls/InputRoll.Drawing.cs @@ -199,17 +199,24 @@ namespace BizHawk.Client.EmuHawk var point = new Point(x + strOffsetX, y + strOffsetY); var rePrep = false; - if (j == 1) - if (_selectedItems.Contains(new Cell { Column = visibleColumns[j], RowIndex = i + startRow })) + //if (j == 1) + //if (_selectedItems.Contains(new Cell { Column = visibleColumns[j], RowIndex = i + startRow })) + //{ + // _renderer.PrepDrawString(_font, SystemColors.HighlightText, rotate: true); + // rePrep = true; + //} + //else if (j == 1) + //{ + // // 1. not sure about this; 2. repreps may be excess, but if we render one column at a time, we do need to change back after rendering the header + // rePrep = true; + // _renderer.PrepDrawString(_font, _foreColor, rotate: true); + //} + + //if (visibleColumns[j].Type == RollColumn.InputType.Text) + if (visibleColumns[j].Name == "FrameColumn") { - _renderer.PrepDrawString(_font, SystemColors.HighlightText, rotate: true); - rePrep = true; - } - else if (j == 1) - { - // 1. not sure about this; 2. repreps may be excess, but if we render one column at a time, we do need to change back after rendering the header - rePrep = true; _renderer.PrepDrawString(_font, _foreColor, rotate: true); + rePrep = true; } DrawString(text, ColumnWidth, point); From 064a78d7f3cb7fead27f83ff2375109d1c178f9e Mon Sep 17 00:00:00 2001 From: adelikat Date: Sat, 26 Oct 2019 14:37:42 -0500 Subject: [PATCH 125/166] inputroll - fix crash when resized to 0 --- BizHawk.Client.EmuHawk/CustomControls/InputRoll.cs | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/BizHawk.Client.EmuHawk/CustomControls/InputRoll.cs b/BizHawk.Client.EmuHawk/CustomControls/InputRoll.cs index a28826ca48..6dbacdaf68 100644 --- a/BizHawk.Client.EmuHawk/CustomControls/InputRoll.cs +++ b/BizHawk.Client.EmuHawk/CustomControls/InputRoll.cs @@ -1665,10 +1665,19 @@ namespace BizHawk.Client.EmuHawk if (HorizontalOrientation) { _vBar.Maximum = ((columns.Count() * CellHeight) - DrawHeight) + _vBar.LargeChange; + if (_vBar.Maximum < 0) + { + _vBar.Maximum = 0; + } } else { _vBar.Maximum = RowsToPixels(RowCount + 1) - (CellHeight * 3) + _vBar.LargeChange - 1; + + if (_vBar.Maximum < 0) + { + _vBar.Maximum = 0; + } } _vBar.Location = new Point(Width - _vBar.Width, 0); From 4d576ea9da814127a9129f462ab9c17d8f1a9a40 Mon Sep 17 00:00:00 2001 From: adelikat Date: Sat, 26 Oct 2019 15:08:54 -0500 Subject: [PATCH 126/166] Hex Editor - improve performance a bit when there are highlighted or frozen addresses by not newing up brushes and pens on every draw --- .../tools/HexEditor/HexEditor.cs | 35 ++++++++++++------- 1 file changed, 23 insertions(+), 12 deletions(-) diff --git a/BizHawk.Client.EmuHawk/tools/HexEditor/HexEditor.cs b/BizHawk.Client.EmuHawk/tools/HexEditor/HexEditor.cs index 1a7a5b2314..a7a3259c89 100644 --- a/BizHawk.Client.EmuHawk/tools/HexEditor/HexEditor.cs +++ b/BizHawk.Client.EmuHawk/tools/HexEditor/HexEditor.cs @@ -2250,6 +2250,12 @@ namespace BizHawk.Client.EmuHawk } } + private Pen _blackPen = new Pen(Color.Black); + private SolidBrush _freezeBrush = new SolidBrush(Global.Config.HexFreezeColor); + private SolidBrush _freezeHighlightBrush = new SolidBrush(Global.Config.HexHighlightFreezeColor); + private SolidBrush _highlightBrush = new SolidBrush(Global.Config.HexHighlightColor); + private SolidBrush _secondaryHighlightBrush = new SolidBrush(Color.FromArgb(0x44, Global.Config.HexHighlightColor)); + private void MemoryViewerBox_Paint(object sender, PaintEventArgs e) { var activeCheats = Global.CheatList.Where(x => x.Enabled); @@ -2271,8 +2277,9 @@ namespace BizHawk.Client.EmuHawk var width = (fontWidth * 2 * (int)cheat.Size) + (gaps * fontWidth); var rect = new Rectangle(GetAddressCoordinates(cheat.Address ?? 0), new Size(width, fontHeight)); - e.Graphics.DrawRectangle(new Pen(Brushes.Black), rect); - e.Graphics.FillRectangle(new SolidBrush(Global.Config.HexFreezeColor), rect); + e.Graphics.DrawRectangle(_blackPen, rect); + _freezeBrush.Color = Global.Config.HexFreezeColor; + e.Graphics.FillRectangle(_freezeBrush, rect); } } } @@ -2285,19 +2292,21 @@ namespace BizHawk.Client.EmuHawk var textpoint = new Point(textX, point.Y); var rect = new Rectangle(point, new Size(fontWidth * 2 * DataSize + (NeedsExtra(_addressHighlighted) ? fontWidth : 0) + 2, fontHeight)); - e.Graphics.DrawRectangle(new Pen(Brushes.Black), rect); + e.Graphics.DrawRectangle(_blackPen, rect); var textrect = new Rectangle(textpoint, new Size(fontWidth * DataSize, fontHeight)); if (Global.CheatList.IsActive(_domain, _addressHighlighted)) { - e.Graphics.FillRectangle(new SolidBrush(Global.Config.HexHighlightFreezeColor), rect); - e.Graphics.FillRectangle(new SolidBrush(Global.Config.HexHighlightFreezeColor), textrect); + _freezeHighlightBrush.Color = Global.Config.HexHighlightFreezeColor; + e.Graphics.FillRectangle(_freezeHighlightBrush, rect); + e.Graphics.FillRectangle(_freezeHighlightBrush, textrect); } else { - e.Graphics.FillRectangle(new SolidBrush(Global.Config.HexHighlightColor), rect); - e.Graphics.FillRectangle(new SolidBrush(Global.Config.HexHighlightColor), textrect); + _highlightBrush.Color = Global.Config.HexHighlightColor; + e.Graphics.FillRectangle(_highlightBrush, rect); + e.Graphics.FillRectangle(_highlightBrush, textrect); } } @@ -2310,19 +2319,21 @@ namespace BizHawk.Client.EmuHawk var textpoint = new Point(textX, point.Y); var rect = new Rectangle(point, new Size(fontWidth * 2 * DataSize + 2, fontHeight)); - e.Graphics.DrawRectangle(new Pen(Brushes.Black), rect); + e.Graphics.DrawRectangle(_blackPen, rect); var textrect = new Rectangle(textpoint, new Size(fontWidth * DataSize, fontHeight)); if (Global.CheatList.IsActive(_domain, address)) { - e.Graphics.FillRectangle(new SolidBrush(Global.Config.HexHighlightFreezeColor), rect); - e.Graphics.FillRectangle(new SolidBrush(Global.Config.HexHighlightFreezeColor), textrect); + _freezeHighlightBrush.Color = Global.Config.HexHighlightFreezeColor; + e.Graphics.FillRectangle(_freezeHighlightBrush, rect); + e.Graphics.FillRectangle(_freezeHighlightBrush, textrect); } else { - e.Graphics.FillRectangle(new SolidBrush(Color.FromArgb(0x44, Global.Config.HexHighlightColor)), rect); - e.Graphics.FillRectangle(new SolidBrush(Color.FromArgb(0x44, Global.Config.HexHighlightColor)), textrect); + _secondaryHighlightBrush.Color = Color.FromArgb(0x44, Global.Config.HexHighlightColor); + e.Graphics.FillRectangle(_secondaryHighlightBrush, rect); + e.Graphics.FillRectangle(_secondaryHighlightBrush, textrect); } } } From 772bd5b65eff75f4cb9683c5925f664605c60cc0 Mon Sep 17 00:00:00 2001 From: adelikat Date: Sat, 26 Oct 2019 15:22:47 -0500 Subject: [PATCH 127/166] Remove blend option in IControlRenderer, true was always being passed for GDI, so just always do alpha blend in GDI --- .../CustomControls/ControlRenderer/GDIRenderer.cs | 11 ++--------- .../CustomControls/ControlRenderer/GdiPlusRenderer.cs | 3 +-- .../ControlRenderer/IControlRenderer.cs | 2 +- .../CustomControls/InputRoll.Drawing.cs | 4 ++-- 4 files changed, 6 insertions(+), 14 deletions(-) diff --git a/BizHawk.Client.EmuHawk/CustomControls/ControlRenderer/GDIRenderer.cs b/BizHawk.Client.EmuHawk/CustomControls/ControlRenderer/GDIRenderer.cs index 679b8b3b53..12e76de025 100644 --- a/BizHawk.Client.EmuHawk/CustomControls/ControlRenderer/GDIRenderer.cs +++ b/BizHawk.Client.EmuHawk/CustomControls/ControlRenderer/GDIRenderer.cs @@ -53,19 +53,12 @@ namespace BizHawk.Client.EmuHawk.CustomControls #region Api - public void DrawBitmap(Bitmap bitmap, Point point, bool blend = false) + public void DrawBitmap(Bitmap bitmap, Point point) { IntPtr hBmp = bitmap.GetHbitmap(); var bitHdc = CreateCompatibleDC(CurrentHdc); IntPtr old = SelectObject(bitHdc, hBmp); - if (blend) - { - AlphaBlend(CurrentHdc, point.X, point.Y, bitmap.Width, bitmap.Height, bitHdc, 0, 0, bitmap.Width, bitmap.Height, new BLENDFUNCTION(AC_SRC_OVER, 0, 0xff, AC_SRC_ALPHA)); - } - else - { - BitBlt(CurrentHdc, point.X, point.Y, bitmap.Width, bitmap.Height, bitHdc, 0, 0, 0xCC0020); - } + AlphaBlend(CurrentHdc, point.X, point.Y, bitmap.Width, bitmap.Height, bitHdc, 0, 0, bitmap.Width, bitmap.Height, new BLENDFUNCTION(AC_SRC_OVER, 0, 0xff, AC_SRC_ALPHA)); SelectObject(bitHdc, old); DeleteDC(bitHdc); DeleteObject(hBmp); diff --git a/BizHawk.Client.EmuHawk/CustomControls/ControlRenderer/GdiPlusRenderer.cs b/BizHawk.Client.EmuHawk/CustomControls/ControlRenderer/GdiPlusRenderer.cs index ef23e7b98a..49032aa3c9 100644 --- a/BizHawk.Client.EmuHawk/CustomControls/ControlRenderer/GdiPlusRenderer.cs +++ b/BizHawk.Client.EmuHawk/CustomControls/ControlRenderer/GdiPlusRenderer.cs @@ -36,9 +36,8 @@ namespace BizHawk.Client.EmuHawk.CustomControls _defaultFont.Dispose(); } - public void DrawBitmap(Bitmap bitmap, Point point, bool blend = false) + public void DrawBitmap(Bitmap bitmap, Point point) { - // TODO: implement blend _graphics.DrawImage(bitmap, point); } diff --git a/BizHawk.Client.EmuHawk/CustomControls/ControlRenderer/IControlRenderer.cs b/BizHawk.Client.EmuHawk/CustomControls/ControlRenderer/IControlRenderer.cs index a0d222c0ef..b5a481cd2c 100644 --- a/BizHawk.Client.EmuHawk/CustomControls/ControlRenderer/IControlRenderer.cs +++ b/BizHawk.Client.EmuHawk/CustomControls/ControlRenderer/IControlRenderer.cs @@ -33,7 +33,7 @@ namespace BizHawk.Client.EmuHawk.CustomControls /// /// Draw a bitmap object at the given position /// - void DrawBitmap(Bitmap bitmap, Point point, bool blend = false); + void DrawBitmap(Bitmap bitmap, Point point); void Line(int x1, int y1, int x2, int y2); } } diff --git a/BizHawk.Client.EmuHawk/CustomControls/InputRoll.Drawing.cs b/BizHawk.Client.EmuHawk/CustomControls/InputRoll.Drawing.cs index 24ce6d181d..f130084254 100644 --- a/BizHawk.Client.EmuHawk/CustomControls/InputRoll.Drawing.cs +++ b/BizHawk.Client.EmuHawk/CustomControls/InputRoll.Drawing.cs @@ -185,7 +185,7 @@ namespace BizHawk.Client.EmuHawk { x = RowsToPixels(i) + CellWidthPadding + bitmapOffsetX; y = (j * CellHeight) + (CellHeightPadding * 2) + bitmapOffsetY; - _renderer.DrawBitmap(image, new Point(x, y), true); + _renderer.DrawBitmap(image, new Point(x, y)); } string text; @@ -249,7 +249,7 @@ namespace BizHawk.Client.EmuHawk if (image != null) { - _renderer.DrawBitmap(image, new Point(point.X + bitmapOffsetX, point.Y + bitmapOffsetY + CellHeightPadding), true); + _renderer.DrawBitmap(image, new Point(point.X + bitmapOffsetX, point.Y + bitmapOffsetY + CellHeightPadding)); } QueryItemText(f + startRow, visibleColumns[j], out text, ref strOffsetX, ref strOffsetY); From d2cf95e18fafb8b47788183ca47cd2e576eca36d Mon Sep 17 00:00:00 2001 From: "J.D. Purcell" Date: Sat, 26 Oct 2019 16:31:21 -0400 Subject: [PATCH 128/166] GdiPlusRenderer: Implement string rotation. --- .../ControlRenderer/GdiPlusRenderer.cs | 23 ++++++++++++------- 1 file changed, 15 insertions(+), 8 deletions(-) diff --git a/BizHawk.Client.EmuHawk/CustomControls/ControlRenderer/GdiPlusRenderer.cs b/BizHawk.Client.EmuHawk/CustomControls/ControlRenderer/GdiPlusRenderer.cs index ef23e7b98a..57a826d51e 100644 --- a/BizHawk.Client.EmuHawk/CustomControls/ControlRenderer/GdiPlusRenderer.cs +++ b/BizHawk.Client.EmuHawk/CustomControls/ControlRenderer/GdiPlusRenderer.cs @@ -1,6 +1,6 @@ using System; using System.Drawing; - + namespace BizHawk.Client.EmuHawk.CustomControls { public class GdiPlusRenderer : IControlRenderer @@ -12,6 +12,7 @@ namespace BizHawk.Client.EmuHawk.CustomControls private readonly SolidBrush _currentStringBrush = new SolidBrush(Color.Black); private readonly Font _defaultFont = new Font("Arial", 8, FontStyle.Bold); private Font _currentFont; + private bool _rotateString; public GdiPlusRenderer() { @@ -50,8 +51,18 @@ namespace BizHawk.Client.EmuHawk.CustomControls } public void DrawString(string str, Point point) - { - _graphics.DrawString(str, _currentFont, _currentStringBrush, point); + { + if (_rotateString) + { + _graphics.TranslateTransform(point.X, point.Y); + _graphics.RotateTransform(90); + _graphics.DrawString(str, _currentFont, _currentStringBrush, Point.Empty); + _graphics.ResetTransform(); + } + else + { + _graphics.DrawString(str, _currentFont, _currentStringBrush, point); + } } public void FillRectangle(int x, int y, int w, int h) @@ -80,13 +91,9 @@ namespace BizHawk.Client.EmuHawk.CustomControls public void PrepDrawString(Font font, Color color, bool rotate = false) { - if (rotate) - { - // TODO - } - _currentFont = font; _currentStringBrush.Color = color; + _rotateString = rotate; } public void SetBrush(Color color) From d592526c3c90c25440d50ce927517d30b8de2563 Mon Sep 17 00:00:00 2001 From: adelikat Date: Sat, 26 Oct 2019 15:47:43 -0500 Subject: [PATCH 129/166] InputRoll - stop passing around unused paint event args --- .../CustomControls/InputRoll.Drawing.cs | 32 +++++++++---------- 1 file changed, 16 insertions(+), 16 deletions(-) diff --git a/BizHawk.Client.EmuHawk/CustomControls/InputRoll.Drawing.cs b/BizHawk.Client.EmuHawk/CustomControls/InputRoll.Drawing.cs index 5f4d3e7e41..a37dd7dd4f 100644 --- a/BizHawk.Client.EmuHawk/CustomControls/InputRoll.Drawing.cs +++ b/BizHawk.Client.EmuHawk/CustomControls/InputRoll.Drawing.cs @@ -24,18 +24,18 @@ namespace BizHawk.Client.EmuHawk if (visibleColumns.Any()) { - DrawColumnBg(e, visibleColumns); - DrawColumnText(e, visibleColumns); + DrawColumnBg(visibleColumns); + DrawColumnText(visibleColumns); } // Background - DrawBg(e, visibleColumns); + DrawBg(visibleColumns); // Foreground - DrawData(e, visibleColumns); + DrawData(visibleColumns); - DrawColumnDrag(e); - DrawCellDrag(e); + DrawColumnDrag(); + DrawCellDrag(); } } @@ -63,7 +63,7 @@ namespace BizHawk.Client.EmuHawk // Do nothing, and this should never be called } - private void DrawColumnDrag(PaintEventArgs e) + private void DrawColumnDrag() { if (_columnDown != null && _columnDownMoved && _currentX.HasValue && _currentY.HasValue && IsHoveringOnColumnCell) { @@ -79,7 +79,7 @@ namespace BizHawk.Client.EmuHawk } } - private void DrawCellDrag(PaintEventArgs e) + private void DrawCellDrag() { if (_draggingCell != null) { @@ -104,7 +104,7 @@ namespace BizHawk.Client.EmuHawk } } - private void DrawColumnText(PaintEventArgs e, List visibleColumns) + private void DrawColumnText(List visibleColumns) { if (HorizontalOrientation) { @@ -152,7 +152,7 @@ namespace BizHawk.Client.EmuHawk } } - private void DrawData(PaintEventArgs e, List visibleColumns) + private void DrawData(List visibleColumns) { // Prevent exceptions with small TAStudio windows if (visibleColumns.Count == 0) @@ -280,7 +280,7 @@ namespace BizHawk.Client.EmuHawk } } - private void DrawColumnBg(PaintEventArgs e, List visibleColumns) + private void DrawColumnBg(List visibleColumns) { _renderer.SetBrush(SystemColors.ControlLight); _renderer.SetSolidPen(Color.Black); @@ -401,11 +401,11 @@ namespace BizHawk.Client.EmuHawk /// /// Draw Gridlines and background colors using QueryItemBkColor. /// - private void DrawBg(PaintEventArgs e, List visibleColumns) + private void DrawBg(List visibleColumns) { if (UseCustomBackground && QueryItemBkColor != null) { - DoBackGroundCallback(e, visibleColumns); + DoBackGroundCallback(visibleColumns); } if (GridLines) @@ -452,11 +452,11 @@ namespace BizHawk.Client.EmuHawk if (_selectedItems.Any()) { - DoSelectionBG(e, visibleColumns); + DoSelectionBG(visibleColumns); } } - private void DoSelectionBG(PaintEventArgs e, List visibleColumns) + private void DoSelectionBG(List visibleColumns) { // SuuperW: This allows user to see other colors in selected frames. Color rowColor = Color.White; @@ -545,7 +545,7 @@ namespace BizHawk.Client.EmuHawk /// /// Calls QueryItemBkColor callback for all visible cells and fills in the background of those cells. /// - private void DoBackGroundCallback(PaintEventArgs e, List visibleColumns) + private void DoBackGroundCallback(List visibleColumns) { int startIndex = FirstVisibleRow; int range = Math.Min(LastVisibleRow, RowCount - 1) - startIndex + 1; From 179e71efee3cabca52449d0c29d0e63ed9ab9cee Mon Sep 17 00:00:00 2001 From: adelikat Date: Sat, 26 Oct 2019 16:01:21 -0500 Subject: [PATCH 130/166] remove some now unused control extension methods --- .../Extensions/ControlExtensions.cs | 87 +------------------ 1 file changed, 1 insertion(+), 86 deletions(-) diff --git a/BizHawk.Client.EmuHawk/Extensions/ControlExtensions.cs b/BizHawk.Client.EmuHawk/Extensions/ControlExtensions.cs index 9518dde03e..5f250d055a 100644 --- a/BizHawk.Client.EmuHawk/Extensions/ControlExtensions.cs +++ b/BizHawk.Client.EmuHawk/Extensions/ControlExtensions.cs @@ -43,43 +43,6 @@ namespace BizHawk.Client.EmuHawk.WinFormExtensions return control.BeginInvoke(action); } - public static void AddColumn(this ListView listView, string columnName, bool enabled, int columnWidth) - { - if (enabled) - { - if (listView.Columns[columnName] == null) - { - var column = new ColumnHeader - { - Name = columnName, - Text = columnName.Replace("Column", ""), - Width = columnWidth, - }; - - listView.Columns.Add(column); - } - } - } - - public static void AddColumn(this ListView listView, ToolDialogSettings.Column column) - { - if (column.Visible) - { - if (listView.Columns[column.Name] == null) - { - var lsstViewColumn = new ColumnHeader - { - Name = column.Name, - Text = column.Name.Replace("Column", ""), - Width = column.Width, - DisplayIndex = column.Index - }; - - listView.Columns.Add(lsstViewColumn); - } - } - } - public static ToolStripMenuItem ToColumnsMenu(this InputRoll inputRoll, Action changeCallback) { var menu = new ToolStripMenuItem @@ -116,44 +79,6 @@ namespace BizHawk.Client.EmuHawk.WinFormExtensions return menu; } - public static ToolStripMenuItem GenerateColumnsMenu(this ToolDialogSettings.ColumnList list, Action changeCallback) - { - var menu = new ToolStripMenuItem - { - Name = "GeneratedColumnsSubMenu", - Text = "Columns" - }; - - var dummyList = list; - - foreach (var column in dummyList) - { - var menuItem = new ToolStripMenuItem - { - Name = column.Name, - Text = column.Name.Replace("Column", "") - }; - - menuItem.Click += (o, ev) => - { - dummyList[menuItem.Name].Visible ^= true; - changeCallback(); - }; - - menu.DropDownItems.Add(menuItem); - } - - menu.DropDownOpened += (o, e) => - { - foreach (var column in dummyList) - { - (menu.DropDownItems[column.Name] as ToolStripMenuItem).Checked = column.Visible; - } - }; - - return menu; - } - public static Point ChildPointToScreen(this Control control, Control child) { return control.PointToScreen(new Point(child.Location.X, child.Location.Y)); @@ -175,16 +100,6 @@ namespace BizHawk.Client.EmuHawk.WinFormExtensions return tabControl.TabPages.Cast(); } - public static IEnumerable SelectedIndices(this ListView listView) - { - return listView.SelectedIndices.Cast(); - } - - public static IEnumerable ColumnHeaders(this ListView listView) - { - return listView.Columns.OfType(); - } - #endregion } @@ -287,7 +202,7 @@ namespace BizHawk.Client.EmuHawk.WinFormExtensions { foreach (ListViewItem.ListViewSubItem item in listViewControl.Items[index].SubItems) { - if (!String.IsNullOrWhiteSpace(item.Text)) + if (!string.IsNullOrWhiteSpace(item.Text)) { sb.Append(item.Text).Append('\t'); } From af59d2fe6b6a6804c365b82d319620f700365086 Mon Sep 17 00:00:00 2001 From: adelikat Date: Sat, 26 Oct 2019 16:04:27 -0500 Subject: [PATCH 131/166] InputRoll - misc cleanups --- .../CustomControls/InputRoll.Drawing.cs | 45 ++++++++----------- .../CustomControls/InputRoll.cs | 8 ---- .../Extensions/ControlExtensions.cs | 10 +++-- 3 files changed, 25 insertions(+), 38 deletions(-) diff --git a/BizHawk.Client.EmuHawk/CustomControls/InputRoll.Drawing.cs b/BizHawk.Client.EmuHawk/CustomControls/InputRoll.Drawing.cs index a37dd7dd4f..b12be79fcd 100644 --- a/BizHawk.Client.EmuHawk/CustomControls/InputRoll.Drawing.cs +++ b/BizHawk.Client.EmuHawk/CustomControls/InputRoll.Drawing.cs @@ -3,6 +3,7 @@ using System.Collections.Generic; using System.Drawing; using System.Linq; using System.Windows.Forms; +using BizHawk.Client.EmuHawk.WinFormExtensions; namespace BizHawk.Client.EmuHawk { @@ -58,7 +59,7 @@ namespace BizHawk.Client.EmuHawk _renderer.DrawString(text, point); } - protected override void OnPaintBackground(PaintEventArgs pevent) + protected override void OnPaintBackground(PaintEventArgs e) { // Do nothing, and this should never be called } @@ -312,10 +313,10 @@ namespace BizHawk.Client.EmuHawk _renderer.Line(0, 0, TotalColWidth.Value + 1, 0); _renderer.Line(0, bottomEdge, TotalColWidth.Value + 1, bottomEdge); - // Vertical black seperators - for (int i = 0; i < visibleColumns.Count; i++) + // Vertical black separators + foreach (var column in visibleColumns) { - int pos = visibleColumns[i].Left.Value - _hBar.Value; + int pos = column.Left.Value - _hBar.Value; _renderer.Line(pos, 0, pos, bottomEdge); } @@ -353,14 +354,9 @@ namespace BizHawk.Client.EmuHawk continue; } - if (CurrentCell.Column.Emphasis) - { - _renderer.SetBrush(Add(SystemColors.Highlight, 0x00222222)); - } - else - { - _renderer.SetBrush(SystemColors.Highlight); - } + _renderer.SetBrush(CurrentCell.Column.Emphasis + ? SystemColors.Highlight.Add(0x00222222) + : SystemColors.Highlight); _renderer.FillRectangle(1, i * CellHeight + 1, ColumnWidth - 1, ColumnHeight - 1); } @@ -368,27 +364,22 @@ namespace BizHawk.Client.EmuHawk else { // TODO multiple selected columns - for (int i = 0; i < visibleColumns.Count; i++) + foreach (var column in visibleColumns) { - if (visibleColumns[i] == CurrentCell.Column) + if (column == CurrentCell.Column) { // Left of column is to the right of the viewable area or right of column is to the left of the viewable area - if (visibleColumns[i].Left.Value - _hBar.Value > Width || visibleColumns[i].Right.Value - _hBar.Value < 0) + if (column.Left.Value - _hBar.Value > Width || column.Right.Value - _hBar.Value < 0) { continue; } - int left = visibleColumns[i].Left.Value - _hBar.Value; - int width = visibleColumns[i].Right.Value - _hBar.Value - left; + int left = column.Left.Value - _hBar.Value; + int width = column.Right.Value - _hBar.Value - left; - if (CurrentCell.Column.Emphasis) - { - _renderer.SetBrush(Add(SystemColors.Highlight, 0x00550000)); - } - else - { - _renderer.SetBrush(SystemColors.Highlight); - } + _renderer.SetBrush(CurrentCell.Column.Emphasis + ? SystemColors.Highlight.Add(0x00550000) + : SystemColors.Highlight); _renderer.FillRectangle(left + 1, 1, width - 1, ColumnHeight - 1); } @@ -460,11 +451,11 @@ namespace BizHawk.Client.EmuHawk { // SuuperW: This allows user to see other colors in selected frames. Color rowColor = Color.White; - int _lastVisibleRow = LastVisibleRow; + int lastVisibleRow = LastVisibleRow; int lastRow = -1; foreach (Cell cell in _selectedItems) { - if (cell.RowIndex > _lastVisibleRow || cell.RowIndex < FirstVisibleRow || !VisibleColumns.Contains(cell.Column)) + if (cell.RowIndex > lastVisibleRow || cell.RowIndex < FirstVisibleRow || !VisibleColumns.Contains(cell.Column)) { continue; } diff --git a/BizHawk.Client.EmuHawk/CustomControls/InputRoll.cs b/BizHawk.Client.EmuHawk/CustomControls/InputRoll.cs index 6dbacdaf68..4c97607d1c 100644 --- a/BizHawk.Client.EmuHawk/CustomControls/InputRoll.cs +++ b/BizHawk.Client.EmuHawk/CustomControls/InputRoll.cs @@ -1599,14 +1599,6 @@ namespace BizHawk.Client.EmuHawk #region Helpers - // TODO: Make into an extension method - private static Color Add(Color color, int val) - { - var col = color.ToArgb(); - col += val; - return Color.FromArgb(col); - } - private void DoColumnReorder() { if (_columnDown != CurrentCell.Column) diff --git a/BizHawk.Client.EmuHawk/Extensions/ControlExtensions.cs b/BizHawk.Client.EmuHawk/Extensions/ControlExtensions.cs index 5f250d055a..b37ca52fa2 100644 --- a/BizHawk.Client.EmuHawk/Extensions/ControlExtensions.cs +++ b/BizHawk.Client.EmuHawk/Extensions/ControlExtensions.cs @@ -7,10 +7,7 @@ using System.Runtime.InteropServices; using System.Text; using System.Windows.Forms; -using BizHawk.Common; using BizHawk.Common.ReflectionExtensions; -using BizHawk.Client.Common; - namespace BizHawk.Client.EmuHawk.WinFormExtensions { @@ -84,6 +81,13 @@ namespace BizHawk.Client.EmuHawk.WinFormExtensions return control.PointToScreen(new Point(child.Location.X, child.Location.Y)); } + public static Color Add(this Color color, int val) + { + var col = color.ToArgb(); + col += val; + return Color.FromArgb(col); + } + #region Enumerable to Enumerable /// From 5a17d20cf04aeb8acc21e2b416eb619cebb94929 Mon Sep 17 00:00:00 2001 From: adelikat Date: Sat, 26 Oct 2019 16:20:27 -0500 Subject: [PATCH 132/166] InputRoll - some more cleanup --- .../CustomControls/InputRoll.Drawing.cs | 40 ++++++------------- 1 file changed, 12 insertions(+), 28 deletions(-) diff --git a/BizHawk.Client.EmuHawk/CustomControls/InputRoll.Drawing.cs b/BizHawk.Client.EmuHawk/CustomControls/InputRoll.Drawing.cs index b12be79fcd..2a9e80a1af 100644 --- a/BizHawk.Client.EmuHawk/CustomControls/InputRoll.Drawing.cs +++ b/BizHawk.Client.EmuHawk/CustomControls/InputRoll.Drawing.cs @@ -160,6 +160,7 @@ namespace BizHawk.Client.EmuHawk { return; } + if (QueryItemText != null) { if (HorizontalOrientation) @@ -171,12 +172,12 @@ namespace BizHawk.Client.EmuHawk for (int i = 0, f = 0; f < range; i++, f++) { f += _lagFrames[i]; - int LastVisible = LastVisibleColumnIndex; - for (int j = FirstVisibleColumn; j <= LastVisible; j++) + int lastVisible = LastVisibleColumnIndex; + for (int j = FirstVisibleColumn; j <= lastVisible; j++) { Bitmap image = null; - int x = 0; - int y = 0; + int x; + int y; int bitmapOffsetX = 0; int bitmapOffsetY = 0; @@ -199,32 +200,15 @@ namespace BizHawk.Client.EmuHawk y = (j * CellHeight) + CellHeightPadding - _vBar.Value; var point = new Point(x + strOffsetX, y + strOffsetY); - var rePrep = false; - //if (j == 1) - //if (_selectedItems.Contains(new Cell { Column = visibleColumns[j], RowIndex = i + startRow })) - //{ - // _renderer.PrepDrawString(_font, SystemColors.HighlightText, rotate: true); - // rePrep = true; - //} - //else if (j == 1) - //{ - // // 1. not sure about this; 2. repreps may be excess, but if we render one column at a time, we do need to change back after rendering the header - // rePrep = true; - // _renderer.PrepDrawString(_font, _foreColor, rotate: true); - //} - - //if (visibleColumns[j].Type == RollColumn.InputType.Text) - if (visibleColumns[j].Name == "FrameColumn") + if (visibleColumns[j].Name == "FrameColumn") // TODO: don't do this hack { _renderer.PrepDrawString(_font, _foreColor, rotate: true); - rePrep = true; + DrawString(text, ColumnWidth, point); + _renderer.PrepDrawString(_font, _foreColor, rotate: false); } - - DrawString(text, ColumnWidth, point); - - if (rePrep) + else { - _renderer.PrepDrawString(_font, _foreColor); + DrawString(text, ColumnWidth, point); } } } @@ -239,8 +223,8 @@ namespace BizHawk.Client.EmuHawk for (int i = 0, f = 0; f < range; i++, f++) // Vertical { f += _lagFrames[i]; - int LastVisible = LastVisibleColumnIndex; - for (int j = FirstVisibleColumn; j <= LastVisible; j++) // Horizontal + int lastVisible = LastVisibleColumnIndex; + for (int j = FirstVisibleColumn; j <= lastVisible; j++) // Horizontal { RollColumn col = visibleColumns[j]; From 14ffd143d4fae622555749702fe90432ed807b83 Mon Sep 17 00:00:00 2001 From: adelikat Date: Sat, 26 Oct 2019 16:25:42 -0500 Subject: [PATCH 133/166] InputRoll - fix placement of rotated text --- BizHawk.Client.EmuHawk/CustomControls/InputRoll.Drawing.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/BizHawk.Client.EmuHawk/CustomControls/InputRoll.Drawing.cs b/BizHawk.Client.EmuHawk/CustomControls/InputRoll.Drawing.cs index 2a9e80a1af..a5fa6e87b7 100644 --- a/BizHawk.Client.EmuHawk/CustomControls/InputRoll.Drawing.cs +++ b/BizHawk.Client.EmuHawk/CustomControls/InputRoll.Drawing.cs @@ -203,7 +203,7 @@ namespace BizHawk.Client.EmuHawk if (visibleColumns[j].Name == "FrameColumn") // TODO: don't do this hack { _renderer.PrepDrawString(_font, _foreColor, rotate: true); - DrawString(text, ColumnWidth, point); + DrawString(text, ColumnWidth, new Point(point.X + _charSize.Height + CellWidthPadding, point.Y + CellHeightPadding)); _renderer.PrepDrawString(_font, _foreColor, rotate: false); } else From b54be19e9e1f2d8199a3e1eb230dad362f84babf Mon Sep 17 00:00:00 2001 From: adelikat Date: Sat, 26 Oct 2019 16:49:52 -0500 Subject: [PATCH 134/166] InputRoll - reorg - put in its own folder, break out column and cell classes into separate files --- .../BizHawk.Client.EmuHawk.csproj | 8 +- .../CustomControls/InputRoll/Cell.cs | 71 + .../CustomControls/InputRoll/ColumnType.cs | 10 + .../{ => InputRoll}/InputRoll.Drawing.cs | 1220 ++--- .../{ => InputRoll}/InputRoll.cs | 4382 ++++++++--------- .../CustomControls/InputRoll/RollColumn.cs | 29 + .../CustomControls/InputRoll/RollColumns.cs | 152 + BizHawk.Client.EmuHawk/tools/CDL.cs | 28 +- BizHawk.Client.EmuHawk/tools/Cheats/Cheats.cs | 26 +- .../Debugger/GenericDebugger.Disassembler.cs | 4 +- .../tools/Debugger/GenericDebugger.cs | 8 +- .../Lua/Libraries/EmuLuaLibrary.Tastudio.cs | 2 +- .../tools/Lua/LuaConsole.cs | 16 +- .../tools/TAStudio/BookmarksBranchesBox.cs | 10 +- .../tools/TAStudio/MarkerControl.cs | 8 +- .../tools/TAStudio/TAStudio.Callbacks.cs | 6 +- .../tools/TAStudio/TAStudio.ListView.cs | 10 +- .../tools/TAStudio/TAStudio.MenuItems.cs | 2 +- .../tools/TAStudio/TAStudio.cs | 10 +- .../tools/TAStudio/UndoHistoryForm.cs | 8 +- BizHawk.Client.EmuHawk/tools/TraceLogger.cs | 12 +- .../tools/Watch/RamSearch.cs | 18 +- .../tools/Watch/RamWatch.cs | 26 +- 23 files changed, 3043 insertions(+), 3023 deletions(-) create mode 100644 BizHawk.Client.EmuHawk/CustomControls/InputRoll/Cell.cs create mode 100644 BizHawk.Client.EmuHawk/CustomControls/InputRoll/ColumnType.cs rename BizHawk.Client.EmuHawk/CustomControls/{ => InputRoll}/InputRoll.Drawing.cs (96%) rename BizHawk.Client.EmuHawk/CustomControls/{ => InputRoll}/InputRoll.cs (87%) create mode 100644 BizHawk.Client.EmuHawk/CustomControls/InputRoll/RollColumn.cs create mode 100644 BizHawk.Client.EmuHawk/CustomControls/InputRoll/RollColumns.cs diff --git a/BizHawk.Client.EmuHawk/BizHawk.Client.EmuHawk.csproj b/BizHawk.Client.EmuHawk/BizHawk.Client.EmuHawk.csproj index 70a0bf936e..2251812747 100644 --- a/BizHawk.Client.EmuHawk/BizHawk.Client.EmuHawk.csproj +++ b/BizHawk.Client.EmuHawk/BizHawk.Client.EmuHawk.csproj @@ -587,13 +587,17 @@ Form - + + + Component - + InputRoll.cs Component + + Component diff --git a/BizHawk.Client.EmuHawk/CustomControls/InputRoll/Cell.cs b/BizHawk.Client.EmuHawk/CustomControls/InputRoll/Cell.cs new file mode 100644 index 0000000000..3273aeef46 --- /dev/null +++ b/BizHawk.Client.EmuHawk/CustomControls/InputRoll/Cell.cs @@ -0,0 +1,71 @@ +using System.Collections.Generic; + +namespace BizHawk.Client.EmuHawk +{ + /// + /// Represents a single cell of the + /// + public class Cell + { + public RollColumn Column { get; internal set; } + public int? RowIndex { get; internal set; } + public string CurrentText { get; internal set; } + + public Cell() { } + + public Cell(Cell cell) + { + Column = cell.Column; + RowIndex = cell.RowIndex; + } + + public bool IsDataCell => Column != null && RowIndex.HasValue; + + public override bool Equals(object obj) + { + if (obj is Cell) + { + var cell = obj as Cell; + return this.Column == cell.Column && this.RowIndex == cell.RowIndex; + } + + return base.Equals(obj); + } + + public override int GetHashCode() + { + return Column.GetHashCode() + RowIndex.GetHashCode(); + } + } + + internal class SortCell : IComparer + { + int IComparer.Compare(Cell a, Cell b) + { + Cell c1 = a as Cell; + Cell c2 = b as Cell; + if (c1.RowIndex.HasValue) + { + if (c2.RowIndex.HasValue) + { + int row = c1.RowIndex.Value.CompareTo(c2.RowIndex.Value); + if (row == 0) + { + return c1.Column.Name.CompareTo(c2.Column.Name); + } + + return row; + } + + return 1; + } + + if (c2.RowIndex.HasValue) + { + return -1; + } + + return c1.Column.Name.CompareTo(c2.Column.Name); + } + } +} diff --git a/BizHawk.Client.EmuHawk/CustomControls/InputRoll/ColumnType.cs b/BizHawk.Client.EmuHawk/CustomControls/InputRoll/ColumnType.cs new file mode 100644 index 0000000000..b0fb0ce845 --- /dev/null +++ b/BizHawk.Client.EmuHawk/CustomControls/InputRoll/ColumnType.cs @@ -0,0 +1,10 @@ +namespace BizHawk.Client.EmuHawk +{ + /// + /// Specifies the type of column of a + /// + public enum ColumnType + { + Boolean, Float, Text, Image + } +} diff --git a/BizHawk.Client.EmuHawk/CustomControls/InputRoll.Drawing.cs b/BizHawk.Client.EmuHawk/CustomControls/InputRoll/InputRoll.Drawing.cs similarity index 96% rename from BizHawk.Client.EmuHawk/CustomControls/InputRoll.Drawing.cs rename to BizHawk.Client.EmuHawk/CustomControls/InputRoll/InputRoll.Drawing.cs index a5fa6e87b7..ebe9209f53 100644 --- a/BizHawk.Client.EmuHawk/CustomControls/InputRoll.Drawing.cs +++ b/BizHawk.Client.EmuHawk/CustomControls/InputRoll/InputRoll.Drawing.cs @@ -1,610 +1,610 @@ -using System; -using System.Collections.Generic; -using System.Drawing; -using System.Linq; -using System.Windows.Forms; -using BizHawk.Client.EmuHawk.WinFormExtensions; - -namespace BizHawk.Client.EmuHawk -{ - public partial class InputRoll - { - protected override void OnPaint(PaintEventArgs e) - { - using (_renderer.LockGraphics(e.Graphics, Width, Height)) - { - // White Background - _renderer.SetBrush(Color.White); - _renderer.SetSolidPen(Color.White); - _renderer.FillRectangle(0, 0, Width, Height); - - // Lag frame calculations - SetLagFramesArray(); - - var visibleColumns = _columns.VisibleColumns.ToList(); - - if (visibleColumns.Any()) - { - DrawColumnBg(visibleColumns); - DrawColumnText(visibleColumns); - } - - // Background - DrawBg(visibleColumns); - - // Foreground - DrawData(visibleColumns); - - DrawColumnDrag(); - DrawCellDrag(); - } - } - - private void DrawString(string text, int? width, Point point) - { - if (string.IsNullOrWhiteSpace(text)) - { - return; - } - - if (width.HasValue) - { - var max = (width.Value - CellWidthPadding) / _charSize.Width; - if (text.Length >= max) - { - text = text.Substring(0, max); - } - } - - _renderer.DrawString(text, point); - } - - protected override void OnPaintBackground(PaintEventArgs e) - { - // Do nothing, and this should never be called - } - - private void DrawColumnDrag() - { - if (_columnDown != null && _columnDownMoved && _currentX.HasValue && _currentY.HasValue && IsHoveringOnColumnCell) - { - int x1 = _currentX.Value - (_columnDown.Width.Value / 2); - int y1 = _currentY.Value - (CellHeight / 2); - int x2 = x1 + _columnDown.Width.Value; - int y2 = y1 + CellHeight; - - _renderer.SetSolidPen(_backColor); - _renderer.DrawRectangle(x1, y1, x2, y2); - _renderer.PrepDrawString(_font, _foreColor); - _renderer.DrawString(_columnDown.Text, new Point(x1 + CellWidthPadding, y1 + CellHeightPadding)); - } - } - - private void DrawCellDrag() - { - if (_draggingCell != null) - { - var text = ""; - int offsetX = 0; - int offsetY = 0; - QueryItemText?.Invoke(_draggingCell.RowIndex.Value, _draggingCell.Column, out text, ref offsetX, ref offsetY); - - Color bgColor = _backColor; - QueryItemBkColor?.Invoke(_draggingCell.RowIndex.Value, _draggingCell.Column, ref bgColor); - - int x1 = _currentX.Value - (_draggingCell.Column.Width.Value / 2); - int y1 = _currentY.Value - (CellHeight / 2); - int x2 = x1 + _draggingCell.Column.Width.Value; - int y2 = y1 + CellHeight; - - - _renderer.SetBrush(bgColor); - _renderer.FillRectangle(x1, y1, x2 - x1, y2 - y1); - _renderer.PrepDrawString(_font, _foreColor); - _renderer.DrawString(text, new Point(x1 + CellWidthPadding + offsetX, y1 + CellHeightPadding + offsetY)); - } - } - - private void DrawColumnText(List visibleColumns) - { - if (HorizontalOrientation) - { - int start = -_vBar.Value; - - _renderer.PrepDrawString(_font, _foreColor); - - foreach (var column in visibleColumns) - { - var point = new Point(CellWidthPadding, start + CellHeightPadding); - - if (IsHoveringOnColumnCell && column == CurrentCell.Column) - { - _renderer.PrepDrawString(_font, SystemColors.HighlightText); - DrawString(column.Text, column.Width, point); - _renderer.PrepDrawString(_font, _foreColor); - } - else - { - DrawString(column.Text, column.Width, point); - } - - start += CellHeight; - } - } - else - { - _renderer.PrepDrawString(_font, _foreColor); - - foreach (var column in visibleColumns) - { - var point = new Point(column.Left.Value + 2 * CellWidthPadding - _hBar.Value, CellHeightPadding); // TODO: fix this CellPadding issue (2 * CellPadding vs just CellPadding) - - if (IsHoveringOnColumnCell && column == CurrentCell.Column) - { - _renderer.PrepDrawString(_font, SystemColors.HighlightText); - DrawString(column.Text, column.Width, point); - _renderer.PrepDrawString(_font, _foreColor); - } - else - { - DrawString(column.Text, column.Width, point); - } - } - } - } - - private void DrawData(List visibleColumns) - { - // Prevent exceptions with small TAStudio windows - if (visibleColumns.Count == 0) - { - return; - } - - if (QueryItemText != null) - { - if (HorizontalOrientation) - { - int startRow = FirstVisibleRow; - int range = Math.Min(LastVisibleRow, RowCount - 1) - startRow + 1; - - _renderer.PrepDrawString(_font, _foreColor); - for (int i = 0, f = 0; f < range; i++, f++) - { - f += _lagFrames[i]; - int lastVisible = LastVisibleColumnIndex; - for (int j = FirstVisibleColumn; j <= lastVisible; j++) - { - Bitmap image = null; - int x; - int y; - int bitmapOffsetX = 0; - int bitmapOffsetY = 0; - - QueryItemIcon?.Invoke(f + startRow, visibleColumns[j], ref image, ref bitmapOffsetX, ref bitmapOffsetY); - - if (image != null) - { - x = RowsToPixels(i) + CellWidthPadding + bitmapOffsetX; - y = (j * CellHeight) + (CellHeightPadding * 2) + bitmapOffsetY; - _renderer.DrawBitmap(image, new Point(x, y)); - } - - string text; - int strOffsetX = 0; - int strOffsetY = 0; - QueryItemText(f + startRow, visibleColumns[j], out text, ref strOffsetX, ref strOffsetY); - - // Center Text - x = RowsToPixels(i) + ((CellWidth - (text.Length * _charSize.Width)) / 2); - y = (j * CellHeight) + CellHeightPadding - _vBar.Value; - var point = new Point(x + strOffsetX, y + strOffsetY); - - if (visibleColumns[j].Name == "FrameColumn") // TODO: don't do this hack - { - _renderer.PrepDrawString(_font, _foreColor, rotate: true); - DrawString(text, ColumnWidth, new Point(point.X + _charSize.Height + CellWidthPadding, point.Y + CellHeightPadding)); - _renderer.PrepDrawString(_font, _foreColor, rotate: false); - } - else - { - DrawString(text, ColumnWidth, point); - } - } - } - } - else - { - int startRow = FirstVisibleRow; - int range = Math.Min(LastVisibleRow, RowCount - 1) - startRow + 1; - - _renderer.PrepDrawString(_font, _foreColor); - int xPadding = CellWidthPadding + 1 - _hBar.Value; - for (int i = 0, f = 0; f < range; i++, f++) // Vertical - { - f += _lagFrames[i]; - int lastVisible = LastVisibleColumnIndex; - for (int j = FirstVisibleColumn; j <= lastVisible; j++) // Horizontal - { - RollColumn col = visibleColumns[j]; - - string text; - int strOffsetX = 0; - int strOffsetY = 0; - Point point = new Point(col.Left.Value + xPadding, RowsToPixels(i) + CellHeightPadding); - - Bitmap image = null; - int bitmapOffsetX = 0; - int bitmapOffsetY = 0; - - QueryItemIcon?.Invoke(f + startRow, visibleColumns[j], ref image, ref bitmapOffsetX, ref bitmapOffsetY); - - if (image != null) - { - _renderer.DrawBitmap(image, new Point(point.X + bitmapOffsetX, point.Y + bitmapOffsetY + CellHeightPadding)); - } - - QueryItemText(f + startRow, visibleColumns[j], out text, ref strOffsetX, ref strOffsetY); - - bool rePrep = false; - if (_selectedItems.Contains(new Cell { Column = visibleColumns[j], RowIndex = f + startRow })) - { - _renderer.PrepDrawString(_font, SystemColors.HighlightText); - rePrep = true; - } - - DrawString(text, col.Width, new Point(point.X + strOffsetX, point.Y + strOffsetY)); - - if (rePrep) - { - _renderer.PrepDrawString(_font, _foreColor); - } - } - } - } - } - } - - private void DrawColumnBg(List visibleColumns) - { - _renderer.SetBrush(SystemColors.ControlLight); - _renderer.SetSolidPen(Color.Black); - - if (HorizontalOrientation) - { - _renderer.FillRectangle(0, 0, ColumnWidth + 1, DrawHeight + 1); - _renderer.Line(0, 0, 0, visibleColumns.Count * CellHeight + 1); - _renderer.Line(ColumnWidth, 0, ColumnWidth, visibleColumns.Count * CellHeight + 1); - - int start = -_vBar.Value; - foreach (var column in visibleColumns) - { - _renderer.Line(1, start, ColumnWidth, start); - start += CellHeight; - } - - if (visibleColumns.Any()) - { - _renderer.Line(1, start, ColumnWidth, start); - } - } - else - { - int bottomEdge = RowsToPixels(0); - - // Gray column box and black line underneath - _renderer.FillRectangle(0, 0, Width + 1, bottomEdge + 1); - _renderer.Line(0, 0, TotalColWidth.Value + 1, 0); - _renderer.Line(0, bottomEdge, TotalColWidth.Value + 1, bottomEdge); - - // Vertical black separators - foreach (var column in visibleColumns) - { - int pos = column.Left.Value - _hBar.Value; - _renderer.Line(pos, 0, pos, bottomEdge); - } - - // Draw right most line - if (visibleColumns.Any()) - { - int right = TotalColWidth.Value - _hBar.Value; - _renderer.Line(right, 0, right, bottomEdge); - } - } - - // Emphasis - foreach (var column in visibleColumns.Where(c => c.Emphasis)) - { - _renderer.SetBrush(SystemColors.ActiveBorder); - if (HorizontalOrientation) - { - _renderer.FillRectangle(1, visibleColumns.IndexOf(column) * CellHeight + 1, ColumnWidth - 1, ColumnHeight - 1); - } - else - { - _renderer.FillRectangle(column.Left.Value + 1 - _hBar.Value, 1, column.Width.Value - 1, ColumnHeight - 1); - } - } - - // If the user is hovering over a column - if (IsHoveringOnColumnCell) - { - if (HorizontalOrientation) - { - for (int i = 0; i < visibleColumns.Count; i++) - { - if (visibleColumns[i] != CurrentCell.Column) - { - continue; - } - - _renderer.SetBrush(CurrentCell.Column.Emphasis - ? SystemColors.Highlight.Add(0x00222222) - : SystemColors.Highlight); - - _renderer.FillRectangle(1, i * CellHeight + 1, ColumnWidth - 1, ColumnHeight - 1); - } - } - else - { - // TODO multiple selected columns - foreach (var column in visibleColumns) - { - if (column == CurrentCell.Column) - { - // Left of column is to the right of the viewable area or right of column is to the left of the viewable area - if (column.Left.Value - _hBar.Value > Width || column.Right.Value - _hBar.Value < 0) - { - continue; - } - - int left = column.Left.Value - _hBar.Value; - int width = column.Right.Value - _hBar.Value - left; - - _renderer.SetBrush(CurrentCell.Column.Emphasis - ? SystemColors.Highlight.Add(0x00550000) - : SystemColors.Highlight); - - _renderer.FillRectangle(left + 1, 1, width - 1, ColumnHeight - 1); - } - } - } - } - } - - // TODO refactor this and DoBackGroundCallback functions. - /// - /// Draw Gridlines and background colors using QueryItemBkColor. - /// - private void DrawBg(List visibleColumns) - { - if (UseCustomBackground && QueryItemBkColor != null) - { - DoBackGroundCallback(visibleColumns); - } - - if (GridLines) - { - _renderer.SetSolidPen(SystemColors.ControlLight); - if (HorizontalOrientation) - { - // Columns - for (int i = 1; i < VisibleRows + 1; i++) - { - int x = RowsToPixels(i); - _renderer.Line(x, 1, x, DrawHeight); - } - - // Rows - for (int i = 0; i < visibleColumns.Count + 1; i++) - { - _renderer.Line(RowsToPixels(0) + 1, i * CellHeight - _vBar.Value, DrawWidth, i * CellHeight - _vBar.Value); - } - } - else - { - // Columns - int y = ColumnHeight + 1; - int? totalColWidth = TotalColWidth; - foreach (var column in visibleColumns) - { - int x = column.Left.Value - _hBar.Value; - _renderer.Line(x, y, x, Height - 1); - } - - if (visibleColumns.Any()) - { - _renderer.Line(totalColWidth.Value - _hBar.Value, y, totalColWidth.Value - _hBar.Value, Height - 1); - } - - // Rows - for (int i = 1; i < VisibleRows + 1; i++) - { - _renderer.Line(0, RowsToPixels(i), Width + 1, RowsToPixels(i)); - } - } - } - - if (_selectedItems.Any()) - { - DoSelectionBG(visibleColumns); - } - } - - private void DoSelectionBG(List visibleColumns) - { - // SuuperW: This allows user to see other colors in selected frames. - Color rowColor = Color.White; - int lastVisibleRow = LastVisibleRow; - int lastRow = -1; - foreach (Cell cell in _selectedItems) - { - if (cell.RowIndex > lastVisibleRow || cell.RowIndex < FirstVisibleRow || !VisibleColumns.Contains(cell.Column)) - { - continue; - } - - Cell relativeCell = new Cell - { - RowIndex = cell.RowIndex - FirstVisibleRow, - Column = cell.Column, - }; - relativeCell.RowIndex -= CountLagFramesAbsolute(relativeCell.RowIndex.Value); - - if (QueryRowBkColor != null && lastRow != cell.RowIndex.Value) - { - QueryRowBkColor(cell.RowIndex.Value, ref rowColor); - lastRow = cell.RowIndex.Value; - } - - Color cellColor = rowColor; - QueryItemBkColor?.Invoke(cell.RowIndex.Value, cell.Column, ref cellColor); - - // Alpha layering for cell before selection - float alpha = (float)cellColor.A / 255; - if (cellColor.A != 255 && cellColor.A != 0) - { - cellColor = Color.FromArgb(rowColor.R - (int)((rowColor.R - cellColor.R) * alpha), - rowColor.G - (int)((rowColor.G - cellColor.G) * alpha), - rowColor.B - (int)((rowColor.B - cellColor.B) * alpha)); - } - - // Alpha layering for selection - alpha = 0.33f; - cellColor = Color.FromArgb(cellColor.R - (int)((cellColor.R - SystemColors.Highlight.R) * alpha), - cellColor.G - (int)((cellColor.G - SystemColors.Highlight.G) * alpha), - cellColor.B - (int)((cellColor.B - SystemColors.Highlight.B) * alpha)); - DrawCellBG(cellColor, relativeCell, visibleColumns); - } - } - - /// - /// Given a cell with rowindex inbetween 0 and VisibleRows, it draws the background color specified. Do not call with absolute rowindices. - /// - private void DrawCellBG(Color color, Cell cell, List visibleColumns) - { - int x, y, w, h; - - if (HorizontalOrientation) - { - x = RowsToPixels(cell.RowIndex.Value) + 1; - w = CellWidth - 1; - y = (CellHeight * visibleColumns.IndexOf(cell.Column)) + 1 - _vBar.Value; // We can't draw without row and column, so assume they exist and fail catastrophically if they don't - h = CellHeight - 1; - if (x < ColumnWidth) - { - return; - } - } - else - { - w = cell.Column.Width.Value - 1; - x = cell.Column.Left.Value - _hBar.Value + 1; - y = RowsToPixels(cell.RowIndex.Value) + 1; // We can't draw without row and column, so assume they exist and fail catastrophically if they don't - h = CellHeight - 1; - if (y < ColumnHeight) - { - return; - } - } - - if (x > DrawWidth || y > DrawHeight) - { - return; - } // Don't draw if off screen. - - _renderer.SetBrush(color); - _renderer.FillRectangle(x, y, w, h); - } - - /// - /// Calls QueryItemBkColor callback for all visible cells and fills in the background of those cells. - /// - private void DoBackGroundCallback(List visibleColumns) - { - int startIndex = FirstVisibleRow; - int range = Math.Min(LastVisibleRow, RowCount - 1) - startIndex + 1; - int lastVisible = LastVisibleColumnIndex; - int firstVisibleColumn = FirstVisibleColumn; - // Prevent exceptions with small TAStudio windows - if (firstVisibleColumn < 0) - { - return; - } - if (HorizontalOrientation) - { - for (int i = 0, f = 0; f < range; i++, f++) - { - f += _lagFrames[i]; - - Color rowColor = Color.White; - QueryRowBkColor?.Invoke(f + startIndex, ref rowColor); - - for (int j = firstVisibleColumn; j <= lastVisible; j++) - { - Color itemColor = Color.White; - QueryItemBkColor?.Invoke(f + startIndex, visibleColumns[j], ref itemColor); - if (itemColor == Color.White) - { - itemColor = rowColor; - } - else if (itemColor.A != 255 && itemColor.A != 0) - { - float alpha = (float)itemColor.A / 255; - itemColor = Color.FromArgb(rowColor.R - (int)((rowColor.R - itemColor.R) * alpha), - rowColor.G - (int)((rowColor.G - itemColor.G) * alpha), - rowColor.B - (int)((rowColor.B - itemColor.B) * alpha)); - } - - if (itemColor != Color.White) // An easy optimization, don't draw unless the user specified something other than the default - { - var cell = new Cell - { - Column = visibleColumns[j], - RowIndex = i - }; - DrawCellBG(itemColor, cell, visibleColumns); - } - } - } - } - else - { - for (int i = 0, f = 0; f < range; i++, f++) // Vertical - { - f += _lagFrames[i]; - - Color rowColor = Color.White; - QueryRowBkColor?.Invoke(f + startIndex, ref rowColor); - - for (int j = FirstVisibleColumn; j <= lastVisible; j++) // Horizontal - { - Color itemColor = Color.White; - QueryItemBkColor?.Invoke(f + startIndex, visibleColumns[j], ref itemColor); - if (itemColor == Color.White) - { - itemColor = rowColor; - } - else if (itemColor.A != 255 && itemColor.A != 0) - { - float alpha = (float)itemColor.A / 255; - itemColor = Color.FromArgb(rowColor.R - (int)((rowColor.R - itemColor.R) * alpha), - rowColor.G - (int)((rowColor.G - itemColor.G) * alpha), - rowColor.B - (int)((rowColor.B - itemColor.B) * alpha)); - } - - if (itemColor != Color.White) // An easy optimization, don't draw unless the user specified something other than the default - { - var cell = new Cell - { - Column = visibleColumns[j], - RowIndex = i - }; - DrawCellBG(itemColor, cell, visibleColumns); - } - } - } - } - } - } -} +using System; +using System.Collections.Generic; +using System.Drawing; +using System.Linq; +using System.Windows.Forms; +using BizHawk.Client.EmuHawk.WinFormExtensions; + +namespace BizHawk.Client.EmuHawk +{ + public partial class InputRoll + { + protected override void OnPaint(PaintEventArgs e) + { + using (_renderer.LockGraphics(e.Graphics, Width, Height)) + { + // White Background + _renderer.SetBrush(Color.White); + _renderer.SetSolidPen(Color.White); + _renderer.FillRectangle(0, 0, Width, Height); + + // Lag frame calculations + SetLagFramesArray(); + + var visibleColumns = _columns.VisibleColumns.ToList(); + + if (visibleColumns.Any()) + { + DrawColumnBg(visibleColumns); + DrawColumnText(visibleColumns); + } + + // Background + DrawBg(visibleColumns); + + // Foreground + DrawData(visibleColumns); + + DrawColumnDrag(); + DrawCellDrag(); + } + } + + private void DrawString(string text, int? width, Point point) + { + if (string.IsNullOrWhiteSpace(text)) + { + return; + } + + if (width.HasValue) + { + var max = (width.Value - CellWidthPadding) / _charSize.Width; + if (text.Length >= max) + { + text = text.Substring(0, max); + } + } + + _renderer.DrawString(text, point); + } + + protected override void OnPaintBackground(PaintEventArgs e) + { + // Do nothing, and this should never be called + } + + private void DrawColumnDrag() + { + if (_columnDown != null && _columnDownMoved && _currentX.HasValue && _currentY.HasValue && IsHoveringOnColumnCell) + { + int x1 = _currentX.Value - (_columnDown.Width.Value / 2); + int y1 = _currentY.Value - (CellHeight / 2); + int x2 = x1 + _columnDown.Width.Value; + int y2 = y1 + CellHeight; + + _renderer.SetSolidPen(_backColor); + _renderer.DrawRectangle(x1, y1, x2, y2); + _renderer.PrepDrawString(_font, _foreColor); + _renderer.DrawString(_columnDown.Text, new Point(x1 + CellWidthPadding, y1 + CellHeightPadding)); + } + } + + private void DrawCellDrag() + { + if (_draggingCell != null) + { + var text = ""; + int offsetX = 0; + int offsetY = 0; + QueryItemText?.Invoke(_draggingCell.RowIndex.Value, _draggingCell.Column, out text, ref offsetX, ref offsetY); + + Color bgColor = _backColor; + QueryItemBkColor?.Invoke(_draggingCell.RowIndex.Value, _draggingCell.Column, ref bgColor); + + int x1 = _currentX.Value - (_draggingCell.Column.Width.Value / 2); + int y1 = _currentY.Value - (CellHeight / 2); + int x2 = x1 + _draggingCell.Column.Width.Value; + int y2 = y1 + CellHeight; + + + _renderer.SetBrush(bgColor); + _renderer.FillRectangle(x1, y1, x2 - x1, y2 - y1); + _renderer.PrepDrawString(_font, _foreColor); + _renderer.DrawString(text, new Point(x1 + CellWidthPadding + offsetX, y1 + CellHeightPadding + offsetY)); + } + } + + private void DrawColumnText(List visibleColumns) + { + if (HorizontalOrientation) + { + int start = -_vBar.Value; + + _renderer.PrepDrawString(_font, _foreColor); + + foreach (var column in visibleColumns) + { + var point = new Point(CellWidthPadding, start + CellHeightPadding); + + if (IsHoveringOnColumnCell && column == CurrentCell.Column) + { + _renderer.PrepDrawString(_font, SystemColors.HighlightText); + DrawString(column.Text, column.Width, point); + _renderer.PrepDrawString(_font, _foreColor); + } + else + { + DrawString(column.Text, column.Width, point); + } + + start += CellHeight; + } + } + else + { + _renderer.PrepDrawString(_font, _foreColor); + + foreach (var column in visibleColumns) + { + var point = new Point(column.Left.Value + 2 * CellWidthPadding - _hBar.Value, CellHeightPadding); // TODO: fix this CellPadding issue (2 * CellPadding vs just CellPadding) + + if (IsHoveringOnColumnCell && column == CurrentCell.Column) + { + _renderer.PrepDrawString(_font, SystemColors.HighlightText); + DrawString(column.Text, column.Width, point); + _renderer.PrepDrawString(_font, _foreColor); + } + else + { + DrawString(column.Text, column.Width, point); + } + } + } + } + + private void DrawData(List visibleColumns) + { + // Prevent exceptions with small TAStudio windows + if (visibleColumns.Count == 0) + { + return; + } + + if (QueryItemText != null) + { + if (HorizontalOrientation) + { + int startRow = FirstVisibleRow; + int range = Math.Min(LastVisibleRow, RowCount - 1) - startRow + 1; + + _renderer.PrepDrawString(_font, _foreColor); + for (int i = 0, f = 0; f < range; i++, f++) + { + f += _lagFrames[i]; + int lastVisible = LastVisibleColumnIndex; + for (int j = FirstVisibleColumn; j <= lastVisible; j++) + { + Bitmap image = null; + int x; + int y; + int bitmapOffsetX = 0; + int bitmapOffsetY = 0; + + QueryItemIcon?.Invoke(f + startRow, visibleColumns[j], ref image, ref bitmapOffsetX, ref bitmapOffsetY); + + if (image != null) + { + x = RowsToPixels(i) + CellWidthPadding + bitmapOffsetX; + y = (j * CellHeight) + (CellHeightPadding * 2) + bitmapOffsetY; + _renderer.DrawBitmap(image, new Point(x, y)); + } + + string text; + int strOffsetX = 0; + int strOffsetY = 0; + QueryItemText(f + startRow, visibleColumns[j], out text, ref strOffsetX, ref strOffsetY); + + // Center Text + x = RowsToPixels(i) + ((CellWidth - (text.Length * _charSize.Width)) / 2); + y = (j * CellHeight) + CellHeightPadding - _vBar.Value; + var point = new Point(x + strOffsetX, y + strOffsetY); + + if (visibleColumns[j].Name == "FrameColumn") // TODO: don't do this hack + { + _renderer.PrepDrawString(_font, _foreColor, rotate: true); + DrawString(text, ColumnWidth, new Point(point.X + _charSize.Height + CellWidthPadding, point.Y + CellHeightPadding)); + _renderer.PrepDrawString(_font, _foreColor, rotate: false); + } + else + { + DrawString(text, ColumnWidth, point); + } + } + } + } + else + { + int startRow = FirstVisibleRow; + int range = Math.Min(LastVisibleRow, RowCount - 1) - startRow + 1; + + _renderer.PrepDrawString(_font, _foreColor); + int xPadding = CellWidthPadding + 1 - _hBar.Value; + for (int i = 0, f = 0; f < range; i++, f++) // Vertical + { + f += _lagFrames[i]; + int lastVisible = LastVisibleColumnIndex; + for (int j = FirstVisibleColumn; j <= lastVisible; j++) // Horizontal + { + RollColumn col = visibleColumns[j]; + + string text; + int strOffsetX = 0; + int strOffsetY = 0; + Point point = new Point(col.Left.Value + xPadding, RowsToPixels(i) + CellHeightPadding); + + Bitmap image = null; + int bitmapOffsetX = 0; + int bitmapOffsetY = 0; + + QueryItemIcon?.Invoke(f + startRow, visibleColumns[j], ref image, ref bitmapOffsetX, ref bitmapOffsetY); + + if (image != null) + { + _renderer.DrawBitmap(image, new Point(point.X + bitmapOffsetX, point.Y + bitmapOffsetY + CellHeightPadding)); + } + + QueryItemText(f + startRow, visibleColumns[j], out text, ref strOffsetX, ref strOffsetY); + + bool rePrep = false; + if (_selectedItems.Contains(new Cell { Column = visibleColumns[j], RowIndex = f + startRow })) + { + _renderer.PrepDrawString(_font, SystemColors.HighlightText); + rePrep = true; + } + + DrawString(text, col.Width, new Point(point.X + strOffsetX, point.Y + strOffsetY)); + + if (rePrep) + { + _renderer.PrepDrawString(_font, _foreColor); + } + } + } + } + } + } + + private void DrawColumnBg(List visibleColumns) + { + _renderer.SetBrush(SystemColors.ControlLight); + _renderer.SetSolidPen(Color.Black); + + if (HorizontalOrientation) + { + _renderer.FillRectangle(0, 0, ColumnWidth + 1, DrawHeight + 1); + _renderer.Line(0, 0, 0, visibleColumns.Count * CellHeight + 1); + _renderer.Line(ColumnWidth, 0, ColumnWidth, visibleColumns.Count * CellHeight + 1); + + int start = -_vBar.Value; + foreach (var column in visibleColumns) + { + _renderer.Line(1, start, ColumnWidth, start); + start += CellHeight; + } + + if (visibleColumns.Any()) + { + _renderer.Line(1, start, ColumnWidth, start); + } + } + else + { + int bottomEdge = RowsToPixels(0); + + // Gray column box and black line underneath + _renderer.FillRectangle(0, 0, Width + 1, bottomEdge + 1); + _renderer.Line(0, 0, TotalColWidth.Value + 1, 0); + _renderer.Line(0, bottomEdge, TotalColWidth.Value + 1, bottomEdge); + + // Vertical black separators + foreach (var column in visibleColumns) + { + int pos = column.Left.Value - _hBar.Value; + _renderer.Line(pos, 0, pos, bottomEdge); + } + + // Draw right most line + if (visibleColumns.Any()) + { + int right = TotalColWidth.Value - _hBar.Value; + _renderer.Line(right, 0, right, bottomEdge); + } + } + + // Emphasis + foreach (var column in visibleColumns.Where(c => c.Emphasis)) + { + _renderer.SetBrush(SystemColors.ActiveBorder); + if (HorizontalOrientation) + { + _renderer.FillRectangle(1, visibleColumns.IndexOf(column) * CellHeight + 1, ColumnWidth - 1, ColumnHeight - 1); + } + else + { + _renderer.FillRectangle(column.Left.Value + 1 - _hBar.Value, 1, column.Width.Value - 1, ColumnHeight - 1); + } + } + + // If the user is hovering over a column + if (IsHoveringOnColumnCell) + { + if (HorizontalOrientation) + { + for (int i = 0; i < visibleColumns.Count; i++) + { + if (visibleColumns[i] != CurrentCell.Column) + { + continue; + } + + _renderer.SetBrush(CurrentCell.Column.Emphasis + ? SystemColors.Highlight.Add(0x00222222) + : SystemColors.Highlight); + + _renderer.FillRectangle(1, i * CellHeight + 1, ColumnWidth - 1, ColumnHeight - 1); + } + } + else + { + // TODO multiple selected columns + foreach (var column in visibleColumns) + { + if (column == CurrentCell.Column) + { + // Left of column is to the right of the viewable area or right of column is to the left of the viewable area + if (column.Left.Value - _hBar.Value > Width || column.Right.Value - _hBar.Value < 0) + { + continue; + } + + int left = column.Left.Value - _hBar.Value; + int width = column.Right.Value - _hBar.Value - left; + + _renderer.SetBrush(CurrentCell.Column.Emphasis + ? SystemColors.Highlight.Add(0x00550000) + : SystemColors.Highlight); + + _renderer.FillRectangle(left + 1, 1, width - 1, ColumnHeight - 1); + } + } + } + } + } + + // TODO refactor this and DoBackGroundCallback functions. + /// + /// Draw Gridlines and background colors using QueryItemBkColor. + /// + private void DrawBg(List visibleColumns) + { + if (UseCustomBackground && QueryItemBkColor != null) + { + DoBackGroundCallback(visibleColumns); + } + + if (GridLines) + { + _renderer.SetSolidPen(SystemColors.ControlLight); + if (HorizontalOrientation) + { + // Columns + for (int i = 1; i < VisibleRows + 1; i++) + { + int x = RowsToPixels(i); + _renderer.Line(x, 1, x, DrawHeight); + } + + // Rows + for (int i = 0; i < visibleColumns.Count + 1; i++) + { + _renderer.Line(RowsToPixels(0) + 1, i * CellHeight - _vBar.Value, DrawWidth, i * CellHeight - _vBar.Value); + } + } + else + { + // Columns + int y = ColumnHeight + 1; + int? totalColWidth = TotalColWidth; + foreach (var column in visibleColumns) + { + int x = column.Left.Value - _hBar.Value; + _renderer.Line(x, y, x, Height - 1); + } + + if (visibleColumns.Any()) + { + _renderer.Line(totalColWidth.Value - _hBar.Value, y, totalColWidth.Value - _hBar.Value, Height - 1); + } + + // Rows + for (int i = 1; i < VisibleRows + 1; i++) + { + _renderer.Line(0, RowsToPixels(i), Width + 1, RowsToPixels(i)); + } + } + } + + if (_selectedItems.Any()) + { + DoSelectionBG(visibleColumns); + } + } + + private void DoSelectionBG(List visibleColumns) + { + // SuuperW: This allows user to see other colors in selected frames. + Color rowColor = Color.White; + int lastVisibleRow = LastVisibleRow; + int lastRow = -1; + foreach (Cell cell in _selectedItems) + { + if (cell.RowIndex > lastVisibleRow || cell.RowIndex < FirstVisibleRow || !VisibleColumns.Contains(cell.Column)) + { + continue; + } + + Cell relativeCell = new Cell + { + RowIndex = cell.RowIndex - FirstVisibleRow, + Column = cell.Column, + }; + relativeCell.RowIndex -= CountLagFramesAbsolute(relativeCell.RowIndex.Value); + + if (QueryRowBkColor != null && lastRow != cell.RowIndex.Value) + { + QueryRowBkColor(cell.RowIndex.Value, ref rowColor); + lastRow = cell.RowIndex.Value; + } + + Color cellColor = rowColor; + QueryItemBkColor?.Invoke(cell.RowIndex.Value, cell.Column, ref cellColor); + + // Alpha layering for cell before selection + float alpha = (float)cellColor.A / 255; + if (cellColor.A != 255 && cellColor.A != 0) + { + cellColor = Color.FromArgb(rowColor.R - (int)((rowColor.R - cellColor.R) * alpha), + rowColor.G - (int)((rowColor.G - cellColor.G) * alpha), + rowColor.B - (int)((rowColor.B - cellColor.B) * alpha)); + } + + // Alpha layering for selection + alpha = 0.33f; + cellColor = Color.FromArgb(cellColor.R - (int)((cellColor.R - SystemColors.Highlight.R) * alpha), + cellColor.G - (int)((cellColor.G - SystemColors.Highlight.G) * alpha), + cellColor.B - (int)((cellColor.B - SystemColors.Highlight.B) * alpha)); + DrawCellBG(cellColor, relativeCell, visibleColumns); + } + } + + /// + /// Given a cell with rowindex inbetween 0 and VisibleRows, it draws the background color specified. Do not call with absolute rowindices. + /// + private void DrawCellBG(Color color, Cell cell, List visibleColumns) + { + int x, y, w, h; + + if (HorizontalOrientation) + { + x = RowsToPixels(cell.RowIndex.Value) + 1; + w = CellWidth - 1; + y = (CellHeight * visibleColumns.IndexOf(cell.Column)) + 1 - _vBar.Value; // We can't draw without row and column, so assume they exist and fail catastrophically if they don't + h = CellHeight - 1; + if (x < ColumnWidth) + { + return; + } + } + else + { + w = cell.Column.Width.Value - 1; + x = cell.Column.Left.Value - _hBar.Value + 1; + y = RowsToPixels(cell.RowIndex.Value) + 1; // We can't draw without row and column, so assume they exist and fail catastrophically if they don't + h = CellHeight - 1; + if (y < ColumnHeight) + { + return; + } + } + + if (x > DrawWidth || y > DrawHeight) + { + return; + } // Don't draw if off screen. + + _renderer.SetBrush(color); + _renderer.FillRectangle(x, y, w, h); + } + + /// + /// Calls QueryItemBkColor callback for all visible cells and fills in the background of those cells. + /// + private void DoBackGroundCallback(List visibleColumns) + { + int startIndex = FirstVisibleRow; + int range = Math.Min(LastVisibleRow, RowCount - 1) - startIndex + 1; + int lastVisible = LastVisibleColumnIndex; + int firstVisibleColumn = FirstVisibleColumn; + // Prevent exceptions with small TAStudio windows + if (firstVisibleColumn < 0) + { + return; + } + if (HorizontalOrientation) + { + for (int i = 0, f = 0; f < range; i++, f++) + { + f += _lagFrames[i]; + + Color rowColor = Color.White; + QueryRowBkColor?.Invoke(f + startIndex, ref rowColor); + + for (int j = firstVisibleColumn; j <= lastVisible; j++) + { + Color itemColor = Color.White; + QueryItemBkColor?.Invoke(f + startIndex, visibleColumns[j], ref itemColor); + if (itemColor == Color.White) + { + itemColor = rowColor; + } + else if (itemColor.A != 255 && itemColor.A != 0) + { + float alpha = (float)itemColor.A / 255; + itemColor = Color.FromArgb(rowColor.R - (int)((rowColor.R - itemColor.R) * alpha), + rowColor.G - (int)((rowColor.G - itemColor.G) * alpha), + rowColor.B - (int)((rowColor.B - itemColor.B) * alpha)); + } + + if (itemColor != Color.White) // An easy optimization, don't draw unless the user specified something other than the default + { + var cell = new Cell + { + Column = visibleColumns[j], + RowIndex = i + }; + DrawCellBG(itemColor, cell, visibleColumns); + } + } + } + } + else + { + for (int i = 0, f = 0; f < range; i++, f++) // Vertical + { + f += _lagFrames[i]; + + Color rowColor = Color.White; + QueryRowBkColor?.Invoke(f + startIndex, ref rowColor); + + for (int j = FirstVisibleColumn; j <= lastVisible; j++) // Horizontal + { + Color itemColor = Color.White; + QueryItemBkColor?.Invoke(f + startIndex, visibleColumns[j], ref itemColor); + if (itemColor == Color.White) + { + itemColor = rowColor; + } + else if (itemColor.A != 255 && itemColor.A != 0) + { + float alpha = (float)itemColor.A / 255; + itemColor = Color.FromArgb(rowColor.R - (int)((rowColor.R - itemColor.R) * alpha), + rowColor.G - (int)((rowColor.G - itemColor.G) * alpha), + rowColor.B - (int)((rowColor.B - itemColor.B) * alpha)); + } + + if (itemColor != Color.White) // An easy optimization, don't draw unless the user specified something other than the default + { + var cell = new Cell + { + Column = visibleColumns[j], + RowIndex = i + }; + DrawCellBG(itemColor, cell, visibleColumns); + } + } + } + } + } + } +} diff --git a/BizHawk.Client.EmuHawk/CustomControls/InputRoll.cs b/BizHawk.Client.EmuHawk/CustomControls/InputRoll/InputRoll.cs similarity index 87% rename from BizHawk.Client.EmuHawk/CustomControls/InputRoll.cs rename to BizHawk.Client.EmuHawk/CustomControls/InputRoll/InputRoll.cs index 4c97607d1c..a7c1a5a6e5 100644 --- a/BizHawk.Client.EmuHawk/CustomControls/InputRoll.cs +++ b/BizHawk.Client.EmuHawk/CustomControls/InputRoll/InputRoll.cs @@ -1,2314 +1,2068 @@ -using System; -using System.Collections.Generic; -using System.ComponentModel; -using System.Drawing; -using System.Linq; -using System.Windows.Forms; - -using BizHawk.Client.Common; -using BizHawk.Client.EmuHawk.CustomControls; -using BizHawk.Common; - -namespace BizHawk.Client.EmuHawk -{ - // Row width depends on font size and padding - // Column width is specified in column headers - // Row width is specified for horizontal orientation - public partial class InputRoll : Control - { - private readonly IControlRenderer _renderer; - private readonly SortedSet _selectedItems = new SortedSet(new SortCell()); - - // scrollbar location(s) are calculated later (e.g. on resize) - private readonly VScrollBar _vBar = new VScrollBar { Visible = false }; - private readonly HScrollBar _hBar = new HScrollBar { Visible = false }; - - private readonly Timer _hoverTimer = new Timer(); - private readonly byte[] _lagFrames = new byte[256]; // Large enough value that it shouldn't ever need resizing. // apparently not large enough for 4K - - private readonly Color _foreColor; - private readonly Color _backColor; - - private RollColumns _columns = new RollColumns(); - private bool _horizontalOrientation; - private bool _programmaticallyUpdatingScrollBarValues; - private int _maxCharactersInHorizontal = 1; - - private int _rowCount; - private Size _charSize; - - private RollColumn _columnDown; - private RollColumn _columnResizing; - - private int? _currentX; - private int? _currentY; - - // Hiding lag frames (Mainly intended for < 60fps play.) - public int LagFramesToHide { get; set; } - public bool HideWasLagFrames { get; set; } - - public bool AllowRightClickSelecton { get; set; } - public bool LetKeysModifySelection { get; set; } - public bool SuspendHotkeys { get; set; } - - private Font _font = new Font("Arial", 8, FontStyle.Bold); - - public InputRoll() - { - UseCustomBackground = true; - GridLines = true; - CellWidthPadding = 3; - CellHeightPadding = 0; - CurrentCell = null; - ScrollMethod = "near"; - - SetStyle(ControlStyles.AllPaintingInWmPaint, true); - SetStyle(ControlStyles.UserPaint, true); - SetStyle(ControlStyles.SupportsTransparentBackColor, true); - SetStyle(ControlStyles.Opaque, true); - SetStyle(ControlStyles.OptimizedDoubleBuffer, true); - - if (OSTailoredCode.CurrentOS == OSTailoredCode.DistinctOS.Windows) - { - _renderer = new GdiRenderer(); - } - else - { - _renderer = new GdiPlusRenderer(); - } - - using (var g = CreateGraphics()) - using (_renderer.LockGraphics(g, Width, Height)) - { - _charSize = _renderer.MeasureString("A", _font); // TODO make this a property so changing it updates other values. - } - - UpdateCellSize(); - ColumnWidth = CellWidth; - ColumnHeight = CellHeight + 2; - - _vBar.SmallChange = CellHeight; - _vBar.LargeChange = CellHeight * 20; - - _hBar.SmallChange = CellWidth; - _hBar.LargeChange = 20; - - Controls.Add(_vBar); - Controls.Add(_hBar); - - _vBar.ValueChanged += VerticalBar_ValueChanged; - _hBar.ValueChanged += HorizontalBar_ValueChanged; - - RecalculateScrollBars(); - _columns.ChangedCallback = ColumnChangedCallback; - - _hoverTimer.Interval = 750; - _hoverTimer.Tick += HoverTimerEventProcessor; - _hoverTimer.Stop(); - - _foreColor = ForeColor; - _backColor = BackColor; - } - - private void HoverTimerEventProcessor(object sender, EventArgs e) - { - _hoverTimer.Stop(); - - CellHovered?.Invoke(this, new CellEventArgs(LastCell, CurrentCell)); - } - - protected override void Dispose(bool disposing) - { - _renderer.Dispose(); - base.Dispose(disposing); - } - - protected override void OnDoubleClick(EventArgs e) - { - if (IsHoveringOnColumnEdge) - { - if (HorizontalOrientation) - { - // TODO - } - else - { - var maxLength = CurrentCell.Column.Text?.Length ?? 0; - - - for (int i = 0; i < RowCount; i++) - { - string text = ""; - int offSetX = 0, offSetY = 0; - QueryItemText?.Invoke(i, CurrentCell.Column, out text, ref offSetX, ref offSetY); - if (text.Length > maxLength) - { - maxLength = text.Length; - } - } - - var newWidth = (maxLength * _charSize.Width) + (CellWidthPadding * 2); - CurrentCell.Column.Width = newWidth; - _columns.ColumnsChanged(); - Refresh(); - } - - } - - base.OnDoubleClick(e); - } - - #region Properties - - /// - /// Gets or sets the amount of left and right padding on the text inside a cell - /// - [DefaultValue(3)] - [Category("Behavior")] - public int CellWidthPadding { get; set; } - - /// - /// Gets or sets the amount of top and bottom padding on the text inside a cell - /// - [DefaultValue(1)] - [Category("Behavior")] - public int CellHeightPadding { get; set; } - - /// - /// Gets or sets a value indicating whether grid lines are displayed around cells - /// - [Category("Appearance")] - [DefaultValue(true)] - public bool GridLines { get; set; } - - /// - /// Gets or sets a value indicating whether the control is horizontal or vertical - /// - [Category("Behavior")] - public bool HorizontalOrientation - { - get - { - return _horizontalOrientation; - } - set - { - if (_horizontalOrientation != value) - { - int temp = ScrollSpeed; - _horizontalOrientation = value; - OrientationChanged(); - _hBar.SmallChange = CellWidth; - _vBar.SmallChange = CellHeight; - ScrollSpeed = temp; - } - } - } - - /// - /// Gets or sets the scrolling speed - /// - [Category("Behavior")] - public int ScrollSpeed - { - get - { - if (HorizontalOrientation) - { - return _hBar.SmallChange / CellWidth; - } - - return _vBar.SmallChange / CellHeight; - } - - set - { - if (HorizontalOrientation) - { - _hBar.SmallChange = value * CellWidth; - } - else - { - _vBar.SmallChange = value * CellHeight; - } - } - } - - /// - /// Gets or sets the sets the virtual number of rows to be displayed. Does not include the column header row. - /// - [Category("Behavior")] - public int RowCount - { - get - { - return _rowCount; - } - - set - { - _rowCount = value; - RecalculateScrollBars(); - } - } - - /// - /// Gets or sets a value indicating whether columns can be resized - /// - [Category("Behavior")] - public bool AllowColumnResize { get; set; } - - /// - /// Gets or sets a value indicating whether columns can be reordered - /// - [Category("Behavior")] - public bool AllowColumnReorder { get; set; } - - /// - /// Gets or sets a value indicating whether the entire row will always be selected - /// - [Category("Appearance")] - [DefaultValue(false)] - public bool FullRowSelect { get; set; } - - /// - /// Gets or sets a value indicating whether multiple items can to be selected - /// - [Category("Behavior")] - [DefaultValue(true)] - public bool MultiSelect { get; set; } - - /// - /// Gets or sets a value indicating whether the control is in input painting mode - /// - [Category("Behavior")] - [DefaultValue(false)] - public bool InputPaintingMode { get; set; } - - /// - /// All visible columns - /// - [Category("Behavior")] - public IEnumerable VisibleColumns => _columns.VisibleColumns; - - /// - /// Gets or sets how the InputRoll scrolls when calling ScrollToIndex. - /// - [DefaultValue("near")] - [Category("Behavior")] - public string ScrollMethod { get; set; } - - /// - /// Gets or sets a value indicating how the Intever for the hover event - /// - [Category("Behavior")] - public bool AlwaysScroll { get; set; } - - /// - /// Gets or sets the lowest seek interval to activate the progress bar - /// - [Category("Behavior")] - public int SeekingCutoffInterval { get; set; } - - /// - /// Returns all columns including those that are not visible - /// - [Browsable(false)] - [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] - public RollColumns AllColumns => _columns; - - [DefaultValue(750)] - [Category("Behavior")] - public int HoverInterval - { - get { return _hoverTimer.Interval; } - set { _hoverTimer.Interval = value; } - } - - #endregion - - #region Event Handlers - - /// - /// Fire the event which requests the text for the passed cell - /// - [Category("Virtual")] - public event QueryItemTextHandler QueryItemText; - - /// - /// Fire the event which requests the background color for the passed cell - /// - [Category("Virtual")] - public event QueryItemBkColorHandler QueryItemBkColor; - - [Category("Virtual")] - public event QueryRowBkColorHandler QueryRowBkColor; - - /// - /// Fire the event which requests an icon for a given cell - /// - [Category("Virtual")] - public event QueryItemIconHandler QueryItemIcon; - - /// - /// Fire the QueryFrameLag event which checks if a given frame is a lag frame - /// - [Category("Virtual")] - public event QueryFrameLagHandler QueryFrameLag; - - /// - /// Fires when the mouse moves from one cell to another (including column header cells) - /// - [Category("Mouse")] - public event CellChangeEventHandler PointedCellChanged; - - /// - /// Fires when a cell is hovered on - /// - [Category("Mouse")] - public event HoverEventHandler CellHovered; - - /// - /// Occurs when a column header is clicked - /// - [Category("Action")] - public event ColumnClickEventHandler ColumnClick; - - /// - /// Occurs when a column header is right-clicked - /// - [Category("Action")] - public event ColumnClickEventHandler ColumnRightClick; - - /// - /// Occurs whenever the 'SelectedItems' property for this control changes - /// - [Category("Behavior")] - public event EventHandler SelectedIndexChanged; - - /// - /// Occurs whenever the mouse wheel is scrolled while the right mouse button is held - /// - [Category("Behavior")] - public event RightMouseScrollEventHandler RightMouseScrolled; - - [Category("Property Changed")] - [Description("Occurs when the column header has been reordered")] - public event ColumnReorderedEventHandler ColumnReordered; - - [Category("Action")] - [Description("Occurs when the scroll value of the visible rows change (in vertical orientation this is the vertical scroll bar change, and in horizontal it is the horizontal scroll bar)")] - public event RowScrollEvent RowScroll; - - [Category("Action")] - [Description("Occurs when the scroll value of the columns (in vertical orientation this is the horizontal scroll bar change, and in horizontal it is the vertical scroll bar)")] - public event ColumnScrollEvent ColumnScroll; - - [Category("Action")] - [Description("Occurs when a cell is dragged and then dropped into a new cell, old cell is the cell that was being dragged, new cell is its new destination")] - public event CellDroppedEvent CellDropped; - - /// - /// Retrieve the text for a cell - /// - public delegate void QueryItemTextHandler(int index, RollColumn column, out string text, ref int offsetX, ref int offsetY); - - /// - /// Retrieve the background color for a cell - /// - public delegate void QueryItemBkColorHandler(int index, RollColumn column, ref Color color); - public delegate void QueryRowBkColorHandler(int index, ref Color color); - - /// - /// Retrieve the image for a given cell - /// - public delegate void QueryItemIconHandler(int index, RollColumn column, ref Bitmap icon, ref int offsetX, ref int offsetY); - - /// - /// Check if a given frame is a lag frame - /// - public delegate bool QueryFrameLagHandler(int index, bool hideWasLag); - - public delegate void CellChangeEventHandler(object sender, CellEventArgs e); - - public delegate void HoverEventHandler(object sender, CellEventArgs e); - - public delegate void RightMouseScrollEventHandler(object sender, MouseEventArgs e); - - public delegate void ColumnClickEventHandler(object sender, ColumnClickEventArgs e); - - public delegate void ColumnReorderedEventHandler(object sender, ColumnReorderedEventArgs e); - - public delegate void RowScrollEvent(object sender, EventArgs e); - - public delegate void ColumnScrollEvent(object sender, EventArgs e); - - public delegate void CellDroppedEvent(object sender, CellEventArgs e); - - public class CellEventArgs - { - public CellEventArgs(Cell oldCell, Cell newCell) - { - OldCell = oldCell; - NewCell = newCell; - } - - public Cell OldCell { get; private set; } - public Cell NewCell { get; private set; } - } - - public class ColumnClickEventArgs - { - public ColumnClickEventArgs(RollColumn column) - { - Column = column; - } - - public RollColumn Column { get; private set; } - } - - public class ColumnReorderedEventArgs - { - public ColumnReorderedEventArgs(int oldDisplayIndex, int newDisplayIndex, RollColumn column) - { - Column = column; - OldDisplayIndex = oldDisplayIndex; - NewDisplayIndex = newDisplayIndex; - } - - public RollColumn Column { get; private set; } - public int OldDisplayIndex { get; private set; } - public int NewDisplayIndex { get; private set; } - } - - #endregion - - #region Api - - public void SelectRow(int index, bool val) - { - if (_columns.VisibleColumns.Any()) - { - if (val) - { - SelectCell(new Cell - { - RowIndex = index, - Column = _columns[0] - }); - } - else - { - IEnumerable items = _selectedItems.Where(cell => cell.RowIndex == index); - _selectedItems.RemoveWhere(items.Contains); - } - } - } - - public void SelectAll() - { - var oldFullRowVal = FullRowSelect; - FullRowSelect = true; - for (int i = 0; i < RowCount; i++) - { - SelectRow(i, true); - } - - FullRowSelect = oldFullRowVal; - } - - public void DeselectAll() - { - _selectedItems.Clear(); - } - - public void TruncateSelection(int index) - { - _selectedItems.RemoveWhere(cell => cell.RowIndex > index); - } - - [Browsable(false)] - [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] - public bool IsPointingAtColumnHeader => IsHoveringOnColumnCell; - - [Browsable(false)] - [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] - public int? FirstSelectedIndex - { - get - { - if (AnyRowsSelected) - { - return SelectedRows.Min(); - } - - return null; - } - } - - [Browsable(false)] - [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] - public int? LastSelectedIndex - { - get - { - if (AnyRowsSelected) - { - return SelectedRows.Max(); - } - - return null; - } - } - - /// - /// Gets or sets the current Cell that the mouse was in. - /// - [Browsable(false)] - [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] - public Cell CurrentCell { get; set; } - - [Browsable(false)] - [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] - public bool CurrentCellIsDataCell => CurrentCell?.RowIndex != null && CurrentCell.Column != null; - - /// - /// Gets or sets the previous Cell that the mouse was in. - /// - [Browsable(false)] - [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] - public Cell LastCell { get; private set; } - - [Browsable(false)] - [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] - public bool IsPaintDown { get; private set; } - - [Browsable(false)] - [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] - public bool UseCustomBackground { get; set; } - - [Browsable(false)] - [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] - public int DrawHeight { get; private set; } - - [Browsable(false)] - [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] - public int DrawWidth { get; private set; } - - /// - /// Gets or sets the width of data cells when in Horizontal orientation. - /// - public int MaxCharactersInHorizontal - { - get - { - return _maxCharactersInHorizontal; - } - - set - { - _maxCharactersInHorizontal = value; - UpdateCellSize(); - } - } - - [Browsable(false)] - [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] - public bool RightButtonHeld { get; private set; } - - public string UserSettingsSerialized() - { - var settings = ConfigService.SaveWithType(Settings); - return settings; - } - - public void LoadSettingsSerialized(string settingsJson) - { - var settings = ConfigService.LoadWithType(settingsJson); - - // TODO: don't silently fail, inform the user somehow - if (settings is InputRollSettings) - { - var rollSettings = settings as InputRollSettings; - _columns = rollSettings.Columns; - _columns.ChangedCallback = ColumnChangedCallback; - HorizontalOrientation = rollSettings.HorizontalOrientation; - LagFramesToHide = rollSettings.LagFramesToHide; - HideWasLagFrames = rollSettings.HideWasLagFrames; - } - } - - private InputRollSettings Settings => new InputRollSettings - { - Columns = _columns, - HorizontalOrientation = HorizontalOrientation, - LagFramesToHide = LagFramesToHide, - HideWasLagFrames = HideWasLagFrames - }; - - public class InputRollSettings - { - public RollColumns Columns { get; set; } - public bool HorizontalOrientation { get; set; } - public int LagFramesToHide { get; set; } - public bool HideWasLagFrames { get; set; } - } - - /// - /// Gets or sets the first visible row index, if scrolling is needed - /// - [Browsable(false)] - [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] - public int FirstVisibleRow - { - get // SuuperW: This was checking if the scroll bars were needed, which is useless because their Value is 0 if they aren't needed. - { - if (HorizontalOrientation) - { - return _hBar.Value / CellWidth; - } - - return _vBar.Value / CellHeight; - } - - set - { - if (HorizontalOrientation) - { - if (NeedsHScrollbar) - { - _programmaticallyUpdatingScrollBarValues = true; - if (value * CellWidth <= _hBar.Maximum) - { - _hBar.Value = value * CellWidth; - } - else - { - _hBar.Value = _hBar.Maximum; - } - - _programmaticallyUpdatingScrollBarValues = false; - } - } - else - { - if (NeedsVScrollbar) - { - _programmaticallyUpdatingScrollBarValues = true; - if (value * CellHeight <= _vBar.Maximum) - { - _vBar.Value = value * CellHeight; - } - else - { - _vBar.Value = _vBar.Maximum; - } - - _programmaticallyUpdatingScrollBarValues = false; - } - } - } - } - - [Browsable(false)] - [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] - private int LastFullyVisibleRow - { - get - { - int halfRow = 0; - if ((DrawHeight - ColumnHeight - 3) % CellHeight < CellHeight / 2) - { - halfRow = 1; - } - - return FirstVisibleRow + VisibleRows - halfRow + CountLagFramesDisplay(VisibleRows - halfRow); - } - } - - [Browsable(false)] - [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] - public int LastVisibleRow - { - get - { - return FirstVisibleRow + VisibleRows + CountLagFramesDisplay(VisibleRows); - } - - set - { - int halfRow = 0; - if ((DrawHeight - ColumnHeight - 3) % CellHeight < CellHeight / 2) - { - halfRow = 1; - } - - if (LagFramesToHide == 0) - { - FirstVisibleRow = Math.Max(value - (VisibleRows - halfRow), 0); - } - else - { - if (Math.Abs(LastFullyVisibleRow - value) > VisibleRows) // Big jump - { - FirstVisibleRow = Math.Max(value - (ExpectedDisplayRange() - halfRow), 0); - SetLagFramesArray(); - } - - // Small jump, more accurate - int lastVisible = LastFullyVisibleRow; - do - { - if ((lastVisible - value) / (LagFramesToHide + 1) != 0) - { - FirstVisibleRow = Math.Max(FirstVisibleRow - ((lastVisible - value) / (LagFramesToHide + 1)), 0); - } - else - { - FirstVisibleRow -= Math.Sign(lastVisible - value); - } - - SetLagFramesArray(); - lastVisible = LastFullyVisibleRow; - } - while ((lastVisible - value < 0 || lastVisible - value > _lagFrames[VisibleRows - halfRow]) && FirstVisibleRow != 0); - } - } - } - - public bool IsVisible(int index) - { - return (index >= FirstVisibleRow) && (index <= LastFullyVisibleRow); - } - - public bool IsPartiallyVisible(int index) - { - return index >= FirstVisibleRow && index <= LastVisibleRow; - } - - /// - /// Gets the number of rows currently visible including partially visible rows. - /// - [Browsable(false)] - [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] - public int VisibleRows - { - get - { - if (HorizontalOrientation) - { - return (DrawWidth - ColumnWidth) / CellWidth; - } - - return (DrawHeight - ColumnHeight - 3) / CellHeight; // Minus three makes it work - } - } - - /// - /// Gets the first visible column index, if scrolling is needed - /// - [Browsable(false)] - [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] - public int FirstVisibleColumn - { - get - { - if (HorizontalOrientation) - { - return _vBar.Value / CellHeight; - } - - var columnList = VisibleColumns.ToList(); - return columnList.FindIndex(c => c.Right > _hBar.Value); - } - } - - [Browsable(false)] - [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] - public int LastVisibleColumnIndex - { - get - { - List columnList = VisibleColumns.ToList(); - int ret; - if (HorizontalOrientation) - { - ret = (_vBar.Value + DrawHeight) / CellHeight; - if (ret >= columnList.Count) - { - ret = columnList.Count - 1; - } - } - else - { - ret = columnList.FindLastIndex(c => c.Left <= DrawWidth + _hBar.Value); - } - - return ret; - } - } - - private Cell _draggingCell; - - public void DragCurrentCell() - { - _draggingCell = CurrentCell; - } - - public void ReleaseCurrentCell() - { - if (_draggingCell != null) - { - var draggedCell = _draggingCell; - _draggingCell = null; - - if (CurrentCell != draggedCell) - { - CellDropped?.Invoke(this, new CellEventArgs(draggedCell, CurrentCell)); - } - } - } - - /// - /// Scrolls to the given index, according to the scroll settings. - /// - public void ScrollToIndex(int index) - { - if (ScrollMethod == "near") - { - MakeIndexVisible(index); - } - - if (!IsVisible(index) || AlwaysScroll) - { - if (ScrollMethod == "top") - { - FirstVisibleRow = index; - } - else if (ScrollMethod == "bottom") - { - LastVisibleRow = index; - } - else if (ScrollMethod == "center") - { - if (LagFramesToHide == 0) - { - FirstVisibleRow = Math.Max(index - (VisibleRows / 2), 0); - } - else - { - if (Math.Abs(FirstVisibleRow + CountLagFramesDisplay(VisibleRows / 2) - index) > VisibleRows) // Big jump - { - FirstVisibleRow = Math.Max(index - (ExpectedDisplayRange() / 2), 0); - SetLagFramesArray(); - } - - // Small jump, more accurate - int lastVisible = FirstVisibleRow + CountLagFramesDisplay(VisibleRows / 2); - do - { - if ((lastVisible - index) / (LagFramesToHide + 1) != 0) - { - FirstVisibleRow = Math.Max(FirstVisibleRow - ((lastVisible - index) / (LagFramesToHide + 1)), 0); - } - else - { - FirstVisibleRow -= Math.Sign(lastVisible - index); - } - - SetLagFramesArray(); - lastVisible = FirstVisibleRow + CountLagFramesDisplay(VisibleRows / 2); - } - while ((lastVisible - index < 0 || lastVisible - index > _lagFrames[VisibleRows]) && FirstVisibleRow != 0); - } - } - } - } - - /// - /// Scrolls so that the given index is visible, if it isn't already; doesn't use scroll settings. - /// - public void MakeIndexVisible(int index) - { - if (!IsVisible(index)) - { - if (FirstVisibleRow > index) - { - FirstVisibleRow = index; - } - else - { - LastVisibleRow = index; - } - } - } - - [Browsable(false)] - [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] - public IEnumerable SelectedRows - { - get - { - return _selectedItems - .Where(cell => cell.RowIndex.HasValue) - .Select(cell => cell.RowIndex.Value) - .Distinct(); - } - } - - public bool AnyRowsSelected - { - get - { - return _selectedItems.Any(cell => cell.RowIndex.HasValue); - } - } - - public void ClearSelectedRows() - { - _selectedItems.Clear(); - } - - public IEnumerable GenerateContextMenuItems() - { - yield return new ToolStripSeparator(); - - var rotate = new ToolStripMenuItem - { - Name = "RotateMenuItem", - Text = "Rotate", - ShortcutKeyDisplayString = RotateHotkeyStr, - }; - - rotate.Click += (o, ev) => - { - HorizontalOrientation ^= true; - }; - - yield return rotate; - } - - public string RotateHotkeyStr => "Ctrl+Shift+F"; - - #endregion - - #region Mouse and Key Events - - private bool _columnDownMoved; - private int _previousX = 0; // TODO: move me - - protected override void OnMouseMove(MouseEventArgs e) - { - _previousX = _currentX ?? 0; - _currentX = e.X; - _currentY = e.Y; - - if (_columnResizing != null) - { - if (_currentX != _previousX) - { - _columnResizing.Width += _currentX - _previousX; - _columns.ColumnsChanged(); - Refresh(); - } - } - else if (_columnDown != null) - { - _columnDownMoved = true; - } - - Cell newCell = CalculatePointedCell(_currentX.Value, _currentY.Value); - - // SuuperW: Hide lag frames - if (QueryFrameLag != null && newCell.RowIndex.HasValue) - { - newCell.RowIndex += CountLagFramesDisplay(newCell.RowIndex.Value); - } - - newCell.RowIndex += FirstVisibleRow; - if (newCell.RowIndex < 0) - { - newCell.RowIndex = 0; - } - - if (!newCell.Equals(CurrentCell)) - { - CellChanged(newCell); - - if (IsHoveringOnColumnCell || - (WasHoveringOnColumnCell && !IsHoveringOnColumnCell)) - { - Refresh(); - } - else if (_columnDown != null) - { - Refresh(); - } - } - else if (_columnDown != null) // Kind of silly feeling to have this check twice, but the only alternative I can think of has it refreshing twice when pointed column changes with column down, and speed matters - { - Refresh(); - } - - Cursor = IsHoveringOnColumnEdge || _columnResizing != null - ? Cursors.VSplit - : Cursors.Default; - - base.OnMouseMove(e); - } - - protected override void OnMouseEnter(EventArgs e) - { - CurrentCell = new Cell - { - Column = null, - RowIndex = null - }; - - base.OnMouseEnter(e); - } - - protected override void OnMouseLeave(EventArgs e) - { - _currentX = null; - _currentY = null; - CurrentCell = null; - IsPaintDown = false; - _columnResizing = null; - _hoverTimer.Stop(); - Refresh(); - base.OnMouseLeave(e); - } - - // TODO add query callback of whether to select the cell or not - protected override void OnMouseDown(MouseEventArgs e) - { - if (!GlobalWin.MainForm.EmulatorPaused && _currentX.HasValue) - { - // copypaste from OnMouseMove() - Cell newCell = CalculatePointedCell(_currentX.Value, _currentY.Value); - if (QueryFrameLag != null && newCell.RowIndex.HasValue) - { - newCell.RowIndex += CountLagFramesDisplay(newCell.RowIndex.Value); - } - - newCell.RowIndex += FirstVisibleRow; - if (newCell.RowIndex < 0) - { - newCell.RowIndex = 0; - } - - if (!newCell.Equals(CurrentCell)) - { - CellChanged(newCell); - - if (IsHoveringOnColumnCell || - (WasHoveringOnColumnCell && !IsHoveringOnColumnCell)) - { - Refresh(); - } - else if (_columnDown != null) - { - Refresh(); - } - } - else if (_columnDown != null) - { - Refresh(); - } - } - - if (e.Button == MouseButtons.Left) - { - if (IsHoveringOnColumnEdge) - { - _columnResizing = CurrentCell.Column; - } - if (IsHoveringOnColumnCell) - { - _columnDown = CurrentCell.Column; - } - else if (InputPaintingMode) - { - IsPaintDown = true; - } - } - - if (e.Button == MouseButtons.Right) - { - if (!IsHoveringOnColumnCell) - { - RightButtonHeld = true; - } - } - - if (e.Button == MouseButtons.Left) - { - if (IsHoveringOnDataCell) - { - if (ModifierKeys == Keys.Alt) - { - // do marker drag here - } - else if (ModifierKeys == Keys.Shift && (CurrentCell.Column.Name == "FrameColumn" || CurrentCell.Column.Type == RollColumn.InputType.Text)) - { - if (_selectedItems.Any()) - { - if (FullRowSelect) - { - var selected = _selectedItems.Any(c => c.RowIndex.HasValue && CurrentCell.RowIndex.HasValue && c.RowIndex == CurrentCell.RowIndex); - - if (!selected) - { - var rowIndices = _selectedItems - .Where(c => c.RowIndex.HasValue) - .Select(c => c.RowIndex ?? -1) - .Where(c => c >= 0) // Hack to avoid possible Nullable exceptions - .Distinct() - .ToList(); - - var firstIndex = rowIndices.Min(); - var lastIndex = rowIndices.Max(); - - if (CurrentCell.RowIndex.Value < firstIndex) - { - for (int i = CurrentCell.RowIndex.Value; i < firstIndex; i++) - { - SelectCell(new Cell - { - RowIndex = i, - Column = CurrentCell.Column - }); - } - } - else if (CurrentCell.RowIndex.Value > lastIndex) - { - for (int i = lastIndex + 1; i <= CurrentCell.RowIndex.Value; i++) - { - SelectCell(new Cell - { - RowIndex = i, - Column = CurrentCell.Column - }); - } - } - else // Somewhere in between, a scenario that can happen with ctrl-clicking, find the previous and highlight from there - { - var nearest = rowIndices - .Where(x => x < CurrentCell.RowIndex.Value) - .Max(); - - for (int i = nearest + 1; i <= CurrentCell.RowIndex.Value; i++) - { - SelectCell(new Cell - { - RowIndex = i, - Column = CurrentCell.Column - }); - } - } - } - } - else - { - MessageBox.Show("Shift click logic for individual cells has not yet implemented"); - } - } - else - { - SelectCell(CurrentCell); - } - } - else if (ModifierKeys == Keys.Control && (CurrentCell.Column.Name == "FrameColumn" || CurrentCell.Column.Type == RollColumn.InputType.Text)) - { - SelectCell(CurrentCell, toggle: true); - } - else if (ModifierKeys != Keys.Shift) - { - var hadIndex = _selectedItems.Any(); - _selectedItems.Clear(); - SelectCell(CurrentCell); - } - - Refresh(); - - SelectedIndexChanged?.Invoke(this, new EventArgs()); - } - } - - base.OnMouseDown(e); - - if (AllowRightClickSelecton && e.Button == MouseButtons.Right) - { - if (!IsHoveringOnColumnCell && CurrentCell != null) - { - _currentX = e.X; - _currentY = e.Y; - Cell newCell = CalculatePointedCell(_currentX.Value, _currentY.Value); - newCell.RowIndex += FirstVisibleRow; - CellChanged(newCell); - SelectCell(CurrentCell); - } - } - } - - protected override void OnMouseUp(MouseEventArgs e) - { - if (_columnResizing == null && IsHoveringOnColumnCell) - { - if (_columnDown != null && _columnDownMoved) - { - DoColumnReorder(); - _columnDown = null; - Refresh(); - } - else if (e.Button == MouseButtons.Left) - { - ColumnClickEvent(ColumnAtX(e.X)); - } - else if (e.Button == MouseButtons.Right) - { - ColumnRightClickEvent(ColumnAtX(e.X)); - } - } - - _columnResizing = null; - _columnDown = null; - _columnDownMoved = false; - RightButtonHeld = false; - IsPaintDown = false; - base.OnMouseUp(e); - } - - private void IncrementScrollBar(ScrollBar bar, bool increment) - { - int newVal; - if (increment) - { - newVal = bar.Value + bar.SmallChange; - if (newVal > bar.Maximum - bar.LargeChange) - { - newVal = bar.Maximum - bar.LargeChange; - } - } - else - { - newVal = bar.Value - bar.SmallChange; - if (newVal < 0) - { - newVal = 0; - } - } - - _programmaticallyUpdatingScrollBarValues = true; - bar.Value = newVal; - _programmaticallyUpdatingScrollBarValues = false; - } - - protected override void OnMouseWheel(MouseEventArgs e) - { - if (RightButtonHeld) - { - DoRightMouseScroll(this, e); - } - else - { - if (HorizontalOrientation) - { - do - { - IncrementScrollBar(_hBar, e.Delta < 0); - SetLagFramesFirst(); - } - while (_lagFrames[0] != 0 && _hBar.Value != 0 && _hBar.Value != _hBar.Maximum); - } - else - { - do - { - IncrementScrollBar(_vBar, e.Delta < 0); - SetLagFramesFirst(); - } - while (_lagFrames[0] != 0 && _vBar.Value != 0 && _vBar.Value != _vBar.Maximum); - } - - if (_currentX != null) - { - OnMouseMove(new MouseEventArgs(MouseButtons.None, 0, _currentX.Value, _currentY.Value, 0)); - } - - Refresh(); - } - } - - private void DoRightMouseScroll(object sender, MouseEventArgs e) - { - RightMouseScrolled?.Invoke(sender, e); - } - - private void ColumnClickEvent(RollColumn column) - { - ColumnClick?.Invoke(this, new ColumnClickEventArgs(column)); - } - - private void ColumnRightClickEvent(RollColumn column) - { - ColumnRightClick?.Invoke(this, new ColumnClickEventArgs(column)); - } - - protected override void OnKeyDown(KeyEventArgs e) - { - if (!SuspendHotkeys) - { - if (e.Control && !e.Alt && e.Shift && e.KeyCode == Keys.F) // Ctrl+Shift+F - { - HorizontalOrientation ^= true; - } - // Scroll - else if (!e.Control && !e.Alt && !e.Shift && e.KeyCode == Keys.PageUp) // Page Up - { - if (FirstVisibleRow > 0) - { - LastVisibleRow = FirstVisibleRow; - Refresh(); - } - } - else if (!e.Control && !e.Alt && !e.Shift && e.KeyCode == Keys.PageDown) // Page Down - { - var totalRows = LastVisibleRow - FirstVisibleRow; - if (totalRows <= RowCount) - { - var final = LastVisibleRow + totalRows; - if (final > RowCount) - { - final = RowCount; - } - - LastVisibleRow = final; - Refresh(); - } - } - else if (!e.Control && !e.Alt && !e.Shift && e.KeyCode == Keys.Home) // Home - { - FirstVisibleRow = 0; - Refresh(); - } - else if (!e.Control && !e.Alt && !e.Shift && e.KeyCode == Keys.End) // End - { - LastVisibleRow = RowCount; - Refresh(); - } - else if (!e.Control && !e.Shift && !e.Alt && e.KeyCode == Keys.Up) // Up - { - if (FirstVisibleRow > 0) - { - FirstVisibleRow--; - Refresh(); - } - } - else if (!e.Control && !e.Shift && !e.Alt && e.KeyCode == Keys.Down) // Down - { - if (FirstVisibleRow < RowCount - 1) - { - FirstVisibleRow++; - Refresh(); - } - } - // Selection courser - else if (e.Control && !e.Shift && !e.Alt && e.KeyCode == Keys.Up) // Ctrl + Up - { - if (SelectedRows.Any() && LetKeysModifySelection && SelectedRows.First() > 0) - { - foreach (var row in SelectedRows.ToList()) // clones SelectedRows - { - SelectRow(row - 1, true); - SelectRow(row, false); - } - } - } - else if (e.Control && !e.Shift && !e.Alt && e.KeyCode == Keys.Down) // Ctrl + Down - { - if (SelectedRows.Any() && LetKeysModifySelection) - { - foreach (var row in SelectedRows.Reverse()) // clones SelectedRows - { - SelectRow(row + 1, true); - SelectRow(row, false); - } - } - } - else if (e.Control && !e.Shift && !e.Alt && e.KeyCode == Keys.Left) // Ctrl + Left - { - if (SelectedRows.Any() && LetKeysModifySelection) - { - SelectRow(SelectedRows.Last(), false); - } - } - else if (e.Control && !e.Shift && !e.Alt && e.KeyCode == Keys.Right) // Ctrl + Right - { - if (SelectedRows.Any() && LetKeysModifySelection && SelectedRows.Last() < _rowCount - 1) - { - SelectRow(SelectedRows.Last() + 1, true); - } - } - else if (e.Control && e.Shift && !e.Alt && e.KeyCode == Keys.Left) // Ctrl + Shift + Left - { - if (SelectedRows.Any() && LetKeysModifySelection && SelectedRows.First() > 0) - { - SelectRow(SelectedRows.First() - 1, true); - } - } - else if (e.Control && e.Shift && !e.Alt && e.KeyCode == Keys.Right) // Ctrl + Shift + Right - { - if (SelectedRows.Any() && LetKeysModifySelection) - { - SelectRow(SelectedRows.First(), false); - } - } - else if (e.Control && !e.Shift && !e.Alt && e.KeyCode == Keys.PageUp) // Ctrl + Page Up - { - //jump to above marker with selection courser - if (LetKeysModifySelection) - { - - } - } - else if (e.Control && !e.Shift && !e.Alt && e.KeyCode == Keys.PageDown) // Ctrl + Page Down - { - //jump to below marker with selection courser - if (LetKeysModifySelection) - { - - } - - } - else if (e.Control && !e.Shift && !e.Alt && e.KeyCode == Keys.Home) // Ctrl + Home - { - //move selection courser to frame 0 - if (LetKeysModifySelection) - { - DeselectAll(); - SelectRow(0, true); - } - } - else if (e.Control && !e.Shift && !e.Alt && e.KeyCode == Keys.End) // Ctrl + End - { - //move selection courser to end of movie - if (LetKeysModifySelection) - { - DeselectAll(); - SelectRow(RowCount-1, true); - } - } - - } - - base.OnKeyDown(e); - } - - #endregion - - #region Change Events - - protected override void OnResize(EventArgs e) - { - RecalculateScrollBars(); - base.OnResize(e); - Refresh(); - } - - private void OrientationChanged() - { - RecalculateScrollBars(); - - // TODO scroll to correct positions - ColumnChangedCallback(); - RecalculateScrollBars(); - - Refresh(); - } - - /// - /// Call this function to change the CurrentCell to newCell - /// - private void CellChanged(Cell newCell) - { - LastCell = CurrentCell; - CurrentCell = newCell; - - if (PointedCellChanged != null && - (LastCell.Column != CurrentCell.Column || LastCell.RowIndex != CurrentCell.RowIndex)) - { - PointedCellChanged(this, new CellEventArgs(LastCell, CurrentCell)); - } - - if (CurrentCell?.Column != null && CurrentCell.RowIndex.HasValue) - { - _hoverTimer.Start(); - } - else - { - _hoverTimer.Stop(); - } - } - - private void VerticalBar_ValueChanged(object sender, EventArgs e) - { - if (!_programmaticallyUpdatingScrollBarValues) - { - Refresh(); - } - - if (_horizontalOrientation) - { - ColumnScroll?.Invoke(_vBar, e); - } - else - { - RowScroll?.Invoke(_vBar, e); - } - } - - private void HorizontalBar_ValueChanged(object sender, EventArgs e) - { - if (!_programmaticallyUpdatingScrollBarValues) - { - Refresh(); - } - - if (_horizontalOrientation) - { - RowScroll?.Invoke(_hBar, e); - } - else - { - ColumnScroll?.Invoke(_vBar, e); - } - } - - private void ColumnChangedCallback() - { - RecalculateScrollBars(); - if (_columns.VisibleColumns.Any()) - { - ColumnWidth = _columns.VisibleColumns.Max(c => c.Width.Value) + CellWidthPadding * 4; - } - } - - #endregion - - #region Helpers - - private void DoColumnReorder() - { - if (_columnDown != CurrentCell.Column) - { - var oldIndex = _columns.IndexOf(_columnDown); - var newIndex = _columns.IndexOf(CurrentCell.Column); - - ColumnReordered?.Invoke(this, new ColumnReorderedEventArgs(oldIndex, newIndex, _columnDown)); - - _columns.Remove(_columnDown); - _columns.Insert(newIndex, _columnDown); - } - } - - // ScrollBar.Maximum = DesiredValue + ScrollBar.LargeChange - 1 - // See MSDN Page for more information on the dumb ScrollBar.Maximum Property - private void RecalculateScrollBars() - { - UpdateDrawSize(); - - var columns = _columns.VisibleColumns.ToList(); - - if (HorizontalOrientation) - { - NeedsVScrollbar = columns.Count > DrawHeight / CellHeight; - NeedsHScrollbar = RowCount > 1; - } - else - { - NeedsVScrollbar = ColumnHeight + (RowCount * RowHeight) > Height; - NeedsHScrollbar = TotalColWidth.HasValue && TotalColWidth.Value - DrawWidth + 1 > 0; - } - - UpdateDrawSize(); - if (VisibleRows > 0) - { - if (HorizontalOrientation) - { - _vBar.LargeChange = DrawHeight / 2; - _hBar.Maximum = Math.Max((VisibleRows - 1) * CellHeight, _hBar.Maximum); - _hBar.LargeChange = (VisibleRows - 1) * CellHeight; - } - else - { - _vBar.Maximum = Math.Max((VisibleRows - 1) * CellHeight, _vBar.Maximum); // ScrollBar.Maximum is dumb - _vBar.LargeChange = (VisibleRows - 1) * CellHeight; - // DrawWidth can be negative if the TAStudio window is small enough - // Clamp LargeChange to 0 here to prevent exceptions - _hBar.LargeChange = Math.Max(0, DrawWidth / 2); - } - } - - // Update VBar - if (NeedsVScrollbar) - { - if (HorizontalOrientation) - { - _vBar.Maximum = ((columns.Count() * CellHeight) - DrawHeight) + _vBar.LargeChange; - if (_vBar.Maximum < 0) - { - _vBar.Maximum = 0; - } - } - else - { - _vBar.Maximum = RowsToPixels(RowCount + 1) - (CellHeight * 3) + _vBar.LargeChange - 1; - - if (_vBar.Maximum < 0) - { - _vBar.Maximum = 0; - } - } - - _vBar.Location = new Point(Width - _vBar.Width, 0); - _vBar.Height = Height; - _vBar.Visible = true; - } - else - { - _vBar.Visible = false; - _vBar.Value = 0; - } - - // Update HBar - if (NeedsHScrollbar) - { - if (HorizontalOrientation) - { - _hBar.Maximum = RowsToPixels(RowCount + 1) - (CellHeight * 3) + _hBar.LargeChange - 1; - } - else - { - _hBar.Maximum = TotalColWidth.Value - DrawWidth + _hBar.LargeChange; - } - - _hBar.Location = new Point(0, Height - _hBar.Height); - _hBar.Width = Width - (NeedsVScrollbar ? (_vBar.Width + 1) : 0); - _hBar.Visible = true; - } - else - { - _hBar.Visible = false; - _hBar.Value = 0; - } - } - - private void UpdateDrawSize() - { - if (NeedsVScrollbar) - { - DrawWidth = Width - _vBar.Width; - } - else - { - DrawWidth = Width; - } - if (NeedsHScrollbar) - { - DrawHeight = Height - _hBar.Height; - } - else - { - DrawHeight = Height; - } - } - - /// - /// If FullRowSelect is enabled, selects all cells in the row that contains the given cell. Otherwise only given cell is added. - /// - /// The cell to select. - private void SelectCell(Cell cell, bool toggle = false) - { - if (cell.RowIndex.HasValue && cell.RowIndex < RowCount) - { - if (!MultiSelect) - { - _selectedItems.Clear(); - } - - if (FullRowSelect) - { - if (toggle && _selectedItems.Any(x => x.RowIndex.HasValue && x.RowIndex == cell.RowIndex)) - { - _selectedItems.RemoveWhere(x => x.RowIndex.HasValue && x.RowIndex == cell.RowIndex); - } - else - { - foreach (var column in _columns) - { - _selectedItems.Add(new Cell - { - RowIndex = cell.RowIndex, - Column = column - }); - } - } - } - else - { - if (toggle && _selectedItems.Any(x => x.RowIndex.HasValue && x.RowIndex == cell.RowIndex)) - { - var item = _selectedItems - .FirstOrDefault(x => x.Equals(cell)); - - if (item != null) - { - _selectedItems.Remove(item); - } - } - else - { - _selectedItems.Add(CurrentCell); - } - } - } - } - - private bool IsHoveringOnColumnCell => CurrentCell?.Column != null && !CurrentCell.RowIndex.HasValue; - - private bool IsHoveringOnColumnEdge => AllowColumnResize && IsHoveringOnColumnCell && IsPointingOnCellEdge(_currentX); - - private bool IsHoveringOnDataCell => CurrentCell?.Column != null && CurrentCell.RowIndex.HasValue; - - private bool WasHoveringOnColumnCell => LastCell?.Column != null && !LastCell.RowIndex.HasValue; - - private bool WasHoveringOnDataCell => LastCell?.Column != null && LastCell.RowIndex.HasValue; - - private bool IsPointingOnCellEdge(int? x) - { - if (x.HasValue) - { - if (HorizontalOrientation) - { - return false; // TODO: support column resize in horizontal orientation - } - - foreach (RollColumn column in _columns.VisibleColumns) - { - if (column.Left - _hBar.Value + (column.Width - column.Width / 6) <= x.Value && column.Right - _hBar.Value >= x.Value) - { - return true; - } - } - } - - return false; - } - - /// - /// Finds the specific cell that contains the (x, y) coordinate. - /// - /// The row number that it returns will be between 0 and VisibleRows, NOT the absolute row number. - /// X coordinate point. - /// Y coordinate point. - /// The cell with row number and RollColumn reference, both of which can be null. - private Cell CalculatePointedCell(int x, int y) - { - var newCell = new Cell(); - var columns = _columns.VisibleColumns.ToList(); - - // If pointing to a column header - if (columns.Any()) - { - if (HorizontalOrientation) - { - newCell.RowIndex = PixelsToRows(x); - - int colIndex = (y + _vBar.Value) / CellHeight; - if (colIndex >= 0 && colIndex < columns.Count) - { - newCell.Column = columns[colIndex]; - } - } - else - { - newCell.RowIndex = PixelsToRows(y); - newCell.Column = ColumnAtX(x); - } - } - - if (!(IsPaintDown || RightButtonHeld) && newCell.RowIndex <= -1) // -2 if we're entering from the top - { - newCell.RowIndex = null; - } - - return newCell; - } - - // A boolean that indicates if the InputRoll is too large vertically and requires a vertical scrollbar. - private bool NeedsVScrollbar { get; set; } - - // A boolean that indicates if the InputRoll is too large horizontally and requires a horizontal scrollbar. - private bool NeedsHScrollbar { get; set; } - - /// - /// Gets the total width of all the columns by using the last column's Right property. - /// - /// A nullable Int representing total width. - private int? TotalColWidth - { - get - { - if (_columns.VisibleColumns.Any()) - { - return _columns.VisibleColumns.Last().Right; - } - - return null; - } - } - - /// - /// Returns the RollColumn object at the specified visible x coordinate. Coordinate should be between 0 and Width of the InputRoll Control. - /// - /// The x coordinate. - /// RollColumn object that contains the x coordinate or null if none exists. - private RollColumn ColumnAtX(int x) - { - foreach (RollColumn column in _columns.VisibleColumns) - { - if (column.Left.Value - _hBar.Value <= x && column.Right.Value - _hBar.Value >= x) - { - return column; - } - } - - return null; - } - - /// - /// Converts a row number to a horizontal or vertical coordinate. - /// - /// A vertical coordinate if Vertical Oriented, otherwise a horizontal coordinate. - private int RowsToPixels(int index) - { - if (_horizontalOrientation) - { - return (index * CellWidth) + ColumnWidth; - } - - return (index * CellHeight) + ColumnHeight; - } - - /// - /// Converts a horizontal or vertical coordinate to a row number. - /// - /// A vertical coordinate if Vertical Oriented, otherwise a horizontal coordinate. - /// A row number between 0 and VisibleRows if it is a Datarow, otherwise a negative number if above all Datarows. - private int PixelsToRows(int pixels) - { - // Using Math.Floor and float because integer division rounds towards 0 but we want to round down. - if (_horizontalOrientation) - { - return (int)Math.Floor((float)(pixels - ColumnWidth) / CellWidth); - } - return (int)Math.Floor((float)(pixels - ColumnHeight) / CellHeight); - } - - // The width of the largest column cell in Horizontal Orientation - - private int ColumnWidth { get; set; } - - // The height of a column cell in Vertical Orientation. - private int ColumnHeight { get; set; } - - // The width of a cell in Horizontal Orientation. Only can be changed by changing the Font or CellPadding. - private int CellWidth { get; set; } - - [Browsable(false)] - public int RowHeight => CellHeight; - - /// - /// Gets or sets a value indicating the height of a cell in Vertical Orientation. Only can be changed by changing the Font or CellPadding. - /// - private int CellHeight { get; set; } = 8; - - /// - /// Call when _charSize, MaxCharactersInHorizontal, or CellPadding is changed. - /// - private void UpdateCellSize() - { - CellHeight = _charSize.Height + (CellHeightPadding * 2); - CellWidth = (_charSize.Width * MaxCharactersInHorizontal) + (CellWidthPadding * 4); // Double the padding for horizontal because it looks better - } - - // SuuperW: Count lag frames between FirstDisplayed and given display position - private int CountLagFramesDisplay(int relativeIndex) - { - if (QueryFrameLag != null && LagFramesToHide != 0) - { - int count = 0; - for (int i = 0; i <= relativeIndex; i++) - { - count += _lagFrames[i]; - } - - return count; - } - - return 0; - } - - // Count lag frames between FirstDisplayed and given relative frame index - private int CountLagFramesAbsolute(int relativeIndex) - { - if (QueryFrameLag != null && LagFramesToHide != 0) - { - int count = 0; - for (int i = 0; i + count <= relativeIndex; i++) - { - count += _lagFrames[i]; - } - - return count; - } - - return 0; - } - - private void SetLagFramesArray() - { - if (QueryFrameLag != null && LagFramesToHide != 0) - { - bool showNext = false; - - // First one needs to check BACKWARDS for lag frame count. - SetLagFramesFirst(); - int f = _lagFrames[0]; - if (QueryFrameLag(FirstVisibleRow + f, HideWasLagFrames)) - { - showNext = true; - } - - for (int i = 1; i <= VisibleRows; i++) - { - _lagFrames[i] = 0; - if (!showNext) - { - for (; _lagFrames[i] < LagFramesToHide; _lagFrames[i]++) - { - if (!QueryFrameLag(FirstVisibleRow + i + f, HideWasLagFrames)) - { - break; - } - - f++; - } - } - else - { - if (!QueryFrameLag(FirstVisibleRow + i + f, HideWasLagFrames)) - { - showNext = false; - } - } - - if (_lagFrames[i] == LagFramesToHide && QueryFrameLag(FirstVisibleRow + i + f, HideWasLagFrames)) - { - showNext = true; - } - } - } - else - { - for (int i = 0; i <= VisibleRows; i++) - { - _lagFrames[i] = 0; - } - } - } - private void SetLagFramesFirst() - { - if (QueryFrameLag != null && LagFramesToHide != 0) - { - // Count how many lag frames are above displayed area. - int count = 0; - do - { - count++; - } - while (QueryFrameLag(FirstVisibleRow - count, HideWasLagFrames) && count <= LagFramesToHide); - count--; - - // Count forward - int fCount = -1; - do - { - fCount++; - } - while (QueryFrameLag(FirstVisibleRow + fCount, HideWasLagFrames) && count + fCount < LagFramesToHide); - _lagFrames[0] = (byte)fCount; - } - else - { - _lagFrames[0] = 0; - } - } - - // Number of displayed + hidden frames, if fps is as expected - private int ExpectedDisplayRange() - { - return (VisibleRows + 1) * LagFramesToHide; - } - - #endregion - - #region Classes - - public class RollColumns : List - { - public RollColumn this[string name] - { - get - { - return this.SingleOrDefault(column => column.Name == name); - } - } - - public IEnumerable VisibleColumns - { - get - { - return this.Where(c => c.Visible); - } - } - - public Action ChangedCallback { get; set; } - - private void DoChangeCallback() - { - // no check will make it crash for user too, not sure which way of alarm we prefer. no alarm at all will cause all sorts of subtle bugs - if (ChangedCallback == null) - { - System.Diagnostics.Debug.Fail($"{nameof(ColumnChangedCallback)} has died!"); - } - else - { - ChangedCallback(); - } - } - - // TODO: this shouldn't be exposed. But in order to not expose it, each RollColumn must have a change callback, and all property changes must call it, it is quicker and easier to just call this when needed - public void ColumnsChanged() - { - int pos = 0; - - foreach (var col in VisibleColumns) - { - col.Left = pos; - pos += col.Width.Value; - col.Right = pos; - } - - DoChangeCallback(); - } - - public new void Add(RollColumn column) - { - if (this.Any(c => c.Name == column.Name)) - { - // The designer sucks, doing nothing for now - return; - //throw new InvalidOperationException("A column with this name already exists."); - } - - base.Add(column); - ColumnsChanged(); - } - - public new void AddRange(IEnumerable collection) - { - foreach (var column in collection) - { - if (this.Any(c => c.Name == column.Name)) - { - // The designer sucks, doing nothing for now - return; - - throw new InvalidOperationException("A column with this name already exists."); - } - } - - base.AddRange(collection); - ColumnsChanged(); - } - - public new void Insert(int index, RollColumn column) - { - if (this.Any(c => c.Name == column.Name)) - { - throw new InvalidOperationException("A column with this name already exists."); - } - - base.Insert(index, column); - ColumnsChanged(); - } - - public new void InsertRange(int index, IEnumerable collection) - { - foreach (var column in collection) - { - if (this.Any(c => c.Name == column.Name)) - { - throw new InvalidOperationException("A column with this name already exists."); - } - } - - base.InsertRange(index, collection); - ColumnsChanged(); - } - - public new bool Remove(RollColumn column) - { - var result = base.Remove(column); - ColumnsChanged(); - return result; - } - - public new int RemoveAll(Predicate match) - { - var result = base.RemoveAll(match); - ColumnsChanged(); - return result; - } - - public new void RemoveAt(int index) - { - base.RemoveAt(index); - ColumnsChanged(); - } - - public new void RemoveRange(int index, int count) - { - base.RemoveRange(index, count); - ColumnsChanged(); - } - - public new void Clear() - { - base.Clear(); - ColumnsChanged(); - } - - public IEnumerable Groups - { - get - { - return this - .Select(x => x.Group) - .Distinct(); - } - } - } - - public class RollColumn - { - public enum InputType { Boolean, Float, Text, Image } - - public string Group { get; set; } - public int? Width { get; set; } - public int? Left { get; set; } - public int? Right { get; set; } - public string Name { get; set; } - public string Text { get; set; } - public InputType Type { get; set; } - public bool Visible { get; set; } - - /// - /// Column will be drawn with an emphasized look, if true - /// - private bool _emphasis; - public bool Emphasis - { - get { return _emphasis; } - set { _emphasis = value; } - } - - public RollColumn() - { - Visible = true; - } - } - - /// - /// Represents a single cell of the - /// - public class Cell - { - public RollColumn Column { get; internal set; } - public int? RowIndex { get; internal set; } - public string CurrentText { get; internal set; } - - public Cell() { } - - public Cell(Cell cell) - { - Column = cell.Column; - RowIndex = cell.RowIndex; - } - - public bool IsDataCell => Column != null && RowIndex.HasValue; - - public override bool Equals(object obj) - { - if (obj is Cell) - { - var cell = obj as Cell; - return this.Column == cell.Column && this.RowIndex == cell.RowIndex; - } - - return base.Equals(obj); - } - - public override int GetHashCode() - { - return Column.GetHashCode() + RowIndex.GetHashCode(); - } - } - - private class SortCell : IComparer - { - int IComparer.Compare(Cell a, Cell b) - { - Cell c1 = a as Cell; - Cell c2 = b as Cell; - if (c1.RowIndex.HasValue) - { - if (c2.RowIndex.HasValue) - { - int row = c1.RowIndex.Value.CompareTo(c2.RowIndex.Value); - if (row == 0) - { - return c1.Column.Name.CompareTo(c2.Column.Name); - } - - return row; - } - - return 1; - } - - if (c2.RowIndex.HasValue) - { - return -1; - } - - return c1.Column.Name.CompareTo(c2.Column.Name); - } - } - - #endregion - } -} +using System; +using System.Collections.Generic; +using System.ComponentModel; +using System.Drawing; +using System.Linq; +using System.Windows.Forms; + +using BizHawk.Client.Common; +using BizHawk.Client.EmuHawk.CustomControls; +using BizHawk.Common; + +namespace BizHawk.Client.EmuHawk +{ + // Row width depends on font size and padding + // Column width is specified in column headers + // Row width is specified for horizontal orientation + public partial class InputRoll : Control + { + private readonly IControlRenderer _renderer; + private readonly SortedSet _selectedItems = new SortedSet(new SortCell()); + + // scrollbar location(s) are calculated later (e.g. on resize) + private readonly VScrollBar _vBar = new VScrollBar { Visible = false }; + private readonly HScrollBar _hBar = new HScrollBar { Visible = false }; + + private readonly Timer _hoverTimer = new Timer(); + private readonly byte[] _lagFrames = new byte[256]; // Large enough value that it shouldn't ever need resizing. // apparently not large enough for 4K + + private readonly Color _foreColor; + private readonly Color _backColor; + + private RollColumns _columns = new RollColumns(); + private bool _horizontalOrientation; + private bool _programmaticallyUpdatingScrollBarValues; + private int _maxCharactersInHorizontal = 1; + + private int _rowCount; + private Size _charSize; + + private RollColumn _columnDown; + private RollColumn _columnResizing; + + private int? _currentX; + private int? _currentY; + + // Hiding lag frames (Mainly intended for < 60fps play.) + public int LagFramesToHide { get; set; } + public bool HideWasLagFrames { get; set; } + + public bool AllowRightClickSelecton { get; set; } + public bool LetKeysModifySelection { get; set; } + public bool SuspendHotkeys { get; set; } + + private Font _font = new Font("Arial", 8, FontStyle.Bold); + + public InputRoll() + { + UseCustomBackground = true; + GridLines = true; + CellWidthPadding = 3; + CellHeightPadding = 0; + CurrentCell = null; + ScrollMethod = "near"; + + SetStyle(ControlStyles.AllPaintingInWmPaint, true); + SetStyle(ControlStyles.UserPaint, true); + SetStyle(ControlStyles.SupportsTransparentBackColor, true); + SetStyle(ControlStyles.Opaque, true); + SetStyle(ControlStyles.OptimizedDoubleBuffer, true); + + if (OSTailoredCode.CurrentOS == OSTailoredCode.DistinctOS.Windows) + { + _renderer = new GdiRenderer(); + } + else + { + _renderer = new GdiPlusRenderer(); + } + + using (var g = CreateGraphics()) + using (_renderer.LockGraphics(g, Width, Height)) + { + _charSize = _renderer.MeasureString("A", _font); // TODO make this a property so changing it updates other values. + } + + UpdateCellSize(); + ColumnWidth = CellWidth; + ColumnHeight = CellHeight + 2; + + _vBar.SmallChange = CellHeight; + _vBar.LargeChange = CellHeight * 20; + + _hBar.SmallChange = CellWidth; + _hBar.LargeChange = 20; + + Controls.Add(_vBar); + Controls.Add(_hBar); + + _vBar.ValueChanged += VerticalBar_ValueChanged; + _hBar.ValueChanged += HorizontalBar_ValueChanged; + + RecalculateScrollBars(); + _columns.ChangedCallback = ColumnChangedCallback; + + _hoverTimer.Interval = 750; + _hoverTimer.Tick += HoverTimerEventProcessor; + _hoverTimer.Stop(); + + _foreColor = ForeColor; + _backColor = BackColor; + } + + private void HoverTimerEventProcessor(object sender, EventArgs e) + { + _hoverTimer.Stop(); + + CellHovered?.Invoke(this, new CellEventArgs(LastCell, CurrentCell)); + } + + protected override void Dispose(bool disposing) + { + _renderer.Dispose(); + base.Dispose(disposing); + } + + protected override void OnDoubleClick(EventArgs e) + { + if (IsHoveringOnColumnEdge) + { + if (HorizontalOrientation) + { + // TODO + } + else + { + var maxLength = CurrentCell.Column.Text?.Length ?? 0; + + + for (int i = 0; i < RowCount; i++) + { + string text = ""; + int offSetX = 0, offSetY = 0; + QueryItemText?.Invoke(i, CurrentCell.Column, out text, ref offSetX, ref offSetY); + if (text.Length > maxLength) + { + maxLength = text.Length; + } + } + + var newWidth = (maxLength * _charSize.Width) + (CellWidthPadding * 2); + CurrentCell.Column.Width = newWidth; + _columns.ColumnsChanged(); + Refresh(); + } + + } + + base.OnDoubleClick(e); + } + + #region Properties + + /// + /// Gets or sets the amount of left and right padding on the text inside a cell + /// + [DefaultValue(3)] + [Category("Behavior")] + public int CellWidthPadding { get; set; } + + /// + /// Gets or sets the amount of top and bottom padding on the text inside a cell + /// + [DefaultValue(1)] + [Category("Behavior")] + public int CellHeightPadding { get; set; } + + /// + /// Gets or sets a value indicating whether grid lines are displayed around cells + /// + [Category("Appearance")] + [DefaultValue(true)] + public bool GridLines { get; set; } + + /// + /// Gets or sets a value indicating whether the control is horizontal or vertical + /// + [Category("Behavior")] + public bool HorizontalOrientation + { + get + { + return _horizontalOrientation; + } + set + { + if (_horizontalOrientation != value) + { + int temp = ScrollSpeed; + _horizontalOrientation = value; + OrientationChanged(); + _hBar.SmallChange = CellWidth; + _vBar.SmallChange = CellHeight; + ScrollSpeed = temp; + } + } + } + + /// + /// Gets or sets the scrolling speed + /// + [Category("Behavior")] + public int ScrollSpeed + { + get + { + if (HorizontalOrientation) + { + return _hBar.SmallChange / CellWidth; + } + + return _vBar.SmallChange / CellHeight; + } + + set + { + if (HorizontalOrientation) + { + _hBar.SmallChange = value * CellWidth; + } + else + { + _vBar.SmallChange = value * CellHeight; + } + } + } + + /// + /// Gets or sets the sets the virtual number of rows to be displayed. Does not include the column header row. + /// + [Category("Behavior")] + public int RowCount + { + get + { + return _rowCount; + } + + set + { + _rowCount = value; + RecalculateScrollBars(); + } + } + + /// + /// Gets or sets a value indicating whether columns can be resized + /// + [Category("Behavior")] + public bool AllowColumnResize { get; set; } + + /// + /// Gets or sets a value indicating whether columns can be reordered + /// + [Category("Behavior")] + public bool AllowColumnReorder { get; set; } + + /// + /// Gets or sets a value indicating whether the entire row will always be selected + /// + [Category("Appearance")] + [DefaultValue(false)] + public bool FullRowSelect { get; set; } + + /// + /// Gets or sets a value indicating whether multiple items can to be selected + /// + [Category("Behavior")] + [DefaultValue(true)] + public bool MultiSelect { get; set; } + + /// + /// Gets or sets a value indicating whether the control is in input painting mode + /// + [Category("Behavior")] + [DefaultValue(false)] + public bool InputPaintingMode { get; set; } + + /// + /// All visible columns + /// + [Category("Behavior")] + public IEnumerable VisibleColumns => _columns.VisibleColumns; + + /// + /// Gets or sets how the InputRoll scrolls when calling ScrollToIndex. + /// + [DefaultValue("near")] + [Category("Behavior")] + public string ScrollMethod { get; set; } + + /// + /// Gets or sets a value indicating how the Intever for the hover event + /// + [Category("Behavior")] + public bool AlwaysScroll { get; set; } + + /// + /// Gets or sets the lowest seek interval to activate the progress bar + /// + [Category("Behavior")] + public int SeekingCutoffInterval { get; set; } + + /// + /// Returns all columns including those that are not visible + /// + [Browsable(false)] + [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] + public RollColumns AllColumns => _columns; + + [DefaultValue(750)] + [Category("Behavior")] + public int HoverInterval + { + get { return _hoverTimer.Interval; } + set { _hoverTimer.Interval = value; } + } + + #endregion + + #region Event Handlers + + /// + /// Fire the event which requests the text for the passed cell + /// + [Category("Virtual")] + public event QueryItemTextHandler QueryItemText; + + /// + /// Fire the event which requests the background color for the passed cell + /// + [Category("Virtual")] + public event QueryItemBkColorHandler QueryItemBkColor; + + [Category("Virtual")] + public event QueryRowBkColorHandler QueryRowBkColor; + + /// + /// Fire the event which requests an icon for a given cell + /// + [Category("Virtual")] + public event QueryItemIconHandler QueryItemIcon; + + /// + /// Fire the QueryFrameLag event which checks if a given frame is a lag frame + /// + [Category("Virtual")] + public event QueryFrameLagHandler QueryFrameLag; + + /// + /// Fires when the mouse moves from one cell to another (including column header cells) + /// + [Category("Mouse")] + public event CellChangeEventHandler PointedCellChanged; + + /// + /// Fires when a cell is hovered on + /// + [Category("Mouse")] + public event HoverEventHandler CellHovered; + + /// + /// Occurs when a column header is clicked + /// + [Category("Action")] + public event ColumnClickEventHandler ColumnClick; + + /// + /// Occurs when a column header is right-clicked + /// + [Category("Action")] + public event ColumnClickEventHandler ColumnRightClick; + + /// + /// Occurs whenever the 'SelectedItems' property for this control changes + /// + [Category("Behavior")] + public event EventHandler SelectedIndexChanged; + + /// + /// Occurs whenever the mouse wheel is scrolled while the right mouse button is held + /// + [Category("Behavior")] + public event RightMouseScrollEventHandler RightMouseScrolled; + + [Category("Property Changed")] + [Description("Occurs when the column header has been reordered")] + public event ColumnReorderedEventHandler ColumnReordered; + + [Category("Action")] + [Description("Occurs when the scroll value of the visible rows change (in vertical orientation this is the vertical scroll bar change, and in horizontal it is the horizontal scroll bar)")] + public event RowScrollEvent RowScroll; + + [Category("Action")] + [Description("Occurs when the scroll value of the columns (in vertical orientation this is the horizontal scroll bar change, and in horizontal it is the vertical scroll bar)")] + public event ColumnScrollEvent ColumnScroll; + + [Category("Action")] + [Description("Occurs when a cell is dragged and then dropped into a new cell, old cell is the cell that was being dragged, new cell is its new destination")] + public event CellDroppedEvent CellDropped; + + /// + /// Retrieve the text for a cell + /// + public delegate void QueryItemTextHandler(int index, RollColumn column, out string text, ref int offsetX, ref int offsetY); + + /// + /// Retrieve the background color for a cell + /// + public delegate void QueryItemBkColorHandler(int index, RollColumn column, ref Color color); + public delegate void QueryRowBkColorHandler(int index, ref Color color); + + /// + /// Retrieve the image for a given cell + /// + public delegate void QueryItemIconHandler(int index, RollColumn column, ref Bitmap icon, ref int offsetX, ref int offsetY); + + /// + /// Check if a given frame is a lag frame + /// + public delegate bool QueryFrameLagHandler(int index, bool hideWasLag); + + public delegate void CellChangeEventHandler(object sender, CellEventArgs e); + + public delegate void HoverEventHandler(object sender, CellEventArgs e); + + public delegate void RightMouseScrollEventHandler(object sender, MouseEventArgs e); + + public delegate void ColumnClickEventHandler(object sender, ColumnClickEventArgs e); + + public delegate void ColumnReorderedEventHandler(object sender, ColumnReorderedEventArgs e); + + public delegate void RowScrollEvent(object sender, EventArgs e); + + public delegate void ColumnScrollEvent(object sender, EventArgs e); + + public delegate void CellDroppedEvent(object sender, CellEventArgs e); + + public class CellEventArgs + { + public CellEventArgs(Cell oldCell, Cell newCell) + { + OldCell = oldCell; + NewCell = newCell; + } + + public Cell OldCell { get; private set; } + public Cell NewCell { get; private set; } + } + + public class ColumnClickEventArgs + { + public ColumnClickEventArgs(RollColumn column) + { + Column = column; + } + + public RollColumn Column { get; private set; } + } + + public class ColumnReorderedEventArgs + { + public ColumnReorderedEventArgs(int oldDisplayIndex, int newDisplayIndex, RollColumn column) + { + Column = column; + OldDisplayIndex = oldDisplayIndex; + NewDisplayIndex = newDisplayIndex; + } + + public RollColumn Column { get; private set; } + public int OldDisplayIndex { get; private set; } + public int NewDisplayIndex { get; private set; } + } + + #endregion + + #region Api + + public void SelectRow(int index, bool val) + { + if (_columns.VisibleColumns.Any()) + { + if (val) + { + SelectCell(new Cell + { + RowIndex = index, + Column = _columns[0] + }); + } + else + { + IEnumerable items = _selectedItems.Where(cell => cell.RowIndex == index); + _selectedItems.RemoveWhere(items.Contains); + } + } + } + + public void SelectAll() + { + var oldFullRowVal = FullRowSelect; + FullRowSelect = true; + for (int i = 0; i < RowCount; i++) + { + SelectRow(i, true); + } + + FullRowSelect = oldFullRowVal; + } + + public void DeselectAll() + { + _selectedItems.Clear(); + } + + public void TruncateSelection(int index) + { + _selectedItems.RemoveWhere(cell => cell.RowIndex > index); + } + + [Browsable(false)] + [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] + public bool IsPointingAtColumnHeader => IsHoveringOnColumnCell; + + [Browsable(false)] + [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] + public int? FirstSelectedIndex + { + get + { + if (AnyRowsSelected) + { + return SelectedRows.Min(); + } + + return null; + } + } + + [Browsable(false)] + [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] + public int? LastSelectedIndex + { + get + { + if (AnyRowsSelected) + { + return SelectedRows.Max(); + } + + return null; + } + } + + /// + /// Gets or sets the current Cell that the mouse was in. + /// + [Browsable(false)] + [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] + public Cell CurrentCell { get; set; } + + [Browsable(false)] + [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] + public bool CurrentCellIsDataCell => CurrentCell?.RowIndex != null && CurrentCell.Column != null; + + /// + /// Gets or sets the previous Cell that the mouse was in. + /// + [Browsable(false)] + [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] + public Cell LastCell { get; private set; } + + [Browsable(false)] + [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] + public bool IsPaintDown { get; private set; } + + [Browsable(false)] + [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] + public bool UseCustomBackground { get; set; } + + [Browsable(false)] + [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] + public int DrawHeight { get; private set; } + + [Browsable(false)] + [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] + public int DrawWidth { get; private set; } + + /// + /// Gets or sets the width of data cells when in Horizontal orientation. + /// + public int MaxCharactersInHorizontal + { + get + { + return _maxCharactersInHorizontal; + } + + set + { + _maxCharactersInHorizontal = value; + UpdateCellSize(); + } + } + + [Browsable(false)] + [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] + public bool RightButtonHeld { get; private set; } + + public string UserSettingsSerialized() + { + var settings = ConfigService.SaveWithType(Settings); + return settings; + } + + public void LoadSettingsSerialized(string settingsJson) + { + var settings = ConfigService.LoadWithType(settingsJson); + + // TODO: don't silently fail, inform the user somehow + if (settings is InputRollSettings) + { + var rollSettings = settings as InputRollSettings; + _columns = rollSettings.Columns; + _columns.ChangedCallback = ColumnChangedCallback; + HorizontalOrientation = rollSettings.HorizontalOrientation; + LagFramesToHide = rollSettings.LagFramesToHide; + HideWasLagFrames = rollSettings.HideWasLagFrames; + } + } + + private InputRollSettings Settings => new InputRollSettings + { + Columns = _columns, + HorizontalOrientation = HorizontalOrientation, + LagFramesToHide = LagFramesToHide, + HideWasLagFrames = HideWasLagFrames + }; + + public class InputRollSettings + { + public RollColumns Columns { get; set; } + public bool HorizontalOrientation { get; set; } + public int LagFramesToHide { get; set; } + public bool HideWasLagFrames { get; set; } + } + + /// + /// Gets or sets the first visible row index, if scrolling is needed + /// + [Browsable(false)] + [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] + public int FirstVisibleRow + { + get // SuuperW: This was checking if the scroll bars were needed, which is useless because their Value is 0 if they aren't needed. + { + if (HorizontalOrientation) + { + return _hBar.Value / CellWidth; + } + + return _vBar.Value / CellHeight; + } + + set + { + if (HorizontalOrientation) + { + if (NeedsHScrollbar) + { + _programmaticallyUpdatingScrollBarValues = true; + if (value * CellWidth <= _hBar.Maximum) + { + _hBar.Value = value * CellWidth; + } + else + { + _hBar.Value = _hBar.Maximum; + } + + _programmaticallyUpdatingScrollBarValues = false; + } + } + else + { + if (NeedsVScrollbar) + { + _programmaticallyUpdatingScrollBarValues = true; + if (value * CellHeight <= _vBar.Maximum) + { + _vBar.Value = value * CellHeight; + } + else + { + _vBar.Value = _vBar.Maximum; + } + + _programmaticallyUpdatingScrollBarValues = false; + } + } + } + } + + [Browsable(false)] + [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] + private int LastFullyVisibleRow + { + get + { + int halfRow = 0; + if ((DrawHeight - ColumnHeight - 3) % CellHeight < CellHeight / 2) + { + halfRow = 1; + } + + return FirstVisibleRow + VisibleRows - halfRow + CountLagFramesDisplay(VisibleRows - halfRow); + } + } + + [Browsable(false)] + [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] + public int LastVisibleRow + { + get + { + return FirstVisibleRow + VisibleRows + CountLagFramesDisplay(VisibleRows); + } + + set + { + int halfRow = 0; + if ((DrawHeight - ColumnHeight - 3) % CellHeight < CellHeight / 2) + { + halfRow = 1; + } + + if (LagFramesToHide == 0) + { + FirstVisibleRow = Math.Max(value - (VisibleRows - halfRow), 0); + } + else + { + if (Math.Abs(LastFullyVisibleRow - value) > VisibleRows) // Big jump + { + FirstVisibleRow = Math.Max(value - (ExpectedDisplayRange() - halfRow), 0); + SetLagFramesArray(); + } + + // Small jump, more accurate + int lastVisible = LastFullyVisibleRow; + do + { + if ((lastVisible - value) / (LagFramesToHide + 1) != 0) + { + FirstVisibleRow = Math.Max(FirstVisibleRow - ((lastVisible - value) / (LagFramesToHide + 1)), 0); + } + else + { + FirstVisibleRow -= Math.Sign(lastVisible - value); + } + + SetLagFramesArray(); + lastVisible = LastFullyVisibleRow; + } + while ((lastVisible - value < 0 || lastVisible - value > _lagFrames[VisibleRows - halfRow]) && FirstVisibleRow != 0); + } + } + } + + public bool IsVisible(int index) + { + return (index >= FirstVisibleRow) && (index <= LastFullyVisibleRow); + } + + public bool IsPartiallyVisible(int index) + { + return index >= FirstVisibleRow && index <= LastVisibleRow; + } + + /// + /// Gets the number of rows currently visible including partially visible rows. + /// + [Browsable(false)] + [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] + public int VisibleRows + { + get + { + if (HorizontalOrientation) + { + return (DrawWidth - ColumnWidth) / CellWidth; + } + + return (DrawHeight - ColumnHeight - 3) / CellHeight; // Minus three makes it work + } + } + + /// + /// Gets the first visible column index, if scrolling is needed + /// + [Browsable(false)] + [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] + public int FirstVisibleColumn + { + get + { + if (HorizontalOrientation) + { + return _vBar.Value / CellHeight; + } + + var columnList = VisibleColumns.ToList(); + return columnList.FindIndex(c => c.Right > _hBar.Value); + } + } + + [Browsable(false)] + [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] + public int LastVisibleColumnIndex + { + get + { + List columnList = VisibleColumns.ToList(); + int ret; + if (HorizontalOrientation) + { + ret = (_vBar.Value + DrawHeight) / CellHeight; + if (ret >= columnList.Count) + { + ret = columnList.Count - 1; + } + } + else + { + ret = columnList.FindLastIndex(c => c.Left <= DrawWidth + _hBar.Value); + } + + return ret; + } + } + + private Cell _draggingCell; + + public void DragCurrentCell() + { + _draggingCell = CurrentCell; + } + + public void ReleaseCurrentCell() + { + if (_draggingCell != null) + { + var draggedCell = _draggingCell; + _draggingCell = null; + + if (CurrentCell != draggedCell) + { + CellDropped?.Invoke(this, new CellEventArgs(draggedCell, CurrentCell)); + } + } + } + + /// + /// Scrolls to the given index, according to the scroll settings. + /// + public void ScrollToIndex(int index) + { + if (ScrollMethod == "near") + { + MakeIndexVisible(index); + } + + if (!IsVisible(index) || AlwaysScroll) + { + if (ScrollMethod == "top") + { + FirstVisibleRow = index; + } + else if (ScrollMethod == "bottom") + { + LastVisibleRow = index; + } + else if (ScrollMethod == "center") + { + if (LagFramesToHide == 0) + { + FirstVisibleRow = Math.Max(index - (VisibleRows / 2), 0); + } + else + { + if (Math.Abs(FirstVisibleRow + CountLagFramesDisplay(VisibleRows / 2) - index) > VisibleRows) // Big jump + { + FirstVisibleRow = Math.Max(index - (ExpectedDisplayRange() / 2), 0); + SetLagFramesArray(); + } + + // Small jump, more accurate + int lastVisible = FirstVisibleRow + CountLagFramesDisplay(VisibleRows / 2); + do + { + if ((lastVisible - index) / (LagFramesToHide + 1) != 0) + { + FirstVisibleRow = Math.Max(FirstVisibleRow - ((lastVisible - index) / (LagFramesToHide + 1)), 0); + } + else + { + FirstVisibleRow -= Math.Sign(lastVisible - index); + } + + SetLagFramesArray(); + lastVisible = FirstVisibleRow + CountLagFramesDisplay(VisibleRows / 2); + } + while ((lastVisible - index < 0 || lastVisible - index > _lagFrames[VisibleRows]) && FirstVisibleRow != 0); + } + } + } + } + + /// + /// Scrolls so that the given index is visible, if it isn't already; doesn't use scroll settings. + /// + public void MakeIndexVisible(int index) + { + if (!IsVisible(index)) + { + if (FirstVisibleRow > index) + { + FirstVisibleRow = index; + } + else + { + LastVisibleRow = index; + } + } + } + + [Browsable(false)] + [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] + public IEnumerable SelectedRows + { + get + { + return _selectedItems + .Where(cell => cell.RowIndex.HasValue) + .Select(cell => cell.RowIndex.Value) + .Distinct(); + } + } + + public bool AnyRowsSelected + { + get + { + return _selectedItems.Any(cell => cell.RowIndex.HasValue); + } + } + + public void ClearSelectedRows() + { + _selectedItems.Clear(); + } + + public IEnumerable GenerateContextMenuItems() + { + yield return new ToolStripSeparator(); + + var rotate = new ToolStripMenuItem + { + Name = "RotateMenuItem", + Text = "Rotate", + ShortcutKeyDisplayString = RotateHotkeyStr, + }; + + rotate.Click += (o, ev) => + { + HorizontalOrientation ^= true; + }; + + yield return rotate; + } + + public string RotateHotkeyStr => "Ctrl+Shift+F"; + + #endregion + + #region Mouse and Key Events + + private bool _columnDownMoved; + private int _previousX = 0; // TODO: move me + + protected override void OnMouseMove(MouseEventArgs e) + { + _previousX = _currentX ?? 0; + _currentX = e.X; + _currentY = e.Y; + + if (_columnResizing != null) + { + if (_currentX != _previousX) + { + _columnResizing.Width += _currentX - _previousX; + _columns.ColumnsChanged(); + Refresh(); + } + } + else if (_columnDown != null) + { + _columnDownMoved = true; + } + + Cell newCell = CalculatePointedCell(_currentX.Value, _currentY.Value); + + // SuuperW: Hide lag frames + if (QueryFrameLag != null && newCell.RowIndex.HasValue) + { + newCell.RowIndex += CountLagFramesDisplay(newCell.RowIndex.Value); + } + + newCell.RowIndex += FirstVisibleRow; + if (newCell.RowIndex < 0) + { + newCell.RowIndex = 0; + } + + if (!newCell.Equals(CurrentCell)) + { + CellChanged(newCell); + + if (IsHoveringOnColumnCell || + (WasHoveringOnColumnCell && !IsHoveringOnColumnCell)) + { + Refresh(); + } + else if (_columnDown != null) + { + Refresh(); + } + } + else if (_columnDown != null) // Kind of silly feeling to have this check twice, but the only alternative I can think of has it refreshing twice when pointed column changes with column down, and speed matters + { + Refresh(); + } + + Cursor = IsHoveringOnColumnEdge || _columnResizing != null + ? Cursors.VSplit + : Cursors.Default; + + base.OnMouseMove(e); + } + + protected override void OnMouseEnter(EventArgs e) + { + CurrentCell = new Cell + { + Column = null, + RowIndex = null + }; + + base.OnMouseEnter(e); + } + + protected override void OnMouseLeave(EventArgs e) + { + _currentX = null; + _currentY = null; + CurrentCell = null; + IsPaintDown = false; + _columnResizing = null; + _hoverTimer.Stop(); + Refresh(); + base.OnMouseLeave(e); + } + + // TODO add query callback of whether to select the cell or not + protected override void OnMouseDown(MouseEventArgs e) + { + if (!GlobalWin.MainForm.EmulatorPaused && _currentX.HasValue) + { + // copypaste from OnMouseMove() + Cell newCell = CalculatePointedCell(_currentX.Value, _currentY.Value); + if (QueryFrameLag != null && newCell.RowIndex.HasValue) + { + newCell.RowIndex += CountLagFramesDisplay(newCell.RowIndex.Value); + } + + newCell.RowIndex += FirstVisibleRow; + if (newCell.RowIndex < 0) + { + newCell.RowIndex = 0; + } + + if (!newCell.Equals(CurrentCell)) + { + CellChanged(newCell); + + if (IsHoveringOnColumnCell || + (WasHoveringOnColumnCell && !IsHoveringOnColumnCell)) + { + Refresh(); + } + else if (_columnDown != null) + { + Refresh(); + } + } + else if (_columnDown != null) + { + Refresh(); + } + } + + if (e.Button == MouseButtons.Left) + { + if (IsHoveringOnColumnEdge) + { + _columnResizing = CurrentCell.Column; + } + if (IsHoveringOnColumnCell) + { + _columnDown = CurrentCell.Column; + } + else if (InputPaintingMode) + { + IsPaintDown = true; + } + } + + if (e.Button == MouseButtons.Right) + { + if (!IsHoveringOnColumnCell) + { + RightButtonHeld = true; + } + } + + if (e.Button == MouseButtons.Left) + { + if (IsHoveringOnDataCell) + { + if (ModifierKeys == Keys.Alt) + { + // do marker drag here + } + else if (ModifierKeys == Keys.Shift && (CurrentCell.Column.Name == "FrameColumn" || CurrentCell.Column.Type == ColumnType.Text)) + { + if (_selectedItems.Any()) + { + if (FullRowSelect) + { + var selected = _selectedItems.Any(c => c.RowIndex.HasValue && CurrentCell.RowIndex.HasValue && c.RowIndex == CurrentCell.RowIndex); + + if (!selected) + { + var rowIndices = _selectedItems + .Where(c => c.RowIndex.HasValue) + .Select(c => c.RowIndex ?? -1) + .Where(c => c >= 0) // Hack to avoid possible Nullable exceptions + .Distinct() + .ToList(); + + var firstIndex = rowIndices.Min(); + var lastIndex = rowIndices.Max(); + + if (CurrentCell.RowIndex.Value < firstIndex) + { + for (int i = CurrentCell.RowIndex.Value; i < firstIndex; i++) + { + SelectCell(new Cell + { + RowIndex = i, + Column = CurrentCell.Column + }); + } + } + else if (CurrentCell.RowIndex.Value > lastIndex) + { + for (int i = lastIndex + 1; i <= CurrentCell.RowIndex.Value; i++) + { + SelectCell(new Cell + { + RowIndex = i, + Column = CurrentCell.Column + }); + } + } + else // Somewhere in between, a scenario that can happen with ctrl-clicking, find the previous and highlight from there + { + var nearest = rowIndices + .Where(x => x < CurrentCell.RowIndex.Value) + .Max(); + + for (int i = nearest + 1; i <= CurrentCell.RowIndex.Value; i++) + { + SelectCell(new Cell + { + RowIndex = i, + Column = CurrentCell.Column + }); + } + } + } + } + else + { + MessageBox.Show("Shift click logic for individual cells has not yet implemented"); + } + } + else + { + SelectCell(CurrentCell); + } + } + else if (ModifierKeys == Keys.Control && (CurrentCell.Column.Name == "FrameColumn" || CurrentCell.Column.Type == ColumnType.Text)) + { + SelectCell(CurrentCell, toggle: true); + } + else if (ModifierKeys != Keys.Shift) + { + var hadIndex = _selectedItems.Any(); + _selectedItems.Clear(); + SelectCell(CurrentCell); + } + + Refresh(); + + SelectedIndexChanged?.Invoke(this, new EventArgs()); + } + } + + base.OnMouseDown(e); + + if (AllowRightClickSelecton && e.Button == MouseButtons.Right) + { + if (!IsHoveringOnColumnCell && CurrentCell != null) + { + _currentX = e.X; + _currentY = e.Y; + Cell newCell = CalculatePointedCell(_currentX.Value, _currentY.Value); + newCell.RowIndex += FirstVisibleRow; + CellChanged(newCell); + SelectCell(CurrentCell); + } + } + } + + protected override void OnMouseUp(MouseEventArgs e) + { + if (_columnResizing == null && IsHoveringOnColumnCell) + { + if (_columnDown != null && _columnDownMoved) + { + DoColumnReorder(); + _columnDown = null; + Refresh(); + } + else if (e.Button == MouseButtons.Left) + { + ColumnClickEvent(ColumnAtX(e.X)); + } + else if (e.Button == MouseButtons.Right) + { + ColumnRightClickEvent(ColumnAtX(e.X)); + } + } + + _columnResizing = null; + _columnDown = null; + _columnDownMoved = false; + RightButtonHeld = false; + IsPaintDown = false; + base.OnMouseUp(e); + } + + private void IncrementScrollBar(ScrollBar bar, bool increment) + { + int newVal; + if (increment) + { + newVal = bar.Value + bar.SmallChange; + if (newVal > bar.Maximum - bar.LargeChange) + { + newVal = bar.Maximum - bar.LargeChange; + } + } + else + { + newVal = bar.Value - bar.SmallChange; + if (newVal < 0) + { + newVal = 0; + } + } + + _programmaticallyUpdatingScrollBarValues = true; + bar.Value = newVal; + _programmaticallyUpdatingScrollBarValues = false; + } + + protected override void OnMouseWheel(MouseEventArgs e) + { + if (RightButtonHeld) + { + DoRightMouseScroll(this, e); + } + else + { + if (HorizontalOrientation) + { + do + { + IncrementScrollBar(_hBar, e.Delta < 0); + SetLagFramesFirst(); + } + while (_lagFrames[0] != 0 && _hBar.Value != 0 && _hBar.Value != _hBar.Maximum); + } + else + { + do + { + IncrementScrollBar(_vBar, e.Delta < 0); + SetLagFramesFirst(); + } + while (_lagFrames[0] != 0 && _vBar.Value != 0 && _vBar.Value != _vBar.Maximum); + } + + if (_currentX != null) + { + OnMouseMove(new MouseEventArgs(MouseButtons.None, 0, _currentX.Value, _currentY.Value, 0)); + } + + Refresh(); + } + } + + private void DoRightMouseScroll(object sender, MouseEventArgs e) + { + RightMouseScrolled?.Invoke(sender, e); + } + + private void ColumnClickEvent(RollColumn column) + { + ColumnClick?.Invoke(this, new ColumnClickEventArgs(column)); + } + + private void ColumnRightClickEvent(RollColumn column) + { + ColumnRightClick?.Invoke(this, new ColumnClickEventArgs(column)); + } + + protected override void OnKeyDown(KeyEventArgs e) + { + if (!SuspendHotkeys) + { + if (e.Control && !e.Alt && e.Shift && e.KeyCode == Keys.F) // Ctrl+Shift+F + { + HorizontalOrientation ^= true; + } + // Scroll + else if (!e.Control && !e.Alt && !e.Shift && e.KeyCode == Keys.PageUp) // Page Up + { + if (FirstVisibleRow > 0) + { + LastVisibleRow = FirstVisibleRow; + Refresh(); + } + } + else if (!e.Control && !e.Alt && !e.Shift && e.KeyCode == Keys.PageDown) // Page Down + { + var totalRows = LastVisibleRow - FirstVisibleRow; + if (totalRows <= RowCount) + { + var final = LastVisibleRow + totalRows; + if (final > RowCount) + { + final = RowCount; + } + + LastVisibleRow = final; + Refresh(); + } + } + else if (!e.Control && !e.Alt && !e.Shift && e.KeyCode == Keys.Home) // Home + { + FirstVisibleRow = 0; + Refresh(); + } + else if (!e.Control && !e.Alt && !e.Shift && e.KeyCode == Keys.End) // End + { + LastVisibleRow = RowCount; + Refresh(); + } + else if (!e.Control && !e.Shift && !e.Alt && e.KeyCode == Keys.Up) // Up + { + if (FirstVisibleRow > 0) + { + FirstVisibleRow--; + Refresh(); + } + } + else if (!e.Control && !e.Shift && !e.Alt && e.KeyCode == Keys.Down) // Down + { + if (FirstVisibleRow < RowCount - 1) + { + FirstVisibleRow++; + Refresh(); + } + } + // Selection courser + else if (e.Control && !e.Shift && !e.Alt && e.KeyCode == Keys.Up) // Ctrl + Up + { + if (SelectedRows.Any() && LetKeysModifySelection && SelectedRows.First() > 0) + { + foreach (var row in SelectedRows.ToList()) // clones SelectedRows + { + SelectRow(row - 1, true); + SelectRow(row, false); + } + } + } + else if (e.Control && !e.Shift && !e.Alt && e.KeyCode == Keys.Down) // Ctrl + Down + { + if (SelectedRows.Any() && LetKeysModifySelection) + { + foreach (var row in SelectedRows.Reverse()) // clones SelectedRows + { + SelectRow(row + 1, true); + SelectRow(row, false); + } + } + } + else if (e.Control && !e.Shift && !e.Alt && e.KeyCode == Keys.Left) // Ctrl + Left + { + if (SelectedRows.Any() && LetKeysModifySelection) + { + SelectRow(SelectedRows.Last(), false); + } + } + else if (e.Control && !e.Shift && !e.Alt && e.KeyCode == Keys.Right) // Ctrl + Right + { + if (SelectedRows.Any() && LetKeysModifySelection && SelectedRows.Last() < _rowCount - 1) + { + SelectRow(SelectedRows.Last() + 1, true); + } + } + else if (e.Control && e.Shift && !e.Alt && e.KeyCode == Keys.Left) // Ctrl + Shift + Left + { + if (SelectedRows.Any() && LetKeysModifySelection && SelectedRows.First() > 0) + { + SelectRow(SelectedRows.First() - 1, true); + } + } + else if (e.Control && e.Shift && !e.Alt && e.KeyCode == Keys.Right) // Ctrl + Shift + Right + { + if (SelectedRows.Any() && LetKeysModifySelection) + { + SelectRow(SelectedRows.First(), false); + } + } + else if (e.Control && !e.Shift && !e.Alt && e.KeyCode == Keys.PageUp) // Ctrl + Page Up + { + //jump to above marker with selection courser + if (LetKeysModifySelection) + { + + } + } + else if (e.Control && !e.Shift && !e.Alt && e.KeyCode == Keys.PageDown) // Ctrl + Page Down + { + //jump to below marker with selection courser + if (LetKeysModifySelection) + { + + } + + } + else if (e.Control && !e.Shift && !e.Alt && e.KeyCode == Keys.Home) // Ctrl + Home + { + //move selection courser to frame 0 + if (LetKeysModifySelection) + { + DeselectAll(); + SelectRow(0, true); + } + } + else if (e.Control && !e.Shift && !e.Alt && e.KeyCode == Keys.End) // Ctrl + End + { + //move selection courser to end of movie + if (LetKeysModifySelection) + { + DeselectAll(); + SelectRow(RowCount-1, true); + } + } + + } + + base.OnKeyDown(e); + } + + #endregion + + #region Change Events + + protected override void OnResize(EventArgs e) + { + RecalculateScrollBars(); + base.OnResize(e); + Refresh(); + } + + private void OrientationChanged() + { + RecalculateScrollBars(); + + // TODO scroll to correct positions + ColumnChangedCallback(); + RecalculateScrollBars(); + + Refresh(); + } + + /// + /// Call this function to change the CurrentCell to newCell + /// + private void CellChanged(Cell newCell) + { + LastCell = CurrentCell; + CurrentCell = newCell; + + if (PointedCellChanged != null && + (LastCell.Column != CurrentCell.Column || LastCell.RowIndex != CurrentCell.RowIndex)) + { + PointedCellChanged(this, new CellEventArgs(LastCell, CurrentCell)); + } + + if (CurrentCell?.Column != null && CurrentCell.RowIndex.HasValue) + { + _hoverTimer.Start(); + } + else + { + _hoverTimer.Stop(); + } + } + + private void VerticalBar_ValueChanged(object sender, EventArgs e) + { + if (!_programmaticallyUpdatingScrollBarValues) + { + Refresh(); + } + + if (_horizontalOrientation) + { + ColumnScroll?.Invoke(_vBar, e); + } + else + { + RowScroll?.Invoke(_vBar, e); + } + } + + private void HorizontalBar_ValueChanged(object sender, EventArgs e) + { + if (!_programmaticallyUpdatingScrollBarValues) + { + Refresh(); + } + + if (_horizontalOrientation) + { + RowScroll?.Invoke(_hBar, e); + } + else + { + ColumnScroll?.Invoke(_vBar, e); + } + } + + private void ColumnChangedCallback() + { + RecalculateScrollBars(); + if (_columns.VisibleColumns.Any()) + { + ColumnWidth = _columns.VisibleColumns.Max(c => c.Width.Value) + CellWidthPadding * 4; + } + } + + #endregion + + #region Helpers + + private void DoColumnReorder() + { + if (_columnDown != CurrentCell.Column) + { + var oldIndex = _columns.IndexOf(_columnDown); + var newIndex = _columns.IndexOf(CurrentCell.Column); + + ColumnReordered?.Invoke(this, new ColumnReorderedEventArgs(oldIndex, newIndex, _columnDown)); + + _columns.Remove(_columnDown); + _columns.Insert(newIndex, _columnDown); + } + } + + // ScrollBar.Maximum = DesiredValue + ScrollBar.LargeChange - 1 + // See MSDN Page for more information on the dumb ScrollBar.Maximum Property + private void RecalculateScrollBars() + { + UpdateDrawSize(); + + var columns = _columns.VisibleColumns.ToList(); + + if (HorizontalOrientation) + { + NeedsVScrollbar = columns.Count > DrawHeight / CellHeight; + NeedsHScrollbar = RowCount > 1; + } + else + { + NeedsVScrollbar = ColumnHeight + (RowCount * RowHeight) > Height; + NeedsHScrollbar = TotalColWidth.HasValue && TotalColWidth.Value - DrawWidth + 1 > 0; + } + + UpdateDrawSize(); + if (VisibleRows > 0) + { + if (HorizontalOrientation) + { + _vBar.LargeChange = DrawHeight / 2; + _hBar.Maximum = Math.Max((VisibleRows - 1) * CellHeight, _hBar.Maximum); + _hBar.LargeChange = (VisibleRows - 1) * CellHeight; + } + else + { + _vBar.Maximum = Math.Max((VisibleRows - 1) * CellHeight, _vBar.Maximum); // ScrollBar.Maximum is dumb + _vBar.LargeChange = (VisibleRows - 1) * CellHeight; + // DrawWidth can be negative if the TAStudio window is small enough + // Clamp LargeChange to 0 here to prevent exceptions + _hBar.LargeChange = Math.Max(0, DrawWidth / 2); + } + } + + // Update VBar + if (NeedsVScrollbar) + { + if (HorizontalOrientation) + { + _vBar.Maximum = ((columns.Count() * CellHeight) - DrawHeight) + _vBar.LargeChange; + if (_vBar.Maximum < 0) + { + _vBar.Maximum = 0; + } + } + else + { + _vBar.Maximum = RowsToPixels(RowCount + 1) - (CellHeight * 3) + _vBar.LargeChange - 1; + + if (_vBar.Maximum < 0) + { + _vBar.Maximum = 0; + } + } + + _vBar.Location = new Point(Width - _vBar.Width, 0); + _vBar.Height = Height; + _vBar.Visible = true; + } + else + { + _vBar.Visible = false; + _vBar.Value = 0; + } + + // Update HBar + if (NeedsHScrollbar) + { + if (HorizontalOrientation) + { + _hBar.Maximum = RowsToPixels(RowCount + 1) - (CellHeight * 3) + _hBar.LargeChange - 1; + } + else + { + _hBar.Maximum = TotalColWidth.Value - DrawWidth + _hBar.LargeChange; + } + + _hBar.Location = new Point(0, Height - _hBar.Height); + _hBar.Width = Width - (NeedsVScrollbar ? (_vBar.Width + 1) : 0); + _hBar.Visible = true; + } + else + { + _hBar.Visible = false; + _hBar.Value = 0; + } + } + + private void UpdateDrawSize() + { + if (NeedsVScrollbar) + { + DrawWidth = Width - _vBar.Width; + } + else + { + DrawWidth = Width; + } + if (NeedsHScrollbar) + { + DrawHeight = Height - _hBar.Height; + } + else + { + DrawHeight = Height; + } + } + + /// + /// If FullRowSelect is enabled, selects all cells in the row that contains the given cell. Otherwise only given cell is added. + /// + /// The cell to select. + private void SelectCell(Cell cell, bool toggle = false) + { + if (cell.RowIndex.HasValue && cell.RowIndex < RowCount) + { + if (!MultiSelect) + { + _selectedItems.Clear(); + } + + if (FullRowSelect) + { + if (toggle && _selectedItems.Any(x => x.RowIndex.HasValue && x.RowIndex == cell.RowIndex)) + { + _selectedItems.RemoveWhere(x => x.RowIndex.HasValue && x.RowIndex == cell.RowIndex); + } + else + { + foreach (var column in _columns) + { + _selectedItems.Add(new Cell + { + RowIndex = cell.RowIndex, + Column = column + }); + } + } + } + else + { + if (toggle && _selectedItems.Any(x => x.RowIndex.HasValue && x.RowIndex == cell.RowIndex)) + { + var item = _selectedItems + .FirstOrDefault(x => x.Equals(cell)); + + if (item != null) + { + _selectedItems.Remove(item); + } + } + else + { + _selectedItems.Add(CurrentCell); + } + } + } + } + + private bool IsHoveringOnColumnCell => CurrentCell?.Column != null && !CurrentCell.RowIndex.HasValue; + + private bool IsHoveringOnColumnEdge => AllowColumnResize && IsHoveringOnColumnCell && IsPointingOnCellEdge(_currentX); + + private bool IsHoveringOnDataCell => CurrentCell?.Column != null && CurrentCell.RowIndex.HasValue; + + private bool WasHoveringOnColumnCell => LastCell?.Column != null && !LastCell.RowIndex.HasValue; + + private bool WasHoveringOnDataCell => LastCell?.Column != null && LastCell.RowIndex.HasValue; + + private bool IsPointingOnCellEdge(int? x) + { + if (x.HasValue) + { + if (HorizontalOrientation) + { + return false; // TODO: support column resize in horizontal orientation + } + + foreach (RollColumn column in _columns.VisibleColumns) + { + if (column.Left - _hBar.Value + (column.Width - column.Width / 6) <= x.Value && column.Right - _hBar.Value >= x.Value) + { + return true; + } + } + } + + return false; + } + + /// + /// Finds the specific cell that contains the (x, y) coordinate. + /// + /// The row number that it returns will be between 0 and VisibleRows, NOT the absolute row number. + /// X coordinate point. + /// Y coordinate point. + /// The cell with row number and RollColumn reference, both of which can be null. + private Cell CalculatePointedCell(int x, int y) + { + var newCell = new Cell(); + var columns = _columns.VisibleColumns.ToList(); + + // If pointing to a column header + if (columns.Any()) + { + if (HorizontalOrientation) + { + newCell.RowIndex = PixelsToRows(x); + + int colIndex = (y + _vBar.Value) / CellHeight; + if (colIndex >= 0 && colIndex < columns.Count) + { + newCell.Column = columns[colIndex]; + } + } + else + { + newCell.RowIndex = PixelsToRows(y); + newCell.Column = ColumnAtX(x); + } + } + + if (!(IsPaintDown || RightButtonHeld) && newCell.RowIndex <= -1) // -2 if we're entering from the top + { + newCell.RowIndex = null; + } + + return newCell; + } + + // A boolean that indicates if the InputRoll is too large vertically and requires a vertical scrollbar. + private bool NeedsVScrollbar { get; set; } + + // A boolean that indicates if the InputRoll is too large horizontally and requires a horizontal scrollbar. + private bool NeedsHScrollbar { get; set; } + + /// + /// Gets the total width of all the columns by using the last column's Right property. + /// + /// A nullable Int representing total width. + private int? TotalColWidth + { + get + { + if (_columns.VisibleColumns.Any()) + { + return _columns.VisibleColumns.Last().Right; + } + + return null; + } + } + + /// + /// Returns the RollColumn object at the specified visible x coordinate. Coordinate should be between 0 and Width of the InputRoll Control. + /// + /// The x coordinate. + /// RollColumn object that contains the x coordinate or null if none exists. + private RollColumn ColumnAtX(int x) + { + foreach (RollColumn column in _columns.VisibleColumns) + { + if (column.Left.Value - _hBar.Value <= x && column.Right.Value - _hBar.Value >= x) + { + return column; + } + } + + return null; + } + + /// + /// Converts a row number to a horizontal or vertical coordinate. + /// + /// A vertical coordinate if Vertical Oriented, otherwise a horizontal coordinate. + private int RowsToPixels(int index) + { + if (_horizontalOrientation) + { + return (index * CellWidth) + ColumnWidth; + } + + return (index * CellHeight) + ColumnHeight; + } + + /// + /// Converts a horizontal or vertical coordinate to a row number. + /// + /// A vertical coordinate if Vertical Oriented, otherwise a horizontal coordinate. + /// A row number between 0 and VisibleRows if it is a Datarow, otherwise a negative number if above all Datarows. + private int PixelsToRows(int pixels) + { + // Using Math.Floor and float because integer division rounds towards 0 but we want to round down. + if (_horizontalOrientation) + { + return (int)Math.Floor((float)(pixels - ColumnWidth) / CellWidth); + } + return (int)Math.Floor((float)(pixels - ColumnHeight) / CellHeight); + } + + // The width of the largest column cell in Horizontal Orientation + + private int ColumnWidth { get; set; } + + // The height of a column cell in Vertical Orientation. + private int ColumnHeight { get; set; } + + // The width of a cell in Horizontal Orientation. Only can be changed by changing the Font or CellPadding. + private int CellWidth { get; set; } + + [Browsable(false)] + public int RowHeight => CellHeight; + + /// + /// Gets or sets a value indicating the height of a cell in Vertical Orientation. Only can be changed by changing the Font or CellPadding. + /// + private int CellHeight { get; set; } = 8; + + /// + /// Call when _charSize, MaxCharactersInHorizontal, or CellPadding is changed. + /// + private void UpdateCellSize() + { + CellHeight = _charSize.Height + (CellHeightPadding * 2); + CellWidth = (_charSize.Width * MaxCharactersInHorizontal) + (CellWidthPadding * 4); // Double the padding for horizontal because it looks better + } + + // SuuperW: Count lag frames between FirstDisplayed and given display position + private int CountLagFramesDisplay(int relativeIndex) + { + if (QueryFrameLag != null && LagFramesToHide != 0) + { + int count = 0; + for (int i = 0; i <= relativeIndex; i++) + { + count += _lagFrames[i]; + } + + return count; + } + + return 0; + } + + // Count lag frames between FirstDisplayed and given relative frame index + private int CountLagFramesAbsolute(int relativeIndex) + { + if (QueryFrameLag != null && LagFramesToHide != 0) + { + int count = 0; + for (int i = 0; i + count <= relativeIndex; i++) + { + count += _lagFrames[i]; + } + + return count; + } + + return 0; + } + + private void SetLagFramesArray() + { + if (QueryFrameLag != null && LagFramesToHide != 0) + { + bool showNext = false; + + // First one needs to check BACKWARDS for lag frame count. + SetLagFramesFirst(); + int f = _lagFrames[0]; + if (QueryFrameLag(FirstVisibleRow + f, HideWasLagFrames)) + { + showNext = true; + } + + for (int i = 1; i <= VisibleRows; i++) + { + _lagFrames[i] = 0; + if (!showNext) + { + for (; _lagFrames[i] < LagFramesToHide; _lagFrames[i]++) + { + if (!QueryFrameLag(FirstVisibleRow + i + f, HideWasLagFrames)) + { + break; + } + + f++; + } + } + else + { + if (!QueryFrameLag(FirstVisibleRow + i + f, HideWasLagFrames)) + { + showNext = false; + } + } + + if (_lagFrames[i] == LagFramesToHide && QueryFrameLag(FirstVisibleRow + i + f, HideWasLagFrames)) + { + showNext = true; + } + } + } + else + { + for (int i = 0; i <= VisibleRows; i++) + { + _lagFrames[i] = 0; + } + } + } + private void SetLagFramesFirst() + { + if (QueryFrameLag != null && LagFramesToHide != 0) + { + // Count how many lag frames are above displayed area. + int count = 0; + do + { + count++; + } + while (QueryFrameLag(FirstVisibleRow - count, HideWasLagFrames) && count <= LagFramesToHide); + count--; + + // Count forward + int fCount = -1; + do + { + fCount++; + } + while (QueryFrameLag(FirstVisibleRow + fCount, HideWasLagFrames) && count + fCount < LagFramesToHide); + _lagFrames[0] = (byte)fCount; + } + else + { + _lagFrames[0] = 0; + } + } + + // Number of displayed + hidden frames, if fps is as expected + private int ExpectedDisplayRange() + { + return (VisibleRows + 1) * LagFramesToHide; + } + + #endregion + } +} diff --git a/BizHawk.Client.EmuHawk/CustomControls/InputRoll/RollColumn.cs b/BizHawk.Client.EmuHawk/CustomControls/InputRoll/RollColumn.cs new file mode 100644 index 0000000000..8375120d3d --- /dev/null +++ b/BizHawk.Client.EmuHawk/CustomControls/InputRoll/RollColumn.cs @@ -0,0 +1,29 @@ +namespace BizHawk.Client.EmuHawk +{ + public class RollColumn + { + public string Group { get; set; } + public int? Width { get; set; } + public int? Left { get; set; } + public int? Right { get; set; } + public string Name { get; set; } + public string Text { get; set; } + public ColumnType Type { get; set; } + public bool Visible { get; set; } + + /// + /// Column will be drawn with an emphasized look, if true + /// + private bool _emphasis; + public bool Emphasis + { + get { return _emphasis; } + set { _emphasis = value; } + } + + public RollColumn() + { + Visible = true; + } + } +} diff --git a/BizHawk.Client.EmuHawk/CustomControls/InputRoll/RollColumns.cs b/BizHawk.Client.EmuHawk/CustomControls/InputRoll/RollColumns.cs new file mode 100644 index 0000000000..95fa56788a --- /dev/null +++ b/BizHawk.Client.EmuHawk/CustomControls/InputRoll/RollColumns.cs @@ -0,0 +1,152 @@ +using System; +using System.Collections.Generic; +using System.Linq; + +namespace BizHawk.Client.EmuHawk +{ + public class RollColumns : List + { + public RollColumn this[string name] + { + get + { + return this.SingleOrDefault(column => column.Name == name); + } + } + + public IEnumerable VisibleColumns + { + get + { + return this.Where(c => c.Visible); + } + } + + public Action ChangedCallback { get; set; } + + private void DoChangeCallback() + { + // no check will make it crash for user too, not sure which way of alarm we prefer. no alarm at all will cause all sorts of subtle bugs + if (ChangedCallback == null) + { + System.Diagnostics.Debug.Fail($"{nameof(ChangedCallback)} has died!"); + } + else + { + ChangedCallback(); + } + } + + // TODO: this shouldn't be exposed. But in order to not expose it, each RollColumn must have a change callback, and all property changes must call it, it is quicker and easier to just call this when needed + public void ColumnsChanged() + { + int pos = 0; + + foreach (var col in VisibleColumns) + { + col.Left = pos; + pos += col.Width.Value; + col.Right = pos; + } + + DoChangeCallback(); + } + + public new void Add(RollColumn column) + { + if (this.Any(c => c.Name == column.Name)) + { + // The designer sucks, doing nothing for now + return; + //throw new InvalidOperationException("A column with this name already exists."); + } + + base.Add(column); + ColumnsChanged(); + } + + public new void AddRange(IEnumerable collection) + { + foreach (var column in collection) + { + if (this.Any(c => c.Name == column.Name)) + { + // The designer sucks, doing nothing for now + return; + + throw new InvalidOperationException("A column with this name already exists."); + } + } + + base.AddRange(collection); + ColumnsChanged(); + } + + public new void Insert(int index, RollColumn column) + { + if (this.Any(c => c.Name == column.Name)) + { + throw new InvalidOperationException("A column with this name already exists."); + } + + base.Insert(index, column); + ColumnsChanged(); + } + + public new void InsertRange(int index, IEnumerable collection) + { + foreach (var column in collection) + { + if (this.Any(c => c.Name == column.Name)) + { + throw new InvalidOperationException("A column with this name already exists."); + } + } + + base.InsertRange(index, collection); + ColumnsChanged(); + } + + public new bool Remove(RollColumn column) + { + var result = base.Remove(column); + ColumnsChanged(); + return result; + } + + public new int RemoveAll(Predicate match) + { + var result = base.RemoveAll(match); + ColumnsChanged(); + return result; + } + + public new void RemoveAt(int index) + { + base.RemoveAt(index); + ColumnsChanged(); + } + + public new void RemoveRange(int index, int count) + { + base.RemoveRange(index, count); + ColumnsChanged(); + } + + public new void Clear() + { + base.Clear(); + ColumnsChanged(); + } + + public IEnumerable Groups + { + get + { + return this + .Select(x => x.Group) + .Distinct(); + } + } + } +} diff --git a/BizHawk.Client.EmuHawk/tools/CDL.cs b/BizHawk.Client.EmuHawk/tools/CDL.cs index 47354229de..af444b8e08 100644 --- a/BizHawk.Client.EmuHawk/tools/CDL.cs +++ b/BizHawk.Client.EmuHawk/tools/CDL.cs @@ -64,19 +64,19 @@ namespace BizHawk.Client.EmuHawk lvCDL.AllColumns.Clear(); lvCDL.AllColumns.AddRange(new [] { - new InputRoll.RollColumn { Name = "CDLFile", Text = "CDL File @", Width = 107, Type = InputRoll.RollColumn.InputType.Text }, - new InputRoll.RollColumn { Name = "Domain", Text = "Domain", Width = 126, Type = InputRoll.RollColumn.InputType.Text }, - new InputRoll.RollColumn { Name = "Percent", Text = "%", Width = 58, Type = InputRoll.RollColumn.InputType.Text }, - new InputRoll.RollColumn { Name = "Mapped", Text = "Mapped", Width = 64, Type = InputRoll.RollColumn.InputType.Text }, - new InputRoll.RollColumn { Name = "Size", Text = "Size", Width = 112, Type = InputRoll.RollColumn.InputType.Text }, - new InputRoll.RollColumn { Name = "0x01", Text = "0x01", Width = 56, Type = InputRoll.RollColumn.InputType.Text }, - new InputRoll.RollColumn { Name = "0x02", Text = "0x02", Width = 56, Type = InputRoll.RollColumn.InputType.Text }, - new InputRoll.RollColumn { Name = "0x04", Text = "0x04", Width = 56, Type = InputRoll.RollColumn.InputType.Text }, - new InputRoll.RollColumn { Name = "0x08", Text = "0x08", Width = 56, Type = InputRoll.RollColumn.InputType.Text }, - new InputRoll.RollColumn { Name = "0x10", Text = "0x10", Width = 56, Type = InputRoll.RollColumn.InputType.Text }, - new InputRoll.RollColumn { Name = "0x20", Text = "0x20", Width = 56, Type = InputRoll.RollColumn.InputType.Text }, - new InputRoll.RollColumn { Name = "0x40", Text = "0x40", Width = 56, Type = InputRoll.RollColumn.InputType.Text }, - new InputRoll.RollColumn { Name = "0x80", Text = "0x80", Width = 56, Type = InputRoll.RollColumn.InputType.Text } + new RollColumn { Name = "CDLFile", Text = "CDL File @", Width = 107, Type = ColumnType.Text }, + new RollColumn { Name = "Domain", Text = "Domain", Width = 126, Type = ColumnType.Text }, + new RollColumn { Name = "Percent", Text = "%", Width = 58, Type = ColumnType.Text }, + new RollColumn { Name = "Mapped", Text = "Mapped", Width = 64, Type = ColumnType.Text }, + new RollColumn { Name = "Size", Text = "Size", Width = 112, Type = ColumnType.Text }, + new RollColumn { Name = "0x01", Text = "0x01", Width = 56, Type = ColumnType.Text }, + new RollColumn { Name = "0x02", Text = "0x02", Width = 56, Type = ColumnType.Text }, + new RollColumn { Name = "0x04", Text = "0x04", Width = 56, Type = ColumnType.Text }, + new RollColumn { Name = "0x08", Text = "0x08", Width = 56, Type = ColumnType.Text }, + new RollColumn { Name = "0x10", Text = "0x10", Width = 56, Type = ColumnType.Text }, + new RollColumn { Name = "0x20", Text = "0x20", Width = 56, Type = ColumnType.Text }, + new RollColumn { Name = "0x40", Text = "0x40", Width = 56, Type = ColumnType.Text }, + new RollColumn { Name = "0x80", Text = "0x80", Width = 56, Type = ColumnType.Text } }); } @@ -576,7 +576,7 @@ namespace BizHawk.Client.EmuHawk CodeDataLogger.SetCDL(null); } - private void lvCDL_QueryItemText(int index, InputRoll.RollColumn column, out string text, ref int offsetX, ref int offsetY) + private void lvCDL_QueryItemText(int index, RollColumn column, out string text, ref int offsetX, ref int offsetY) { var subItem = lvCDL.AllColumns.IndexOf(column); text = listContents[index][subItem]; diff --git a/BizHawk.Client.EmuHawk/tools/Cheats/Cheats.cs b/BizHawk.Client.EmuHawk/tools/Cheats/Cheats.cs index c53d2c9e8b..9fff2eadc5 100644 --- a/BizHawk.Client.EmuHawk/tools/Cheats/Cheats.cs +++ b/BizHawk.Client.EmuHawk/tools/Cheats/Cheats.cs @@ -239,7 +239,7 @@ namespace BizHawk.Client.EmuHawk SetColumns(); } - private void CheatListView_QueryItemText(int index, InputRoll.RollColumn column, out string text, ref int offsetX, ref int offsetY) + private void CheatListView_QueryItemText(int index, RollColumn column, out string text, ref int offsetX, ref int offsetY) { text = ""; if (index >= Global.CheatList.Count || Global.CheatList[index].IsSeparator) @@ -311,7 +311,7 @@ namespace BizHawk.Client.EmuHawk } } - private void CheatListView_QueryItemBkColor(int index, InputRoll.RollColumn column, ref Color color) + private void CheatListView_QueryItemBkColor(int index, RollColumn column, ref Color color) { if (index < Global.CheatList.Count) { @@ -737,21 +737,21 @@ namespace BizHawk.Client.EmuHawk { public CheatsSettings() { - Columns = new List + Columns = new List { - new InputRoll.RollColumn { Text = "Names", Name = NameColumn, Visible = true, Width = 128, Type = InputRoll.RollColumn.InputType.Text }, - new InputRoll.RollColumn { Text = "Address", Name = AddressColumn, Visible = true, Width = 60, Type = InputRoll.RollColumn.InputType.Text }, - new InputRoll.RollColumn { Text = "Value", Name = ValueColumn, Visible = true, Width = 59, Type = InputRoll.RollColumn.InputType.Text }, - new InputRoll.RollColumn { Text = "Compare", Name = CompareColumn, Visible = true, Width = 63, Type = InputRoll.RollColumn.InputType.Text }, - new InputRoll.RollColumn { Text = "Compare Type", Name = ComparisonTypeColumn, Visible = true, Width = 98, Type = InputRoll.RollColumn.InputType.Text }, - new InputRoll.RollColumn { Text = "On", Name = OnColumn, Visible = false, Width = 28, Type = InputRoll.RollColumn.InputType.Text }, - new InputRoll.RollColumn { Text = "Size", Name = SizeColumn, Visible = true, Width = 55, Type = InputRoll.RollColumn.InputType.Text }, - new InputRoll.RollColumn { Text = "Endian", Name = EndianColumn, Visible = false, Width = 55, Type = InputRoll.RollColumn.InputType.Text }, - new InputRoll.RollColumn { Text = "Display Type", Name = TypeColumn, Visible = false, Width = 88, Type = InputRoll.RollColumn.InputType.Text } + new RollColumn { Text = "Names", Name = NameColumn, Visible = true, Width = 128, Type = ColumnType.Text }, + new RollColumn { Text = "Address", Name = AddressColumn, Visible = true, Width = 60, Type = ColumnType.Text }, + new RollColumn { Text = "Value", Name = ValueColumn, Visible = true, Width = 59, Type = ColumnType.Text }, + new RollColumn { Text = "Compare", Name = CompareColumn, Visible = true, Width = 63, Type = ColumnType.Text }, + new RollColumn { Text = "Compare Type", Name = ComparisonTypeColumn, Visible = true, Width = 98, Type = ColumnType.Text }, + new RollColumn { Text = "On", Name = OnColumn, Visible = false, Width = 28, Type = ColumnType.Text }, + new RollColumn { Text = "Size", Name = SizeColumn, Visible = true, Width = 55, Type = ColumnType.Text }, + new RollColumn { Text = "Endian", Name = EndianColumn, Visible = false, Width = 55, Type = ColumnType.Text }, + new RollColumn { Text = "Display Type", Name = TypeColumn, Visible = false, Width = 88, Type = ColumnType.Text } }; } - public List Columns { get; set; } + public List Columns { get; set; } } } } diff --git a/BizHawk.Client.EmuHawk/tools/Debugger/GenericDebugger.Disassembler.cs b/BizHawk.Client.EmuHawk/tools/Debugger/GenericDebugger.Disassembler.cs index 0fd2c0a047..c86f93f188 100644 --- a/BizHawk.Client.EmuHawk/tools/Debugger/GenericDebugger.Disassembler.cs +++ b/BizHawk.Client.EmuHawk/tools/Debugger/GenericDebugger.Disassembler.cs @@ -67,7 +67,7 @@ namespace BizHawk.Client.EmuHawk } } - private void DisassemblerView_QueryItemText(int index, InputRoll.RollColumn column, out string text, ref int offsetX, ref int offsetY) + private void DisassemblerView_QueryItemText(int index, RollColumn column, out string text, ref int offsetX, ref int offsetY) { text = ""; @@ -84,7 +84,7 @@ namespace BizHawk.Client.EmuHawk } } - private void DisassemblerView_QueryItemBkColor(int index, InputRoll.RollColumn column, ref Color color) + private void DisassemblerView_QueryItemBkColor(int index, RollColumn column, ref Color color) { if (_disassemblyLines.Any() && index < _disassemblyLines.Count) { diff --git a/BizHawk.Client.EmuHawk/tools/Debugger/GenericDebugger.cs b/BizHawk.Client.EmuHawk/tools/Debugger/GenericDebugger.cs index 58fce366dc..4f180134ff 100644 --- a/BizHawk.Client.EmuHawk/tools/Debugger/GenericDebugger.cs +++ b/BizHawk.Client.EmuHawk/tools/Debugger/GenericDebugger.cs @@ -23,19 +23,19 @@ namespace BizHawk.Client.EmuHawk DisassemblerView.AllColumns.Clear(); DisassemblerView.AllColumns.AddRange(new[] { - new InputRoll.RollColumn + new RollColumn { Name = AddressColumnName, Text = AddressColumnName, Width = 94, - Type = InputRoll.RollColumn.InputType.Text + Type = ColumnType.Text }, - new InputRoll.RollColumn + new RollColumn { Name = InstructionColumnName, Text = InstructionColumnName, Width = 291, - Type = InputRoll.RollColumn.InputType.Text + Type = ColumnType.Text } }); } diff --git a/BizHawk.Client.EmuHawk/tools/Lua/Libraries/EmuLuaLibrary.Tastudio.cs b/BizHawk.Client.EmuHawk/tools/Lua/Libraries/EmuLuaLibrary.Tastudio.cs index bdba64d3a1..24e92d1f42 100644 --- a/BizHawk.Client.EmuHawk/tools/Lua/Libraries/EmuLuaLibrary.Tastudio.cs +++ b/BizHawk.Client.EmuHawk/tools/Lua/Libraries/EmuLuaLibrary.Tastudio.cs @@ -587,7 +587,7 @@ namespace BizHawk.Client.EmuHawk { if (Engaged()) { - Tastudio.AddColumn(name, text, width, InputRoll.RollColumn.InputType.Text); + Tastudio.AddColumn(name, text, width, ColumnType.Text); } } } diff --git a/BizHawk.Client.EmuHawk/tools/Lua/LuaConsole.cs b/BizHawk.Client.EmuHawk/tools/Lua/LuaConsole.cs index fed33dd0b8..9353b10901 100644 --- a/BizHawk.Client.EmuHawk/tools/Lua/LuaConsole.cs +++ b/BizHawk.Client.EmuHawk/tools/Lua/LuaConsole.cs @@ -38,15 +38,15 @@ namespace BizHawk.Client.EmuHawk { public LuaConsoleSettings() { - Columns = new List + Columns = new List { - new InputRoll.RollColumn { Name = IconColumnName, Text = " ", Visible = true, Width = 22, Type = InputRoll.RollColumn.InputType.Image }, - new InputRoll.RollColumn { Name = ScriptColumnName, Text = "Script", Visible = true, Width = 92, Type = InputRoll.RollColumn.InputType.Text }, - new InputRoll.RollColumn { Name = PathColumnName, Text = "Path", Visible = true, Width = 300, Type = InputRoll.RollColumn.InputType.Text } + new RollColumn { Name = IconColumnName, Text = " ", Visible = true, Width = 22, Type = ColumnType.Image }, + new RollColumn { Name = ScriptColumnName, Text = "Script", Visible = true, Width = 92, Type = ColumnType.Text }, + new RollColumn { Name = PathColumnName, Text = "Path", Visible = true, Width = 300, Type = ColumnType.Text } }; } - public List Columns { get; set; } + public List Columns { get; set; } } [ConfigPersist] @@ -362,7 +362,7 @@ namespace BizHawk.Client.EmuHawk Path.GetFileName(LuaImp.ScriptList.Filename); } - private void LuaListView_QueryItemImage(int index, InputRoll.RollColumn column, ref Bitmap bitmap, ref int offsetX, ref int offsetY) + private void LuaListView_QueryItemImage(int index, RollColumn column, ref Bitmap bitmap, ref int offsetX, ref int offsetY) { if (column.Name != IconColumnName) { @@ -388,7 +388,7 @@ namespace BizHawk.Client.EmuHawk } } - private void LuaListView_QueryItemBkColor(int index, InputRoll.RollColumn column, ref Color color) + private void LuaListView_QueryItemBkColor(int index, RollColumn column, ref Color color) { if (LuaImp.ScriptList[index].IsSeparator) { @@ -404,7 +404,7 @@ namespace BizHawk.Client.EmuHawk } } - private void LuaListView_QueryItemText(int index, InputRoll.RollColumn column, out string text, ref int offsetX, ref int offsetY) + private void LuaListView_QueryItemText(int index, RollColumn column, out string text, ref int offsetX, ref int offsetY) { text = ""; diff --git a/BizHawk.Client.EmuHawk/tools/TAStudio/BookmarksBranchesBox.cs b/BizHawk.Client.EmuHawk/tools/TAStudio/BookmarksBranchesBox.cs index fd6d903991..049d8c006d 100644 --- a/BizHawk.Client.EmuHawk/tools/TAStudio/BookmarksBranchesBox.cs +++ b/BizHawk.Client.EmuHawk/tools/TAStudio/BookmarksBranchesBox.cs @@ -63,19 +63,19 @@ namespace BizHawk.Client.EmuHawk BranchView.AllColumns.AddRange(new[] { - new InputRoll.RollColumn + new RollColumn { Name = BranchNumberColumnName, Text = "#", Width = 30 }, - new InputRoll.RollColumn + new RollColumn { Name = FrameColumnName, Text = "Frame", Width = 64 }, - new InputRoll.RollColumn + new RollColumn { Name = UserTextColumnName, Text = "UserText", @@ -89,7 +89,7 @@ namespace BizHawk.Client.EmuHawk #region Query callbacks - private void QueryItemText(int index, InputRoll.RollColumn column, out string text, ref int offsetX, ref int offsetY) + private void QueryItemText(int index, RollColumn column, out string text, ref int offsetX, ref int offsetY) { text = ""; @@ -112,7 +112,7 @@ namespace BizHawk.Client.EmuHawk } } - private void QueryItemBkColor(int index, InputRoll.RollColumn column, ref Color color) + private void QueryItemBkColor(int index, RollColumn column, ref Color color) { TasBranch branch = GetBranch(index); if (branch != null) diff --git a/BizHawk.Client.EmuHawk/tools/TAStudio/MarkerControl.cs b/BizHawk.Client.EmuHawk/tools/TAStudio/MarkerControl.cs index 14b9acce8a..525812c8b5 100644 --- a/BizHawk.Client.EmuHawk/tools/TAStudio/MarkerControl.cs +++ b/BizHawk.Client.EmuHawk/tools/TAStudio/MarkerControl.cs @@ -21,13 +21,13 @@ namespace BizHawk.Client.EmuHawk MarkerView.AllColumns.AddRange(new[] { - new InputRoll.RollColumn + new RollColumn { Name = "FrameColumn", Text = "Frame", Width = 52 }, - new InputRoll.RollColumn + new RollColumn { Name = "LabelColumn", Text = "", @@ -45,7 +45,7 @@ namespace BizHawk.Client.EmuHawk public InputRoll MarkerInputRoll => MarkerView; - private void MarkerView_QueryItemBkColor(int index, InputRoll.RollColumn column, ref Color color) + private void MarkerView_QueryItemBkColor(int index, RollColumn column, ref Color color) { var prev = Markers.PreviousOrCurrent(Tastudio.Emulator.Frame); @@ -81,7 +81,7 @@ namespace BizHawk.Client.EmuHawk } } - private void MarkerView_QueryItemText(int index, InputRoll.RollColumn column, out string text, ref int offsetX, ref int offsetY) + private void MarkerView_QueryItemText(int index, RollColumn column, out string text, ref int offsetX, ref int offsetY) { text = ""; diff --git a/BizHawk.Client.EmuHawk/tools/TAStudio/TAStudio.Callbacks.cs b/BizHawk.Client.EmuHawk/tools/TAStudio/TAStudio.Callbacks.cs index b93e0f2a1a..920056988e 100644 --- a/BizHawk.Client.EmuHawk/tools/TAStudio/TAStudio.Callbacks.cs +++ b/BizHawk.Client.EmuHawk/tools/TAStudio/TAStudio.Callbacks.cs @@ -15,17 +15,17 @@ namespace BizHawk.Client.EmuHawk public Action BranchSavedCallback { get; set; } public Action BranchRemovedCallback { get; set; } - private Color? GetColorOverride(int index, InputRoll.RollColumn column) + private Color? GetColorOverride(int index, RollColumn column) { return QueryItemBgColorCallback?.Invoke(index, column.Name); } - private string GetTextOverride(int index, InputRoll.RollColumn column) + private string GetTextOverride(int index, RollColumn column) { return QueryItemTextCallback?.Invoke(index, column.Name); } - private Bitmap GetIconOverride(int index, InputRoll.RollColumn column) + private Bitmap GetIconOverride(int index, RollColumn column) { return QueryItemIconCallback?.Invoke(index, column.Name); } diff --git a/BizHawk.Client.EmuHawk/tools/TAStudio/TAStudio.ListView.cs b/BizHawk.Client.EmuHawk/tools/TAStudio/TAStudio.ListView.cs index f5cf9410a4..dc707692c6 100644 --- a/BizHawk.Client.EmuHawk/tools/TAStudio/TAStudio.ListView.cs +++ b/BizHawk.Client.EmuHawk/tools/TAStudio/TAStudio.ListView.cs @@ -157,7 +157,7 @@ namespace BizHawk.Client.EmuHawk private Bitmap icon_anchor_lag => Properties.Resources.icon_anchor_lag; private Bitmap icon_anchor => Properties.Resources.icon_anchor; - private void TasView_QueryItemIcon(int index, InputRoll.RollColumn column, ref Bitmap bitmap, ref int offsetX, ref int offsetY) + private void TasView_QueryItemIcon(int index, RollColumn column, ref Bitmap bitmap, ref int offsetX, ref int offsetY) { var overrideIcon = GetIconOverride(index, column); @@ -214,7 +214,7 @@ namespace BizHawk.Client.EmuHawk } } - private void TasView_QueryItemBkColor(int index, InputRoll.RollColumn column, ref Color color) + private void TasView_QueryItemBkColor(int index, RollColumn column, ref Color color) { Color? overrideColor = GetColorOverride(index, column); @@ -296,7 +296,7 @@ namespace BizHawk.Client.EmuHawk } } - private void TasView_QueryItemText(int index, InputRoll.RollColumn column, out string text, ref int offsetX, ref int offsetY) + private void TasView_QueryItemText(int index, RollColumn column, out string text, ref int offsetX, ref int offsetY) { var overrideText = GetTextOverride(index, column); if (overrideText != null) @@ -333,7 +333,7 @@ namespace BizHawk.Client.EmuHawk else if (index < CurrentTasMovie.InputLogLength) { text = CurrentTasMovie.DisplayValue(index, columnName); - if (column.Type == InputRoll.RollColumn.InputType.Float) + if (column.Type == ColumnType.Float) { // feos: this could be cashed, but I don't notice any slowdown this way either ControllerDefinition.FloatRange range = Global.MovieSession.MovieControllerAdapter.Definition.FloatRanges @@ -601,7 +601,7 @@ namespace BizHawk.Client.EmuHawk _selectionDragState = TasView.SelectedRows.Contains(frame); } } - else if (TasView.CurrentCell.Column.Type != InputRoll.RollColumn.InputType.Text) // User changed input + else if (TasView.CurrentCell.Column.Type != ColumnType.Text) // User changed input { bool wasPaused = Mainform.EmulatorPaused; diff --git a/BizHawk.Client.EmuHawk/tools/TAStudio/TAStudio.MenuItems.cs b/BizHawk.Client.EmuHawk/tools/TAStudio/TAStudio.MenuItems.cs index a4f90146ae..52ae09bd32 100644 --- a/BizHawk.Client.EmuHawk/tools/TAStudio/TAStudio.MenuItems.cs +++ b/BizHawk.Client.EmuHawk/tools/TAStudio/TAStudio.MenuItems.cs @@ -1267,7 +1267,7 @@ namespace BizHawk.Client.EmuHawk playerMenus[i] = new ToolStripMenuItem($"Player {i}"); } - foreach (InputRoll.RollColumn column in columns) + foreach (var column in columns) { ToolStripMenuItem menuItem = new ToolStripMenuItem { diff --git a/BizHawk.Client.EmuHawk/tools/TAStudio/TAStudio.cs b/BizHawk.Client.EmuHawk/tools/TAStudio/TAStudio.cs index 97375fdf25..19136e07e7 100644 --- a/BizHawk.Client.EmuHawk/tools/TAStudio/TAStudio.cs +++ b/BizHawk.Client.EmuHawk/tools/TAStudio/TAStudio.cs @@ -416,18 +416,18 @@ namespace BizHawk.Client.EmuHawk var columnNames = GenerateColumnNames(); foreach (var kvp in columnNames) { - InputRoll.RollColumn.InputType type; + ColumnType type; int digits; if (Global.MovieSession.MovieControllerAdapter.Definition.FloatControls.Contains(kvp.Key)) { ControllerDefinition.FloatRange range = Global.MovieSession.MovieControllerAdapter.Definition.FloatRanges [Global.MovieSession.MovieControllerAdapter.Definition.FloatControls.IndexOf(kvp.Key)]; - type = InputRoll.RollColumn.InputType.Float; + type = ColumnType.Float; digits = Math.Max(kvp.Value.Length, range.MaxDigits()); } else { - type = InputRoll.RollColumn.InputType.Boolean; + type = ColumnType.Boolean; digits = kvp.Value.Length; } @@ -494,11 +494,11 @@ namespace BizHawk.Client.EmuHawk SetUpToolStripColumns(); } - public void AddColumn(string columnName, string columnText, int columnWidth, InputRoll.RollColumn.InputType columnType = InputRoll.RollColumn.InputType.Boolean) + public void AddColumn(string columnName, string columnText, int columnWidth, ColumnType columnType = ColumnType.Boolean) { if (TasView.AllColumns[columnName] == null) { - var column = new InputRoll.RollColumn + var column = new RollColumn { Name = columnName, Text = columnText, diff --git a/BizHawk.Client.EmuHawk/tools/TAStudio/UndoHistoryForm.cs b/BizHawk.Client.EmuHawk/tools/TAStudio/UndoHistoryForm.cs index b08c0e49db..7e5ed8f466 100644 --- a/BizHawk.Client.EmuHawk/tools/TAStudio/UndoHistoryForm.cs +++ b/BizHawk.Client.EmuHawk/tools/TAStudio/UndoHistoryForm.cs @@ -26,21 +26,21 @@ namespace BizHawk.Client.EmuHawk HistoryView.AllColumns.Clear(); HistoryView.AllColumns.AddRange(new[] { - new InputRoll.RollColumn { Name = IdColumnName, Text = IdColumnName, Width = 40, Type = InputRoll.RollColumn.InputType.Text }, - new InputRoll.RollColumn { Name = UndoColumnName, Text = UndoColumnName, Width = 280, Type = InputRoll.RollColumn.InputType.Text } + new RollColumn { Name = IdColumnName, Text = IdColumnName, Width = 40, Type = ColumnType.Text }, + new RollColumn { Name = UndoColumnName, Text = UndoColumnName, Width = 280, Type = ColumnType.Text } }); MaxStepsNum.Value = Log.MaxSteps; } - private void HistoryView_QueryItemText(int index, InputRoll.RollColumn column, out string text, ref int offsetX, ref int offsetY) + private void HistoryView_QueryItemText(int index, RollColumn column, out string text, ref int offsetX, ref int offsetY) { text = column.Name == UndoColumnName ? Log.Names[index] : index.ToString(); } - private void HistoryView_QueryItemBkColor(int index, InputRoll.RollColumn column, ref Color color) + private void HistoryView_QueryItemBkColor(int index, RollColumn column, ref Color color) { if (index == Log.UndoIndex) { diff --git a/BizHawk.Client.EmuHawk/tools/TraceLogger.cs b/BizHawk.Client.EmuHawk/tools/TraceLogger.cs index 85eb746632..1c0cb24a42 100644 --- a/BizHawk.Client.EmuHawk/tools/TraceLogger.cs +++ b/BizHawk.Client.EmuHawk/tools/TraceLogger.cs @@ -24,7 +24,7 @@ namespace BizHawk.Client.EmuHawk private int FileSizeCap { get; set; } [ConfigPersist] - private List Columns + private List Columns { get { return TraceView.AllColumns; } set @@ -78,19 +78,19 @@ namespace BizHawk.Client.EmuHawk _splitFile = FileSizeCap != 0; TraceView.AllColumns.Clear(); - TraceView.AllColumns.Add(new InputRoll.RollColumn + TraceView.AllColumns.Add(new RollColumn { Name = DisasmColumnName, Text = DisasmColumnName, Width = 239, - Type = InputRoll.RollColumn.InputType.Text + Type = ColumnType.Text }); - TraceView.AllColumns.Add(new InputRoll.RollColumn + TraceView.AllColumns.Add(new RollColumn { Name = RegistersColumnName, Text = RegistersColumnName, Width = 357, - Type = InputRoll.RollColumn.InputType.Text + Type = ColumnType.Text }); } @@ -109,7 +109,7 @@ namespace BizHawk.Client.EmuHawk //Tracer.Enabled = LoggingEnabled.Checked; } - private void TraceView_QueryItemText(int index, InputRoll.RollColumn column, out string text, ref int offsetX, ref int offsetY) + private void TraceView_QueryItemText(int index, RollColumn column, out string text, ref int offsetX, ref int offsetY) { text = ""; if (index < _instructions.Count) diff --git a/BizHawk.Client.EmuHawk/tools/Watch/RamSearch.cs b/BizHawk.Client.EmuHawk/tools/Watch/RamSearch.cs index a7be2ebb0e..c398b89730 100644 --- a/BizHawk.Client.EmuHawk/tools/Watch/RamSearch.cs +++ b/BizHawk.Client.EmuHawk/tools/Watch/RamSearch.cs @@ -166,7 +166,7 @@ namespace BizHawk.Client.EmuHawk ErrorIconButton.Visible = _searches.OutOfRangeAddress.Any(); } - private void ListView_QueryItemBkColor(int index, InputRoll.RollColumn column, ref Color color) + private void ListView_QueryItemBkColor(int index, RollColumn column, ref Color color) { if (_searches.Count > 0) { @@ -195,7 +195,7 @@ namespace BizHawk.Client.EmuHawk } } - private void ListView_QueryItemText(int index, InputRoll.RollColumn column, out string text, ref int offsetX, ref int offsetY) + private void ListView_QueryItemText(int index, RollColumn column, out string text, ref int offsetX, ref int offsetY) { text = ""; @@ -974,13 +974,13 @@ namespace BizHawk.Client.EmuHawk { public RamSearchSettings() { - Columns = new List + Columns = new List { - new InputRoll.RollColumn { Text = "Address", Name = WatchList.ADDRESS, Visible = true, Width = 60, Type = InputRoll.RollColumn.InputType.Text }, - new InputRoll.RollColumn { Text = "Value", Name = WatchList.VALUE, Visible = true, Width = 59, Type = InputRoll.RollColumn.InputType.Text }, - new InputRoll.RollColumn { Text = "Prev", Name = WatchList.PREV, Visible = true, Width = 59, Type = InputRoll.RollColumn.InputType.Text }, - new InputRoll.RollColumn { Text = "Changes", Name = WatchList.CHANGES, Visible = true, Width = 60, Type = InputRoll.RollColumn.InputType.Text }, - new InputRoll.RollColumn { Text = "Diff", Name = WatchList.DIFF, Visible = false, Width = 59, Type = InputRoll.RollColumn.InputType.Text }, + new RollColumn { Text = "Address", Name = WatchList.ADDRESS, Visible = true, Width = 60, Type = ColumnType.Text }, + new RollColumn { Text = "Value", Name = WatchList.VALUE, Visible = true, Width = 59, Type = ColumnType.Text }, + new RollColumn { Text = "Prev", Name = WatchList.PREV, Visible = true, Width = 59, Type = ColumnType.Text }, + new RollColumn { Text = "Changes", Name = WatchList.CHANGES, Visible = true, Width = 60, Type = ColumnType.Text }, + new RollColumn { Text = "Diff", Name = WatchList.DIFF, Visible = false, Width = 59, Type = ColumnType.Text }, }; PreviewMode = true; @@ -988,7 +988,7 @@ namespace BizHawk.Client.EmuHawk AutoSearchTakeLagFramesIntoAccount = true; } - public List Columns { get; set; } + public List Columns { get; set; } public bool PreviewMode { get; set; } public bool AlwaysExcludeRamWatch { get; set; } public bool AutoSearchTakeLagFramesIntoAccount { get; set; } diff --git a/BizHawk.Client.EmuHawk/tools/Watch/RamWatch.cs b/BizHawk.Client.EmuHawk/tools/Watch/RamWatch.cs index 7377d33b4c..b29c6137e2 100644 --- a/BizHawk.Client.EmuHawk/tools/Watch/RamWatch.cs +++ b/BizHawk.Client.EmuHawk/tools/Watch/RamWatch.cs @@ -79,20 +79,20 @@ namespace BizHawk.Client.EmuHawk { public RamWatchSettings() { - Columns = new List + Columns = new List { - new InputRoll.RollColumn { Text = "Address", Name = WatchList.ADDRESS, Visible = true, Width = 60, Type = InputRoll.RollColumn.InputType.Text }, - new InputRoll.RollColumn { Text = "Value", Name = WatchList.VALUE, Visible = true, Width = 59, Type = InputRoll.RollColumn.InputType.Text }, - new InputRoll.RollColumn { Text = "Prev", Name = WatchList.PREV, Visible = false, Width = 59, Type = InputRoll.RollColumn.InputType.Text }, - new InputRoll.RollColumn { Text = "Changes", Name = WatchList.CHANGES, Visible = true, Width = 60, Type = InputRoll.RollColumn.InputType.Text }, - new InputRoll.RollColumn { Text = "Diff", Name = WatchList.DIFF, Visible = false, Width = 59, Type = InputRoll.RollColumn.InputType.Text }, - new InputRoll.RollColumn { Text = "Type", Name = WatchList.TYPE, Visible = false, Width = 55, Type = InputRoll.RollColumn.InputType.Text }, - new InputRoll.RollColumn { Text = "Domain", Name = WatchList.DOMAIN, Visible = true, Width = 55, Type = InputRoll.RollColumn.InputType.Text }, - new InputRoll.RollColumn { Text = "Notes", Name = WatchList.NOTES, Visible = true, Width = 128, Type = InputRoll.RollColumn.InputType.Text } + new RollColumn { Text = "Address", Name = WatchList.ADDRESS, Visible = true, Width = 60, Type = ColumnType.Text }, + new RollColumn { Text = "Value", Name = WatchList.VALUE, Visible = true, Width = 59, Type = ColumnType.Text }, + new RollColumn { Text = "Prev", Name = WatchList.PREV, Visible = false, Width = 59, Type = ColumnType.Text }, + new RollColumn { Text = "Changes", Name = WatchList.CHANGES, Visible = true, Width = 60, Type = ColumnType.Text }, + new RollColumn { Text = "Diff", Name = WatchList.DIFF, Visible = false, Width = 59, Type = ColumnType.Text }, + new RollColumn { Text = "Type", Name = WatchList.TYPE, Visible = false, Width = 55, Type = ColumnType.Text }, + new RollColumn { Text = "Domain", Name = WatchList.DOMAIN, Visible = true, Width = 55, Type = ColumnType.Text }, + new RollColumn { Text = "Notes", Name = WatchList.NOTES, Visible = true, Width = 128, Type = ColumnType.Text } }; } - public List Columns { get; set; } + public List Columns { get; set; } } private IEnumerable SelectedIndices => WatchListView.SelectedRows; @@ -553,7 +553,7 @@ namespace BizHawk.Client.EmuHawk } } - private void OrderColumn(InputRoll.RollColumn column) + private void OrderColumn(RollColumn column) { if (column.Name != _sortedColumn) { @@ -621,7 +621,7 @@ namespace BizHawk.Client.EmuHawk WatchCountLabel.Text = _watches.WatchCount + (_watches.WatchCount == 1 ? " watch" : " watches"); } - private void WatchListView_QueryItemBkColor(int index, InputRoll.RollColumn column, ref Color color) + private void WatchListView_QueryItemBkColor(int index, RollColumn column, ref Color color) { if (index >= _watches.Count) { @@ -642,7 +642,7 @@ namespace BizHawk.Client.EmuHawk } } - private void WatchListView_QueryItemText(int index, InputRoll.RollColumn column, out string text, ref int offsetX, ref int offsetY) + private void WatchListView_QueryItemText(int index, RollColumn column, out string text, ref int offsetX, ref int offsetY) { text = ""; if (index >= _watches.Count) From 0ce50460614601b40bad333d633ef4f8a2ffd391 Mon Sep 17 00:00:00 2001 From: adelikat Date: Sat, 26 Oct 2019 17:06:42 -0500 Subject: [PATCH 135/166] cleanup input roll column and cell classes --- .../CustomControls/InputRoll/Cell.cs | 34 ++- .../CustomControls/InputRoll/RollColumn.cs | 14 +- .../CustomControls/InputRoll/RollColumns.cs | 206 ++++++++---------- 3 files changed, 114 insertions(+), 140 deletions(-) diff --git a/BizHawk.Client.EmuHawk/CustomControls/InputRoll/Cell.cs b/BizHawk.Client.EmuHawk/CustomControls/InputRoll/Cell.cs index 3273aeef46..e9b71c9eb5 100644 --- a/BizHawk.Client.EmuHawk/CustomControls/InputRoll/Cell.cs +++ b/BizHawk.Client.EmuHawk/CustomControls/InputRoll/Cell.cs @@ -23,10 +23,10 @@ namespace BizHawk.Client.EmuHawk public override bool Equals(object obj) { - if (obj is Cell) + var cell = obj as Cell; + if (cell != null) { - var cell = obj as Cell; - return this.Column == cell.Column && this.RowIndex == cell.RowIndex; + return Column == cell.Column && RowIndex == cell.RowIndex; } return base.Equals(obj); @@ -40,21 +40,31 @@ namespace BizHawk.Client.EmuHawk internal class SortCell : IComparer { - int IComparer.Compare(Cell a, Cell b) + int IComparer.Compare(Cell c1, Cell c2) { - Cell c1 = a as Cell; - Cell c2 = b as Cell; + if (c1 == null && c2 == null) + { + return 0; + } + + if (c2 == null) + { + return 1; + } + + if (c1 == null) + { + return -1; + } + if (c1.RowIndex.HasValue) { if (c2.RowIndex.HasValue) { int row = c1.RowIndex.Value.CompareTo(c2.RowIndex.Value); - if (row == 0) - { - return c1.Column.Name.CompareTo(c2.Column.Name); - } - - return row; + return row == 0 + ? c1.Column.Name.CompareTo(c2.Column.Name) + : row; } return 1; diff --git a/BizHawk.Client.EmuHawk/CustomControls/InputRoll/RollColumn.cs b/BizHawk.Client.EmuHawk/CustomControls/InputRoll/RollColumn.cs index 8375120d3d..1ddb5346cc 100644 --- a/BizHawk.Client.EmuHawk/CustomControls/InputRoll/RollColumn.cs +++ b/BizHawk.Client.EmuHawk/CustomControls/InputRoll/RollColumn.cs @@ -9,21 +9,11 @@ public string Name { get; set; } public string Text { get; set; } public ColumnType Type { get; set; } - public bool Visible { get; set; } + public bool Visible { get; set; } = true; /// /// Column will be drawn with an emphasized look, if true /// - private bool _emphasis; - public bool Emphasis - { - get { return _emphasis; } - set { _emphasis = value; } - } - - public RollColumn() - { - Visible = true; - } + public bool Emphasis { get; set; } } } diff --git a/BizHawk.Client.EmuHawk/CustomControls/InputRoll/RollColumns.cs b/BizHawk.Client.EmuHawk/CustomControls/InputRoll/RollColumns.cs index 95fa56788a..96ee91ea59 100644 --- a/BizHawk.Client.EmuHawk/CustomControls/InputRoll/RollColumns.cs +++ b/BizHawk.Client.EmuHawk/CustomControls/InputRoll/RollColumns.cs @@ -5,148 +5,122 @@ using System.Linq; namespace BizHawk.Client.EmuHawk { public class RollColumns : List + { + public RollColumn this[string name] => this.SingleOrDefault(column => column.Name == name); + + public IEnumerable VisibleColumns => this.Where(c => c.Visible); + + public Action ChangedCallback { get; set; } + + // TODO: this shouldn't be exposed. But in order to not expose it, each RollColumn must have a change callback, and all property changes must call it, it is quicker and easier to just call this when needed + public void ColumnsChanged() { - public RollColumn this[string name] + int pos = 0; + + foreach (var col in VisibleColumns) { - get - { - return this.SingleOrDefault(column => column.Name == name); - } + col.Left = pos; + pos += col.Width ?? 0; + col.Right = pos; } - public IEnumerable VisibleColumns + ChangedCallback?.Invoke(); + } + + public new void Add(RollColumn column) + { + if (this.Any(c => c.Name == column.Name)) { - get - { - return this.Where(c => c.Visible); - } + // The designer sucks, doing nothing for now + return; + //throw new InvalidOperationException("A column with this name already exists."); } - public Action ChangedCallback { get; set; } + base.Add(column); + ColumnsChanged(); + } - private void DoChangeCallback() - { - // no check will make it crash for user too, not sure which way of alarm we prefer. no alarm at all will cause all sorts of subtle bugs - if (ChangedCallback == null) - { - System.Diagnostics.Debug.Fail($"{nameof(ChangedCallback)} has died!"); - } - else - { - ChangedCallback(); - } - } - - // TODO: this shouldn't be exposed. But in order to not expose it, each RollColumn must have a change callback, and all property changes must call it, it is quicker and easier to just call this when needed - public void ColumnsChanged() - { - int pos = 0; - - foreach (var col in VisibleColumns) - { - col.Left = pos; - pos += col.Width.Value; - col.Right = pos; - } - - DoChangeCallback(); - } - - public new void Add(RollColumn column) + public new void AddRange(IEnumerable collection) + { + var items = collection.ToList(); + foreach (var column in items) { if (this.Any(c => c.Name == column.Name)) { // The designer sucks, doing nothing for now return; - //throw new InvalidOperationException("A column with this name already exists."); - } - base.Add(column); - ColumnsChanged(); + throw new InvalidOperationException("A column with this name already exists."); + } } - public new void AddRange(IEnumerable collection) + base.AddRange(items); + ColumnsChanged(); + } + + public new void Insert(int index, RollColumn column) + { + if (this.Any(c => c.Name == column.Name)) { - foreach (var column in collection) - { - if (this.Any(c => c.Name == column.Name)) - { - // The designer sucks, doing nothing for now - return; + // The designer sucks, doing nothing for now + return; - throw new InvalidOperationException("A column with this name already exists."); - } - } - - base.AddRange(collection); - ColumnsChanged(); + throw new InvalidOperationException("A column with this name already exists."); } - public new void Insert(int index, RollColumn column) + base.Insert(index, column); + ColumnsChanged(); + } + + public new void InsertRange(int index, IEnumerable collection) + { + var items = collection.ToList(); + foreach (var column in items) { if (this.Any(c => c.Name == column.Name)) { throw new InvalidOperationException("A column with this name already exists."); } - - base.Insert(index, column); - ColumnsChanged(); } - public new void InsertRange(int index, IEnumerable collection) - { - foreach (var column in collection) - { - if (this.Any(c => c.Name == column.Name)) - { - throw new InvalidOperationException("A column with this name already exists."); - } - } - - base.InsertRange(index, collection); - ColumnsChanged(); - } - - public new bool Remove(RollColumn column) - { - var result = base.Remove(column); - ColumnsChanged(); - return result; - } - - public new int RemoveAll(Predicate match) - { - var result = base.RemoveAll(match); - ColumnsChanged(); - return result; - } - - public new void RemoveAt(int index) - { - base.RemoveAt(index); - ColumnsChanged(); - } - - public new void RemoveRange(int index, int count) - { - base.RemoveRange(index, count); - ColumnsChanged(); - } - - public new void Clear() - { - base.Clear(); - ColumnsChanged(); - } - - public IEnumerable Groups - { - get - { - return this - .Select(x => x.Group) - .Distinct(); - } - } + base.InsertRange(index, items); + ColumnsChanged(); } + + public new bool Remove(RollColumn column) + { + var result = base.Remove(column); + ColumnsChanged(); + return result; + } + + public new int RemoveAll(Predicate match) + { + var result = base.RemoveAll(match); + ColumnsChanged(); + return result; + } + + public new void RemoveAt(int index) + { + base.RemoveAt(index); + ColumnsChanged(); + } + + public new void RemoveRange(int index, int count) + { + base.RemoveRange(index, count); + ColumnsChanged(); + } + + public new void Clear() + { + base.Clear(); + ColumnsChanged(); + } + + public IEnumerable Groups => this + .Select(x => x.Group) + .Distinct(); + } } From 6604e5dc176b9459a8a415fa76b55638d64f063f Mon Sep 17 00:00:00 2001 From: adelikat Date: Sat, 26 Oct 2019 17:16:15 -0500 Subject: [PATCH 136/166] InputRoll - cleanup and fix some typos --- .../CustomControls/InputRoll/InputRoll.cs | 30 +++++++++---------- .../TAStudio/BookmarksBranchesBox.Designer.cs | 2 +- .../tools/TAStudio/MarkerControl.Designer.cs | 2 +- .../tools/TAStudio/TAStudio.Designer.cs | 2 +- BizHawk.sln.DotSettings | 2 ++ 5 files changed, 20 insertions(+), 18 deletions(-) diff --git a/BizHawk.Client.EmuHawk/CustomControls/InputRoll/InputRoll.cs b/BizHawk.Client.EmuHawk/CustomControls/InputRoll/InputRoll.cs index a7c1a5a6e5..4d734c0dd2 100644 --- a/BizHawk.Client.EmuHawk/CustomControls/InputRoll/InputRoll.cs +++ b/BizHawk.Client.EmuHawk/CustomControls/InputRoll/InputRoll.cs @@ -47,11 +47,11 @@ namespace BizHawk.Client.EmuHawk public int LagFramesToHide { get; set; } public bool HideWasLagFrames { get; set; } - public bool AllowRightClickSelecton { get; set; } + public bool AllowRightClickSelection { get; set; } public bool LetKeysModifySelection { get; set; } public bool SuspendHotkeys { get; set; } - private Font _font = new Font("Arial", 8, FontStyle.Bold); + private readonly Font _font = new Font("Arial", 8, FontStyle.Bold); public InputRoll() { @@ -299,7 +299,7 @@ namespace BizHawk.Client.EmuHawk public string ScrollMethod { get; set; } /// - /// Gets or sets a value indicating how the Intever for the hover event + /// Gets or sets a value indicating how the scrolling behavior for the hover event /// [Category("Behavior")] public bool AlwaysScroll { get; set; } @@ -453,8 +453,8 @@ namespace BizHawk.Client.EmuHawk NewCell = newCell; } - public Cell OldCell { get; private set; } - public Cell NewCell { get; private set; } + public Cell OldCell { get; } + public Cell NewCell { get; } } public class ColumnClickEventArgs @@ -464,7 +464,7 @@ namespace BizHawk.Client.EmuHawk Column = column; } - public RollColumn Column { get; private set; } + public RollColumn Column { get; } } public class ColumnReorderedEventArgs @@ -476,9 +476,9 @@ namespace BizHawk.Client.EmuHawk NewDisplayIndex = newDisplayIndex; } - public RollColumn Column { get; private set; } - public int OldDisplayIndex { get; private set; } - public int NewDisplayIndex { get; private set; } + public RollColumn Column { get; } + public int OldDisplayIndex { get; } + public int NewDisplayIndex { get; } } #endregion @@ -661,7 +661,7 @@ namespace BizHawk.Client.EmuHawk [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] public int FirstVisibleRow { - get // SuuperW: This was checking if the scroll bars were needed, which is useless because their Value is 0 if they aren't needed. + get { if (HorizontalOrientation) { @@ -995,7 +995,7 @@ namespace BizHawk.Client.EmuHawk #region Mouse and Key Events private bool _columnDownMoved; - private int _previousX = 0; // TODO: move me + private int _previousX; // TODO: move me protected override void OnMouseMove(MouseEventArgs e) { @@ -1085,7 +1085,7 @@ namespace BizHawk.Client.EmuHawk { if (!GlobalWin.MainForm.EmulatorPaused && _currentX.HasValue) { - // copypaste from OnMouseMove() + // TODO: this is copy pasta from OnMouseMove() Cell newCell = CalculatePointedCell(_currentX.Value, _currentY.Value); if (QueryFrameLag != null && newCell.RowIndex.HasValue) { @@ -1225,7 +1225,6 @@ namespace BizHawk.Client.EmuHawk } else if (ModifierKeys != Keys.Shift) { - var hadIndex = _selectedItems.Any(); _selectedItems.Clear(); SelectCell(CurrentCell); } @@ -1238,7 +1237,7 @@ namespace BizHawk.Client.EmuHawk base.OnMouseDown(e); - if (AllowRightClickSelecton && e.Button == MouseButtons.Right) + if (AllowRightClickSelection && e.Button == MouseButtons.Right) { if (!IsHoveringOnColumnCell && CurrentCell != null) { @@ -1729,6 +1728,7 @@ namespace BizHawk.Client.EmuHawk /// If FullRowSelect is enabled, selects all cells in the row that contains the given cell. Otherwise only given cell is added. /// /// The cell to select. + /// Specifies whether or not to toggle the current state, rather than force the value to true private void SelectCell(Cell cell, bool toggle = false) { if (cell.RowIndex.HasValue && cell.RowIndex < RowCount) @@ -1906,7 +1906,7 @@ namespace BizHawk.Client.EmuHawk /// Converts a horizontal or vertical coordinate to a row number. /// /// A vertical coordinate if Vertical Oriented, otherwise a horizontal coordinate. - /// A row number between 0 and VisibleRows if it is a Datarow, otherwise a negative number if above all Datarows. + /// A row number between 0 and VisibleRows if it is a data row, otherwise a negative number if above all Datarows. private int PixelsToRows(int pixels) { // Using Math.Floor and float because integer division rounds towards 0 but we want to round down. diff --git a/BizHawk.Client.EmuHawk/tools/TAStudio/BookmarksBranchesBox.Designer.cs b/BizHawk.Client.EmuHawk/tools/TAStudio/BookmarksBranchesBox.Designer.cs index 3e91765166..da6880ddde 100644 --- a/BizHawk.Client.EmuHawk/tools/TAStudio/BookmarksBranchesBox.Designer.cs +++ b/BizHawk.Client.EmuHawk/tools/TAStudio/BookmarksBranchesBox.Designer.cs @@ -148,7 +148,7 @@ // this.BranchView.AllowColumnReorder = false; this.BranchView.AllowColumnResize = false; - this.BranchView.AllowRightClickSelecton = true; + this.BranchView.AllowRightClickSelection = true; this.BranchView.AlwaysScroll = false; this.BranchView.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom) | System.Windows.Forms.AnchorStyles.Left) diff --git a/BizHawk.Client.EmuHawk/tools/TAStudio/MarkerControl.Designer.cs b/BizHawk.Client.EmuHawk/tools/TAStudio/MarkerControl.Designer.cs index a3726d0fe4..57eb976625 100644 --- a/BizHawk.Client.EmuHawk/tools/TAStudio/MarkerControl.Designer.cs +++ b/BizHawk.Client.EmuHawk/tools/TAStudio/MarkerControl.Designer.cs @@ -187,7 +187,7 @@ // this.MarkerView.AllowColumnReorder = false; this.MarkerView.AllowColumnResize = false; - this.MarkerView.AllowRightClickSelecton = true; + this.MarkerView.AllowRightClickSelection = true; this.MarkerView.AlwaysScroll = false; this.MarkerView.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom) | System.Windows.Forms.AnchorStyles.Left) diff --git a/BizHawk.Client.EmuHawk/tools/TAStudio/TAStudio.Designer.cs b/BizHawk.Client.EmuHawk/tools/TAStudio/TAStudio.Designer.cs index 8972f50607..7a154e5ccf 100644 --- a/BizHawk.Client.EmuHawk/tools/TAStudio/TAStudio.Designer.cs +++ b/BizHawk.Client.EmuHawk/tools/TAStudio/TAStudio.Designer.cs @@ -1230,7 +1230,7 @@ namespace BizHawk.Client.EmuHawk // this.TasView.AllowColumnReorder = false; this.TasView.AllowColumnResize = false; - this.TasView.AllowRightClickSelecton = false; + this.TasView.AllowRightClickSelection = false; this.TasView.AlwaysScroll = false; this.TasView.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom) | System.Windows.Forms.AnchorStyles.Left) diff --git a/BizHawk.sln.DotSettings b/BizHawk.sln.DotSettings index b6b12fa574..e6b55cb2f1 100644 --- a/BizHawk.sln.DotSettings +++ b/BizHawk.sln.DotSettings @@ -192,6 +192,8 @@ True True True + True + True True True True From 9d87550c2a03f45b6330f76817de5c0417577a94 Mon Sep 17 00:00:00 2001 From: adelikat Date: Sat, 26 Oct 2019 17:22:49 -0500 Subject: [PATCH 137/166] Cell - implement == and != overrides, this might fix some subtle problems in input roll --- .../CustomControls/InputRoll/Cell.cs | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/BizHawk.Client.EmuHawk/CustomControls/InputRoll/Cell.cs b/BizHawk.Client.EmuHawk/CustomControls/InputRoll/Cell.cs index e9b71c9eb5..4ccc3e8e9e 100644 --- a/BizHawk.Client.EmuHawk/CustomControls/InputRoll/Cell.cs +++ b/BizHawk.Client.EmuHawk/CustomControls/InputRoll/Cell.cs @@ -29,13 +29,28 @@ namespace BizHawk.Client.EmuHawk return Column == cell.Column && RowIndex == cell.RowIndex; } - return base.Equals(obj); + return false; } public override int GetHashCode() { return Column.GetHashCode() + RowIndex.GetHashCode(); } + + public static bool operator ==(Cell a, Cell b) + { + if (ReferenceEquals(a, null)) + { + return ReferenceEquals(b, null); + } + + return a.Equals(b); + } + + public static bool operator !=(Cell a, Cell b) + { + return !(a == b); + } } internal class SortCell : IComparer From 5f021ca0e2b88acc60348958d76f73751fcb886d Mon Sep 17 00:00:00 2001 From: adelikat Date: Sat, 26 Oct 2019 18:35:12 -0500 Subject: [PATCH 138/166] InputRoll - attempt to put some attributes on public properties. This is a control, public properties without attributes and/or documentation should be avoided --- .../CustomControls/InputRoll/InputRoll.cs | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/BizHawk.Client.EmuHawk/CustomControls/InputRoll/InputRoll.cs b/BizHawk.Client.EmuHawk/CustomControls/InputRoll/InputRoll.cs index 4d734c0dd2..9ea372f611 100644 --- a/BizHawk.Client.EmuHawk/CustomControls/InputRoll/InputRoll.cs +++ b/BizHawk.Client.EmuHawk/CustomControls/InputRoll/InputRoll.cs @@ -44,11 +44,22 @@ namespace BizHawk.Client.EmuHawk private int? _currentY; // Hiding lag frames (Mainly intended for < 60fps play.) + [Browsable(false)] + [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] public int LagFramesToHide { get; set; } + + [Browsable(false)] + [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] public bool HideWasLagFrames { get; set; } + [Category("Behavior")] public bool AllowRightClickSelection { get; set; } + + [Category("Behavior")] public bool LetKeysModifySelection { get; set; } + + [Browsable(false)] + [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] public bool SuspendHotkeys { get; set; } private readonly Font _font = new Font("Arial", 8, FontStyle.Bold); @@ -598,6 +609,8 @@ namespace BizHawk.Client.EmuHawk /// /// Gets or sets the width of data cells when in Horizontal orientation. /// + [Browsable(false)] + [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] public int MaxCharactersInHorizontal { get From 290cf4c4a4861b289fe6d85a47757fd0bc1f0a67 Mon Sep 17 00:00:00 2001 From: adelikat Date: Sun, 27 Oct 2019 09:18:14 -0500 Subject: [PATCH 139/166] InputRoll - attempt to cleanup drawing logic a bit --- .../InputRoll/InputRoll.Drawing.cs | 42 +++++++++++-------- 1 file changed, 24 insertions(+), 18 deletions(-) diff --git a/BizHawk.Client.EmuHawk/CustomControls/InputRoll/InputRoll.Drawing.cs b/BizHawk.Client.EmuHawk/CustomControls/InputRoll/InputRoll.Drawing.cs index ebe9209f53..ae84969b6c 100644 --- a/BizHawk.Client.EmuHawk/CustomControls/InputRoll/InputRoll.Drawing.cs +++ b/BizHawk.Client.EmuHawk/CustomControls/InputRoll/InputRoll.Drawing.cs @@ -66,7 +66,7 @@ namespace BizHawk.Client.EmuHawk private void DrawColumnDrag() { - if (_columnDown != null && _columnDownMoved && _currentX.HasValue && _currentY.HasValue && IsHoveringOnColumnCell) + if (_columnDown?.Width != null && _columnDownMoved && _currentX.HasValue && _currentY.HasValue && IsHoveringOnColumnCell) { int x1 = _currentX.Value - (_columnDown.Width.Value / 2); int y1 = _currentY.Value - (CellHeight / 2); @@ -82,7 +82,8 @@ namespace BizHawk.Client.EmuHawk private void DrawCellDrag() { - if (_draggingCell != null) + if (_draggingCell != null && _draggingCell.RowIndex.HasValue && _draggingCell.Column.Width.HasValue + && _currentX.HasValue && _currentY.HasValue) { var text = ""; int offsetX = 0; @@ -398,23 +399,24 @@ namespace BizHawk.Client.EmuHawk // Rows for (int i = 0; i < visibleColumns.Count + 1; i++) { - _renderer.Line(RowsToPixels(0) + 1, i * CellHeight - _vBar.Value, DrawWidth, i * CellHeight - _vBar.Value); + int y = i * CellHeight - _vBar.Value; + _renderer.Line(RowsToPixels(0) + 1, y, DrawWidth, y); } } else { // Columns int y = ColumnHeight + 1; - int? totalColWidth = TotalColWidth; foreach (var column in visibleColumns) { - int x = column.Left.Value - _hBar.Value; + int x = (column.Left ?? 0) - _hBar.Value; _renderer.Line(x, y, x, Height - 1); } if (visibleColumns.Any()) { - _renderer.Line(totalColWidth.Value - _hBar.Value, y, totalColWidth.Value - _hBar.Value, Height - 1); + int x = (TotalColWidth ?? 0) - _hBar.Value; + _renderer.Line(x, y, x, Height - 1); } // Rows @@ -433,7 +435,6 @@ namespace BizHawk.Client.EmuHawk private void DoSelectionBG(List visibleColumns) { - // SuuperW: This allows user to see other colors in selected frames. Color rowColor = Color.White; int lastVisibleRow = LastVisibleRow; int lastRow = -1; @@ -479,7 +480,7 @@ namespace BizHawk.Client.EmuHawk } /// - /// Given a cell with rowindex inbetween 0 and VisibleRows, it draws the background color specified. Do not call with absolute rowindices. + /// Given a cell with RowIndex in between 0 and VisibleRows, it draws the background color specified. Do not call with absolute row indices. /// private void DrawCellBG(Color color, Cell cell, List visibleColumns) { @@ -488,30 +489,33 @@ namespace BizHawk.Client.EmuHawk if (HorizontalOrientation) { x = RowsToPixels(cell.RowIndex.Value) + 1; - w = CellWidth - 1; - y = (CellHeight * visibleColumns.IndexOf(cell.Column)) + 1 - _vBar.Value; // We can't draw without row and column, so assume they exist and fail catastrophically if they don't - h = CellHeight - 1; if (x < ColumnWidth) { return; } + + w = CellWidth - 1; + y = (CellHeight * visibleColumns.IndexOf(cell.Column)) + 1 - _vBar.Value; // We can't draw without row and column, so assume they exist and fail catastrophically if they don't + h = CellHeight - 1; } else { - w = cell.Column.Width.Value - 1; - x = cell.Column.Left.Value - _hBar.Value + 1; y = RowsToPixels(cell.RowIndex.Value) + 1; // We can't draw without row and column, so assume they exist and fail catastrophically if they don't - h = CellHeight - 1; if (y < ColumnHeight) { return; } + + x = cell.Column.Left.Value - _hBar.Value + 1; + w = cell.Column.Width.Value - 1; + h = CellHeight - 1; } + // Don't draw if off screen. if (x > DrawWidth || y > DrawHeight) { return; - } // Don't draw if off screen. + } _renderer.SetBrush(color); _renderer.FillRectangle(x, y, w, h); @@ -524,13 +528,15 @@ namespace BizHawk.Client.EmuHawk { int startIndex = FirstVisibleRow; int range = Math.Min(LastVisibleRow, RowCount - 1) - startIndex + 1; - int lastVisible = LastVisibleColumnIndex; + int lastVisibleColumn = LastVisibleColumnIndex; int firstVisibleColumn = FirstVisibleColumn; + // Prevent exceptions with small TAStudio windows if (firstVisibleColumn < 0) { return; } + if (HorizontalOrientation) { for (int i = 0, f = 0; f < range; i++, f++) @@ -540,7 +546,7 @@ namespace BizHawk.Client.EmuHawk Color rowColor = Color.White; QueryRowBkColor?.Invoke(f + startIndex, ref rowColor); - for (int j = firstVisibleColumn; j <= lastVisible; j++) + for (int j = firstVisibleColumn; j <= lastVisibleColumn; j++) { Color itemColor = Color.White; QueryItemBkColor?.Invoke(f + startIndex, visibleColumns[j], ref itemColor); @@ -577,7 +583,7 @@ namespace BizHawk.Client.EmuHawk Color rowColor = Color.White; QueryRowBkColor?.Invoke(f + startIndex, ref rowColor); - for (int j = FirstVisibleColumn; j <= lastVisible; j++) // Horizontal + for (int j = FirstVisibleColumn; j <= lastVisibleColumn; j++) // Horizontal { Color itemColor = Color.White; QueryItemBkColor?.Invoke(f + startIndex, visibleColumns[j], ref itemColor); From aaee3cf48ccf22a944c45f55b3da00ff28de2d92 Mon Sep 17 00:00:00 2001 From: adelikat Date: Sun, 27 Oct 2019 09:34:32 -0500 Subject: [PATCH 140/166] Tastudio - fix splitter restore logic on restore defaults --- .../tools/TAStudio/TAStudio.MenuItems.cs | 19 ++------------- .../tools/TAStudio/TAStudio.cs | 24 ++++--------------- BizHawk.Client.EmuHawk/tools/ToolManager.cs | 2 +- 3 files changed, 7 insertions(+), 38 deletions(-) diff --git a/BizHawk.Client.EmuHawk/tools/TAStudio/TAStudio.MenuItems.cs b/BizHawk.Client.EmuHawk/tools/TAStudio/TAStudio.MenuItems.cs index 52ae09bd32..1c914e6415 100644 --- a/BizHawk.Client.EmuHawk/tools/TAStudio/TAStudio.MenuItems.cs +++ b/BizHawk.Client.EmuHawk/tools/TAStudio/TAStudio.MenuItems.cs @@ -1403,23 +1403,8 @@ namespace BizHawk.Client.EmuHawk RefreshTasView(); CurrentTasMovie.FlagChanges(); - try - { - MainVertialSplit.SplitterDistance = Settings.MainVerticalSplitDistance; - } - catch (Exception) - { - MainVertialSplit.SplitterDistance = _defaultMainSplitDistance; - } - - try - { - BranchesMarkersSplit.SplitterDistance = Settings.BranchMarkerSplitDistance; - } - catch (Exception) - { - BranchesMarkersSplit.SplitterDistance = _defaultBranchMarkerSplitDistance; - } + MainVertialSplit.SplitterDistance = _defaultMainSplitDistance; + BranchesMarkersSplit.SplitterDistance = _defaultBranchMarkerSplitDistance; } #endregion diff --git a/BizHawk.Client.EmuHawk/tools/TAStudio/TAStudio.cs b/BizHawk.Client.EmuHawk/tools/TAStudio/TAStudio.cs index 19136e07e7..f45de742a6 100644 --- a/BizHawk.Client.EmuHawk/tools/TAStudio/TAStudio.cs +++ b/BizHawk.Client.EmuHawk/tools/TAStudio/TAStudio.cs @@ -33,8 +33,8 @@ namespace BizHawk.Client.EmuHawk private UndoHistoryForm _undoForm; private Timer _autosaveTimer; - private int _defaultMainSplitDistance; - private int _defaultBranchMarkerSplitDistance; + private readonly int _defaultMainSplitDistance; + private readonly int _defaultBranchMarkerSplitDistance; /// /// Gets a value that separates "restore last position" logic from seeking caused by navigation. @@ -273,22 +273,6 @@ namespace BizHawk.Client.EmuHawk } // Remembering Split container logic - int defaultMainSplitDistance = MainVertialSplit.SplitterDistance; - int defaultBranchMarkerSplitDistance = BranchesMarkersSplit.SplitterDistance; - - ToolStripMenuItem restoreDefaults = TASMenu.Items - .OfType() - .Single(t => t.Name == "SettingsSubMenu") - .DropDownItems - .OfType() - .Single(t => t.Text == "Restore &Defaults"); - - restoreDefaults.Click += (o, ev) => - { - MainVertialSplit.SplitterDistance = defaultMainSplitDistance; - BranchesMarkersSplit.SplitterDistance = defaultBranchMarkerSplitDistance; - }; - if (Settings.MainVerticalSplitDistance > 0) { try @@ -297,7 +281,7 @@ namespace BizHawk.Client.EmuHawk } catch (Exception) { - MainVertialSplit.SplitterDistance = defaultMainSplitDistance; + MainVertialSplit.SplitterDistance = _defaultMainSplitDistance; } } @@ -310,7 +294,7 @@ namespace BizHawk.Client.EmuHawk } catch (Exception) { - BranchesMarkersSplit.SplitterDistance = defaultBranchMarkerSplitDistance; + BranchesMarkersSplit.SplitterDistance = _defaultBranchMarkerSplitDistance; } } diff --git a/BizHawk.Client.EmuHawk/tools/ToolManager.cs b/BizHawk.Client.EmuHawk/tools/ToolManager.cs index 1c0a1c17e7..86973efc73 100644 --- a/BizHawk.Client.EmuHawk/tools/ToolManager.cs +++ b/BizHawk.Client.EmuHawk/tools/ToolManager.cs @@ -42,7 +42,7 @@ namespace BizHawk.Client.EmuHawk /// Type of tool you want to load /// Define if the tool form has to get the focus or not (Default is true) /// An instantiated - /// Raised if can't be casted into IToolForm + /// Raised if can't cast into IToolForm internal IToolForm Load(Type toolType, bool focus = true) { if (!typeof(IToolForm).IsAssignableFrom(toolType)) From cbace55d01da2141b558536eb5841341dd64c03d Mon Sep 17 00:00:00 2001 From: adelikat Date: Sun, 27 Oct 2019 09:59:05 -0500 Subject: [PATCH 141/166] Tastudio - misc cleanups --- .../tools/TAStudio/TAStudio.Callbacks.cs | 15 ----- .../tools/TAStudio/TAStudio.Designer.cs | 7 +-- .../tools/TAStudio/TAStudio.ListView.cs | 63 +++++++------------ .../tools/TAStudio/TAStudio.MenuItems.cs | 61 ++++++++---------- .../tools/TAStudio/TAStudio.Navigation.cs | 5 -- .../tools/TAStudio/TAStudio.cs | 24 ++----- BizHawk.sln.DotSettings | 1 + 7 files changed, 57 insertions(+), 119 deletions(-) diff --git a/BizHawk.Client.EmuHawk/tools/TAStudio/TAStudio.Callbacks.cs b/BizHawk.Client.EmuHawk/tools/TAStudio/TAStudio.Callbacks.cs index 920056988e..a9dff4b5ec 100644 --- a/BizHawk.Client.EmuHawk/tools/TAStudio/TAStudio.Callbacks.cs +++ b/BizHawk.Client.EmuHawk/tools/TAStudio/TAStudio.Callbacks.cs @@ -15,21 +15,6 @@ namespace BizHawk.Client.EmuHawk public Action BranchSavedCallback { get; set; } public Action BranchRemovedCallback { get; set; } - private Color? GetColorOverride(int index, RollColumn column) - { - return QueryItemBgColorCallback?.Invoke(index, column.Name); - } - - private string GetTextOverride(int index, RollColumn column) - { - return QueryItemTextCallback?.Invoke(index, column.Name); - } - - private Bitmap GetIconOverride(int index, RollColumn column) - { - return QueryItemIconCallback?.Invoke(index, column.Name); - } - private void GreenzoneInvalidated(int index) { GreenzoneInvalidatedCallback?.Invoke(index); diff --git a/BizHawk.Client.EmuHawk/tools/TAStudio/TAStudio.Designer.cs b/BizHawk.Client.EmuHawk/tools/TAStudio/TAStudio.Designer.cs index 7a154e5ccf..fc20dcb1fb 100644 --- a/BizHawk.Client.EmuHawk/tools/TAStudio/TAStudio.Designer.cs +++ b/BizHawk.Client.EmuHawk/tools/TAStudio/TAStudio.Designer.cs @@ -814,7 +814,7 @@ namespace BizHawk.Client.EmuHawk this.LoadBranchOnDoubleclickMenuItem.Name = "LoadBranchOnDoubleclickMenuItem"; this.LoadBranchOnDoubleclickMenuItem.Size = new System.Drawing.Size(244, 22); this.LoadBranchOnDoubleclickMenuItem.Text = "Load Branch on double-click"; - this.LoadBranchOnDoubleclickMenuItem.Click += new System.EventHandler(this.LoadBranchOnDoubleclickMenuItem_Click); + this.LoadBranchOnDoubleclickMenuItem.Click += new System.EventHandler(this.LoadBranchOnDoubleClickMenuItem_Click); // // OsdInBranchScreenshotsMenuItem // @@ -834,7 +834,7 @@ namespace BizHawk.Client.EmuHawk this.AutopauseAtEndOfMovieMenuItem.Name = "AutopauseAtEndOfMovieMenuItem"; this.AutopauseAtEndOfMovieMenuItem.Size = new System.Drawing.Size(244, 22); this.AutopauseAtEndOfMovieMenuItem.Text = "Autopause at end of Movie"; - this.AutopauseAtEndOfMovieMenuItem.Click += new System.EventHandler(this.AutopauseAtEndMenuItem_Click); + this.AutopauseAtEndOfMovieMenuItem.Click += new System.EventHandler(this.AutoPauseAtEndMenuItem_Click); // // sepToolStripMenuItem // @@ -1590,7 +1590,7 @@ namespace BizHawk.Client.EmuHawk this.MainVertialSplit.Size = new System.Drawing.Size(507, 528); this.MainVertialSplit.SplitterDistance = 295; this.MainVertialSplit.TabIndex = 10; - this.MainVertialSplit.SplitterMoved += new System.Windows.Forms.SplitterEventHandler(this.MainVertialSplit_SplitterMoved); + this.MainVertialSplit.SplitterMoved += new System.Windows.Forms.SplitterEventHandler(this.MainVerticalSplit_SplitterMoved); // // TAStudio // @@ -1612,7 +1612,6 @@ namespace BizHawk.Client.EmuHawk this.Load += new System.EventHandler(this.Tastudio_Load); this.DragDrop += new System.Windows.Forms.DragEventHandler(this.TAStudio_DragDrop); this.DragEnter += new System.Windows.Forms.DragEventHandler(this.DragEnterWrapper); - this.KeyDown += new System.Windows.Forms.KeyEventHandler(this.TAStudio_KeyDown); this.MouseLeave += new System.EventHandler(this.TAStudio_MouseLeave); this.TASMenu.ResumeLayout(false); this.TASMenu.PerformLayout(); diff --git a/BizHawk.Client.EmuHawk/tools/TAStudio/TAStudio.ListView.cs b/BizHawk.Client.EmuHawk/tools/TAStudio/TAStudio.ListView.cs index dc707692c6..147b7b8389 100644 --- a/BizHawk.Client.EmuHawk/tools/TAStudio/TAStudio.ListView.cs +++ b/BizHawk.Client.EmuHawk/tools/TAStudio/TAStudio.ListView.cs @@ -18,12 +18,12 @@ namespace BizHawk.Client.EmuHawk private bool _boolPaintState; private float _floatPaintState; private float _floatBackupState; - private bool _patternPaint = false; + private bool _patternPaint; private bool _startCursorDrag; private bool _startSelectionDrag; private bool _selectionDragState; - private bool _supressContextMenu; - private int _startrow; + private bool _suppressContextMenu; + private int _startRow; // Editing analog input private string _floatEditColumn = ""; @@ -99,7 +99,7 @@ namespace BizHawk.Client.EmuHawk TastudioPlayMode(); // suspend rec mode until seek ends, to allow mouse editing Mainform.UnpauseEmulator(); - if (!_seekBackgroundWorker.IsBusy && diff.Value > TasView.VisibleRows) + if (!_seekBackgroundWorker.IsBusy && diff > TasView.VisibleRows) { _seekBackgroundWorker.RunWorkerAsync(); } @@ -159,7 +159,7 @@ namespace BizHawk.Client.EmuHawk private void TasView_QueryItemIcon(int index, RollColumn column, ref Bitmap bitmap, ref int offsetX, ref int offsetY) { - var overrideIcon = GetIconOverride(index, column); + var overrideIcon = QueryItemIconCallback?.Invoke(index, column.Name); if (overrideIcon != null) { @@ -216,7 +216,7 @@ namespace BizHawk.Client.EmuHawk private void TasView_QueryItemBkColor(int index, RollColumn column, ref Color color) { - Color? overrideColor = GetColorOverride(index, column); + Color? overrideColor = QueryItemBgColorCallback?.Invoke(index, column.Name); if (overrideColor.HasValue) { @@ -242,11 +242,10 @@ namespace BizHawk.Client.EmuHawk color = Color.FromArgb(0x60, 0xFF, 0xFF, 0xFF); } } - else if (FloatEditingMode && - (index == _floatEditRow || _extraFloatRows.Contains(index)) && - columnName == _floatEditColumn) + else if (FloatEditingMode + && (index == _floatEditRow || _extraFloatRows.Contains(index)) + && columnName == _floatEditColumn) { - // SuuperW: Analog editing is indicated by a color change. color = AnalogEdit_Col; } @@ -298,7 +297,7 @@ namespace BizHawk.Client.EmuHawk private void TasView_QueryItemText(int index, RollColumn column, out string text, ref int offsetX, ref int offsetY) { - var overrideText = GetTextOverride(index, column); + var overrideText = QueryItemTextCallback?.Invoke(index, column.Name); if (overrideText != null) { text = overrideText; @@ -533,7 +532,6 @@ namespace BizHawk.Client.EmuHawk return; } - // SuuperW: Moved these. if (TasView.CurrentCell?.RowIndex == null || TasView.CurrentCell.Column == null) { return; @@ -616,7 +614,7 @@ namespace BizHawk.Client.EmuHawk BoolPatterns[ControllerType.BoolButtons.IndexOf(buttonName)].Reset(); //BoolPatterns[ControllerType.BoolButtons.IndexOf(buttonName)].GetNextValue(); _patternPaint = true; - _startrow = TasView.CurrentCell.RowIndex.Value; + _startRow = TasView.CurrentCell.RowIndex.Value; _boolPaintState = !CurrentTasMovie.BoolIsPressed(frame, buttonName); } else if (Control.ModifierKeys == Keys.Shift && Control.ModifierKeys != Keys.Alt) @@ -804,16 +802,16 @@ namespace BizHawk.Client.EmuHawk _floatEditYPos = -1; _leftButtonHeld = false; - if (!FloatEditingMode && CurrentTasMovie.ChangeLog != null) + if (!FloatEditingMode) { - CurrentTasMovie.ChangeLog.EndBatch(); + CurrentTasMovie.ChangeLog?.EndBatch(); } } private void TasView_MouseUp(object sender, MouseEventArgs e) { if (e.Button == MouseButtons.Right && !TasView.IsPointingAtColumnHeader && - !_supressContextMenu && TasView.SelectedRows.Any() && !_leftButtonHeld) + !_suppressContextMenu && TasView.SelectedRows.Any() && !_leftButtonHeld) { if (Global.MovieSession.Movie.FrameCount < TasView.SelectedRows.Max()) { @@ -852,7 +850,7 @@ namespace BizHawk.Client.EmuHawk } } - _supressContextMenu = false; + _suppressContextMenu = false; DoTriggeredAutoRestoreIfNeeded(); } @@ -861,14 +859,14 @@ namespace BizHawk.Client.EmuHawk { if (TasView.RightButtonHeld && TasView.CurrentCell.RowIndex.HasValue) { - _supressContextMenu = true; + _suppressContextMenu = true; int notch = e.Delta / 120; if (notch > 1) { notch *= 2; } - // warning: tastudio rewind hotkey/button logic is copypasted from here! + // warning: tastudio rewind hotkey/button logic is copy pasted from here! if (Mainform.IsSeeking && !Mainform.EmulatorPaused) { Mainform.PauseOnFrame -= notch; @@ -965,7 +963,7 @@ namespace BizHawk.Client.EmuHawk endVal = e.OldCell.RowIndex.Value; if(_patternPaint) { - endVal = _startrow; + endVal = _startRow; } } @@ -1104,7 +1102,7 @@ namespace BizHawk.Client.EmuHawk { JumpToGreenzone(); _triggerAutoRestore = true; - _supressContextMenu = true; + _suppressContextMenu = true; } } @@ -1115,8 +1113,6 @@ namespace BizHawk.Client.EmuHawk if (e.OldCell.RowIndex.HasValue && e.NewCell.RowIndex.HasValue) { - - for (int i = startVal; i <= endVal; i++) // Inclusive on both ends (drawing up or down) { bool setVal = _boolPaintState; @@ -1354,14 +1350,9 @@ namespace BizHawk.Client.EmuHawk } else if (e.KeyCode == Keys.OemMinus || e.KeyCode == Keys.Subtract) { - if (_floatTypedValue.StartsWith("-")) - { - _floatTypedValue = _floatTypedValue.Substring(1); - } - else - { - _floatTypedValue = $"-{_floatTypedValue}"; - } + _floatTypedValue = _floatTypedValue.StartsWith("-") + ? _floatTypedValue.Substring(1) + : $"-{_floatTypedValue}"; } else if (e.KeyCode == Keys.Back) { @@ -1476,7 +1467,7 @@ namespace BizHawk.Client.EmuHawk private void TasView_KeyDown(object sender, KeyEventArgs e) { - // taseditor uses Ctrl for selection and Shift for framecourser + // taseditor uses Ctrl for selection and Shift for frame cursor if (!e.Control && e.Shift && !e.Alt && e.KeyCode == Keys.PageUp) // Shift + Page Up { GoToPreviousMarker(); @@ -1493,14 +1484,6 @@ namespace BizHawk.Client.EmuHawk { GoToFrame(CurrentTasMovie.InputLogLength-1); } - else if (!e.Control && e.Shift && !e.Alt && e.KeyCode == Keys.Up) // Shift + Up - { - //GoToPreviousFrame(); - } - else if (!e.Control && e.Shift && !e.Alt && e.KeyCode == Keys.Down) // Shift + Down - { - //GoToNextFrame(); - } if (FloatEditingMode && e.KeyCode != Keys.Right diff --git a/BizHawk.Client.EmuHawk/tools/TAStudio/TAStudio.MenuItems.cs b/BizHawk.Client.EmuHawk/tools/TAStudio/TAStudio.MenuItems.cs index 1c914e6415..178cd9b6de 100644 --- a/BizHawk.Client.EmuHawk/tools/TAStudio/TAStudio.MenuItems.cs +++ b/BizHawk.Client.EmuHawk/tools/TAStudio/TAStudio.MenuItems.cs @@ -1,5 +1,4 @@ using System; -using System.Collections.Generic; using System.IO; using System.Linq; using System.Text; @@ -101,7 +100,7 @@ namespace BizHawk.Client.EmuHawk if (string.IsNullOrEmpty(CurrentTasMovie.Filename) || CurrentTasMovie.Filename == DefaultTasProjName()) { - SaveAsTas(sender, e); + SaveAsTas(); } else { @@ -133,7 +132,7 @@ namespace BizHawk.Client.EmuHawk } } - private void SaveAsTas(object sender, EventArgs e) + private void SaveAsTas() { _autosaveTimer.Stop(); GlobalWin.Sound.StopSound(); @@ -176,7 +175,7 @@ namespace BizHawk.Client.EmuHawk // call this one from the menu only private void SaveAsTasMenuItem_Click(object sender, EventArgs e) { - SaveAsTas(sender, e); + SaveAsTas(); if (Settings.BackupPerFileSave) { SaveBackupMenuItem_Click(sender, e); @@ -188,7 +187,7 @@ namespace BizHawk.Client.EmuHawk if (string.IsNullOrEmpty(CurrentTasMovie.Filename) || CurrentTasMovie.Filename == DefaultTasProjName()) { - SaveAsTas(sender, e); + SaveAsTas(); } else { @@ -331,8 +330,8 @@ namespace BizHawk.Client.EmuHawk ReselectClipboardMenuItem.Enabled = PasteMenuItem.Enabled = - PasteInsertMenuItem.Enabled = - Clipboard.GetDataObject().GetDataPresent(DataFormats.StringFormat) && TasView.AnyRowsSelected; + PasteInsertMenuItem.Enabled = TasView.AnyRowsSelected + && Clipboard.GetDataObject().GetDataPresent(DataFormats.StringFormat); ClearGreenzoneMenuItem.Enabled = CurrentTasMovie != null && CurrentTasMovie.TasStateManager.Any(); @@ -483,9 +482,8 @@ namespace BizHawk.Client.EmuHawk { // TODO: if highlighting 2 rows and pasting 3, only paste 2 of them // FCEUX Taseditor doesn't do this, but I think it is the expected behavior in editor programs - var wasPaused = Mainform.EmulatorPaused; - // copy paste from PasteInsertMenuItem_Click! + // TODO: copy paste from PasteInsertMenuItem_Click! IDataObject data = Clipboard.GetDataObject(); if (data.GetDataPresent(DataFormats.StringFormat)) { @@ -503,10 +501,8 @@ namespace BizHawk.Client.EmuHawk { return; } - else - { - _tasClipboard.Add(new TasClipboardEntry(i, line)); - } + + _tasClipboard.Add(new TasClipboardEntry(i, line)); } var needsToRollback = TasView.FirstSelectedIndex < Emulator.Frame; @@ -530,8 +526,6 @@ namespace BizHawk.Client.EmuHawk { if (TasView.AnyRowsSelected) { - var wasPaused = Mainform.EmulatorPaused; - // copy paste from PasteMenuItem_Click! IDataObject data = Clipboard.GetDataObject(); if (data.GetDataPresent(DataFormats.StringFormat)) @@ -577,7 +571,6 @@ namespace BizHawk.Client.EmuHawk { if (TasView.AnyRowsSelected) { - var wasPaused = Mainform.EmulatorPaused; var needsToRollback = TasView.FirstSelectedIndex < Emulator.Frame; var rollBackFrame = TasView.FirstSelectedIndex.Value; @@ -602,7 +595,6 @@ namespace BizHawk.Client.EmuHawk Clipboard.SetDataObject(sb.ToString()); CurrentTasMovie.RemoveFrames(list); SetSplicer(); - ////TasView.DeselectAll(); feos: what if I want to continuously cut? if (needsToRollback) { @@ -982,7 +974,7 @@ namespace BizHawk.Client.EmuHawk Settings.EmptyMarkers ^= true; } - private void AutopauseAtEndMenuItem_Click(object sender, EventArgs e) + private void AutoPauseAtEndMenuItem_Click(object sender, EventArgs e) { Settings.AutoPause ^= true; } @@ -1047,7 +1039,7 @@ namespace BizHawk.Client.EmuHawk Settings.OldControlSchemeForBranches ^= true; } - private void LoadBranchOnDoubleclickMenuItem_Click(object sender, EventArgs e) + private void LoadBranchOnDoubleClickMenuItem_Click(object sender, EventArgs e) { Settings.LoadBranchOnDoubleClick ^= true; } @@ -1243,8 +1235,9 @@ namespace BizHawk.Client.EmuHawk ColumnsSubMenu.DropDownItems.Clear(); var columns = TasView.AllColumns - .Where(x => !string.IsNullOrWhiteSpace(x.Text)) - .Where(x => x.Name != "FrameColumn"); + .Where(c => !string.IsNullOrWhiteSpace(c.Text)) + .Where(c => c.Name != "FrameColumn") + .ToList(); int workingHeight = Screen.FromControl(this).WorkingArea.Height; int rowHeight = ColumnsSubMenu.Height + 4; @@ -1252,14 +1245,14 @@ namespace BizHawk.Client.EmuHawk int keyCount = columns.Count(c => c.Name.StartsWith("Key ")); int keysMenusCount = (int)Math.Ceiling((double)keyCount / maxRows); - ToolStripMenuItem[] keysMenus = new ToolStripMenuItem[keysMenusCount]; + var keysMenus = new ToolStripMenuItem[keysMenusCount]; for (int i = 0; i < keysMenus.Length; i++) { keysMenus[i] = new ToolStripMenuItem(); } - ToolStripMenuItem[] playerMenus = new ToolStripMenuItem[Emulator.ControllerDefinition.PlayerCount + 1]; + var playerMenus = new ToolStripMenuItem[Emulator.ControllerDefinition.PlayerCount + 1]; playerMenus[0] = ColumnsSubMenu; for (int i = 1; i < playerMenus.Length; i++) @@ -1269,7 +1262,7 @@ namespace BizHawk.Client.EmuHawk foreach (var column in columns) { - ToolStripMenuItem menuItem = new ToolStripMenuItem + var menuItem = new ToolStripMenuItem { Text = $"{column.Text} ({column.Name})", Checked = column.Visible, @@ -1279,13 +1272,13 @@ namespace BizHawk.Client.EmuHawk menuItem.CheckedChanged += (o, ev) => { - ToolStripMenuItem sender = o as ToolStripMenuItem; + ToolStripMenuItem sender = (ToolStripMenuItem)o; TasView.AllColumns.Find(c => c.Name == (string)sender.Tag).Visible = sender.Checked; TasView.AllColumns.ColumnsChanged(); CurrentTasMovie.FlagChanges(); RefreshTasView(); ColumnsSubMenu.ShowDropDown(); - (sender.OwnerItem as ToolStripMenuItem).ShowDropDown(); + ((ToolStripMenuItem)sender.OwnerItem).ShowDropDown(); }; if (column.Name.StartsWith("Key ")) @@ -1312,11 +1305,11 @@ namespace BizHawk.Client.EmuHawk } } - for (int i = 0; i < keysMenus.Length; i++) + foreach (var menu in keysMenus) { - string text = $"Keys ({keysMenus[i].DropDownItems[0].Tag} - {keysMenus[i].DropDownItems[keysMenus[i].DropDownItems.Count - 1].Tag})"; - keysMenus[i].Text = text.Replace("Key ", ""); - ColumnsSubMenu.DropDownItems.Add(keysMenus[i]); + string text = $"Keys ({menu.DropDownItems[0].Tag} - {menu.DropDownItems[menu.DropDownItems.Count - 1].Tag})"; + menu.Text = text.Replace("Key ", ""); + ColumnsSubMenu.DropDownItems.Add(menu); } for (int i = 1; i < playerMenus.Length; i++) @@ -1344,13 +1337,12 @@ namespace BizHawk.Client.EmuHawk Checked = false }; - for (int i = 0; i < keysMenus.Length; i++) + foreach (var menu in keysMenus) { - ToolStripMenuItem dummyObject = keysMenus[i]; + var dummyObject1 = menu; item.CheckedChanged += (o, ev) => { - ToolStripMenuItem sender = o as ToolStripMenuItem; - foreach (ToolStripMenuItem menuItem in dummyObject.DropDownItems) + foreach (ToolStripMenuItem menuItem in dummyObject1.DropDownItems) { menuItem.Checked ^= true; } @@ -1377,7 +1369,6 @@ namespace BizHawk.Client.EmuHawk ToolStripMenuItem dummyObject = playerMenus[i]; item.CheckedChanged += (o, ev) => { - ToolStripMenuItem sender = o as ToolStripMenuItem; foreach (ToolStripMenuItem menuItem in dummyObject.DropDownItems) { menuItem.Checked ^= true; diff --git a/BizHawk.Client.EmuHawk/tools/TAStudio/TAStudio.Navigation.cs b/BizHawk.Client.EmuHawk/tools/TAStudio/TAStudio.Navigation.cs index 92cfc9f365..ff83c74f67 100644 --- a/BizHawk.Client.EmuHawk/tools/TAStudio/TAStudio.Navigation.cs +++ b/BizHawk.Client.EmuHawk/tools/TAStudio/TAStudio.Navigation.cs @@ -78,11 +78,6 @@ namespace BizHawk.Client.EmuHawk } } - public void GoToNextFrame() - { - GoToFrame(Emulator.Frame + 1); - } - public void GoToPreviousMarker() { if (Emulator.Frame > 0) diff --git a/BizHawk.Client.EmuHawk/tools/TAStudio/TAStudio.cs b/BizHawk.Client.EmuHawk/tools/TAStudio/TAStudio.cs index f45de742a6..88166d2401 100644 --- a/BizHawk.Client.EmuHawk/tools/TAStudio/TAStudio.cs +++ b/BizHawk.Client.EmuHawk/tools/TAStudio/TAStudio.cs @@ -892,8 +892,8 @@ namespace BizHawk.Client.EmuHawk else { // GUI users may want to be protected from clobbering their video when skipping around... - // well, users who are rewinding arent. (that gets done through the seeking system in the call above) - // users who are clicking around.. I dont know. + // well, users who are rewinding aren't. (that gets done through the seeking system in the call above) + // users who are clicking around.. I don't know. } } } @@ -1035,11 +1035,6 @@ namespace BizHawk.Client.EmuHawk SetTextProperty(); } - private void LuaConsole_DragEnter(object sender, DragEventArgs e) - { - e.Effect = e.Data.GetDataPresent(DataFormats.FileDrop) ? DragDropEffects.Copy : DragDropEffects.None; - } - private void TAStudio_DragDrop(object sender, DragEventArgs e) { if (!AskSaveChanges()) @@ -1115,13 +1110,7 @@ namespace BizHawk.Client.EmuHawk return false; } - private void TAStudio_KeyDown(object sender, KeyEventArgs e) - { - //if (e.KeyCode == Keys.F) - // TasPlaybackBox.FollowCursor ^= true; - } - - private void MainVertialSplit_SplitterMoved(object sender, SplitterEventArgs e) + private void MainVerticalSplit_SplitterMoved(object sender, SplitterEventArgs e) { Settings.MainVerticalSplitDistance = MainVertialSplit.SplitterDistance; } @@ -1168,12 +1157,7 @@ namespace BizHawk.Client.EmuHawk // Stupid designer protected void DragEnterWrapper(object sender, DragEventArgs e) { - base.GenericDragEnter(sender, e); - } - - private void TasPlaybackBox_Load(object sender, EventArgs e) - { - + GenericDragEnter(sender, e); } } } diff --git a/BizHawk.sln.DotSettings b/BizHawk.sln.DotSettings index e6b55cb2f1..d7b5fb984c 100644 --- a/BizHawk.sln.DotSettings +++ b/BizHawk.sln.DotSettings @@ -182,6 +182,7 @@ True True True + True True True True From f57996182366a17dca5123b3cf769103148d9087 Mon Sep 17 00:00:00 2001 From: adelikat Date: Sun, 27 Oct 2019 10:14:29 -0500 Subject: [PATCH 142/166] marker control - no need to set Color.White, that is the default --- BizHawk.Client.EmuHawk/tools/TAStudio/MarkerControl.cs | 8 -------- 1 file changed, 8 deletions(-) diff --git a/BizHawk.Client.EmuHawk/tools/TAStudio/MarkerControl.cs b/BizHawk.Client.EmuHawk/tools/TAStudio/MarkerControl.cs index 525812c8b5..20473abe85 100644 --- a/BizHawk.Client.EmuHawk/tools/TAStudio/MarkerControl.cs +++ b/BizHawk.Client.EmuHawk/tools/TAStudio/MarkerControl.cs @@ -70,14 +70,6 @@ namespace BizHawk.Client.EmuHawk color = column.Name == "LabelColumn" ? TAStudio.GreenZone_FrameCol : TAStudio.GreenZone_InputLog; } } - else - { - color = Color.White; - } - } - else - { - color = Color.White; } } From 2fece04b5adc80daafddedda69f7f178b2ca7cc5 Mon Sep 17 00:00:00 2001 From: adelikat Date: Sun, 27 Oct 2019 10:35:29 -0500 Subject: [PATCH 143/166] set DeveloperBuild back to true --- Version/VersionInfo.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Version/VersionInfo.cs b/Version/VersionInfo.cs index 4517d707f7..b2114a1dde 100644 --- a/Version/VersionInfo.cs +++ b/Version/VersionInfo.cs @@ -5,7 +5,7 @@ internal static class VersionInfo // keep this updated at every major release public const string Mainversion = "2.3.2"; // Use numbers only or the new version notification won't work public static readonly string RELEASEDATE = "June 18, 2019"; - public static readonly bool DeveloperBuild = false; + public static readonly bool DeveloperBuild = true; public static readonly string HomePage = "http://tasvideos.org/BizHawk.html"; public static readonly string CustomBuildString; From 12c64dc40dd175ef0a06aedd62b0f5528cc7d373 Mon Sep 17 00:00:00 2001 From: "J.D. Purcell" Date: Sun, 27 Oct 2019 11:45:42 -0400 Subject: [PATCH 144/166] InputRoll: Fix text clipping too early with GDI+ renderer. --- .../CustomControls/InputRoll/InputRoll.cs | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/BizHawk.Client.EmuHawk/CustomControls/InputRoll/InputRoll.cs b/BizHawk.Client.EmuHawk/CustomControls/InputRoll/InputRoll.cs index 9ea372f611..7488101d84 100644 --- a/BizHawk.Client.EmuHawk/CustomControls/InputRoll/InputRoll.cs +++ b/BizHawk.Client.EmuHawk/CustomControls/InputRoll/InputRoll.cs @@ -91,7 +91,13 @@ namespace BizHawk.Client.EmuHawk using (var g = CreateGraphics()) using (_renderer.LockGraphics(g, Width, Height)) { - _charSize = _renderer.MeasureString("A", _font); // TODO make this a property so changing it updates other values. + // Set font + _renderer.PrepDrawString(_font, _foreColor); + + // Measure width change to ignore extra padding at start/end + var size1 = _renderer.MeasureString("A", _font); + var size2 = _renderer.MeasureString("AA", _font); + _charSize = new Size(size2.Width - size1.Width, size1.Height); // TODO make this a property so changing it updates other values. } UpdateCellSize(); From 924618ee8f218db6803aa59a0e479b83aecd4619 Mon Sep 17 00:00:00 2001 From: adelikat Date: Sun, 27 Oct 2019 10:54:29 -0500 Subject: [PATCH 145/166] Set resharper language level to 7, add some emulator lingo to the resharper dictionary --- .../BizHawk.Client.ApiHawk.csproj.DotSettings | 2 +- .../BizHawk.Client.Common.csproj.DotSettings | 2 +- .../BizHawk.Client.DBMan.csproj.DotSettings | 2 +- ...izHawk.Client.DiscoHawk.csproj.DotSettings | 2 +- .../BizHawk.Client.EmuHawk.csproj.DotSettings | 2 +- .../BizHawk.Common.csproj.DotSettings | 2 +- ...izHawk.Emulation.Common.csproj.DotSettings | 2 +- ...BizHawk.Emulation.Cores.csproj.DotSettings | 2 +- ...wk.Emulation.DiscSystem.csproj.DotSettings | 2 +- BizHawk.sln.DotSettings | 32 ++++++++++++++++++- ...zware.BizwareGL.GdiPlus.csproj.DotSettings | 2 +- ...izware.BizwareGL.OpenTK.csproj.DotSettings | 2 +- ...izware.BizwareGL.SlimDX.csproj.DotSettings | 2 +- ...zHawk.Bizware.BizwareGL.csproj.DotSettings | 2 +- Version/Version.csproj.DotSettings | 2 +- 15 files changed, 45 insertions(+), 15 deletions(-) diff --git a/BizHawk.Client.ApiHawk/BizHawk.Client.ApiHawk.csproj.DotSettings b/BizHawk.Client.ApiHawk/BizHawk.Client.ApiHawk.csproj.DotSettings index 73e96563f9..c54c126d26 100644 --- a/BizHawk.Client.ApiHawk/BizHawk.Client.ApiHawk.csproj.DotSettings +++ b/BizHawk.Client.ApiHawk/BizHawk.Client.ApiHawk.csproj.DotSettings @@ -1,2 +1,2 @@  - CSharp60 \ No newline at end of file + CSharp70 \ No newline at end of file diff --git a/BizHawk.Client.Common/BizHawk.Client.Common.csproj.DotSettings b/BizHawk.Client.Common/BizHawk.Client.Common.csproj.DotSettings index 73e96563f9..c54c126d26 100644 --- a/BizHawk.Client.Common/BizHawk.Client.Common.csproj.DotSettings +++ b/BizHawk.Client.Common/BizHawk.Client.Common.csproj.DotSettings @@ -1,2 +1,2 @@  - CSharp60 \ No newline at end of file + CSharp70 \ No newline at end of file diff --git a/BizHawk.Client.DBMan/BizHawk.Client.DBMan.csproj.DotSettings b/BizHawk.Client.DBMan/BizHawk.Client.DBMan.csproj.DotSettings index 73e96563f9..c54c126d26 100644 --- a/BizHawk.Client.DBMan/BizHawk.Client.DBMan.csproj.DotSettings +++ b/BizHawk.Client.DBMan/BizHawk.Client.DBMan.csproj.DotSettings @@ -1,2 +1,2 @@  - CSharp60 \ No newline at end of file + CSharp70 \ No newline at end of file diff --git a/BizHawk.Client.DiscoHawk/BizHawk.Client.DiscoHawk.csproj.DotSettings b/BizHawk.Client.DiscoHawk/BizHawk.Client.DiscoHawk.csproj.DotSettings index 73e96563f9..c54c126d26 100644 --- a/BizHawk.Client.DiscoHawk/BizHawk.Client.DiscoHawk.csproj.DotSettings +++ b/BizHawk.Client.DiscoHawk/BizHawk.Client.DiscoHawk.csproj.DotSettings @@ -1,2 +1,2 @@  - CSharp60 \ No newline at end of file + CSharp70 \ No newline at end of file diff --git a/BizHawk.Client.EmuHawk/BizHawk.Client.EmuHawk.csproj.DotSettings b/BizHawk.Client.EmuHawk/BizHawk.Client.EmuHawk.csproj.DotSettings index 73e96563f9..c54c126d26 100644 --- a/BizHawk.Client.EmuHawk/BizHawk.Client.EmuHawk.csproj.DotSettings +++ b/BizHawk.Client.EmuHawk/BizHawk.Client.EmuHawk.csproj.DotSettings @@ -1,2 +1,2 @@  - CSharp60 \ No newline at end of file + CSharp70 \ No newline at end of file diff --git a/BizHawk.Common/BizHawk.Common.csproj.DotSettings b/BizHawk.Common/BizHawk.Common.csproj.DotSettings index 73e96563f9..c54c126d26 100644 --- a/BizHawk.Common/BizHawk.Common.csproj.DotSettings +++ b/BizHawk.Common/BizHawk.Common.csproj.DotSettings @@ -1,2 +1,2 @@  - CSharp60 \ No newline at end of file + CSharp70 \ No newline at end of file diff --git a/BizHawk.Emulation.Common/BizHawk.Emulation.Common.csproj.DotSettings b/BizHawk.Emulation.Common/BizHawk.Emulation.Common.csproj.DotSettings index 73e96563f9..c54c126d26 100644 --- a/BizHawk.Emulation.Common/BizHawk.Emulation.Common.csproj.DotSettings +++ b/BizHawk.Emulation.Common/BizHawk.Emulation.Common.csproj.DotSettings @@ -1,2 +1,2 @@  - CSharp60 \ No newline at end of file + CSharp70 \ No newline at end of file diff --git a/BizHawk.Emulation.Cores/BizHawk.Emulation.Cores.csproj.DotSettings b/BizHawk.Emulation.Cores/BizHawk.Emulation.Cores.csproj.DotSettings index 6e05d923f6..ae23115e0a 100644 --- a/BizHawk.Emulation.Cores/BizHawk.Emulation.Cores.csproj.DotSettings +++ b/BizHawk.Emulation.Cores/BizHawk.Emulation.Cores.csproj.DotSettings @@ -1,5 +1,5 @@  - CSharp60 + CSharp70 DO_NOT_SHOW \ No newline at end of file diff --git a/BizHawk.Emulation.DiscSystem/BizHawk.Emulation.DiscSystem.csproj.DotSettings b/BizHawk.Emulation.DiscSystem/BizHawk.Emulation.DiscSystem.csproj.DotSettings index 73e96563f9..c54c126d26 100644 --- a/BizHawk.Emulation.DiscSystem/BizHawk.Emulation.DiscSystem.csproj.DotSettings +++ b/BizHawk.Emulation.DiscSystem/BizHawk.Emulation.DiscSystem.csproj.DotSettings @@ -1,2 +1,2 @@  - CSharp60 \ No newline at end of file + CSharp70 \ No newline at end of file diff --git a/BizHawk.sln.DotSettings b/BizHawk.sln.DotSettings index d7b5fb984c..be11f16d90 100644 --- a/BizHawk.sln.DotSettings +++ b/BizHawk.sln.DotSettings @@ -178,34 +178,64 @@ True True True + True True True True True True True + True + True + True + True True True True + True True + True + True True True True + True + True True True True True + True + True + True + True + True True True + True + True + True + True + True + True + True True True True True + True True True True True True True - True + True + True + True + True + True + True + True + True \ No newline at end of file diff --git a/Bizware/BizHawk.Bizware.BizwareGL.GdiPlus/BizHawk.Bizware.BizwareGL.GdiPlus.csproj.DotSettings b/Bizware/BizHawk.Bizware.BizwareGL.GdiPlus/BizHawk.Bizware.BizwareGL.GdiPlus.csproj.DotSettings index 73e96563f9..c54c126d26 100644 --- a/Bizware/BizHawk.Bizware.BizwareGL.GdiPlus/BizHawk.Bizware.BizwareGL.GdiPlus.csproj.DotSettings +++ b/Bizware/BizHawk.Bizware.BizwareGL.GdiPlus/BizHawk.Bizware.BizwareGL.GdiPlus.csproj.DotSettings @@ -1,2 +1,2 @@  - CSharp60 \ No newline at end of file + CSharp70 \ No newline at end of file diff --git a/Bizware/BizHawk.Bizware.BizwareGL.OpenTK/BizHawk.Bizware.BizwareGL.OpenTK.csproj.DotSettings b/Bizware/BizHawk.Bizware.BizwareGL.OpenTK/BizHawk.Bizware.BizwareGL.OpenTK.csproj.DotSettings index 73e96563f9..c54c126d26 100644 --- a/Bizware/BizHawk.Bizware.BizwareGL.OpenTK/BizHawk.Bizware.BizwareGL.OpenTK.csproj.DotSettings +++ b/Bizware/BizHawk.Bizware.BizwareGL.OpenTK/BizHawk.Bizware.BizwareGL.OpenTK.csproj.DotSettings @@ -1,2 +1,2 @@  - CSharp60 \ No newline at end of file + CSharp70 \ No newline at end of file diff --git a/Bizware/BizHawk.Bizware.BizwareGL.SlimDX/BizHawk.Bizware.BizwareGL.SlimDX.csproj.DotSettings b/Bizware/BizHawk.Bizware.BizwareGL.SlimDX/BizHawk.Bizware.BizwareGL.SlimDX.csproj.DotSettings index 73e96563f9..c54c126d26 100644 --- a/Bizware/BizHawk.Bizware.BizwareGL.SlimDX/BizHawk.Bizware.BizwareGL.SlimDX.csproj.DotSettings +++ b/Bizware/BizHawk.Bizware.BizwareGL.SlimDX/BizHawk.Bizware.BizwareGL.SlimDX.csproj.DotSettings @@ -1,2 +1,2 @@  - CSharp60 \ No newline at end of file + CSharp70 \ No newline at end of file diff --git a/Bizware/BizHawk.Bizware.BizwareGL/BizHawk.Bizware.BizwareGL.csproj.DotSettings b/Bizware/BizHawk.Bizware.BizwareGL/BizHawk.Bizware.BizwareGL.csproj.DotSettings index 73e96563f9..c54c126d26 100644 --- a/Bizware/BizHawk.Bizware.BizwareGL/BizHawk.Bizware.BizwareGL.csproj.DotSettings +++ b/Bizware/BizHawk.Bizware.BizwareGL/BizHawk.Bizware.BizwareGL.csproj.DotSettings @@ -1,2 +1,2 @@  - CSharp60 \ No newline at end of file + CSharp70 \ No newline at end of file diff --git a/Version/Version.csproj.DotSettings b/Version/Version.csproj.DotSettings index 73e96563f9..c54c126d26 100644 --- a/Version/Version.csproj.DotSettings +++ b/Version/Version.csproj.DotSettings @@ -1,2 +1,2 @@  - CSharp60 \ No newline at end of file + CSharp70 \ No newline at end of file From 3dfb0d39c8bbddc07f2eaec98b7a19a6b78068da Mon Sep 17 00:00:00 2001 From: "J.D. Purcell" Date: Sun, 27 Oct 2019 12:05:06 -0400 Subject: [PATCH 146/166] AppVeyor test (C# 8.0?) --- BizHawk.Client.EmuHawk/BizHawk.Client.EmuHawk.csproj | 1 + BizHawk.Client.EmuHawk/EmuHawkUtil.cs | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/BizHawk.Client.EmuHawk/BizHawk.Client.EmuHawk.csproj b/BizHawk.Client.EmuHawk/BizHawk.Client.EmuHawk.csproj index 2251812747..fbfcb642fe 100644 --- a/BizHawk.Client.EmuHawk/BizHawk.Client.EmuHawk.csproj +++ b/BizHawk.Client.EmuHawk/BizHawk.Client.EmuHawk.csproj @@ -38,6 +38,7 @@ true None true + 8.0 app.manifest diff --git a/BizHawk.Client.EmuHawk/EmuHawkUtil.cs b/BizHawk.Client.EmuHawk/EmuHawkUtil.cs index 41ed03e16f..3bd9ea51b3 100644 --- a/BizHawk.Client.EmuHawk/EmuHawkUtil.cs +++ b/BizHawk.Client.EmuHawk/EmuHawkUtil.cs @@ -12,7 +12,7 @@ namespace BizHawk.Client.EmuHawk { public static bool EnsureCoreIsAccurate(IEmulator emulator) { - bool PromptToSwitchCore(string currentCore, string recommendedCore, Action disableCurrentCore) + static bool PromptToSwitchCore(string currentCore, string recommendedCore, Action disableCurrentCore) { var box = new MsgBox( $"While the {currentCore} core is faster, it is not nearly as accurate as {recommendedCore}.{Environment.NewLine}It is recommended that you switch to the {recommendedCore} core for movie recording. {Environment.NewLine}Switch to {recommendedCore}?", From 69edada441ab7767356531f76ebb5961fa96def9 Mon Sep 17 00:00:00 2001 From: "J.D. Purcell" Date: Sun, 27 Oct 2019 12:14:19 -0400 Subject: [PATCH 147/166] Set LangVersion to 8.0. Requires Visual Studio 2019 with 16.3+ update installed. --- BizHawk.Client.ApiHawk/BizHawk.Client.ApiHawk.csproj | 1 + BizHawk.Client.Common/BizHawk.Client.Common.csproj | 1 + BizHawk.Client.DBMan/BizHawk.Client.DBMan.csproj | 1 + BizHawk.Client.DiscoHawk/BizHawk.Client.DiscoHawk.csproj | 1 + BizHawk.Common/BizHawk.Common.csproj | 1 + BizHawk.Emulation.Common/BizHawk.Emulation.Common.csproj | 1 + BizHawk.Emulation.Cores/BizHawk.Emulation.Cores.csproj | 1 + BizHawk.Emulation.DiscSystem/BizHawk.Emulation.DiscSystem.csproj | 1 + .../BizHawk.Bizware.BizwareGL.GdiPlus.csproj | 1 + .../BizHawk.Bizware.BizwareGL.OpenTK.csproj | 1 + .../BizHawk.Bizware.BizwareGL.SlimDX.csproj | 1 + .../BizHawk.Bizware.BizwareGL/BizHawk.Bizware.BizwareGL.csproj | 1 + Version/Version.csproj | 1 + 13 files changed, 13 insertions(+) diff --git a/BizHawk.Client.ApiHawk/BizHawk.Client.ApiHawk.csproj b/BizHawk.Client.ApiHawk/BizHawk.Client.ApiHawk.csproj index e80de5d5ae..06dc0b4412 100644 --- a/BizHawk.Client.ApiHawk/BizHawk.Client.ApiHawk.csproj +++ b/BizHawk.Client.ApiHawk/BizHawk.Client.ApiHawk.csproj @@ -33,6 +33,7 @@ v4.6.1 512 + 8.0 1591 diff --git a/BizHawk.Client.Common/BizHawk.Client.Common.csproj b/BizHawk.Client.Common/BizHawk.Client.Common.csproj index de8ff5983c..23ee9e52b8 100644 --- a/BizHawk.Client.Common/BizHawk.Client.Common.csproj +++ b/BizHawk.Client.Common/BizHawk.Client.Common.csproj @@ -13,6 +13,7 @@ v4.6.1 512 + 8.0 None diff --git a/BizHawk.Client.DBMan/BizHawk.Client.DBMan.csproj b/BizHawk.Client.DBMan/BizHawk.Client.DBMan.csproj index e65442660a..6d14eca92e 100644 --- a/BizHawk.Client.DBMan/BizHawk.Client.DBMan.csproj +++ b/BizHawk.Client.DBMan/BizHawk.Client.DBMan.csproj @@ -39,6 +39,7 @@ 512 true + 8.0 diff --git a/BizHawk.Client.DiscoHawk/BizHawk.Client.DiscoHawk.csproj b/BizHawk.Client.DiscoHawk/BizHawk.Client.DiscoHawk.csproj index 19809199c9..e45f56b5ce 100644 --- a/BizHawk.Client.DiscoHawk/BizHawk.Client.DiscoHawk.csproj +++ b/BizHawk.Client.DiscoHawk/BizHawk.Client.DiscoHawk.csproj @@ -32,6 +32,7 @@ false true + 8.0 true diff --git a/BizHawk.Common/BizHawk.Common.csproj b/BizHawk.Common/BizHawk.Common.csproj index 2a93d8a56f..4783b3c4e0 100644 --- a/BizHawk.Common/BizHawk.Common.csproj +++ b/BizHawk.Common/BizHawk.Common.csproj @@ -13,6 +13,7 @@ v4.6.1 512 + 8.0 true diff --git a/BizHawk.Emulation.Common/BizHawk.Emulation.Common.csproj b/BizHawk.Emulation.Common/BizHawk.Emulation.Common.csproj index 7287faab8b..5dfecb7cfa 100644 --- a/BizHawk.Emulation.Common/BizHawk.Emulation.Common.csproj +++ b/BizHawk.Emulation.Common/BizHawk.Emulation.Common.csproj @@ -38,6 +38,7 @@ v4.6.1 512 + 8.0 diff --git a/BizHawk.Emulation.Cores/BizHawk.Emulation.Cores.csproj b/BizHawk.Emulation.Cores/BizHawk.Emulation.Cores.csproj index f589bfa790..882192d4e9 100644 --- a/BizHawk.Emulation.Cores/BizHawk.Emulation.Cores.csproj +++ b/BizHawk.Emulation.Cores/BizHawk.Emulation.Cores.csproj @@ -32,6 +32,7 @@ false true + 8.0 true diff --git a/BizHawk.Emulation.DiscSystem/BizHawk.Emulation.DiscSystem.csproj b/BizHawk.Emulation.DiscSystem/BizHawk.Emulation.DiscSystem.csproj index deb41e4f0d..53c1fa2faa 100644 --- a/BizHawk.Emulation.DiscSystem/BizHawk.Emulation.DiscSystem.csproj +++ b/BizHawk.Emulation.DiscSystem/BizHawk.Emulation.DiscSystem.csproj @@ -38,6 +38,7 @@ v4.6.1 512 + 8.0 diff --git a/Bizware/BizHawk.Bizware.BizwareGL.GdiPlus/BizHawk.Bizware.BizwareGL.GdiPlus.csproj b/Bizware/BizHawk.Bizware.BizwareGL.GdiPlus/BizHawk.Bizware.BizwareGL.GdiPlus.csproj index d672923fe1..0e72db75f6 100644 --- a/Bizware/BizHawk.Bizware.BizwareGL.GdiPlus/BizHawk.Bizware.BizwareGL.GdiPlus.csproj +++ b/Bizware/BizHawk.Bizware.BizwareGL.GdiPlus/BizHawk.Bizware.BizwareGL.GdiPlus.csproj @@ -13,6 +13,7 @@ v4.6.1 512 + 8.0 true diff --git a/Bizware/BizHawk.Bizware.BizwareGL.OpenTK/BizHawk.Bizware.BizwareGL.OpenTK.csproj b/Bizware/BizHawk.Bizware.BizwareGL.OpenTK/BizHawk.Bizware.BizwareGL.OpenTK.csproj index 2f55beb615..f5eb241bec 100644 --- a/Bizware/BizHawk.Bizware.BizwareGL.OpenTK/BizHawk.Bizware.BizwareGL.OpenTK.csproj +++ b/Bizware/BizHawk.Bizware.BizwareGL.OpenTK/BizHawk.Bizware.BizwareGL.OpenTK.csproj @@ -13,6 +13,7 @@ v4.6.1 512 + 8.0 true diff --git a/Bizware/BizHawk.Bizware.BizwareGL.SlimDX/BizHawk.Bizware.BizwareGL.SlimDX.csproj b/Bizware/BizHawk.Bizware.BizwareGL.SlimDX/BizHawk.Bizware.BizwareGL.SlimDX.csproj index cf7d477acb..0da773623b 100644 --- a/Bizware/BizHawk.Bizware.BizwareGL.SlimDX/BizHawk.Bizware.BizwareGL.SlimDX.csproj +++ b/Bizware/BizHawk.Bizware.BizwareGL.SlimDX/BizHawk.Bizware.BizwareGL.SlimDX.csproj @@ -13,6 +13,7 @@ v4.6.1 512 + 8.0 true diff --git a/Bizware/BizHawk.Bizware.BizwareGL/BizHawk.Bizware.BizwareGL.csproj b/Bizware/BizHawk.Bizware.BizwareGL/BizHawk.Bizware.BizwareGL.csproj index 91d0f9902d..bf7f208770 100644 --- a/Bizware/BizHawk.Bizware.BizwareGL/BizHawk.Bizware.BizwareGL.csproj +++ b/Bizware/BizHawk.Bizware.BizwareGL/BizHawk.Bizware.BizwareGL.csproj @@ -13,6 +13,7 @@ v4.6.1 512 + 8.0 true diff --git a/Version/Version.csproj b/Version/Version.csproj index 85cf67cfdb..a09fa674e8 100644 --- a/Version/Version.csproj +++ b/Version/Version.csproj @@ -15,6 +15,7 @@ v4.6.1 512 + 8.0 true From 3e64051c7d787140580f42308a264473a17bf410 Mon Sep 17 00:00:00 2001 From: adelikat Date: Sun, 27 Oct 2019 11:42:05 -0500 Subject: [PATCH 148/166] Mainform - cleanups, remove unused code, typos, C#7isms --- BizHawk.Client.EmuHawk/MainForm.Designer.cs | 971 ++++++++++---------- BizHawk.Client.EmuHawk/MainForm.Events.cs | 497 +++++----- BizHawk.Client.EmuHawk/MainForm.cs | 403 ++++---- BizHawk.sln.DotSettings | 27 + 4 files changed, 941 insertions(+), 957 deletions(-) diff --git a/BizHawk.Client.EmuHawk/MainForm.Designer.cs b/BizHawk.Client.EmuHawk/MainForm.Designer.cs index 83c8c0544a..0d8d91dfff 100644 --- a/BizHawk.Client.EmuHawk/MainForm.Designer.cs +++ b/BizHawk.Client.EmuHawk/MainForm.Designer.cs @@ -496,42 +496,42 @@ // this.MainformMenu.ClickThrough = true; this.MainformMenu.Items.AddRange(new System.Windows.Forms.ToolStripItem[] { - this.FileSubMenu, - this.EmulationSubMenu, - this.ViewSubMenu, - this.ConfigSubMenu, - this.ToolsSubMenu, - this.NESSubMenu, - this.PCESubMenu, - this.SMSSubMenu, - this.TI83SubMenu, - this.AtariSubMenu, - this.A7800SubMenu, - this.GBSubMenu, - this.GBASubMenu, - this.PSXSubMenu, - this.SNESSubMenu, - this.ColecoSubMenu, - this.N64SubMenu, - this.SaturnSubMenu, - this.DGBSubMenu, - this.DGBHawkSubMenu, + this.FileSubMenu, + this.EmulationSubMenu, + this.ViewSubMenu, + this.ConfigSubMenu, + this.ToolsSubMenu, + this.NESSubMenu, + this.PCESubMenu, + this.SMSSubMenu, + this.TI83SubMenu, + this.AtariSubMenu, + this.A7800SubMenu, + this.GBSubMenu, + this.GBASubMenu, + this.PSXSubMenu, + this.SNESSubMenu, + this.ColecoSubMenu, + this.N64SubMenu, + this.SaturnSubMenu, + this.DGBSubMenu, + this.DGBHawkSubMenu, this.GB3xSubMenu, this.GB4xSubMenu, this.GGLSubMenu, - this.GenesisSubMenu, - this.wonderSwanToolStripMenuItem, - this.AppleSubMenu, - this.C64SubMenu, - this.IntvSubMenu, - this.sNESToolStripMenuItem, - this.pCFXToolStripMenuItem, - this.virtualBoyToolStripMenuItem, - this.neoGeoPocketToolStripMenuItem, - this.zXSpectrumToolStripMenuItem, + this.GenesisSubMenu, + this.wonderSwanToolStripMenuItem, + this.AppleSubMenu, + this.C64SubMenu, + this.IntvSubMenu, + this.sNESToolStripMenuItem, + this.pCFXToolStripMenuItem, + this.virtualBoyToolStripMenuItem, + this.neoGeoPocketToolStripMenuItem, + this.zXSpectrumToolStripMenuItem, this.VectrexSubMenu, - this.HelpSubMenu, - this.amstradCPCToolStripMenuItem}); + this.HelpSubMenu, + this.amstradCPCToolStripMenuItem}); this.MainformMenu.LayoutStyle = System.Windows.Forms.ToolStripLayoutStyle.Flow; this.MainformMenu.Location = new System.Drawing.Point(0, 0); this.MainformMenu.Name = "MainformMenu"; @@ -545,21 +545,21 @@ // FileSubMenu // this.FileSubMenu.DropDownItems.AddRange(new System.Windows.Forms.ToolStripItem[] { - this.OpenRomMenuItem, - this.RecentRomSubMenu, - this.OpenAdvancedMenuItem, - this.CloseRomMenuItem, - this.toolStripMenuItem1, - this.SaveStateSubMenu, - this.LoadStateSubMenu, - this.SaveSlotSubMenu, - this.SaveRAMSubMenu, - this.toolStripMenuItem2, - this.MovieSubMenu, - this.AVSubMenu, - this.ScreenshotSubMenu, - this.toolStripSeparator4, - this.ExitMenuItem}); + this.OpenRomMenuItem, + this.RecentRomSubMenu, + this.OpenAdvancedMenuItem, + this.CloseRomMenuItem, + this.toolStripMenuItem1, + this.SaveStateSubMenu, + this.LoadStateSubMenu, + this.SaveSlotSubMenu, + this.SaveRAMSubMenu, + this.toolStripMenuItem2, + this.MovieSubMenu, + this.AVSubMenu, + this.ScreenshotSubMenu, + this.toolStripSeparator4, + this.ExitMenuItem}); this.FileSubMenu.Name = "FileSubMenu"; this.FileSubMenu.Size = new System.Drawing.Size(37, 19); this.FileSubMenu.Text = "&File"; @@ -576,7 +576,7 @@ // RecentRomSubMenu // this.RecentRomSubMenu.DropDownItems.AddRange(new System.Windows.Forms.ToolStripItem[] { - this.toolStripSeparator3}); + this.toolStripSeparator3}); this.RecentRomSubMenu.Image = global::BizHawk.Client.EmuHawk.Properties.Resources.Recent; this.RecentRomSubMenu.Name = "RecentRomSubMenu"; this.RecentRomSubMenu.Size = new System.Drawing.Size(159, 22); @@ -611,18 +611,18 @@ // SaveStateSubMenu // this.SaveStateSubMenu.DropDownItems.AddRange(new System.Windows.Forms.ToolStripItem[] { - this.SaveState1MenuItem, - this.SaveState2MenuItem, - this.SaveState3MenuItem, - this.SaveState4MenuItem, - this.SaveState5MenuItem, - this.SaveState6MenuItem, - this.SaveState7MenuItem, - this.SaveState8MenuItem, - this.SaveState9MenuItem, - this.SaveState0MenuItem, - this.toolStripSeparator6, - this.SaveNamedStateMenuItem}); + this.SaveState1MenuItem, + this.SaveState2MenuItem, + this.SaveState3MenuItem, + this.SaveState4MenuItem, + this.SaveState5MenuItem, + this.SaveState6MenuItem, + this.SaveState7MenuItem, + this.SaveState8MenuItem, + this.SaveState9MenuItem, + this.SaveState0MenuItem, + this.toolStripSeparator6, + this.SaveNamedStateMenuItem}); this.SaveStateSubMenu.Name = "SaveStateSubMenu"; this.SaveStateSubMenu.Size = new System.Drawing.Size(159, 22); this.SaveStateSubMenu.Text = "&Save State"; @@ -713,20 +713,20 @@ // LoadStateSubMenu // this.LoadStateSubMenu.DropDownItems.AddRange(new System.Windows.Forms.ToolStripItem[] { - this.LoadState1MenuItem, - this.LoadState2MenuItem, - this.LoadState3MenuItem, - this.LoadState4MenuItem, - this.LoadState5MenuItem, - this.LoadState6MenuItem, - this.LoadState7MenuItem, - this.LoadState8MenuItem, - this.LoadState9MenuItem, - this.LoadState0MenuItem, - this.toolStripSeparator7, - this.LoadNamedStateMenuItem, - this.toolStripSeparator21, - this.AutoloadLastSlotMenuItem}); + this.LoadState1MenuItem, + this.LoadState2MenuItem, + this.LoadState3MenuItem, + this.LoadState4MenuItem, + this.LoadState5MenuItem, + this.LoadState6MenuItem, + this.LoadState7MenuItem, + this.LoadState8MenuItem, + this.LoadState9MenuItem, + this.LoadState0MenuItem, + this.toolStripSeparator7, + this.LoadNamedStateMenuItem, + this.toolStripSeparator21, + this.AutoloadLastSlotMenuItem}); this.LoadStateSubMenu.Name = "LoadStateSubMenu"; this.LoadStateSubMenu.Size = new System.Drawing.Size(159, 22); this.LoadStateSubMenu.Text = "&Load State"; @@ -829,21 +829,21 @@ // SaveSlotSubMenu // this.SaveSlotSubMenu.DropDownItems.AddRange(new System.Windows.Forms.ToolStripItem[] { - this.SelectSlot0MenuItem, - this.SelectSlot1MenuItem, - this.SelectSlot2MenuItem, - this.SelectSlot3MenuItem, - this.SelectSlot4MenuItem, - this.SelectSlot5MenuItem, - this.SelectSlot6MenuItem, - this.SelectSlot7MenuItem, - this.SelectSlot8MenuItem, - this.SelectSlot9MenuItem, - this.PreviousSlotMenuItem, - this.NextSlotMenuItem, - this.toolStripSeparator5, - this.SaveToCurrentSlotMenuItem, - this.LoadCurrentSlotMenuItem}); + this.SelectSlot0MenuItem, + this.SelectSlot1MenuItem, + this.SelectSlot2MenuItem, + this.SelectSlot3MenuItem, + this.SelectSlot4MenuItem, + this.SelectSlot5MenuItem, + this.SelectSlot6MenuItem, + this.SelectSlot7MenuItem, + this.SelectSlot8MenuItem, + this.SelectSlot9MenuItem, + this.PreviousSlotMenuItem, + this.NextSlotMenuItem, + this.toolStripSeparator5, + this.SaveToCurrentSlotMenuItem, + this.LoadCurrentSlotMenuItem}); this.SaveSlotSubMenu.Name = "SaveSlotSubMenu"; this.SaveSlotSubMenu.Size = new System.Drawing.Size(159, 22); this.SaveSlotSubMenu.Text = "Save S&lot"; @@ -957,7 +957,7 @@ // SaveRAMSubMenu // this.SaveRAMSubMenu.DropDownItems.AddRange(new System.Windows.Forms.ToolStripItem[] { - this.FlushSaveRAMMenuItem}); + this.FlushSaveRAMMenuItem}); this.SaveRAMSubMenu.Name = "SaveRAMSubMenu"; this.SaveRAMSubMenu.Size = new System.Drawing.Size(159, 22); this.SaveRAMSubMenu.Text = "Save &RAM"; @@ -978,21 +978,21 @@ // MovieSubMenu // this.MovieSubMenu.DropDownItems.AddRange(new System.Windows.Forms.ToolStripItem[] { - this.ReadonlyMenuItem, - this.toolStripSeparator15, - this.RecentMovieSubMenu, - this.RecordMovieMenuItem, - this.PlayMovieMenuItem, - this.StopMovieMenuItem, - this.PlayFromBeginningMenuItem, - this.ImportMoviesMenuItem, - this.SaveMovieMenuItem, - this.SaveMovieAsMenuItem, - this.StopMovieWithoutSavingMenuItem, - this.toolStripSeparator14, - this.AutomaticallyBackupMoviesMenuItem, - this.FullMovieLoadstatesMenuItem, - this.MovieEndSubMenu}); + this.ReadonlyMenuItem, + this.toolStripSeparator15, + this.RecentMovieSubMenu, + this.RecordMovieMenuItem, + this.PlayMovieMenuItem, + this.StopMovieMenuItem, + this.PlayFromBeginningMenuItem, + this.ImportMoviesMenuItem, + this.SaveMovieMenuItem, + this.SaveMovieAsMenuItem, + this.StopMovieWithoutSavingMenuItem, + this.toolStripSeparator14, + this.AutomaticallyBackupMoviesMenuItem, + this.FullMovieLoadstatesMenuItem, + this.MovieEndSubMenu}); this.MovieSubMenu.Name = "MovieSubMenu"; this.MovieSubMenu.Size = new System.Drawing.Size(159, 22); this.MovieSubMenu.Text = "&Movie"; @@ -1014,7 +1014,7 @@ // RecentMovieSubMenu // this.RecentMovieSubMenu.DropDownItems.AddRange(new System.Windows.Forms.ToolStripItem[] { - this.toolStripSeparator16}); + this.toolStripSeparator16}); this.RecentMovieSubMenu.Image = global::BizHawk.Client.EmuHawk.Properties.Resources.Recent; this.RecentMovieSubMenu.Name = "RecentMovieSubMenu"; this.RecentMovieSubMenu.Size = new System.Drawing.Size(231, 22); @@ -1112,10 +1112,10 @@ // MovieEndSubMenu // this.MovieEndSubMenu.DropDownItems.AddRange(new System.Windows.Forms.ToolStripItem[] { - this.MovieEndFinishMenuItem, - this.MovieEndRecordMenuItem, - this.MovieEndStopMenuItem, - this.MovieEndPauseMenuItem}); + this.MovieEndFinishMenuItem, + this.MovieEndRecordMenuItem, + this.MovieEndStopMenuItem, + this.MovieEndPauseMenuItem}); this.MovieEndSubMenu.Name = "MovieEndSubMenu"; this.MovieEndSubMenu.Size = new System.Drawing.Size(231, 22); this.MovieEndSubMenu.Text = "On Movie End"; @@ -1152,12 +1152,12 @@ // AVSubMenu // this.AVSubMenu.DropDownItems.AddRange(new System.Windows.Forms.ToolStripItem[] { - this.RecordAVMenuItem, - this.ConfigAndRecordAVMenuItem, - this.StopAVIMenuItem, - this.toolStripSeparator19, - this.CaptureOSDMenuItem, - this.SynclessRecordingMenuItem}); + this.RecordAVMenuItem, + this.ConfigAndRecordAVMenuItem, + this.StopAVIMenuItem, + this.toolStripSeparator19, + this.CaptureOSDMenuItem, + this.SynclessRecordingMenuItem}); this.AVSubMenu.Name = "AVSubMenu"; this.AVSubMenu.Size = new System.Drawing.Size(159, 22); this.AVSubMenu.Text = "&AVI/WAV"; @@ -1209,12 +1209,12 @@ // ScreenshotSubMenu // this.ScreenshotSubMenu.DropDownItems.AddRange(new System.Windows.Forms.ToolStripItem[] { - this.ScreenshotMenuItem, - this.ScreenshotAsMenuItem, - this.ScreenshotClipboardMenuItem, - this.ScreenshotClientClipboardMenuItem, - this.toolStripSeparator20, - this.ScreenshotCaptureOSDMenuItem1}); + this.ScreenshotMenuItem, + this.ScreenshotAsMenuItem, + this.ScreenshotClipboardMenuItem, + this.ScreenshotClientClipboardMenuItem, + this.toolStripSeparator20, + this.ScreenshotCaptureOSDMenuItem1}); this.ScreenshotSubMenu.Name = "ScreenshotSubMenu"; this.ScreenshotSubMenu.Size = new System.Drawing.Size(159, 22); this.ScreenshotSubMenu.Text = "Scree&nshot"; @@ -1277,11 +1277,11 @@ // EmulationSubMenu // this.EmulationSubMenu.DropDownItems.AddRange(new System.Windows.Forms.ToolStripItem[] { - this.PauseMenuItem, - this.RebootCoreMenuItem, - this.toolStripSeparator1, - this.SoftResetMenuItem, - this.HardResetMenuItem}); + this.PauseMenuItem, + this.RebootCoreMenuItem, + this.toolStripSeparator1, + this.SoftResetMenuItem, + this.HardResetMenuItem}); this.EmulationSubMenu.Name = "EmulationSubMenu"; this.EmulationSubMenu.Size = new System.Drawing.Size(73, 19); this.EmulationSubMenu.Text = "&Emulation"; @@ -1325,19 +1325,19 @@ // ViewSubMenu // this.ViewSubMenu.DropDownItems.AddRange(new System.Windows.Forms.ToolStripItem[] { - this.WindowSizeSubMenu, - this.SwitchToFullscreenMenuItem, - this.toolStripSeparator2, - this.DisplayFPSMenuItem, - this.DisplayFrameCounterMenuItem, - this.DisplayLagCounterMenuItem, - this.DisplayInputMenuItem, - this.DisplayRerecordCountMenuItem, - this.DisplaySubtitlesMenuItem, - this.toolStripMenuItem4, - this.DisplayStatusBarMenuItem, - this.DisplayMessagesMenuItem, - this.DisplayLogWindowMenuItem}); + this.WindowSizeSubMenu, + this.SwitchToFullscreenMenuItem, + this.toolStripSeparator2, + this.DisplayFPSMenuItem, + this.DisplayFrameCounterMenuItem, + this.DisplayLagCounterMenuItem, + this.DisplayInputMenuItem, + this.DisplayRerecordCountMenuItem, + this.DisplaySubtitlesMenuItem, + this.toolStripMenuItem4, + this.DisplayStatusBarMenuItem, + this.DisplayMessagesMenuItem, + this.DisplayLogWindowMenuItem}); this.ViewSubMenu.Name = "ViewSubMenu"; this.ViewSubMenu.Size = new System.Drawing.Size(44, 19); this.ViewSubMenu.Text = "&View"; @@ -1346,12 +1346,12 @@ // WindowSizeSubMenu // this.WindowSizeSubMenu.DropDownItems.AddRange(new System.Windows.Forms.ToolStripItem[] { - this.x1MenuItem, - this.x2MenuItem, - this.x3MenuItem, - this.x4MenuItem, - this.x5MenuItem, - this.mzMenuItem}); + this.x1MenuItem, + this.x2MenuItem, + this.x3MenuItem, + this.x4MenuItem, + this.x5MenuItem, + this.mzMenuItem}); this.WindowSizeSubMenu.Name = "WindowSizeSubMenu"; this.WindowSizeSubMenu.Size = new System.Drawing.Size(198, 22); this.WindowSizeSubMenu.Text = "&Window Size"; @@ -1483,27 +1483,27 @@ // ConfigSubMenu // this.ConfigSubMenu.DropDownItems.AddRange(new System.Windows.Forms.ToolStripItem[] { - this.ControllersMenuItem, - this.HotkeysMenuItem, - this.DisplayConfigMenuItem, - this.SoundMenuItem, - this.PathsMenuItem, - this.FirmwaresMenuItem, - this.MessagesMenuItem, - this.AutofireMenuItem, - this.RewindOptionsMenuItem, - this.extensionsToolStripMenuItem, - this.ClientOptionsMenuItem, - this.ProfilesMenuItem, - this.toolStripSeparator9, - this.SpeedSkipSubMenu, - this.KeyPrioritySubMenu, - this.CoresSubMenu, - this.toolStripSeparator10, - this.SaveConfigMenuItem, - this.SaveConfigAsMenuItem, - this.LoadConfigMenuItem, - this.LoadConfigFromMenuItem}); + this.ControllersMenuItem, + this.HotkeysMenuItem, + this.DisplayConfigMenuItem, + this.SoundMenuItem, + this.PathsMenuItem, + this.FirmwaresMenuItem, + this.MessagesMenuItem, + this.AutofireMenuItem, + this.RewindOptionsMenuItem, + this.extensionsToolStripMenuItem, + this.ClientOptionsMenuItem, + this.ProfilesMenuItem, + this.toolStripSeparator9, + this.SpeedSkipSubMenu, + this.KeyPrioritySubMenu, + this.CoresSubMenu, + this.toolStripSeparator10, + this.SaveConfigMenuItem, + this.SaveConfigAsMenuItem, + this.LoadConfigMenuItem, + this.LoadConfigFromMenuItem}); this.ConfigSubMenu.Name = "ConfigSubMenu"; this.ConfigSubMenu.Size = new System.Drawing.Size(55, 19); this.ConfigSubMenu.Text = "&Config"; @@ -1611,23 +1611,23 @@ // SpeedSkipSubMenu // this.SpeedSkipSubMenu.DropDownItems.AddRange(new System.Windows.Forms.ToolStripItem[] { - this.ClockThrottleMenuItem, - this.AudioThrottleMenuItem, - this.VsyncThrottleMenuItem, - this.toolStripSeparator27, - this.VsyncEnabledMenuItem, - this.toolStripMenuItem3, - this.miUnthrottled, - this.MinimizeSkippingMenuItem, - this.NeverSkipMenuItem, - this.toolStripMenuItem17, - this.toolStripMenuItem5, - this.Speed50MenuItem, - this.Speed75MenuItem, - this.Speed100MenuItem, - this.Speed150MenuItem, - this.Speed200MenuItem, - this.Speed400MenuItem}); + this.ClockThrottleMenuItem, + this.AudioThrottleMenuItem, + this.VsyncThrottleMenuItem, + this.toolStripSeparator27, + this.VsyncEnabledMenuItem, + this.toolStripMenuItem3, + this.miUnthrottled, + this.MinimizeSkippingMenuItem, + this.NeverSkipMenuItem, + this.toolStripMenuItem17, + this.toolStripMenuItem5, + this.Speed50MenuItem, + this.Speed75MenuItem, + this.Speed100MenuItem, + this.Speed150MenuItem, + this.Speed200MenuItem, + this.Speed400MenuItem}); this.SpeedSkipSubMenu.Name = "SpeedSkipSubMenu"; this.SpeedSkipSubMenu.Size = new System.Drawing.Size(180, 22); this.SpeedSkipSubMenu.Text = "Speed/Skip"; @@ -1695,15 +1695,15 @@ // toolStripMenuItem17 // this.toolStripMenuItem17.DropDownItems.AddRange(new System.Windows.Forms.ToolStripItem[] { - this.Frameskip1MenuItem, - this.Frameskip2MenuItem, - this.Frameskip3MenuItem, - this.Frameskip4MenuItem, - this.Frameskip5MenuItem, - this.Frameskip6MenuItem, - this.Frameskip7MenuItem, - this.Frameskip8MenuItem, - this.Frameskip9MenuItem}); + this.Frameskip1MenuItem, + this.Frameskip2MenuItem, + this.Frameskip3MenuItem, + this.Frameskip4MenuItem, + this.Frameskip5MenuItem, + this.Frameskip6MenuItem, + this.Frameskip7MenuItem, + this.Frameskip8MenuItem, + this.Frameskip9MenuItem}); this.toolStripMenuItem17.Name = "toolStripMenuItem17"; this.toolStripMenuItem17.Size = new System.Drawing.Size(202, 22); this.toolStripMenuItem17.Text = "Skip 1..9"; @@ -1821,9 +1821,9 @@ // KeyPrioritySubMenu // this.KeyPrioritySubMenu.DropDownItems.AddRange(new System.Windows.Forms.ToolStripItem[] { - this.BothHkAndControllerMenuItem, - this.InputOverHkMenuItem, - this.HkOverInputMenuItem}); + this.BothHkAndControllerMenuItem, + this.InputOverHkMenuItem, + this.HkOverInputMenuItem}); this.KeyPrioritySubMenu.Name = "KeyPrioritySubMenu"; this.KeyPrioritySubMenu.Size = new System.Drawing.Size(180, 22); this.KeyPrioritySubMenu.Text = "Key Priority"; @@ -1853,17 +1853,17 @@ // CoresSubMenu // this.CoresSubMenu.DropDownItems.AddRange(new System.Windows.Forms.ToolStripItem[] { - this.NesCoreSubMenu, - this.CoreSNESSubMenu, - this.GbaCoreSubMenu, - this.SGBCoreSubmenu, - this.GBCoreSubmenu, - this.GBInSGBMenuItem, - this.toolStripMenuItem16, - this.allowGameDBCoreOverridesToolStripMenuItem, - this.toolStripSeparator8, - this.N64VideoPluginSettingsMenuItem, - this.setLibretroCoreToolStripMenuItem}); + this.NesCoreSubMenu, + this.CoreSNESSubMenu, + this.GbaCoreSubMenu, + this.SGBCoreSubmenu, + this.GBCoreSubmenu, + this.GBInSGBMenuItem, + this.toolStripMenuItem16, + this.allowGameDBCoreOverridesToolStripMenuItem, + this.toolStripSeparator8, + this.N64VideoPluginSettingsMenuItem, + this.setLibretroCoreToolStripMenuItem}); this.CoresSubMenu.Name = "CoresSubMenu"; this.CoresSubMenu.Size = new System.Drawing.Size(180, 22); this.CoresSubMenu.Text = "Cores"; @@ -1872,10 +1872,10 @@ // NesCoreSubMenu // this.NesCoreSubMenu.DropDownItems.AddRange(new System.Windows.Forms.ToolStripItem[] { - this.QuicknesCoreMenuItem, - this.NesCoreMenuItem, - this.toolStripSeparator38, - this.SubNesHawkMenuItem}); + this.QuicknesCoreMenuItem, + this.NesCoreMenuItem, + this.toolStripSeparator38, + this.SubNesHawkMenuItem}); this.NesCoreSubMenu.Name = "NesCoreSubMenu"; this.NesCoreSubMenu.Size = new System.Drawing.Size(239, 22); this.NesCoreSubMenu.Text = "NES"; @@ -1910,8 +1910,8 @@ // CoreSNESSubMenu // this.CoreSNESSubMenu.DropDownItems.AddRange(new System.Windows.Forms.ToolStripItem[] { - this.Coresnes9xMenuItem, - this.CorebsnesMenuItem}); + this.Coresnes9xMenuItem, + this.CorebsnesMenuItem}); this.CoreSNESSubMenu.Name = "CoreSNESSubMenu"; this.CoreSNESSubMenu.Size = new System.Drawing.Size(239, 22); this.CoreSNESSubMenu.Text = "SNES"; @@ -1934,8 +1934,8 @@ // GbaCoreSubMenu // this.GbaCoreSubMenu.DropDownItems.AddRange(new System.Windows.Forms.ToolStripItem[] { - this.VbaNextCoreMenuItem, - this.MgbaCoreMenuItem}); + this.VbaNextCoreMenuItem, + this.MgbaCoreMenuItem}); this.GbaCoreSubMenu.Name = "GbaCoreSubMenu"; this.GbaCoreSubMenu.Size = new System.Drawing.Size(239, 22); this.GbaCoreSubMenu.Text = "GBA"; @@ -1958,8 +1958,8 @@ // SGBCoreSubmenu // this.SGBCoreSubmenu.DropDownItems.AddRange(new System.Windows.Forms.ToolStripItem[] { - this.SgbBsnesMenuItem, - this.SgbSameBoyMenuItem}); + this.SgbBsnesMenuItem, + this.SgbSameBoyMenuItem}); this.SGBCoreSubmenu.Name = "SGBCoreSubmenu"; this.SGBCoreSubmenu.Size = new System.Drawing.Size(239, 22); this.SGBCoreSubmenu.Text = "SGB"; @@ -1982,8 +1982,8 @@ // GBCoreSubmenu // this.GBCoreSubmenu.DropDownItems.AddRange(new System.Windows.Forms.ToolStripItem[] { - this.GBGambatteMenuItem, - this.GBGBHawkMenuItem}); + this.GBGambatteMenuItem, + this.GBGBHawkMenuItem}); this.GBCoreSubmenu.Name = "GBCoreSubmenu"; this.GBCoreSubmenu.Size = new System.Drawing.Size(239, 22); this.GBCoreSubmenu.Text = "GB"; @@ -2080,27 +2080,27 @@ // ToolsSubMenu // this.ToolsSubMenu.DropDownItems.AddRange(new System.Windows.Forms.ToolStripItem[] { - this.ToolBoxMenuItem, - this.toolStripSeparator12, - this.RamWatchMenuItem, - this.RamSearchMenuItem, - this.LuaConsoleMenuItem, - this.TAStudioMenuItem, - this.HexEditorMenuItem, - this.TraceLoggerMenuItem, - this.DebuggerMenuItem, - this.CodeDataLoggerMenuItem, - this.MacroToolMenuItem, - this.VirtualPadMenuItem, - this.BasicBotMenuItem, - this.toolStripSeparator11, - this.CheatsMenuItem, - this.gameSharkConverterToolStripMenuItem, - this.toolStripSeparator29, - this.MultiDiskBundlerFileMenuItem, - this.externalToolToolStripMenuItem, - this.batchRunnerToolStripMenuItem, - this.ExperimentalToolsSubMenu}); + this.ToolBoxMenuItem, + this.toolStripSeparator12, + this.RamWatchMenuItem, + this.RamSearchMenuItem, + this.LuaConsoleMenuItem, + this.TAStudioMenuItem, + this.HexEditorMenuItem, + this.TraceLoggerMenuItem, + this.DebuggerMenuItem, + this.CodeDataLoggerMenuItem, + this.MacroToolMenuItem, + this.VirtualPadMenuItem, + this.BasicBotMenuItem, + this.toolStripSeparator11, + this.CheatsMenuItem, + this.gameSharkConverterToolStripMenuItem, + this.toolStripSeparator29, + this.MultiDiskBundlerFileMenuItem, + this.externalToolToolStripMenuItem, + this.batchRunnerToolStripMenuItem, + this.ExperimentalToolsSubMenu}); this.ToolsSubMenu.Name = "ToolsSubMenu"; this.ToolsSubMenu.Size = new System.Drawing.Size(47, 19); this.ToolsSubMenu.Text = "&Tools"; @@ -2242,7 +2242,7 @@ // externalToolToolStripMenuItem // this.externalToolToolStripMenuItem.DropDownItems.AddRange(new System.Windows.Forms.ToolStripItem[] { - this.dummyExternalTool}); + this.dummyExternalTool}); this.externalToolToolStripMenuItem.Name = "externalToolToolStripMenuItem"; this.externalToolToolStripMenuItem.Size = new System.Drawing.Size(191, 22); this.externalToolToolStripMenuItem.Text = "External Tool"; @@ -2265,8 +2265,8 @@ // ExperimentalToolsSubMenu // this.ExperimentalToolsSubMenu.DropDownItems.AddRange(new System.Windows.Forms.ToolStripItem[] { - this.AutoHawkMenuItem, - this.NewHexEditorMenuItem}); + this.AutoHawkMenuItem, + this.NewHexEditorMenuItem}); this.ExperimentalToolsSubMenu.Name = "ExperimentalToolsSubMenu"; this.ExperimentalToolsSubMenu.Size = new System.Drawing.Size(191, 22); this.ExperimentalToolsSubMenu.Text = "Experimental Tools"; @@ -2289,22 +2289,22 @@ // NESSubMenu // this.NESSubMenu.DropDownItems.AddRange(new System.Windows.Forms.ToolStripItem[] { - this.coreToolStripMenuItem, - this.toolStripSeparator34, - this.NESPPUViewerMenuItem, - this.NESNametableViewerMenuItem, - this.NESGameGenieCodesMenuItem, - this.musicRipperToolStripMenuItem, - this.toolStripSeparator17, - this.NesControllerSettingsMenuItem, - this.NESGraphicSettingsMenuItem, - this.NESSoundChannelsMenuItem, - this.VSSettingsMenuItem, - this.MovieSettingsMenuItem, - this.toolStripSeparator22, - this.FDSControlsMenuItem, - this.VSControlsMenuItem, - this.barcodeReaderToolStripMenuItem}); + this.coreToolStripMenuItem, + this.toolStripSeparator34, + this.NESPPUViewerMenuItem, + this.NESNametableViewerMenuItem, + this.NESGameGenieCodesMenuItem, + this.musicRipperToolStripMenuItem, + this.toolStripSeparator17, + this.NesControllerSettingsMenuItem, + this.NESGraphicSettingsMenuItem, + this.NESSoundChannelsMenuItem, + this.VSSettingsMenuItem, + this.MovieSettingsMenuItem, + this.toolStripSeparator22, + this.FDSControlsMenuItem, + this.VSControlsMenuItem, + this.barcodeReaderToolStripMenuItem}); this.NESSubMenu.Name = "NESSubMenu"; this.NESSubMenu.Size = new System.Drawing.Size(40, 19); this.NESSubMenu.Text = "&NES"; @@ -2313,8 +2313,8 @@ // coreToolStripMenuItem // this.coreToolStripMenuItem.DropDownItems.AddRange(new System.Windows.Forms.ToolStripItem[] { - this.quickNESToolStripMenuItem, - this.nesHawkToolStripMenuItem}); + this.quickNESToolStripMenuItem, + this.nesHawkToolStripMenuItem}); this.coreToolStripMenuItem.Name = "coreToolStripMenuItem"; this.coreToolStripMenuItem.Size = new System.Drawing.Size(233, 22); this.coreToolStripMenuItem.Text = "&Core"; @@ -2418,7 +2418,7 @@ // FDSControlsMenuItem // this.FDSControlsMenuItem.DropDownItems.AddRange(new System.Windows.Forms.ToolStripItem[] { - this.FdsEjectDiskMenuItem}); + this.FdsEjectDiskMenuItem}); this.FDSControlsMenuItem.Name = "FDSControlsMenuItem"; this.FDSControlsMenuItem.Size = new System.Drawing.Size(233, 22); this.FDSControlsMenuItem.Text = "FDS Controls"; @@ -2434,9 +2434,9 @@ // VSControlsMenuItem // this.VSControlsMenuItem.DropDownItems.AddRange(new System.Windows.Forms.ToolStripItem[] { - this.VSInsertCoinP1MenuItem, - this.VSInsertCoinP2MenuItem, - this.VSServiceSwitchMenuItem}); + this.VSInsertCoinP1MenuItem, + this.VSInsertCoinP2MenuItem, + this.VSServiceSwitchMenuItem}); this.VSControlsMenuItem.Name = "VSControlsMenuItem"; this.VSControlsMenuItem.Size = new System.Drawing.Size(233, 22); this.VSControlsMenuItem.Text = "VS Controls"; @@ -2472,16 +2472,16 @@ // PCESubMenu // this.PCESubMenu.DropDownItems.AddRange(new System.Windows.Forms.ToolStripItem[] { - this.PceControllerSettingsMenuItem, - this.PCEGraphicsSettingsMenuItem, - this.toolStripSeparator32, - this.PCEBGViewerMenuItem, - this.PCEtileViewerToolStripMenuItem, - this.PceSoundDebuggerToolStripMenuItem, - this.toolStripSeparator25, - this.PCEAlwaysPerformSpriteLimitMenuItem, - this.PCEAlwaysEqualizeVolumesMenuItem, - this.PCEArcadeCardRewindEnableMenuItem}); + this.PceControllerSettingsMenuItem, + this.PCEGraphicsSettingsMenuItem, + this.toolStripSeparator32, + this.PCEBGViewerMenuItem, + this.PCEtileViewerToolStripMenuItem, + this.PceSoundDebuggerToolStripMenuItem, + this.toolStripSeparator25, + this.PCEAlwaysPerformSpriteLimitMenuItem, + this.PCEAlwaysEqualizeVolumesMenuItem, + this.PCEArcadeCardRewindEnableMenuItem}); this.PCESubMenu.Name = "PCESubMenu"; this.PCESubMenu.Size = new System.Drawing.Size(40, 19); this.PCESubMenu.Text = "&PCE"; @@ -2558,23 +2558,23 @@ // SMSSubMenu // this.SMSSubMenu.DropDownItems.AddRange(new System.Windows.Forms.ToolStripItem[] { - this.SMSregionToolStripMenuItem, - this.SMSdisplayToolStripMenuItem, - this.SMSControllerToolStripMenuItem, - this.SMStoolStripMenuItem2, - this.SMSenableBIOSToolStripMenuItem, - this.SMSEnableFMChipMenuItem, - this.SMSOverclockMenuItem, - this.SMSForceStereoMenuItem, - this.SMSSpriteLimitMenuItem, - this.SMSDisplayOverscanMenuItem, - this.SMSFix3DGameDisplayToolStripMenuItem, - this.ShowClippedRegionsMenuItem, - this.HighlightActiveDisplayRegionMenuItem, - this.SMSGraphicsSettingsMenuItem, - this.toolStripSeparator24, - this.SMSVDPViewerToolStripMenuItem, - this.GGGameGenieMenuItem}); + this.SMSregionToolStripMenuItem, + this.SMSdisplayToolStripMenuItem, + this.SMSControllerToolStripMenuItem, + this.SMStoolStripMenuItem2, + this.SMSenableBIOSToolStripMenuItem, + this.SMSEnableFMChipMenuItem, + this.SMSOverclockMenuItem, + this.SMSForceStereoMenuItem, + this.SMSSpriteLimitMenuItem, + this.SMSDisplayOverscanMenuItem, + this.SMSFix3DGameDisplayToolStripMenuItem, + this.ShowClippedRegionsMenuItem, + this.HighlightActiveDisplayRegionMenuItem, + this.SMSGraphicsSettingsMenuItem, + this.toolStripSeparator24, + this.SMSVDPViewerToolStripMenuItem, + this.GGGameGenieMenuItem}); this.SMSSubMenu.Name = "SMSSubMenu"; this.SMSSubMenu.Size = new System.Drawing.Size(42, 19); this.SMSSubMenu.Text = "&SMS"; @@ -2583,10 +2583,10 @@ // SMSregionToolStripMenuItem // this.SMSregionToolStripMenuItem.DropDownItems.AddRange(new System.Windows.Forms.ToolStripItem[] { - this.SMSregionExportToolStripMenuItem, - this.SMSregionJapanToolStripMenuItem, - this.SMSregionKoreaToolStripMenuItem, - this.SMSregionAutoToolStripMenuItem}); + this.SMSregionExportToolStripMenuItem, + this.SMSregionJapanToolStripMenuItem, + this.SMSregionKoreaToolStripMenuItem, + this.SMSregionAutoToolStripMenuItem}); this.SMSregionToolStripMenuItem.Name = "SMSregionToolStripMenuItem"; this.SMSregionToolStripMenuItem.Size = new System.Drawing.Size(277, 22); this.SMSregionToolStripMenuItem.Text = "Region"; @@ -2622,9 +2622,9 @@ // SMSdisplayToolStripMenuItem // this.SMSdisplayToolStripMenuItem.DropDownItems.AddRange(new System.Windows.Forms.ToolStripItem[] { - this.SMSdisplayNtscToolStripMenuItem, - this.SMSdisplayPalToolStripMenuItem, - this.SMSdisplayAutoToolStripMenuItem}); + this.SMSdisplayNtscToolStripMenuItem, + this.SMSdisplayPalToolStripMenuItem, + this.SMSdisplayAutoToolStripMenuItem}); this.SMSdisplayToolStripMenuItem.Name = "SMSdisplayToolStripMenuItem"; this.SMSdisplayToolStripMenuItem.Size = new System.Drawing.Size(277, 22); this.SMSdisplayToolStripMenuItem.Text = "Display Type"; @@ -2653,11 +2653,11 @@ // SMSControllerToolStripMenuItem // this.SMSControllerToolStripMenuItem.DropDownItems.AddRange(new System.Windows.Forms.ToolStripItem[] { - this.SMSControllerStandardToolStripMenuItem, - this.SMSControllerPaddleToolStripMenuItem, - this.SMSControllerLightPhaserToolStripMenuItem, - this.SMSControllerSportsPadToolStripMenuItem, - this.SMSControllerKeyboardToolStripMenuItem}); + this.SMSControllerStandardToolStripMenuItem, + this.SMSControllerPaddleToolStripMenuItem, + this.SMSControllerLightPhaserToolStripMenuItem, + this.SMSControllerSportsPadToolStripMenuItem, + this.SMSControllerKeyboardToolStripMenuItem}); this.SMSControllerToolStripMenuItem.Name = "SMSControllerToolStripMenuItem"; this.SMSControllerToolStripMenuItem.Size = new System.Drawing.Size(277, 22); this.SMSControllerToolStripMenuItem.Text = "&Controller Type"; @@ -2794,11 +2794,11 @@ // TI83SubMenu // this.TI83SubMenu.DropDownItems.AddRange(new System.Windows.Forms.ToolStripItem[] { - this.KeypadMenuItem, - this.LoadTIFileMenuItem, - this.toolStripSeparator13, - this.AutoloadKeypadMenuItem, - this.paletteToolStripMenuItem}); + this.KeypadMenuItem, + this.LoadTIFileMenuItem, + this.toolStripSeparator13, + this.AutoloadKeypadMenuItem, + this.paletteToolStripMenuItem}); this.TI83SubMenu.Name = "TI83SubMenu"; this.TI83SubMenu.Size = new System.Drawing.Size(41, 19); this.TI83SubMenu.Text = "TI83"; @@ -2843,7 +2843,7 @@ // AtariSubMenu // this.AtariSubMenu.DropDownItems.AddRange(new System.Windows.Forms.ToolStripItem[] { - this.AtariSettingsToolStripMenuItem}); + this.AtariSettingsToolStripMenuItem}); this.AtariSubMenu.Name = "AtariSubMenu"; this.AtariSubMenu.Size = new System.Drawing.Size(44, 19); this.AtariSubMenu.Text = "&Atari"; @@ -2858,8 +2858,8 @@ // A7800SubMenu // this.A7800SubMenu.DropDownItems.AddRange(new System.Windows.Forms.ToolStripItem[] { - this.A7800ControllerSettingsMenuItem, - this.A7800FilterSettingsMenuItem}); + this.A7800ControllerSettingsMenuItem, + this.A7800FilterSettingsMenuItem}); this.A7800SubMenu.Name = "A7800SubMenu"; this.A7800SubMenu.Size = new System.Drawing.Size(51, 19); this.A7800SubMenu.Text = "&A7800"; @@ -2882,12 +2882,12 @@ // GBSubMenu // this.GBSubMenu.DropDownItems.AddRange(new System.Windows.Forms.ToolStripItem[] { - this.GBcoreSettingsToolStripMenuItem, - this.LoadGBInSGBMenuItem, - this.toolStripSeparator28, - this.GBGPUViewerMenuItem, - this.GBGameGenieMenuItem, - this.GBPrinterViewerMenuItem}); + this.GBcoreSettingsToolStripMenuItem, + this.LoadGBInSGBMenuItem, + this.toolStripSeparator28, + this.GBGPUViewerMenuItem, + this.GBGameGenieMenuItem, + this.GBPrinterViewerMenuItem}); this.GBSubMenu.Name = "GBSubMenu"; this.GBSubMenu.Size = new System.Drawing.Size(34, 19); this.GBSubMenu.Text = "&GB"; @@ -2936,10 +2936,10 @@ // GBASubMenu // this.GBASubMenu.DropDownItems.AddRange(new System.Windows.Forms.ToolStripItem[] { - this.GBACoreSelectionSubMenu, - this.GBAcoresettingsToolStripMenuItem1, - this.toolStripSeparator33, - this.GbaGpuViewerMenuItem}); + this.GBACoreSelectionSubMenu, + this.GBAcoresettingsToolStripMenuItem1, + this.toolStripSeparator33, + this.GbaGpuViewerMenuItem}); this.GBASubMenu.Name = "GBASubMenu"; this.GBASubMenu.Size = new System.Drawing.Size(42, 19); this.GBASubMenu.Text = "GBA"; @@ -2947,8 +2947,8 @@ // GBACoreSelectionSubMenu // this.GBACoreSelectionSubMenu.DropDownItems.AddRange(new System.Windows.Forms.ToolStripItem[] { - this.GBAmGBAMenuItem, - this.GBAVBANextMenuItem}); + this.GBAmGBAMenuItem, + this.GBAVBANextMenuItem}); this.GBACoreSelectionSubMenu.Name = "GBACoreSelectionSubMenu"; this.GBACoreSelectionSubMenu.Size = new System.Drawing.Size(135, 22); this.GBACoreSelectionSubMenu.Text = "&Core"; @@ -2973,7 +2973,7 @@ this.GBAcoresettingsToolStripMenuItem1.Name = "GBAcoresettingsToolStripMenuItem1"; this.GBAcoresettingsToolStripMenuItem1.Size = new System.Drawing.Size(135, 22); this.GBAcoresettingsToolStripMenuItem1.Text = "&Settings..."; - this.GBAcoresettingsToolStripMenuItem1.Click += new System.EventHandler(this.GBAcoresettingsToolStripMenuItem1_Click); + this.GBAcoresettingsToolStripMenuItem1.Click += new System.EventHandler(this.GBACoreSettingsToolStripMenuItem_Click); // // toolStripSeparator33 // @@ -2990,10 +2990,10 @@ // PSXSubMenu // this.PSXSubMenu.DropDownItems.AddRange(new System.Windows.Forms.ToolStripItem[] { - this.PSXControllerSettingsMenuItem, - this.PSXOptionsMenuItem, - this.PSXDiscControlsMenuItem, - this.PSXHashDiscsToolStripMenuItem}); + this.PSXControllerSettingsMenuItem, + this.PSXOptionsMenuItem, + this.PSXDiscControlsMenuItem, + this.PSXHashDiscsToolStripMenuItem}); this.PSXSubMenu.Name = "PSXSubMenu"; this.PSXSubMenu.Size = new System.Drawing.Size(39, 19); this.PSXSubMenu.Text = "PSX"; @@ -3031,12 +3031,12 @@ // SNESSubMenu // this.SNESSubMenu.DropDownItems.AddRange(new System.Windows.Forms.ToolStripItem[] { - this.SNESControllerConfigurationMenuItem, - this.toolStripSeparator18, - this.SnesGfxDebuggerMenuItem, - this.SnesGBInSGBMenuItem, - this.SnesGameGenieMenuItem, - this.SnesOptionsMenuItem}); + this.SNESControllerConfigurationMenuItem, + this.toolStripSeparator18, + this.SnesGfxDebuggerMenuItem, + this.SnesGBInSGBMenuItem, + this.SnesGameGenieMenuItem, + this.SnesOptionsMenuItem}); this.SNESSubMenu.Name = "SNESSubMenu"; this.SNESSubMenu.Size = new System.Drawing.Size(46, 19); this.SNESSubMenu.Text = "&SNES"; @@ -3087,10 +3087,10 @@ // ColecoSubMenu // this.ColecoSubMenu.DropDownItems.AddRange(new System.Windows.Forms.ToolStripItem[] { - this.ColecoControllerSettingsMenuItem, - this.toolStripSeparator35, - this.ColecoSkipBiosMenuItem, - this.ColecoUseSGMMenuItem}); + this.ColecoControllerSettingsMenuItem, + this.toolStripSeparator35, + this.ColecoSkipBiosMenuItem, + this.ColecoUseSGMMenuItem}); this.ColecoSubMenu.Name = "ColecoSubMenu"; this.ColecoSubMenu.Size = new System.Drawing.Size(56, 19); this.ColecoSubMenu.Text = "&Coleco"; @@ -3126,12 +3126,12 @@ // N64SubMenu // this.N64SubMenu.DropDownItems.AddRange(new System.Windows.Forms.ToolStripItem[] { - this.N64PluginSettingsMenuItem, - this.N64ControllerSettingsMenuItem, - this.toolStripSeparator23, - this.N64CircularAnalogRangeMenuItem, - this.MupenStyleLagMenuItem, - this.N64ExpansionSlotMenuItem}); + this.N64PluginSettingsMenuItem, + this.N64ControllerSettingsMenuItem, + this.toolStripSeparator23, + this.N64CircularAnalogRangeMenuItem, + this.MupenStyleLagMenuItem, + this.N64ExpansionSlotMenuItem}); this.N64SubMenu.Name = "N64SubMenu"; this.N64SubMenu.Size = new System.Drawing.Size(40, 19); this.N64SubMenu.Text = "N64"; @@ -3182,7 +3182,7 @@ // SaturnSubMenu // this.SaturnSubMenu.DropDownItems.AddRange(new System.Windows.Forms.ToolStripItem[] { - this.SaturnPreferencesMenuItem}); + this.SaturnPreferencesMenuItem}); this.SaturnSubMenu.Name = "SaturnSubMenu"; this.SaturnSubMenu.Size = new System.Drawing.Size(53, 19); this.SaturnSubMenu.Text = "&Saturn"; @@ -3197,7 +3197,7 @@ // DGBSubMenu // this.DGBSubMenu.DropDownItems.AddRange(new System.Windows.Forms.ToolStripItem[] { - this.DGBsettingsToolStripMenuItem}); + this.DGBsettingsToolStripMenuItem}); this.DGBSubMenu.Name = "DGBSubMenu"; this.DGBSubMenu.Size = new System.Drawing.Size(59, 19); this.DGBSubMenu.Text = "&GB Link"; @@ -3212,7 +3212,7 @@ // DGBHawkSubMenu // this.DGBHawkSubMenu.DropDownItems.AddRange(new System.Windows.Forms.ToolStripItem[] { - this.DGBHawksettingsToolStripMenuItem}); + this.DGBHawksettingsToolStripMenuItem}); this.DGBHawkSubMenu.Name = "DGBHawkSubMenu"; this.DGBHawkSubMenu.Size = new System.Drawing.Size(59, 19); this.DGBHawkSubMenu.Text = "&GB Link"; @@ -3257,7 +3257,7 @@ // GGLSubMenu // this.GGLSubMenu.DropDownItems.AddRange(new System.Windows.Forms.ToolStripItem[] { - this.GGLsettingsToolStripMenuItem}); + this.GGLsettingsToolStripMenuItem}); this.GGLSubMenu.Name = "GGLSubMenu"; this.GGLSubMenu.Size = new System.Drawing.Size(60, 19); this.GGLSubMenu.Text = "&GG Link"; @@ -3287,10 +3287,10 @@ // GenesisSubMenu // this.GenesisSubMenu.DropDownItems.AddRange(new System.Windows.Forms.ToolStripItem[] { - this.vDPViewerToolStripMenuItem, - this.GenesisGameGenieECDC, - this.toolStripSeparator26, - this.GenesisSettingsToolStripMenuItem}); + this.vDPViewerToolStripMenuItem, + this.GenesisGameGenieECDC, + this.toolStripSeparator26, + this.GenesisSettingsToolStripMenuItem}); this.GenesisSubMenu.Name = "GenesisSubMenu"; this.GenesisSubMenu.Size = new System.Drawing.Size(59, 19); this.GenesisSubMenu.Text = "&Genesis"; @@ -3324,7 +3324,7 @@ // wonderSwanToolStripMenuItem // this.wonderSwanToolStripMenuItem.DropDownItems.AddRange(new System.Windows.Forms.ToolStripItem[] { - this.settingsToolStripMenuItem}); + this.settingsToolStripMenuItem}); this.wonderSwanToolStripMenuItem.Name = "wonderSwanToolStripMenuItem"; this.wonderSwanToolStripMenuItem.Size = new System.Drawing.Size(89, 19); this.wonderSwanToolStripMenuItem.Text = "&WonderSwan"; @@ -3334,13 +3334,13 @@ this.settingsToolStripMenuItem.Name = "settingsToolStripMenuItem"; this.settingsToolStripMenuItem.Size = new System.Drawing.Size(125, 22); this.settingsToolStripMenuItem.Text = "&Settings..."; - this.settingsToolStripMenuItem.Click += new System.EventHandler(this.WondersawnSettingsMenuItem_Click); + this.settingsToolStripMenuItem.Click += new System.EventHandler(this.WonderSwanSettingsMenuItem_Click); // // AppleSubMenu // this.AppleSubMenu.DropDownItems.AddRange(new System.Windows.Forms.ToolStripItem[] { - this.AppleDisksSubMenu, - this.settingsToolStripMenuItem1}); + this.AppleDisksSubMenu, + this.settingsToolStripMenuItem1}); this.AppleSubMenu.Name = "AppleSubMenu"; this.AppleSubMenu.Size = new System.Drawing.Size(50, 19); this.AppleSubMenu.Text = "Apple"; @@ -3349,7 +3349,7 @@ // AppleDisksSubMenu // this.AppleDisksSubMenu.DropDownItems.AddRange(new System.Windows.Forms.ToolStripItem[] { - this.toolStripSeparator31}); + this.toolStripSeparator31}); this.AppleDisksSubMenu.Name = "AppleDisksSubMenu"; this.AppleDisksSubMenu.Size = new System.Drawing.Size(125, 22); this.AppleDisksSubMenu.Text = "Disks"; @@ -3370,8 +3370,8 @@ // C64SubMenu // this.C64SubMenu.DropDownItems.AddRange(new System.Windows.Forms.ToolStripItem[] { - this.C64DisksSubMenu, - this.C64SettingsMenuItem}); + this.C64DisksSubMenu, + this.C64SettingsMenuItem}); this.C64SubMenu.Name = "C64SubMenu"; this.C64SubMenu.Size = new System.Drawing.Size(39, 19); this.C64SubMenu.Text = "&C64"; @@ -3380,7 +3380,7 @@ // C64DisksSubMenu // this.C64DisksSubMenu.DropDownItems.AddRange(new System.Windows.Forms.ToolStripItem[] { - this.toolStripSeparator36}); + this.toolStripSeparator36}); this.C64DisksSubMenu.Name = "C64DisksSubMenu"; this.C64DisksSubMenu.Size = new System.Drawing.Size(125, 22); this.C64DisksSubMenu.Text = "Disks"; @@ -3401,11 +3401,11 @@ // IntvSubMenu // this.IntvSubMenu.DropDownItems.AddRange(new System.Windows.Forms.ToolStripItem[] { - this.IntVControllerSettingsMenuItem}); + this.IntVControllerSettingsMenuItem}); this.IntvSubMenu.Name = "IntvSubMenu"; this.IntvSubMenu.Size = new System.Drawing.Size(39, 19); this.IntvSubMenu.Text = "&Intv"; - this.IntvSubMenu.DropDownOpened += new System.EventHandler(this.IntvSubMenu_DropDownOpened); + this.IntvSubMenu.DropDownOpened += new System.EventHandler(this.IntVSubMenu_DropDownOpened); // // IntVControllerSettingsMenuItem // @@ -3418,7 +3418,7 @@ // sNESToolStripMenuItem // this.sNESToolStripMenuItem.DropDownItems.AddRange(new System.Windows.Forms.ToolStripItem[] { - this.preferencesToolStripMenuItem}); + this.preferencesToolStripMenuItem}); this.sNESToolStripMenuItem.Name = "sNESToolStripMenuItem"; this.sNESToolStripMenuItem.Size = new System.Drawing.Size(46, 19); this.sNESToolStripMenuItem.Text = "&SNES"; @@ -3428,12 +3428,12 @@ this.preferencesToolStripMenuItem.Name = "preferencesToolStripMenuItem"; this.preferencesToolStripMenuItem.Size = new System.Drawing.Size(144, 22); this.preferencesToolStripMenuItem.Text = "Preferences..."; - this.preferencesToolStripMenuItem.Click += new System.EventHandler(this.preferencesToolStripMenuItem_Click); + this.preferencesToolStripMenuItem.Click += new System.EventHandler(this.Snes9xSettingsMenuItem_Click); // // pCFXToolStripMenuItem // this.pCFXToolStripMenuItem.DropDownItems.AddRange(new System.Windows.Forms.ToolStripItem[] { - this.preferencesToolStripMenuItem3}); + this.preferencesToolStripMenuItem3}); this.pCFXToolStripMenuItem.Name = "pCFXToolStripMenuItem"; this.pCFXToolStripMenuItem.Size = new System.Drawing.Size(52, 19); this.pCFXToolStripMenuItem.Text = "&PC-FX"; @@ -3443,12 +3443,12 @@ this.preferencesToolStripMenuItem3.Name = "preferencesToolStripMenuItem3"; this.preferencesToolStripMenuItem3.Size = new System.Drawing.Size(144, 22); this.preferencesToolStripMenuItem3.Text = "Preferences..."; - this.preferencesToolStripMenuItem3.Click += new System.EventHandler(this.preferencesToolStripMenuItem3_Click); + this.preferencesToolStripMenuItem3.Click += new System.EventHandler(this.PCFXSettingsMenuItem_Click); // // virtualBoyToolStripMenuItem // this.virtualBoyToolStripMenuItem.DropDownItems.AddRange(new System.Windows.Forms.ToolStripItem[] { - this.preferencesToolStripMenuItem1}); + this.preferencesToolStripMenuItem1}); this.virtualBoyToolStripMenuItem.Name = "virtualBoyToolStripMenuItem"; this.virtualBoyToolStripMenuItem.Size = new System.Drawing.Size(73, 19); this.virtualBoyToolStripMenuItem.Text = "&VirtualBoy"; @@ -3458,12 +3458,12 @@ this.preferencesToolStripMenuItem1.Name = "preferencesToolStripMenuItem1"; this.preferencesToolStripMenuItem1.Size = new System.Drawing.Size(144, 22); this.preferencesToolStripMenuItem1.Text = "Preferences..."; - this.preferencesToolStripMenuItem1.Click += new System.EventHandler(this.preferencesToolStripMenuItem1_Click); + this.preferencesToolStripMenuItem1.Click += new System.EventHandler(this.VirtualBoySettingsMenuItem_Click); // // neoGeoPocketToolStripMenuItem // this.neoGeoPocketToolStripMenuItem.DropDownItems.AddRange(new System.Windows.Forms.ToolStripItem[] { - this.preferencesToolStripMenuItem2}); + this.preferencesToolStripMenuItem2}); this.neoGeoPocketToolStripMenuItem.Name = "neoGeoPocketToolStripMenuItem"; this.neoGeoPocketToolStripMenuItem.Size = new System.Drawing.Size(101, 19); this.neoGeoPocketToolStripMenuItem.Text = "&NeoGeo Pocket"; @@ -3473,21 +3473,20 @@ this.preferencesToolStripMenuItem2.Name = "preferencesToolStripMenuItem2"; this.preferencesToolStripMenuItem2.Size = new System.Drawing.Size(144, 22); this.preferencesToolStripMenuItem2.Text = "Preferences..."; - this.preferencesToolStripMenuItem2.Click += new System.EventHandler(this.preferencesToolStripMenuItem2_Click); + this.preferencesToolStripMenuItem2.Click += new System.EventHandler(this.NeoGeoSettingsMenuItem_Click); // // zXSpectrumToolStripMenuItem // this.zXSpectrumToolStripMenuItem.DropDownItems.AddRange(new System.Windows.Forms.ToolStripItem[] { - this.ZXSpectrumCoreEmulationSettingsMenuItem, - this.ZXSpectrumControllerConfigurationMenuItem, - this.ZXSpectrumAudioSettingsMenuItem, - this.ZXSpectrumNonSyncSettingsMenuItem, - this.ZXSpectrumPokeMemoryMenuItem, - this.ZXSpectrumMediaMenuItem}); + this.ZXSpectrumCoreEmulationSettingsMenuItem, + this.ZXSpectrumControllerConfigurationMenuItem, + this.ZXSpectrumAudioSettingsMenuItem, + this.ZXSpectrumNonSyncSettingsMenuItem, + this.ZXSpectrumPokeMemoryMenuItem, + this.ZXSpectrumMediaMenuItem}); this.zXSpectrumToolStripMenuItem.Name = "zXSpectrumToolStripMenuItem"; this.zXSpectrumToolStripMenuItem.Size = new System.Drawing.Size(87, 19); this.zXSpectrumToolStripMenuItem.Text = "ZX Spectrum"; - this.zXSpectrumToolStripMenuItem.DropDownOpened += new System.EventHandler(this.zXSpectrumToolStripMenuItem_DropDownOpened); // // ZXSpectrumCoreEmulationSettingsMenuItem // @@ -3527,9 +3526,9 @@ // ZXSpectrumMediaMenuItem // this.ZXSpectrumMediaMenuItem.DropDownItems.AddRange(new System.Windows.Forms.ToolStripItem[] { - this.ZXSpectrumTapesSubMenu, - this.ZXSpectrumDisksSubMenu, - this.ZXSpectrumExportSnapshotMenuItemMenuItem}); + this.ZXSpectrumTapesSubMenu, + this.ZXSpectrumDisksSubMenu, + this.ZXSpectrumExportSnapshotMenuItemMenuItem}); this.ZXSpectrumMediaMenuItem.Name = "ZXSpectrumMediaMenuItem"; this.ZXSpectrumMediaMenuItem.Size = new System.Drawing.Size(201, 22); this.ZXSpectrumMediaMenuItem.Text = "Media"; @@ -3538,7 +3537,7 @@ // ZXSpectrumTapesSubMenu // this.ZXSpectrumTapesSubMenu.DropDownItems.AddRange(new System.Windows.Forms.ToolStripItem[] { - this.zxt1ToolStripMenuItem}); + this.zxt1ToolStripMenuItem}); this.ZXSpectrumTapesSubMenu.Name = "ZXSpectrumTapesSubMenu"; this.ZXSpectrumTapesSubMenu.Size = new System.Drawing.Size(159, 22); this.ZXSpectrumTapesSubMenu.Text = "Tapes"; @@ -3553,7 +3552,7 @@ // ZXSpectrumDisksSubMenu // this.ZXSpectrumDisksSubMenu.DropDownItems.AddRange(new System.Windows.Forms.ToolStripItem[] { - this.zxt2ToolStripMenuItem}); + this.zxt2ToolStripMenuItem}); this.ZXSpectrumDisksSubMenu.Name = "ZXSpectrumDisksSubMenu"; this.ZXSpectrumDisksSubMenu.Size = new System.Drawing.Size(159, 22); this.ZXSpectrumDisksSubMenu.Text = "Disks"; @@ -3575,10 +3574,10 @@ // HelpSubMenu // this.HelpSubMenu.DropDownItems.AddRange(new System.Windows.Forms.ToolStripItem[] { - this.OnlineHelpMenuItem, - this.ForumsMenuItem, - this.FeaturesMenuItem, - this.AboutMenuItem}); + this.OnlineHelpMenuItem, + this.ForumsMenuItem, + this.FeaturesMenuItem, + this.AboutMenuItem}); this.HelpSubMenu.Name = "HelpSubMenu"; this.HelpSubMenu.Size = new System.Drawing.Size(44, 19); this.HelpSubMenu.Text = "&Help"; @@ -3619,11 +3618,11 @@ // amstradCPCToolStripMenuItem // this.amstradCPCToolStripMenuItem.DropDownItems.AddRange(new System.Windows.Forms.ToolStripItem[] { - this.amstradCPCCoreEmulationSettingsToolStripMenuItem, - this.AmstradCPCAudioSettingsToolStripMenuItem, - this.AmstradCPCNonSyncSettingsToolStripMenuItem, - this.AmstradCPCPokeMemoryToolStripMenuItem, - this.AmstradCPCMediaToolStripMenuItem}); + this.amstradCPCCoreEmulationSettingsToolStripMenuItem, + this.AmstradCPCAudioSettingsToolStripMenuItem, + this.AmstradCPCNonSyncSettingsToolStripMenuItem, + this.AmstradCPCPokeMemoryToolStripMenuItem, + this.AmstradCPCMediaToolStripMenuItem}); this.amstradCPCToolStripMenuItem.Name = "amstradCPCToolStripMenuItem"; this.amstradCPCToolStripMenuItem.Size = new System.Drawing.Size(90, 19); this.amstradCPCToolStripMenuItem.Text = "Amstrad CPC"; @@ -3659,8 +3658,8 @@ // AmstradCPCMediaToolStripMenuItem // this.AmstradCPCMediaToolStripMenuItem.DropDownItems.AddRange(new System.Windows.Forms.ToolStripItem[] { - this.AmstradCPCTapesSubMenu, - this.AmstradCPCDisksSubMenu}); + this.AmstradCPCTapesSubMenu, + this.AmstradCPCDisksSubMenu}); this.AmstradCPCMediaToolStripMenuItem.Name = "AmstradCPCMediaToolStripMenuItem"; this.AmstradCPCMediaToolStripMenuItem.Size = new System.Drawing.Size(201, 22); this.AmstradCPCMediaToolStripMenuItem.Text = "Media"; @@ -3669,7 +3668,7 @@ // AmstradCPCTapesSubMenu // this.AmstradCPCTapesSubMenu.DropDownItems.AddRange(new System.Windows.Forms.ToolStripItem[] { - this.cpct1ToolStripMenuItem}); + this.cpct1ToolStripMenuItem}); this.AmstradCPCTapesSubMenu.Name = "AmstradCPCTapesSubMenu"; this.AmstradCPCTapesSubMenu.Size = new System.Drawing.Size(104, 22); this.AmstradCPCTapesSubMenu.Text = "Tapes"; @@ -3684,7 +3683,7 @@ // AmstradCPCDisksSubMenu // this.AmstradCPCDisksSubMenu.DropDownItems.AddRange(new System.Windows.Forms.ToolStripItem[] { - this.cpcd1ToolStripMenuItem}); + this.cpcd1ToolStripMenuItem}); this.AmstradCPCDisksSubMenu.Name = "AmstradCPCDisksSubMenu"; this.AmstradCPCDisksSubMenu.Size = new System.Drawing.Size(104, 22); this.AmstradCPCDisksSubMenu.Text = "Disks"; @@ -3706,30 +3705,30 @@ // this.MainStatusBar.ClickThrough = true; this.MainStatusBar.Items.AddRange(new System.Windows.Forms.ToolStripItem[] { - this.DumpStatusButton, - this.EmuStatus, - this.PlayRecordStatusButton, - this.PauseStatusButton, - this.RebootStatusBarIcon, - this.AVIStatusLabel, - this.LedLightStatusLabel, - this.SaveSlotsStatusLabel, - this.Slot1StatusButton, - this.Slot2StatusButton, - this.Slot3StatusButton, - this.Slot4StatusButton, - this.Slot5StatusButton, - this.Slot6StatusButton, - this.Slot7StatusButton, - this.Slot8StatusButton, - this.Slot9StatusButton, - this.Slot0StatusButton, - this.CheatStatusButton, - this.KeyPriorityStatusLabel, - this.CoreNameStatusBarButton, - this.ProfileFirstBootLabel, - this.LinkConnectStatusBarButton, - this.UpdateNotification}); + this.DumpStatusButton, + this.EmuStatus, + this.PlayRecordStatusButton, + this.PauseStatusButton, + this.RebootStatusBarIcon, + this.AVIStatusLabel, + this.LedLightStatusLabel, + this.SaveSlotsStatusLabel, + this.Slot1StatusButton, + this.Slot2StatusButton, + this.Slot3StatusButton, + this.Slot4StatusButton, + this.Slot5StatusButton, + this.Slot6StatusButton, + this.Slot7StatusButton, + this.Slot8StatusButton, + this.Slot9StatusButton, + this.Slot0StatusButton, + this.CheatStatusButton, + this.KeyPriorityStatusLabel, + this.CoreNameStatusBarButton, + this.ProfileFirstBootLabel, + this.LinkConnectStatusBarButton, + this.UpdateNotification}); this.MainStatusBar.Location = new System.Drawing.Point(0, 386); this.MainStatusBar.Name = "MainStatusBar"; this.MainStatusBar.ShowItemToolTips = true; @@ -3949,31 +3948,31 @@ // MainFormContextMenu // this.MainFormContextMenu.Items.AddRange(new System.Windows.Forms.ToolStripItem[] { - this.OpenRomContextMenuItem, - this.LoadLastRomContextMenuItem, - this.StopAVContextMenuItem, - this.ContextSeparator_AfterROM, - this.RecordMovieContextMenuItem, - this.PlayMovieContextMenuItem, - this.RestartMovieContextMenuItem, - this.StopMovieContextMenuItem, - this.LoadLastMovieContextMenuItem, - this.BackupMovieContextMenuItem, - this.StopNoSaveContextMenuItem, - this.ViewSubtitlesContextMenuItem, - this.AddSubtitleContextMenuItem, - this.ViewCommentsContextMenuItem, - this.SaveMovieContextMenuItem, - this.SaveMovieAsContextMenuItem, - this.ContextSeparator_AfterMovie, - this.UndoSavestateContextMenuItem, - this.ContextSeparator_AfterUndo, - this.ConfigContextMenuItem, - this.ScreenshotContextMenuItem, - this.CloseRomContextMenuItem, - this.ClearSRAMContextMenuItem, - this.ShowMenuContextMenuSeparator, - this.ShowMenuContextMenuItem}); + this.OpenRomContextMenuItem, + this.LoadLastRomContextMenuItem, + this.StopAVContextMenuItem, + this.ContextSeparator_AfterROM, + this.RecordMovieContextMenuItem, + this.PlayMovieContextMenuItem, + this.RestartMovieContextMenuItem, + this.StopMovieContextMenuItem, + this.LoadLastMovieContextMenuItem, + this.BackupMovieContextMenuItem, + this.StopNoSaveContextMenuItem, + this.ViewSubtitlesContextMenuItem, + this.AddSubtitleContextMenuItem, + this.ViewCommentsContextMenuItem, + this.SaveMovieContextMenuItem, + this.SaveMovieAsContextMenuItem, + this.ContextSeparator_AfterMovie, + this.UndoSavestateContextMenuItem, + this.ContextSeparator_AfterUndo, + this.ConfigContextMenuItem, + this.ScreenshotContextMenuItem, + this.CloseRomContextMenuItem, + this.ClearSRAMContextMenuItem, + this.ShowMenuContextMenuSeparator, + this.ShowMenuContextMenuItem}); this.MainFormContextMenu.Name = "contextMenuStrip1"; this.MainFormContextMenu.Size = new System.Drawing.Size(217, 490); this.MainFormContextMenu.Closing += new System.Windows.Forms.ToolStripDropDownClosingEventHandler(this.MainFormContextMenu_Closing); @@ -4121,22 +4120,22 @@ // ConfigContextMenuItem // this.ConfigContextMenuItem.DropDownItems.AddRange(new System.Windows.Forms.ToolStripItem[] { - this.toolStripMenuItem6, - this.toolStripMenuItem7, - this.toolStripMenuItem8, - this.toolStripMenuItem9, - this.toolStripMenuItem10, - this.toolStripMenuItem11, - this.toolStripMenuItem12, - this.toolStripMenuItem13, - this.toolStripMenuItem14, - this.toolStripMenuItem15, - this.customizeToolStripMenuItem, - this.toolStripSeparator30, - this.SavestateTypeContextSubMenu, - this.toolStripSeparator37, - this.toolStripMenuItem66, - this.toolStripMenuItem67}); + this.toolStripMenuItem6, + this.toolStripMenuItem7, + this.toolStripMenuItem8, + this.toolStripMenuItem9, + this.toolStripMenuItem10, + this.toolStripMenuItem11, + this.toolStripMenuItem12, + this.toolStripMenuItem13, + this.toolStripMenuItem14, + this.toolStripMenuItem15, + this.customizeToolStripMenuItem, + this.toolStripSeparator30, + this.SavestateTypeContextSubMenu, + this.toolStripSeparator37, + this.toolStripMenuItem66, + this.toolStripMenuItem67}); this.ConfigContextMenuItem.Name = "ConfigContextMenuItem"; this.ConfigContextMenuItem.Size = new System.Drawing.Size(216, 22); this.ConfigContextMenuItem.Text = "Config"; @@ -4235,9 +4234,9 @@ // SavestateTypeContextSubMenu // this.SavestateTypeContextSubMenu.DropDownItems.AddRange(new System.Windows.Forms.ToolStripItem[] { - this.SavestateTypeDefaultContextMenuItem, - this.SavestateBinaryContextMenuItem, - this.SavestateTextContextMenuItem}); + this.SavestateTypeDefaultContextMenuItem, + this.SavestateBinaryContextMenuItem, + this.SavestateTextContextMenuItem}); this.SavestateTypeContextSubMenu.Name = "SavestateTypeContextSubMenu"; this.SavestateTypeContextSubMenu.Size = new System.Drawing.Size(159, 22); this.SavestateTypeContextSubMenu.Text = "Savestate Type"; @@ -4797,28 +4796,28 @@ private System.Windows.Forms.ToolStripMenuItem SMSControllerLightPhaserToolStripMenuItem; private System.Windows.Forms.ToolStripMenuItem SMSControllerSportsPadToolStripMenuItem; private System.Windows.Forms.ToolStripMenuItem SMSControllerKeyboardToolStripMenuItem; - private System.Windows.Forms.ToolStripMenuItem zXSpectrumToolStripMenuItem; - private System.Windows.Forms.ToolStripMenuItem ZXSpectrumControllerConfigurationMenuItem; - private System.Windows.Forms.ToolStripMenuItem ZXSpectrumCoreEmulationSettingsMenuItem; - private System.Windows.Forms.ToolStripMenuItem ZXSpectrumNonSyncSettingsMenuItem; - private System.Windows.Forms.ToolStripMenuItem ZXSpectrumAudioSettingsMenuItem; - private System.Windows.Forms.ToolStripMenuItem ZXSpectrumPokeMemoryMenuItem; - private System.Windows.Forms.ToolStripMenuItem ZXSpectrumMediaMenuItem; - private System.Windows.Forms.ToolStripMenuItem ZXSpectrumTapesSubMenu; - private System.Windows.Forms.ToolStripMenuItem ZXSpectrumDisksSubMenu; - private System.Windows.Forms.ToolStripMenuItem zxt1ToolStripMenuItem; - private System.Windows.Forms.ToolStripMenuItem zxt2ToolStripMenuItem; - private System.Windows.Forms.ToolStripMenuItem ZXSpectrumExportSnapshotMenuItemMenuItem; - private System.Windows.Forms.ToolStripMenuItem amstradCPCToolStripMenuItem; - private System.Windows.Forms.ToolStripMenuItem amstradCPCCoreEmulationSettingsToolStripMenuItem; - private System.Windows.Forms.ToolStripMenuItem AmstradCPCAudioSettingsToolStripMenuItem; - private System.Windows.Forms.ToolStripMenuItem AmstradCPCPokeMemoryToolStripMenuItem; - private System.Windows.Forms.ToolStripMenuItem AmstradCPCMediaToolStripMenuItem; - private System.Windows.Forms.ToolStripMenuItem AmstradCPCTapesSubMenu; - private System.Windows.Forms.ToolStripMenuItem cpct1ToolStripMenuItem; - private System.Windows.Forms.ToolStripMenuItem AmstradCPCDisksSubMenu; - private System.Windows.Forms.ToolStripMenuItem cpcd1ToolStripMenuItem; - private System.Windows.Forms.ToolStripMenuItem AmstradCPCNonSyncSettingsToolStripMenuItem; + private System.Windows.Forms.ToolStripMenuItem zXSpectrumToolStripMenuItem; + private System.Windows.Forms.ToolStripMenuItem ZXSpectrumControllerConfigurationMenuItem; + private System.Windows.Forms.ToolStripMenuItem ZXSpectrumCoreEmulationSettingsMenuItem; + private System.Windows.Forms.ToolStripMenuItem ZXSpectrumNonSyncSettingsMenuItem; + private System.Windows.Forms.ToolStripMenuItem ZXSpectrumAudioSettingsMenuItem; + private System.Windows.Forms.ToolStripMenuItem ZXSpectrumPokeMemoryMenuItem; + private System.Windows.Forms.ToolStripMenuItem ZXSpectrumMediaMenuItem; + private System.Windows.Forms.ToolStripMenuItem ZXSpectrumTapesSubMenu; + private System.Windows.Forms.ToolStripMenuItem ZXSpectrumDisksSubMenu; + private System.Windows.Forms.ToolStripMenuItem zxt1ToolStripMenuItem; + private System.Windows.Forms.ToolStripMenuItem zxt2ToolStripMenuItem; + private System.Windows.Forms.ToolStripMenuItem ZXSpectrumExportSnapshotMenuItemMenuItem; + private System.Windows.Forms.ToolStripMenuItem amstradCPCToolStripMenuItem; + private System.Windows.Forms.ToolStripMenuItem amstradCPCCoreEmulationSettingsToolStripMenuItem; + private System.Windows.Forms.ToolStripMenuItem AmstradCPCAudioSettingsToolStripMenuItem; + private System.Windows.Forms.ToolStripMenuItem AmstradCPCPokeMemoryToolStripMenuItem; + private System.Windows.Forms.ToolStripMenuItem AmstradCPCMediaToolStripMenuItem; + private System.Windows.Forms.ToolStripMenuItem AmstradCPCTapesSubMenu; + private System.Windows.Forms.ToolStripMenuItem cpct1ToolStripMenuItem; + private System.Windows.Forms.ToolStripMenuItem AmstradCPCDisksSubMenu; + private System.Windows.Forms.ToolStripMenuItem cpcd1ToolStripMenuItem; + private System.Windows.Forms.ToolStripMenuItem AmstradCPCNonSyncSettingsToolStripMenuItem; private System.Windows.Forms.ToolStripMenuItem SubNesHawkMenuItem; private System.Windows.Forms.ToolStripSeparator toolStripSeparator38; } diff --git a/BizHawk.Client.EmuHawk/MainForm.Events.cs b/BizHawk.Client.EmuHawk/MainForm.Events.cs index 32be86ad9e..6d35453072 100644 --- a/BizHawk.Client.EmuHawk/MainForm.Events.cs +++ b/BizHawk.Client.EmuHawk/MainForm.Events.cs @@ -6,21 +6,18 @@ using System.Collections.Generic; using BizHawk.Emulation.Common; using BizHawk.Emulation.Common.IEmulatorExtensions; -using BizHawk.Emulation.Cores.Atari.A7800Hawk; using BizHawk.Emulation.Cores.Calculators; using BizHawk.Emulation.Cores.ColecoVision; using BizHawk.Emulation.Cores.Nintendo.NES; using BizHawk.Emulation.Cores.Nintendo.SubNESHawk; using BizHawk.Emulation.Cores.Nintendo.N64; using BizHawk.Emulation.Cores.Nintendo.SNES; -using BizHawk.Emulation.Cores.Nintendo.SNES9X; using BizHawk.Emulation.Cores.PCEngine; using BizHawk.Emulation.Cores.Sega.MasterSystem; using BizHawk.Emulation.Cores.Consoles.Nintendo.QuickNES; using BizHawk.Client.Common; -using BizHawk.Client.EmuHawk.CustomControls; using BizHawk.Client.EmuHawk.WinFormExtensions; using BizHawk.Client.EmuHawk.ToolExtensions; using BizHawk.Emulation.Cores.Computers.AppleII; @@ -468,8 +465,8 @@ namespace BizHawk.Client.EmuHawk { var result = MessageBox.Show( this, - "Thanks for using Bizhawk! The emulation core you have selected " + - "is currently BETA-status. We appreciate your help in testing Bizhawk. " + + "Thanks for using BizHawk! The emulation core you have selected " + + "is currently BETA-status. We appreciate your help in testing BizHawk. " + "You can record a movie on this core if you'd like to, but expect to " + "encounter bugs and sync problems. Continue?", "BizHawk", MessageBoxButtons.YesNo); @@ -614,7 +611,7 @@ namespace BizHawk.Client.EmuHawk private void RecordAVMenuItem_Click(object sender, EventArgs e) { - RecordAv(null, null); // force unattended, but allow tradtional setup + RecordAv(null, null); // force unattended, but allow traditional setup } private void StopAVMenuItem_Click(object sender, EventArgs e) @@ -979,9 +976,8 @@ namespace BizHawk.Client.EmuHawk private void FirmwaresMenuItem_Click(object sender, EventArgs e) { - if (e is RomLoader.RomErrorArgs) + if (e is RomLoader.RomErrorArgs args) { - var args = (RomLoader.RomErrorArgs)e; var result = new FirmwaresConfig(true, args.RomPath).ShowDialog(); args.Retry = result == DialogResult.Retry; } @@ -1401,7 +1397,7 @@ namespace BizHawk.Client.EmuHawk externalToolToolStripMenuItem.DropDownItems.Add(item); } - + if (externalToolToolStripMenuItem.DropDownItems.Count == 0) { externalToolToolStripMenuItem.DropDownItems.Add("None"); @@ -1430,7 +1426,7 @@ namespace BizHawk.Client.EmuHawk if (OSTailoredCode.CurrentOS != OSTailoredCode.DistinctOS.Windows) { // this is apparently needed for weird mono-forms-on-different-thread issues - // dont do .Show() within Load() for RamSearch - instead put an instance of it here on MainForm, then show here + // don't do .Show() within Load() for RamSearch - instead put an instance of it here on MainForm, then show here // the mono winforms implementation is.... weird and buggy ramSearch.Show(); } @@ -1540,7 +1536,7 @@ namespace BizHawk.Client.EmuHawk VSControlsMenuItem.Enabled = VSSettingsMenuItem.Enabled = - Emulator is NES && ((NES)Emulator).IsVS; + Emulator is NES nes && nes.IsVS; NESSoundChannelsMenuItem.Enabled = GlobalWin.Tools.IsAvailable(); MovieSettingsMenuItem.Enabled = Emulator is NES && !Global.MovieSession.Movie.IsActive; @@ -1616,7 +1612,7 @@ namespace BizHawk.Client.EmuHawk private void VsSettingsMenuItem_Click(object sender, EventArgs e) { - if (Emulator is NES && ((NES)Emulator).IsVS) + if (Emulator is NES nes && nes.IsVS) { new NesVsSettings().ShowHawkDialog(); } @@ -1633,7 +1629,7 @@ namespace BizHawk.Client.EmuHawk private void VsInsertCoinP1MenuItem_Click(object sender, EventArgs e) { - if (Emulator is NES && ((NES)Emulator).IsVS) + if (Emulator is NES nes && nes.IsVS) { if (!Global.MovieSession.Movie.IsPlaying || Global.MovieSession.Movie.IsFinished) { @@ -1645,7 +1641,7 @@ namespace BizHawk.Client.EmuHawk private void VsInsertCoinP2MenuItem_Click(object sender, EventArgs e) { - if (Emulator is NES && ((NES)Emulator).IsVS) + if (Emulator is NES nes && nes.IsVS) { if (!Global.MovieSession.Movie.IsPlaying || Global.MovieSession.Movie.IsFinished) { @@ -1657,7 +1653,7 @@ namespace BizHawk.Client.EmuHawk private void VsServiceSwitchMenuItem_Click(object sender, EventArgs e) { - if (Emulator is NES && ((NES)Emulator).IsVS) + if (Emulator is NES nes && nes.IsVS) { if (!Global.MovieSession.Movie.IsPlaying || Global.MovieSession.Movie.IsFinished) { @@ -1797,7 +1793,7 @@ namespace BizHawk.Client.EmuHawk SMSDisplayOverscanMenuItem.Visible = Global.Game.System == "SMS" || Global.Game.System == "SG"; - + SMSOverclockMenuItem.Visible = SMSForceStereoMenuItem.Visible = SMSdisplayToolStripMenuItem.Visible = @@ -1968,7 +1964,7 @@ namespace BizHawk.Client.EmuHawk s.ControllerType = "Sports Pad"; PutCoreSyncSettings(s); } - + private void SMSControllerKeyboardToolStripMenuItem_Click(object sender, EventArgs e) { var s = ((SMS)Emulator).GetSyncSettings(); @@ -2074,7 +2070,7 @@ namespace BizHawk.Client.EmuHawk { GBPrefs.DoGBPrefsDialog(this); } - else // sameboy + else // SameBoy { GenericCoreConfig.DoDialog(this, "Gameboy Settings"); } @@ -2104,6 +2100,11 @@ namespace BizHawk.Client.EmuHawk #region GBA + private void GBACoreSettingsToolStripMenuItem_Click(object sender, EventArgs e) + { + GenericCoreConfig.DoDialog(this, "Gameboy Advance Settings"); + } + private void GbaGpuViewerMenuItem_Click(object sender, EventArgs e) { GlobalWin.Tools.Load(); @@ -2123,14 +2124,8 @@ namespace BizHawk.Client.EmuHawk private void GBACoreSelectionSubMenu_DropDownOpened(object sender, EventArgs e) { - GBAmGBAMenuItem.Checked = Global.Config.GBA_UsemGBA == true; - GBAVBANextMenuItem.Checked = Global.Config.GBA_UsemGBA == false; - } - - private void GbaWithmGBAMenuItem_Click(object sender, EventArgs e) - { - Global.Config.GBA_UsemGBA ^= true; - FlagNeedsReboot(); + GBAmGBAMenuItem.Checked = Global.Config.GBA_UsemGBA; + GBAVBANextMenuItem.Checked = !Global.Config.GBA_UsemGBA; } #endregion @@ -2211,6 +2206,11 @@ namespace BizHawk.Client.EmuHawk SNESOptions.DoSettingsDialog(this); } + private void Snes9xSettingsMenuItem_Click(object sender, EventArgs e) + { + GenericCoreConfig.DoDialog(this, "Snes9x Settings"); + } + #endregion #region Coleco @@ -2272,7 +2272,7 @@ namespace BizHawk.Client.EmuHawk } else { - // Do nothing, Reboot is being flagged already if they chaned anything + // Do nothing, Reboot is being flagged already if they changed anything } } else @@ -2398,7 +2398,7 @@ namespace BizHawk.Client.EmuHawk #region Wondersawn - private void WondersawnSettingsMenuItem_Click(object sender, EventArgs e) + private void WonderSwanSettingsMenuItem_Click(object sender, EventArgs e) { GenericCoreConfig.DoDialog(this, "WonderSwan Settings"); } @@ -2424,9 +2424,8 @@ namespace BizHawk.Client.EmuHawk { AppleDisksSubMenu.DropDownItems.Clear(); - if (Emulator is AppleII) + if (Emulator is AppleII appleII) { - var appleII = (AppleII)Emulator; for (int i = 0; i < appleII.DiskCount; i++) { var menuItem = new ToolStripMenuItem @@ -2463,9 +2462,8 @@ namespace BizHawk.Client.EmuHawk { C64DisksSubMenu.DropDownItems.Clear(); - if (Emulator is C64) + if (Emulator is C64 c64) { - var c64 = (C64)Emulator; for (int i = 0; i < c64.DiskCount; i++) { var menuItem = new ToolStripMenuItem @@ -2495,7 +2493,7 @@ namespace BizHawk.Client.EmuHawk #region Intv - private void IntvSubMenu_DropDownOpened(object sender, EventArgs e) + private void IntVSubMenu_DropDownOpened(object sender, EventArgs e) { IntVControllerSettingsMenuItem.Enabled = !Global.MovieSession.Movie.IsActive; } @@ -2505,260 +2503,271 @@ namespace BizHawk.Client.EmuHawk new IntvControllerSettings().ShowDialog(); } - #endregion + #endregion - #region ZXSpectrum + #region VirtualBoy + private void VirtualBoySettingsMenuItem_Click(object sender, EventArgs e) + { + GenericCoreConfig.DoDialog(this, "VirtualBoy Settings"); + } - private void zXSpectrumToolStripMenuItem_DropDownOpened(object sender, EventArgs e) - { + #endregion - } + #region NeoGeoPocket - - private void preferencesToolStripMenuItem4_Click(object sender, EventArgs e) - { - GenericCoreConfig.DoDialog(this, "ZXSpectrum Settings"); - } - + private void NeoGeoSettingsMenuItem_Click(object sender, EventArgs e) + { + GenericCoreConfig.DoDialog(this, "NeoPop Settings"); + } - private void ZXSpectrumControllerConfigurationMenuItem_Click(object sender, EventArgs e) - { - new ZXSpectrumJoystickSettings().ShowDialog(); - } + #endregion - private void ZXSpectrumCoreEmulationSettingsMenuItem_Click(object sender, EventArgs e) - { - new ZXSpectrumCoreEmulationSettings().ShowDialog(); - } + #region PC-FX - private void ZXSpectrumNonSyncSettingsMenuItem_Click(object sender, EventArgs e) - { - new ZXSpectrumNonSyncSettings().ShowDialog(); - } + private void PCFXSettingsMenuItem_Click(object sender, EventArgs e) + { + GenericCoreConfig.DoDialog(this, "PC-FX Settings"); + } - private void ZXSpectrumAudioSettingsMenuItem_Click(object sender, EventArgs e) - { - new ZXSpectrumAudioSettings().ShowDialog(); - } + #endregion - private void ZXSpectrumPokeMemoryMenuItem_Click(object sender, EventArgs e) - { - new ZXSpectrumPokeMemory().ShowDialog(); - } + #region ZXSpectrum - private void ZXSpectrumMediaMenuItem_DropDownOpened(object sender, EventArgs e) - { - if (Emulator is ZXSpectrum) - { - ZXSpectrumTapesSubMenu.Enabled = ((ZXSpectrum)Emulator)._tapeInfo.Count > 0; - ZXSpectrumDisksSubMenu.Enabled = ((ZXSpectrum)Emulator)._diskInfo.Count > 0; - } - } + private void ZXSpectrumControllerConfigurationMenuItem_Click(object sender, EventArgs e) + { + new ZXSpectrumJoystickSettings().ShowDialog(); + } - private void ZXSpectrumTapesSubMenu_DropDownOpened(object sender, EventArgs e) - { - ZXSpectrumTapesSubMenu.DropDownItems.Clear(); + private void ZXSpectrumCoreEmulationSettingsMenuItem_Click(object sender, EventArgs e) + { + new ZXSpectrumCoreEmulationSettings().ShowDialog(); + } - List items = new List(); + private void ZXSpectrumNonSyncSettingsMenuItem_Click(object sender, EventArgs e) + { + new ZXSpectrumNonSyncSettings().ShowDialog(); + } - if (Emulator is ZXSpectrum) - { - var speccy = (ZXSpectrum)Emulator; - var currSel = speccy._machine.TapeMediaIndex; + private void ZXSpectrumAudioSettingsMenuItem_Click(object sender, EventArgs e) + { + new ZXSpectrumAudioSettings().ShowDialog(); + } - for (int i = 0; i < speccy._tapeInfo.Count; i++) - { - string name = speccy._tapeInfo[i].Name; + private void ZXSpectrumPokeMemoryMenuItem_Click(object sender, EventArgs e) + { + new ZXSpectrumPokeMemory().ShowDialog(); + } - var menuItem = new ToolStripMenuItem - { - Name = $"{i}_{name}", - Text = $"{i}: {name}", - Checked = currSel == i - }; + private void ZXSpectrumMediaMenuItem_DropDownOpened(object sender, EventArgs e) + { + if (Emulator is ZXSpectrum) + { + ZXSpectrumTapesSubMenu.Enabled = ((ZXSpectrum)Emulator)._tapeInfo.Count > 0; + ZXSpectrumDisksSubMenu.Enabled = ((ZXSpectrum)Emulator)._diskInfo.Count > 0; + } + } - int dummy = i; - menuItem.Click += (o, ev) => - { - speccy._machine.TapeMediaIndex = dummy; - }; - - items.Add(menuItem); - } - } - - ZXSpectrumTapesSubMenu.DropDownItems.AddRange(items.ToArray()); - } - - private void ZXSpectrumDisksSubMenu_DropDownOpened(object sender, EventArgs e) - { - ZXSpectrumDisksSubMenu.DropDownItems.Clear(); - - List items = new List(); - - if (Emulator is ZXSpectrum) - { - var speccy = (ZXSpectrum)Emulator; - var currSel = speccy._machine.DiskMediaIndex; - - for (int i = 0; i < speccy._diskInfo.Count; i++) - { - string name = speccy._diskInfo[i].Name; - - var menuItem = new ToolStripMenuItem - { - Name = $"{i}_{name}", - Text = $"{i}: {name}", - Checked = currSel == i - }; - - int dummy = i; - menuItem.Click += (o, ev) => - { - speccy._machine.DiskMediaIndex = dummy; - }; - - items.Add(menuItem); - } - } - - ZXSpectrumDisksSubMenu.DropDownItems.AddRange(items.ToArray()); - } - - private void ZXSpectrumExportSnapshotMenuItemMenuItem_Click(object sender, EventArgs e) - { - SaveFileDialog zxSnapExpDialog = new SaveFileDialog(); - zxSnapExpDialog.RestoreDirectory = true; - zxSnapExpDialog.Title = "EXPERIMENTAL - Export 3rd party snapshot formats"; - zxSnapExpDialog.DefaultExt = "szx"; - zxSnapExpDialog.Filter = "ZX-State files (*.szx)|*.szx"; - zxSnapExpDialog.SupportMultiDottedExtensions = true; - - try - { - var res = zxSnapExpDialog.ShowDialog(); - if (res == DialogResult.OK) - { - var speccy = (ZXSpectrum)Emulator; - var snap = speccy.GetSZXSnapshot(); - File.WriteAllBytes(zxSnapExpDialog.FileName, snap); - //File.WriteAllText(zxSnapExpDialog.FileName, snap); - } - } - catch (Exception ex) - { - var ee = ex; - } - } - - #endregion - - #region AmstradCPC - - private void amstradCPCCoreEmulationSettingsToolStripMenuItem_Click(object sender, EventArgs e) - { - new AmstradCPCCoreEmulationSettings().ShowDialog(); - } - - private void AmstradCPCAudioSettingsToolStripMenuItem_Click(object sender, EventArgs e) - { - new AmstradCPCAudioSettings().ShowDialog(); - } - - private void AmstradCPCPokeMemoryToolStripMenuItem_Click(object sender, EventArgs e) - { - new AmstradCPCPokeMemory().ShowDialog(); - } - - private void AmstradCPCMediaToolStripMenuItem_DropDownOpened(object sender, EventArgs e) - { - if (Emulator is AmstradCPC) - { - AmstradCPCTapesSubMenu.Enabled = ((AmstradCPC)Emulator)._tapeInfo.Count > 0; - AmstradCPCDisksSubMenu.Enabled = ((AmstradCPC)Emulator)._diskInfo.Count > 0; - } - } - - private void AmstradCPCTapesSubMenu_DropDownOpened(object sender, EventArgs e) - { - AmstradCPCTapesSubMenu.DropDownItems.Clear(); + private void ZXSpectrumTapesSubMenu_DropDownOpened(object sender, EventArgs e) + { + ZXSpectrumTapesSubMenu.DropDownItems.Clear(); List items = new List(); - if (Emulator is AmstradCPC) - { - var ams = (AmstradCPC)Emulator; - var currSel = ams._machine.TapeMediaIndex; + if (Emulator is ZXSpectrum speccy) + { + var tapeMediaIndex = speccy._machine.TapeMediaIndex; - for (int i = 0; i < ams._tapeInfo.Count; i++) - { - string name = ams._tapeInfo[i].Name; + for (int i = 0; i < speccy._tapeInfo.Count; i++) + { + string name = speccy._tapeInfo[i].Name; - var menuItem = new ToolStripMenuItem - { - Name = $"{i}_{name}", - Text = $"{i}: {name}", - Checked = currSel == i - }; + var menuItem = new ToolStripMenuItem + { + Name = $"{i}_{name}", + Text = $"{i}: {name}", + Checked = tapeMediaIndex == i + }; - int dummy = i; - menuItem.Click += (o, ev) => - { - ams._machine.TapeMediaIndex = dummy; - }; + int dummy = i; + menuItem.Click += (o, ev) => + { + speccy._machine.TapeMediaIndex = dummy; + }; items.Add(menuItem); } - } + } + + ZXSpectrumTapesSubMenu.DropDownItems.AddRange(items.ToArray()); + } + + private void ZXSpectrumDisksSubMenu_DropDownOpened(object sender, EventArgs e) + { + ZXSpectrumDisksSubMenu.DropDownItems.Clear(); + + var items = new List(); + + if (Emulator is ZXSpectrum speccy) + { + var diskMediaIndex = speccy._machine.DiskMediaIndex; + + for (int i = 0; i < speccy._diskInfo.Count; i++) + { + string name = speccy._diskInfo[i].Name; + + var menuItem = new ToolStripMenuItem + { + Name = $"{i}_{name}", + Text = $"{i}: {name}", + Checked = diskMediaIndex == i + }; + + int dummy = i; + menuItem.Click += (o, ev) => + { + speccy._machine.DiskMediaIndex = dummy; + }; + + items.Add(menuItem); + } + } + + ZXSpectrumDisksSubMenu.DropDownItems.AddRange(items.ToArray()); + } + + private void ZXSpectrumExportSnapshotMenuItemMenuItem_Click(object sender, EventArgs e) + { + var zxSnapExpDialog = new SaveFileDialog + { + RestoreDirectory = true + , Title = "EXPERIMENTAL - Export 3rd party snapshot formats" + , DefaultExt = "szx" + , Filter = "ZX-State files (*.szx)|*.szx" + , SupportMultiDottedExtensions = true + }; + + try + { + var res = zxSnapExpDialog.ShowDialog(); + if (res == DialogResult.OK) + { + var speccy = (ZXSpectrum)Emulator; + var snap = speccy.GetSZXSnapshot(); + File.WriteAllBytes(zxSnapExpDialog.FileName, snap); + } + } + catch (Exception ex) + { + var ee = ex; + } + } + + #endregion + + #region AmstradCPC + + private void amstradCPCCoreEmulationSettingsToolStripMenuItem_Click(object sender, EventArgs e) + { + new AmstradCPCCoreEmulationSettings().ShowDialog(); + } + + private void AmstradCPCAudioSettingsToolStripMenuItem_Click(object sender, EventArgs e) + { + new AmstradCPCAudioSettings().ShowDialog(); + } + + private void AmstradCPCPokeMemoryToolStripMenuItem_Click(object sender, EventArgs e) + { + new AmstradCPCPokeMemory().ShowDialog(); + } + + private void AmstradCPCMediaToolStripMenuItem_DropDownOpened(object sender, EventArgs e) + { + if (Emulator is AmstradCPC) + { + AmstradCPCTapesSubMenu.Enabled = ((AmstradCPC)Emulator)._tapeInfo.Count > 0; + AmstradCPCDisksSubMenu.Enabled = ((AmstradCPC)Emulator)._diskInfo.Count > 0; + } + } + + private void AmstradCPCTapesSubMenu_DropDownOpened(object sender, EventArgs e) + { + AmstradCPCTapesSubMenu.DropDownItems.Clear(); + + var items = new List(); + + if (Emulator is AmstradCPC ams) + { + var tapeMediaIndex = ams._machine.TapeMediaIndex; + + for (int i = 0; i < ams._tapeInfo.Count; i++) + { + string name = ams._tapeInfo[i].Name; + + var menuItem = new ToolStripMenuItem + { + Name = $"{i}_{name}", + Text = $"{i}: {name}", + Checked = tapeMediaIndex == i + }; + + int dummy = i; + menuItem.Click += (o, ev) => + { + ams._machine.TapeMediaIndex = dummy; + }; + + items.Add(menuItem); + } + } AmstradCPCTapesSubMenu.DropDownItems.AddRange(items.ToArray()); } - private void AmstradCPCDisksSubMenu_DropDownOpened(object sender, EventArgs e) - { + private void AmstradCPCDisksSubMenu_DropDownOpened(object sender, EventArgs e) + { AmstradCPCDisksSubMenu.DropDownItems.Clear(); - List items = new List(); + var items = new List(); - if (Emulator is AmstradCPC) - { - var ams = (AmstradCPC)Emulator; - var currSel = ams._machine.DiskMediaIndex; + if (Emulator is AmstradCPC ams) + { + var diskMediaIndex = ams._machine.DiskMediaIndex; - for (int i = 0; i < ams._diskInfo.Count; i++) - { - string name = ams._diskInfo[i].Name; + for (int i = 0; i < ams._diskInfo.Count; i++) + { + string name = ams._diskInfo[i].Name; - var menuItem = new ToolStripMenuItem - { - Name = $"{i}_{name}", - Text = $"{i}: {name}", - Checked = currSel == i - }; + var menuItem = new ToolStripMenuItem + { + Name = $"{i}_{name}", + Text = $"{i}: {name}", + Checked = diskMediaIndex == i + }; - int dummy = i; - menuItem.Click += (o, ev) => - { - ams._machine.DiskMediaIndex = dummy; - }; + int dummy = i; + menuItem.Click += (o, ev) => + { + ams._machine.DiskMediaIndex = dummy; + }; items.Add(menuItem); } - } + } AmstradCPCDisksSubMenu.DropDownItems.AddRange(items.ToArray()); } - private void AmstradCPCNonSyncSettingsToolStripMenuItem_Click(object sender, EventArgs e) - { - new AmstradCPCNonSyncSettings().ShowDialog(); - } + private void AmstradCPCNonSyncSettingsToolStripMenuItem_Click(object sender, EventArgs e) + { + new AmstradCPCNonSyncSettings().ShowDialog(); + } - #endregion + #endregion - #region Help + #region Help - private void HelpSubMenu_DropDownOpened(object sender, EventArgs e) + private void HelpSubMenu_DropDownOpened(object sender, EventArgs e) { FeaturesMenuItem.Visible = VersionInfo.DeveloperBuild; } @@ -2808,9 +2817,9 @@ namespace BizHawk.Client.EmuHawk showMenuVisible = true; // need to always be able to restore this as an emergency measure } - if (argParser._chromeless) + if (_argParser._chromeless) { - showMenuVisible = true; // I decided this was always possible in chromeless mode, we'll see what they think + showMenuVisible = true; // I decided this was always possible in chrome-less mode, we'll see what they think } ShowMenuContextMenuItem.Visible = diff --git a/BizHawk.Client.EmuHawk/MainForm.cs b/BizHawk.Client.EmuHawk/MainForm.cs index d199a789df..94e6eeb07f 100644 --- a/BizHawk.Client.EmuHawk/MainForm.cs +++ b/BizHawk.Client.EmuHawk/MainForm.cs @@ -25,7 +25,6 @@ using BizHawk.Emulation.Cores.Nintendo.NES; using BizHawk.Emulation.Cores.Nintendo.SNES; using BizHawk.Emulation.Cores.Nintendo.N64; using BizHawk.Emulation.Cores.Nintendo.GBHawkLink; -using BizHawk.Emulation.Cores.Sega.GGHawkLink; using BizHawk.Client.EmuHawk.WinFormExtensions; using BizHawk.Client.EmuHawk.ToolExtensions; @@ -34,7 +33,6 @@ using BizHawk.Client.ApiHawk; using BizHawk.Emulation.Common.Base_Implementations; using BizHawk.Emulation.Cores.Nintendo.SNES9X; using BizHawk.Emulation.Cores.Consoles.SNK; -using BizHawk.Emulation.Cores.Consoles.Sega.PicoDrive; using BizHawk.Emulation.Cores.Consoles.Nintendo.Gameboy; namespace BizHawk.Client.EmuHawk @@ -47,11 +45,11 @@ namespace BizHawk.Client.EmuHawk { SetWindowText(); - // Hide Status bar icons and general statusbar prep + // Hide Status bar icons and general StatusBar prep MainStatusBar.Padding = new Padding(MainStatusBar.Padding.Left, MainStatusBar.Padding.Top, MainStatusBar.Padding.Left, MainStatusBar.Padding.Bottom); // Workaround to remove extra padding on right PlayRecordStatusButton.Visible = false; AVIStatusLabel.Visible = false; - SetPauseStatusbarIcon(); + SetPauseStatusBarIcon(); ToolFormBase.UpdateCheatRelatedTools(null, null); RebootStatusBarIcon.Visible = false; UpdateNotification.Visible = false; @@ -83,20 +81,19 @@ namespace BizHawk.Client.EmuHawk static MainForm() { - // If this isnt here, then our assemblyresolving hacks wont work due to the check for MainForm.INTERIM - // its.. weird. dont ask. + // If this isn't here, then our assembly resolving hacks wont work due to the check for MainForm.INTERIM + // its.. weird. don't ask. } private CoreComm CreateCoreComm() { - CoreComm ret = new CoreComm(ShowMessageCoreComm, NotifyCoreComm) + return new CoreComm(ShowMessageCoreComm, NotifyCoreComm) { ReleaseGLContext = o => GlobalWin.GLManager.ReleaseGLContext(o), RequestGLContext = (major, minor, forward) => GlobalWin.GLManager.CreateGLContext(major, minor, forward), ActivateGLContext = gl => GlobalWin.GLManager.Activate((GLManager.ContextRef)gl), DeactivateGLContext = () => GlobalWin.GLManager.Deactivate() }; - return ret; } public MainForm(string[] args) @@ -157,13 +154,13 @@ namespace BizHawk.Client.EmuHawk }; try { - argParser.ParseArguments(args); + _argParser.ParseArguments(args); } catch (ArgParserException e) { MessageBox.Show(e.Message); } - + Database.LoadDatabase(Path.Combine(PathManager.GetExeDirectoryAbsolute(), "gamedb", "gamedb.txt")); @@ -281,14 +278,14 @@ namespace BizHawk.Client.EmuHawk Location = new Point(Global.Config.MainWndx, Global.Config.MainWndy); } - if (argParser.cmdRom != null) + if (_argParser.cmdRom != null) { // Commandline should always override auto-load - var ioa = OpenAdvancedSerializer.ParseWithLegacy(argParser.cmdRom); - LoadRom(argParser.cmdRom, new LoadRomArgs { OpenAdvanced = ioa }); + var ioa = OpenAdvancedSerializer.ParseWithLegacy(_argParser.cmdRom); + LoadRom(_argParser.cmdRom, new LoadRomArgs { OpenAdvanced = ioa }); if (Global.Game == null) { - MessageBox.Show($"Failed to load {argParser.cmdRom} specified on commandline"); + MessageBox.Show($"Failed to load {_argParser.cmdRom} specified on commandline"); } } else if (Global.Config.RecentRoms.AutoLoad && !Global.Config.RecentRoms.Empty) @@ -296,14 +293,14 @@ namespace BizHawk.Client.EmuHawk LoadRomFromRecent(Global.Config.RecentRoms.MostRecent); } - if (argParser.audiosync.HasValue) + if (_argParser.audiosync.HasValue) { - Global.Config.VideoWriterAudioSync = argParser.audiosync.Value; + Global.Config.VideoWriterAudioSync = _argParser.audiosync.Value; } - if (argParser.cmdMovie != null) + if (_argParser.cmdMovie != null) { - _supressSyncSettingsWarning = true; // We dont' want to be nagged if we are attempting to automate + _suppressSyncSettingsWarning = true; // We don't want to be nagged if we are attempting to automate if (Global.Game == null) { OpenRom(); @@ -312,21 +309,19 @@ namespace BizHawk.Client.EmuHawk // If user picked a game, then do the commandline logic if (!Global.Game.IsNullInstance) { - var movie = MovieService.Get(argParser.cmdMovie); + var movie = MovieService.Get(_argParser.cmdMovie); Global.MovieSession.ReadOnly = true; - // if user is dumping and didnt supply dump length, make it as long as the loaded movie - if (argParser._autoDumpLength == 0) + // if user is dumping and didn't supply dump length, make it as long as the loaded movie + if (_argParser._autoDumpLength == 0) { - argParser._autoDumpLength = movie.InputLogLength; + _argParser._autoDumpLength = movie.InputLogLength; } // Copy pasta from drag & drop - if (MovieImport.IsValidMovieExtension(Path.GetExtension(argParser.cmdMovie))) + if (MovieImport.IsValidMovieExtension(Path.GetExtension(_argParser.cmdMovie))) { - string errorMsg; - string warningMsg; - var imported = MovieImport.ImportFile(argParser.cmdMovie, out errorMsg, out warningMsg); + var imported = MovieImport.ImportFile(_argParser.cmdMovie, out var errorMsg, out var warningMsg); if (!string.IsNullOrEmpty(errorMsg)) { MessageBox.Show(errorMsg, "Conversion error", MessageBoxButtons.OK, MessageBoxIcon.Error); @@ -344,10 +339,10 @@ namespace BizHawk.Client.EmuHawk else { StartNewMovie(movie, false); - Global.Config.RecentMovies.Add(argParser.cmdMovie); + Global.Config.RecentMovies.Add(_argParser.cmdMovie); } - _supressSyncSettingsWarning = false; + _suppressSyncSettingsWarning = false; } } else if (Global.Config.RecentMovies.AutoLoad && !Global.Config.RecentMovies.Empty) @@ -371,20 +366,20 @@ namespace BizHawk.Client.EmuHawk } } - if (argParser.startFullscreen || Global.Config.StartFullscreen) + if (_argParser.startFullscreen || Global.Config.StartFullscreen) { _needsFullscreenOnLoad = true; } if (!Global.Game.IsNullInstance) { - if (argParser.cmdLoadState != null) + if (_argParser.cmdLoadState != null) { - LoadState(argParser.cmdLoadState, Path.GetFileName(argParser.cmdLoadState)); + LoadState(_argParser.cmdLoadState, Path.GetFileName(_argParser.cmdLoadState)); } - else if (argParser.cmdLoadSlot != null) + else if (_argParser.cmdLoadSlot != null) { - LoadQuickSave($"QuickSave{argParser.cmdLoadSlot}"); + LoadQuickSave($"QuickSave{_argParser.cmdLoadSlot}"); } else if (Global.Config.AutoLoadLastSaveSlot) { @@ -393,14 +388,14 @@ namespace BizHawk.Client.EmuHawk } //start Lua Console if requested in the command line arguments - if (argParser.luaConsole) + if (_argParser.luaConsole) { GlobalWin.Tools.Load(); } //load Lua Script if requested in the command line arguments - if (argParser.luaScript != null) + if (_argParser.luaScript != null) { - GlobalWin.Tools.LuaConsole.LoadLuaFile(argParser.luaScript); + GlobalWin.Tools.LuaConsole.LoadLuaFile(_argParser.luaScript); } GlobalWin.Tools.AutoLoad(); @@ -421,11 +416,11 @@ namespace BizHawk.Client.EmuHawk { PauseEmulator(); } - + // start dumping, if appropriate - if (argParser.cmdDumpType != null && argParser.cmdDumpName != null) + if (_argParser.cmdDumpType != null && _argParser.cmdDumpName != null) { - RecordAv(argParser.cmdDumpType, argParser.cmdDumpName); + RecordAv(_argParser.cmdDumpType, _argParser.cmdDumpName); } SetMainformMovieInfo(); @@ -438,7 +433,7 @@ namespace BizHawk.Client.EmuHawk }; } - private readonly bool _supressSyncSettingsWarning; + private readonly bool _suppressSyncSettingsWarning; public int ProgramRunLoop() { @@ -461,7 +456,7 @@ namespace BizHawk.Client.EmuHawk InitializeFpsData(); - for (;;) + for (; ; ) { Input.Instance.Update(); @@ -551,10 +546,7 @@ namespace BizHawk.Client.EmuHawk private bool _emulatorPaused; public bool EmulatorPaused { - get - { - return _emulatorPaused; - } + get => _emulatorPaused; private set { @@ -578,7 +570,7 @@ namespace BizHawk.Client.EmuHawk Paused = paused; } - public bool Paused { get; private set; } + public bool Paused { get; } } #endregion @@ -601,15 +593,12 @@ namespace BizHawk.Client.EmuHawk private int? _pauseOnFrame; public int? PauseOnFrame // If set, upon completion of this frame, the client wil pause { - get - { - return _pauseOnFrame; - } + get => _pauseOnFrame; set { _pauseOnFrame = value; - SetPauseStatusbarIcon(); + SetPauseStatusBarIcon(); if (value == null) // TODO: make an Event handler instead, but the logic here is that after turbo seeking, tools will want to do a real update when the emulator finally pauses { @@ -660,8 +649,7 @@ namespace BizHawk.Client.EmuHawk // even more special logic for TAStudio: // TODO - implement by event filter in TAStudio - var maybeTAStudio = ActiveForm as TAStudio; - if (maybeTAStudio != null) + if (ActiveForm is TAStudio maybeTAStudio) { if (yieldAlt || maybeTAStudio.IsInMenuLoop) { @@ -691,10 +679,7 @@ namespace BizHawk.Client.EmuHawk // This is a quick hack to reduce the dependency on Global.Emulator private IEmulator Emulator { - get - { - return Global.Emulator; - } + get => Global.Emulator; set { @@ -722,9 +707,9 @@ namespace BizHawk.Client.EmuHawk private void ProcessInput() { - ControllerInputCoalescer conInput = (ControllerInputCoalescer)Global.ControllerInputCoalescer; + var conInput = (ControllerInputCoalescer)Global.ControllerInputCoalescer; - for (;;) + for (; ; ) { // loop through all available events var ie = Input.Instance.DequeueEvent(); @@ -760,11 +745,11 @@ namespace BizHawk.Client.EmuHawk } } - // ordinarily, an alt release with nothing else would move focus to the menubar. but that is sort of useless, and hard to implement exactly right. + // ordinarily, an alt release with nothing else would move focus to the MenuBar. but that is sort of useless, and hard to implement exactly right. } // zero 09-sep-2012 - all input is eligible for controller input. not sure why the above was done. - // maybe because it doesnt make sense to me to bind hotkeys and controller inputs to the same keystrokes + // maybe because it doesn't make sense to me to bind hotkeys and controller inputs to the same keystrokes // adelikat 02-dec-2012 - implemented options for how to handle controller vs hotkey conflicts. This is primarily motivated by computer emulation and thus controller being nearly the entire keyboard bool handled; @@ -780,14 +765,14 @@ namespace BizHawk.Client.EmuHawk handled = triggers.Aggregate(handled, (current, trigger) => current | CheckHotkey(trigger)); } - // hotkeys which arent handled as actions get coalesced as pollable virtual client buttons + // hotkeys which aren't handled as actions get coalesced as pollable virtual client buttons if (!handled) { _hotkeyCoalescer.Receive(ie); } break; - case 1: // Input overrides Hokeys + case 1: // Input overrides Hotkeys conInput.Receive(ie); if (!Global.ActiveController.HasBinding(ie.LogicalButton.ToString())) { @@ -797,7 +782,7 @@ namespace BizHawk.Client.EmuHawk handled = triggers.Aggregate(handled, (current, trigger) => current | CheckHotkey(trigger)); } - // hotkeys which arent handled as actions get coalesced as pollable virtual client buttons + // hotkeys which aren't handled as actions get coalesced as pollable virtual client buttons if (!handled) { _hotkeyCoalescer.Receive(ie); @@ -812,12 +797,12 @@ namespace BizHawk.Client.EmuHawk handled = triggers.Aggregate(handled, (current, trigger) => current | CheckHotkey(trigger)); } - // hotkeys which arent handled as actions get coalesced as pollable virtual client buttons + // hotkeys which aren't handled as actions get coalesced as pollable virtual client buttons if (!handled) { _hotkeyCoalescer.Receive(ie); - // Check for hotkeys that may not be handled through Checkhotkey() method, reject controller input mapped to these + // Check for hotkeys that may not be handled through CheckHotkey() method, reject controller input mapped to these if (!triggers.Any(IsInternalHotkey)) { conInput.Receive(ie); @@ -859,19 +844,19 @@ namespace BizHawk.Client.EmuHawk public void PauseEmulator() { EmulatorPaused = true; - SetPauseStatusbarIcon(); + SetPauseStatusBarIcon(); } public void UnpauseEmulator() { EmulatorPaused = false; - SetPauseStatusbarIcon(); + SetPauseStatusBarIcon(); } public void TogglePause() { EmulatorPaused ^= true; - SetPauseStatusbarIcon(); + SetPauseStatusBarIcon(); // TODO: have tastudio set a pause status change callback, or take control over pause if (GlobalWin.Tools.Has()) @@ -1015,15 +1000,15 @@ namespace BizHawk.Client.EmuHawk { // TODO - maybe apply a hack tracked during fullscreen here to override it FormBorderStyle = FormBorderStyle.None; - MainMenuStrip.Visible = Global.Config.DispChrome_MenuFullscreen && !argParser._chromeless; - MainStatusBar.Visible = Global.Config.DispChrome_StatusBarFullscreen && !argParser._chromeless; + MainMenuStrip.Visible = Global.Config.DispChrome_MenuFullscreen && !_argParser._chromeless; + MainStatusBar.Visible = Global.Config.DispChrome_StatusBarFullscreen && !_argParser._chromeless; } else { - MainStatusBar.Visible = Global.Config.DispChrome_StatusBarWindowed && !argParser._chromeless; - MainMenuStrip.Visible = Global.Config.DispChrome_MenuWindowed && !argParser._chromeless; - MaximizeBox = MinimizeBox = Global.Config.DispChrome_CaptionWindowed && !argParser._chromeless; - if (Global.Config.DispChrome_FrameWindowed == 0 || argParser._chromeless) + MainStatusBar.Visible = Global.Config.DispChrome_StatusBarWindowed && !_argParser._chromeless; + MainMenuStrip.Visible = Global.Config.DispChrome_MenuWindowed && !_argParser._chromeless; + MaximizeBox = MinimizeBox = Global.Config.DispChrome_CaptionWindowed && !_argParser._chromeless; + if (Global.Config.DispChrome_FrameWindowed == 0 || _argParser._chromeless) { FormBorderStyle = FormBorderStyle.None; } @@ -1058,17 +1043,17 @@ namespace BizHawk.Client.EmuHawk // Work around an AMD driver bug in >= vista: // It seems windows will activate opengl fullscreen mode when a GL control is occupying the exact space of a screen (0,0 and dimensions=screensize) // AMD cards manifest a problem under these circumstances, flickering other monitors. - // It isnt clear whether nvidia cards are failing to employ this optimization, or just not flickering. - // (this could be determined with more work; other side affects of the fullscreen mode include: corrupted taskbar, no modal boxes on top of GL control, no screenshots) + // It isn't clear whether nvidia cards are failing to employ this optimization, or just not flickering. + // (this could be determined with more work; other side affects of the fullscreen mode include: corrupted TaskBar, no modal boxes on top of GL control, no screenshots) // At any rate, we can solve this by adding a 1px black border around the GL control // Please note: It is important to do this before resizing things, otherwise momentarily a GL control without WS_BORDER will be at the magic dimensions and cause the flakeout if (OSTailoredCode.CurrentOS == OSTailoredCode.DistinctOS.Windows && Global.Config.DispFullscreenHacks && Global.Config.DispMethod == Config.EDispMethod.OpenGL) { - //ATTENTION: this causes the statusbar to not work well, since the backcolor is now set to black instead of SystemColors.Control. - //It seems that some statusbar elements composite with the backcolor. - //Maybe we could add another control under the statusbar. with a different backcolor + // ATTENTION: this causes the StatusBar to not work well, since the backcolor is now set to black instead of SystemColors.Control. + // It seems that some StatusBar elements composite with the backcolor. + // Maybe we could add another control under the StatusBar. with a different backcolor Padding = new Padding(1); BackColor = Color.Black; @@ -1093,11 +1078,11 @@ namespace BizHawk.Client.EmuHawk if (OSTailoredCode.CurrentOS == OSTailoredCode.DistinctOS.Windows) { - // do this even if DispFullscreenHacks arent enabled, to restore it in case it changed underneath us or something + // do this even if DispFullscreenHacks aren't enabled, to restore it in case it changed underneath us or something Padding = new Padding(0); - // it's important that we set the form color back to this, because the statusbar icons blend onto the mainform, not onto the statusbar-- - // so we need the statusbar and mainform backdrop color to match + // it's important that we set the form color back to this, because the StatusBar icons blend onto the mainform, not onto the StatusBar-- + // so we need the StatusBar and mainform backdrop color to match BackColor = SystemColors.Control; } @@ -1188,8 +1173,6 @@ namespace BizHawk.Client.EmuHawk } } - private LibsnesCore AsSNES => Emulator as LibsnesCore; - private void SNES_ToggleBg(int layer) { if (!(Emulator is LibsnesCore) && !(Emulator is Snes9x)) @@ -1351,7 +1334,7 @@ namespace BizHawk.Client.EmuHawk private AutofireController _autofireNullControls; - // Sound refator TODO: we can enforce async mode here with a property that gets/sets this but does an async check + // Sound refactor TODO: we can enforce async mode here with a property that gets/sets this but does an async check private ISoundProvider _aviSoundInputAsync; // Note: This sound provider must be in async mode! private SimpleSyncSoundProvider _dumpProxy; // an audio proxy used for dumping @@ -1392,7 +1375,7 @@ namespace BizHawk.Client.EmuHawk private int _lastOpenRomFilter; - private ArgParser argParser = new ArgParser(); + private readonly ArgParser _argParser = new ArgParser(); // Resources private Bitmap _statusBarDiskLightOnImage; @@ -1407,7 +1390,7 @@ namespace BizHawk.Client.EmuHawk public PresentationPanel PresentationPanel { get; } - //countdown for saveram autoflushing + // countdown for saveram autoflushing public int AutoFlushSaveRamIn { get; set; } #endregion @@ -1462,7 +1445,7 @@ namespace BizHawk.Client.EmuHawk } } - if (!Global.Config.DispChrome_CaptionWindowed || argParser._chromeless) + if (!Global.Config.DispChrome_CaptionWindowed || _argParser._chromeless) { str = ""; } @@ -1495,11 +1478,7 @@ namespace BizHawk.Client.EmuHawk DumpStatusButton.Image = Properties.Resources.Blank; DumpStatusButton.ToolTipText = ""; - if (Emulator.IsNull()) - { - return; - } - else if (Global.Game == null) + if (Emulator.IsNull() || Global.Game == null) { return; } @@ -1551,10 +1530,10 @@ namespace BizHawk.Client.EmuHawk { annotation = Emulator.CoreComm.RomStatusAnnotation; - if (annotation == "Multi-disk bundler") - { - DumpStatusButton.Image = Properties.Resources.RetroQuestion; - } + if (annotation == "Multi-disk bundler") + { + DumpStatusButton.Image = Properties.Resources.RetroQuestion; + } } DumpStatusButton.ToolTipText = annotation; @@ -1586,8 +1565,8 @@ namespace BizHawk.Client.EmuHawk } else { - var oldram = Emulator.AsSaveRam().CloneSaveRam(); - if (oldram == null) + var oldRam = Emulator.AsSaveRam().CloneSaveRam(); + if (oldRam == null) { // we're eating this one now. The possible negative consequence is that a user could lose // their saveram and not know why @@ -1596,7 +1575,7 @@ namespace BizHawk.Client.EmuHawk } // why do we silently truncate\pad here instead of warning\erroring? - sram = new byte[oldram.Length]; + sram = new byte[oldRam.Length]; using (var reader = new BinaryReader( new FileStream(PathManager.SaveRamPath(Global.Game), FileMode.Open, FileAccess.Read))) { @@ -1612,7 +1591,7 @@ namespace BizHawk.Client.EmuHawk GlobalWin.OSD.AddMessage("An error occurred while loading Sram"); } } - } + } public bool FlushSaveRAM(bool autosave = false) { @@ -1635,15 +1614,15 @@ namespace BizHawk.Client.EmuHawk var backupFile = new FileInfo(backupPath); if (file.Directory != null && !file.Directory.Exists) { - try - { - file.Directory.Create(); - } - catch - { - GlobalWin.OSD.AddMessage($"Unable to flush SaveRAM to: {newFile.Directory}"); - return false; - } + try + { + file.Directory.Create(); + } + catch + { + GlobalWin.OSD.AddMessage($"Unable to flush SaveRAM to: {newFile.Directory}"); + return false; + } } var writer = new BinaryWriter(new FileStream(newPath, FileMode.Create, FileAccess.Write)); @@ -1675,7 +1654,7 @@ namespace BizHawk.Client.EmuHawk newFile.MoveTo(path); } - return true; + return true; } private void RewireSound() @@ -1729,8 +1708,8 @@ namespace BizHawk.Client.EmuHawk sNESToolStripMenuItem.Visible = false; neoGeoPocketToolStripMenuItem.Visible = false; pCFXToolStripMenuItem.Visible = false; - zXSpectrumToolStripMenuItem.Visible = false; - amstradCPCToolStripMenuItem.Visible = false; + zXSpectrumToolStripMenuItem.Visible = false; + amstradCPCToolStripMenuItem.Visible = false; VectrexSubMenu.Visible = false; switch (system) @@ -1810,7 +1789,7 @@ namespace BizHawk.Client.EmuHawk else { DGBSubMenu.Visible = true; - } + } break; case "WSWAN": wonderSwanToolStripMenuItem.Visible = true; @@ -1833,17 +1812,17 @@ namespace BizHawk.Client.EmuHawk case "PCFX": pCFXToolStripMenuItem.Visible = true; break; - case "ZXSpectrum": - zXSpectrumToolStripMenuItem.Visible = true; + case "ZXSpectrum": + zXSpectrumToolStripMenuItem.Visible = true; #if DEBUG - ZXSpectrumExportSnapshotMenuItemMenuItem.Visible = true; + ZXSpectrumExportSnapshotMenuItemMenuItem.Visible = true; #else - ZXSpectrumExportSnapshotMenuItemMenuItem.Visible = false; + ZXSpectrumExportSnapshotMenuItemMenuItem.Visible = false; #endif - break; - case "AmstradCPC": - amstradCPCToolStripMenuItem.Visible = true; - break; + break; + case "AmstradCPC": + amstradCPCToolStripMenuItem.Visible = true; + break; case "GGL": GGLSubMenu.Visible = true; break; @@ -1909,7 +1888,7 @@ namespace BizHawk.Client.EmuHawk } } - private void SetPauseStatusbarIcon() + private void SetPauseStatusBarIcon() { if (EmulatorPaused) { @@ -2031,8 +2010,8 @@ namespace BizHawk.Client.EmuHawk private void SaveSlotSelectedMessage() { int slot = Global.Config.SaveSlot; - string emptypart = _stateSlots.HasSlot(slot) ? "" : " (empty)"; - string message = $"Slot {slot}{emptypart} selected."; + string emptyPart = _stateSlots.HasSlot(slot) ? "" : " (empty)"; + string message = $"Slot {slot}{emptyPart} selected."; GlobalWin.OSD.AddMessage(message); } @@ -2047,19 +2026,18 @@ namespace BizHawk.Client.EmuHawk Size currVideoSize = new Size(video.BufferWidth, video.BufferHeight); Size currVirtualSize = new Size(video.VirtualWidth, video.VirtualHeight); - bool resizeFramebuffer = false; - if (currVideoSize != _lastVideoSize || currVirtualSize != _lastVirtualSize) - resizeFramebuffer = true; - bool isZero = false; - if (currVideoSize.Width == 0 || currVideoSize.Height == 0 || currVirtualSize.Width == 0 || currVirtualSize.Height == 0) - isZero = true; - + bool resizeFramebuffer = currVideoSize != _lastVideoSize || currVirtualSize != _lastVirtualSize; + + bool isZero = currVideoSize.Width == 0 || currVideoSize.Height == 0 || currVirtualSize.Width == 0 || currVirtualSize.Height == 0; + //don't resize if the new size is 0 somehow; we'll wait until we have a sensible size - if(isZero) + if (isZero) + { resizeFramebuffer = false; + } - if(resizeFramebuffer) + if (resizeFramebuffer) { _lastVideoSize = currVideoSize; _lastVirtualSize = currVirtualSize; @@ -2068,7 +2046,7 @@ namespace BizHawk.Client.EmuHawk //rendering flakes out egregiously if we have a zero size //can we fix it later not to? - if(isZero) + if (isZero) GlobalWin.DisplayManager.Blank(); else GlobalWin.DisplayManager.UpdateSource(video); @@ -2142,8 +2120,8 @@ namespace BizHawk.Client.EmuHawk new FileFilterEntry("Atari 2600", "*.a26;%ARCH%", developerFilters: "*.bin"), new FileFilterEntry("Atari 7800", "*.a78;%ARCH%", developerFilters: "*.bin"), new FileFilterEntry("Atari Lynx", "*.lnx;%ARCH%"), - new FileFilterEntry("Colecovision", "*.col;%ARCH%"), - new FileFilterEntry("Intellivision", "*.int;*.bin;*.rom;%ARCH%"), + new FileFilterEntry("ColecoVision", "*.col;%ARCH%"), + new FileFilterEntry("IntelliVision", "*.int;*.bin;*.rom;%ARCH%"), new FileFilterEntry("TI-83", "*.rom;%ARCH%"), new FileFilterEntry("Archive Files", "%ARCH%"), new FileFilterEntry("Genesis", "*.gen;*.md;*.smd;*.32x;*.bin;*.cue;*.ccd;%ARCH%"), @@ -2219,8 +2197,8 @@ namespace BizHawk.Client.EmuHawk { e.Settings = Global.Config.GetCoreSyncSettings(e.Core); - // adelikat: only show this nag if the core actually has sync settings, not all cores do - if (e.Settings != null && !_supressSyncSettingsWarning) + // Only show this nag if the core actually has sync settings, not all cores do + if (e.Settings != null && !_suppressSyncSettingsWarning) { MessageBox.Show( "No sync settings found, using currently configured settings for this core.", @@ -2687,22 +2665,22 @@ namespace BizHawk.Client.EmuHawk var attributes = Emulator.Attributes(); CoreNameStatusBarButton.Text = Emulator.DisplayName(); - CoreNameStatusBarButton.Image = Emulator.Icon(); - CoreNameStatusBarButton.ToolTipText = attributes.Ported ? "(ported) " : ""; + CoreNameStatusBarButton.Image = Emulator.Icon(); + CoreNameStatusBarButton.ToolTipText = attributes.Ported ? "(ported) " : ""; - if (Emulator.SystemId == "ZXSpectrum") - { - var core = (Emulation.Cores.Computers.SinclairSpectrum.ZXSpectrum)Emulator as Emulation.Cores.Computers.SinclairSpectrum.ZXSpectrum; - CoreNameStatusBarButton.ToolTipText = core.GetMachineType(); - } + if (Emulator.SystemId == "ZXSpectrum") + { + var core = (Emulation.Cores.Computers.SinclairSpectrum.ZXSpectrum)Emulator; + CoreNameStatusBarButton.ToolTipText = core.GetMachineType(); + } - if (Emulator.SystemId == "AmstradCPC") - { - var core = (Emulation.Cores.Computers.AmstradCPC.AmstradCPC)Emulator as Emulation.Cores.Computers.AmstradCPC.AmstradCPC; - CoreNameStatusBarButton.ToolTipText = core.GetMachineType(); - } - } + if (Emulator.SystemId == "AmstradCPC") + { + var core = (Emulation.Cores.Computers.AmstradCPC.AmstradCPC)Emulator; + CoreNameStatusBarButton.ToolTipText = core.GetMachineType(); + } + } private void ToggleKeyPriority() { @@ -2819,8 +2797,7 @@ namespace BizHawk.Client.EmuHawk runFrame = true; } - bool returnToRecording; - bool isRewinding = Rewind(ref runFrame, currentTimestamp, out returnToRecording); + bool isRewinding = Rewind(ref runFrame, currentTimestamp, out var returnToRecording); float atten = 0; @@ -2894,7 +2871,7 @@ namespace BizHawk.Client.EmuHawk FlushSaveRAM(true); } } - // why not skip audio if the user doesnt want sound + // why not skip audio if the user doesn't want sound bool renderSound = (Global.Config.SoundEnabled && !IsTurboing) || (_currAviWriter?.UsesAudio ?? false); if (!renderSound) { @@ -3046,11 +3023,11 @@ namespace BizHawk.Client.EmuHawk /// /// start AVI recording, unattended /// - /// match the short name of an + /// match the short name of an /// filename to save to - private void RecordAv(string videowritername, string filename) + private void RecordAv(string videoWriterName, string filename) { - RecordAvBase(videowritername, filename, true); + RecordAvBase(videoWriterName, filename, true); } /// @@ -3064,7 +3041,7 @@ namespace BizHawk.Client.EmuHawk /// /// start AV recording /// - private void RecordAvBase(string videowritername, string filename, bool unattended) + private void RecordAvBase(string videoWriterName, string filename, bool unattended) { if (_currAviWriter != null) { @@ -3074,15 +3051,15 @@ namespace BizHawk.Client.EmuHawk // select IVideoWriter to use IVideoWriter aw; - if (string.IsNullOrEmpty(videowritername) && !string.IsNullOrEmpty(Global.Config.VideoWriter)) + if (string.IsNullOrEmpty(videoWriterName) && !string.IsNullOrEmpty(Global.Config.VideoWriter)) { - videowritername = Global.Config.VideoWriter; + videoWriterName = Global.Config.VideoWriter; } _dumpaudiosync = Global.Config.VideoWriterAudioSync; - if (unattended && !string.IsNullOrEmpty(videowritername)) + if (unattended && !string.IsNullOrEmpty(videoWriterName)) { - aw = VideoWriterInventory.GetVideoWriter(videowritername); + aw = VideoWriterInventory.GetVideoWriter(videoWriterName); } else { @@ -3093,7 +3070,7 @@ namespace BizHawk.Client.EmuHawk if (aw == null) { GlobalWin.OSD.AddMessage( - unattended ? $"Couldn't start video writer \"{videowritername}\"" : "A/V capture canceled."); + unattended ? $"Couldn't start video writer \"{videoWriterName}\"" : "A/V capture canceled."); return; } @@ -3176,7 +3153,7 @@ namespace BizHawk.Client.EmuHawk var sfd = new SaveFileDialog(); if (Global.Game != null) { - sfd.FileName = $"{PathManager.FilesystemSafeName(Global.Game)}.{ext}"; // dont use Path.ChangeExtension, it might wreck game names with dots in them + sfd.FileName = $"{PathManager.FilesystemSafeName(Global.Game)}.{ext}"; // don't use Path.ChangeExtension, it might wreck game names with dots in them sfd.InitialDirectory = PathManager.MakeAbsolutePath(Global.Config.PathEntries.AvPathFragment, null); } else @@ -3285,9 +3262,9 @@ namespace BizHawk.Client.EmuHawk try { // is this the best time to handle this? or deeper inside? - if (argParser._currAviWriterFrameList != null) + if (_argParser._currAviWriterFrameList != null) { - if (!argParser._currAviWriterFrameList.Contains(Emulator.Frame)) + if (!_argParser._currAviWriterFrameList.Contains(Emulator.Frame)) { goto HANDLE_AUTODUMP; } @@ -3369,14 +3346,14 @@ namespace BizHawk.Client.EmuHawk AbortAv(); } - HANDLE_AUTODUMP: - if (argParser._autoDumpLength > 0) + HANDLE_AUTODUMP: + if (_argParser._autoDumpLength > 0) { - argParser._autoDumpLength--; - if (argParser._autoDumpLength == 0) // finish + _argParser._autoDumpLength--; + if (_argParser._autoDumpLength == 0) // finish { StopAv(); - if (argParser._autoCloseOnDump) + if (_argParser._autoCloseOnDump) { _exitRequestPending = true; } @@ -3385,7 +3362,7 @@ namespace BizHawk.Client.EmuHawk } } - private int? LoadArhiveChooser(HawkFile file) + private int? LoadArchiveChooser(HawkFile file) { var ac = new ArchiveChooser(file); if (ac.ShowDialog(this) == DialogResult.OK) @@ -3467,11 +3444,11 @@ namespace BizHawk.Client.EmuHawk if (!LoadRomInternal(path, args)) return false; - //what's the meaning of the last rom path when opening an archive? based on the archive file location + // what's the meaning of the last rom path when opening an archive? based on the archive file location if (args.OpenAdvanced is OpenAdvanced_OpenRom) { - var leftpart = path.Split('|')[0]; - Global.Config.LastRomPath = Path.GetFullPath(Path.GetDirectoryName(leftpart)); + var leftPart = path.Split('|')[0]; + Global.Config.LastRomPath = Path.GetFullPath(Path.GetDirectoryName(leftPart)); } return true; @@ -3505,7 +3482,7 @@ namespace BizHawk.Client.EmuHawk // if the core is managing its own DE through SyncSettings a 'deterministic' bool can be passed into the core's constructor // it is then up to the core itself to override its own local DeterministicEmulation setting bool deterministic = args.Deterministic ?? Global.MovieSession.QueuedMovie != null; - + if (!GlobalWin.Tools.AskSave()) { return false; @@ -3515,7 +3492,7 @@ namespace BizHawk.Client.EmuHawk var loader = new RomLoader { - ChooseArchive = LoadArhiveChooser, + ChooseArchive = LoadArchiveChooser, ChoosePlatform = ChoosePlatformForRom, Deterministic = deterministic, MessageCallback = GlobalWin.OSD.AddMessage, @@ -3544,7 +3521,7 @@ namespace BizHawk.Client.EmuHawk if (ioa_retro != null) { // prepare a core specification - // if it wasnt already specified, use the current default + // if it wasn't already specified, use the current default if (ioa_retro.CorePath == null) { ioa_retro.CorePath = Global.Config.LibretroCore; @@ -3560,7 +3537,7 @@ namespace BizHawk.Client.EmuHawk if (oa_openrom != null) { // path already has the right value, while ioa.Path is null (interestingly, these are swapped below) - // I doubt null is meant to be assigned here, and it just prevents gameload + // I doubt null is meant to be assigned here, and it just prevents game load //path = ioa_openrom.Path; } @@ -3568,7 +3545,7 @@ namespace BizHawk.Client.EmuHawk var result = loader.LoadRom(path, nextComm); // we need to replace the path in the OpenAdvanced with the canonical one the user chose. - // It can't be done until loder.LoadRom happens (for CanonicalFullPath) + // It can't be done until loader.LoadRom happens (for CanonicalFullPath) // i'm not sure this needs to be more abstractly engineered yet until we have more OpenAdvanced examples if (oa_retro != null) { @@ -3588,7 +3565,7 @@ namespace BizHawk.Client.EmuHawk CoreFileProvider.SyncCoreCommInputSignals(nextComm); InputManager.SyncControls(); - if (oa_openrom != null && Path.GetExtension(oa_openrom.Path.Replace("|","")).ToLowerInvariant() == ".xml" && !(Emulator is LibsnesCore)) + if (oa_openrom != null && Path.GetExtension(oa_openrom.Path.Replace("|", "")).ToLowerInvariant() == ".xml" && !(Emulator is LibsnesCore)) { // this is a multi-disk bundler file // determine the xml assets and create RomStatusDetails for all of them @@ -3625,9 +3602,8 @@ namespace BizHawk.Client.EmuHawk GlobalWin.Tools.Load(); } - if (loader.LoadedEmulator is NES) + if (loader.LoadedEmulator is NES nes) { - var nes = (NES)loader.LoadedEmulator; if (!string.IsNullOrWhiteSpace(nes.GameName)) { Global.Game.Name = nes.GameName; @@ -3635,9 +3611,8 @@ namespace BizHawk.Client.EmuHawk Global.Game.Status = nes.RomStatus; } - else if (loader.LoadedEmulator is QuickNES) + else if (loader.LoadedEmulator is QuickNES qns) { - var qns = (QuickNES)loader.LoadedEmulator; if (!string.IsNullOrWhiteSpace(qns.BootGodName)) { Global.Game.Name = qns.BootGodName; @@ -3804,15 +3779,15 @@ namespace BizHawk.Client.EmuHawk else if (Emulator.HasSaveRam() && Emulator.AsSaveRam().SaveRamModified) { if (!FlushSaveRAM()) - { - var msgRes = MessageBox.Show("Failed flushing the game's Save RAM to your disk.\nClose without flushing Save RAM?", - "Directory IO Error", MessageBoxButtons.YesNo, MessageBoxIcon.Error); + { + var msgRes = MessageBox.Show("Failed flushing the game's Save RAM to your disk.\nClose without flushing Save RAM?", + "Directory IO Error", MessageBoxButtons.YesNo, MessageBoxIcon.Error); - if (msgRes != DialogResult.Yes) - { - return; - } - } + if (msgRes != DialogResult.Yes) + { + return; + } + } } StopAv(); @@ -3918,7 +3893,7 @@ namespace BizHawk.Client.EmuHawk return int.Parse(slot.Substring(slot.Length - 1, 1)); } - public void LoadState(string path, string userFriendlyStateName, bool fromLua = false, bool supressOSD = false) // Move to client.common + public void LoadState(string path, string userFriendlyStateName, bool fromLua = false, bool suppressOSD = false) // Move to client.common { if (!Emulator.HasSavestates()) { @@ -3960,7 +3935,7 @@ namespace BizHawk.Client.EmuHawk ClearRewindData(); } - if (!supressOSD) + if (!suppressOSD) { GlobalWin.OSD.AddMessage($"Loaded state: {userFriendlyStateName}"); } @@ -3973,15 +3948,14 @@ namespace BizHawk.Client.EmuHawk Global.MovieSession.Movie.IsCountingRerecords = wasCountingRerecords; } - public void LoadQuickSave(string quickSlotName, bool fromLua = false, bool supressOSD = false) + public void LoadQuickSave(string quickSlotName, bool fromLua = false, bool suppressOSD = false) { if (!Emulator.HasSavestates()) { return; } - bool handled; - ClientApi.OnBeforeQuickLoad(this, quickSlotName, out handled); + ClientApi.OnBeforeQuickLoad(this, quickSlotName, out var handled); if (handled) { return; @@ -4001,7 +3975,7 @@ namespace BizHawk.Client.EmuHawk return; } - LoadState(path, quickSlotName, fromLua, supressOSD); + LoadState(path, quickSlotName, fromLua, suppressOSD); } public void SaveState(string path, string userFriendlyStateName, bool fromLua) @@ -4268,11 +4242,6 @@ namespace BizHawk.Client.EmuHawk } } - private void GBAcoresettingsToolStripMenuItem1_Click(object sender, EventArgs e) - { - GenericCoreConfig.DoDialog(this, "Gameboy Advance Settings"); - } - private void CaptureRewind(bool suppressCaptureRewind) { if (IsRewindSlave) @@ -4285,26 +4254,6 @@ namespace BizHawk.Client.EmuHawk } } - private void preferencesToolStripMenuItem1_Click(object sender, EventArgs e) - { - GenericCoreConfig.DoDialog(this, "VirtualBoy Settings"); - } - - private void preferencesToolStripMenuItem_Click(object sender, EventArgs e) - { - GenericCoreConfig.DoDialog(this, "Snes9x Settings"); - } - - private void preferencesToolStripMenuItem2_Click(object sender, EventArgs e) - { - GenericCoreConfig.DoDialog(this, "NeoPop Settings"); - } - - private void preferencesToolStripMenuItem3_Click(object sender, EventArgs e) - { - GenericCoreConfig.DoDialog(this, "PC-FX Settings"); - } - private bool Rewind(ref bool runFrame, long currentTimestamp, out bool returnToRecording) { var isRewinding = false; @@ -4332,7 +4281,7 @@ namespace BizHawk.Client.EmuHawk _frameRewindWasPaused = false; } - // if we're freely running, there's no need for reverse frame progress semantics (that may be debateable though) + // if we're freely running, there's no need for reverse frame progress semantics (that may be debatable though) if (!EmulatorPaused) { isRewinding = true; diff --git a/BizHawk.sln.DotSettings b/BizHawk.sln.DotSettings index be11f16d90..a23de6417a 100644 --- a/BizHawk.sln.DotSettings +++ b/BizHawk.sln.DotSettings @@ -179,15 +179,22 @@ True True True + True + True True True True True + True True True True True + True True + True + True + True True True True @@ -199,13 +206,19 @@ True True True + True True + True True + True True True + True True True True + True + True True True True @@ -215,26 +228,40 @@ True True True + True True + True + True + True True + True True True True + True True True True True + True + True True True + True True True True + True True True + True + True + True True True True True + True True True True From 9471f7ca0381ab8c1917138043934691ac9b9f48 Mon Sep 17 00:00:00 2001 From: "J.D. Purcell" Date: Sun, 27 Oct 2019 14:00:02 -0400 Subject: [PATCH 149/166] Cleanups --- .../CustomControls/ControlRenderer/IControlRenderer.cs | 1 - BizHawk.Client.EmuHawk/CustomControls/InputRoll/InputRoll.cs | 5 +---- BizHawk.Client.EmuHawk/EmuHawkUtil.cs | 5 ++--- 3 files changed, 3 insertions(+), 8 deletions(-) diff --git a/BizHawk.Client.EmuHawk/CustomControls/ControlRenderer/IControlRenderer.cs b/BizHawk.Client.EmuHawk/CustomControls/ControlRenderer/IControlRenderer.cs index b5a481cd2c..9a5475cd9e 100644 --- a/BizHawk.Client.EmuHawk/CustomControls/ControlRenderer/IControlRenderer.cs +++ b/BizHawk.Client.EmuHawk/CustomControls/ControlRenderer/IControlRenderer.cs @@ -26,7 +26,6 @@ namespace BizHawk.Client.EmuHawk.CustomControls /// void DrawString(string str, Point point); - void DrawRectangle(int nLeftRect, int nTopRect, int nRightRect, int nBottomRect); void FillRectangle(int x, int y, int w, int h); diff --git a/BizHawk.Client.EmuHawk/CustomControls/InputRoll/InputRoll.cs b/BizHawk.Client.EmuHawk/CustomControls/InputRoll/InputRoll.cs index 7488101d84..b614d1bf17 100644 --- a/BizHawk.Client.EmuHawk/CustomControls/InputRoll/InputRoll.cs +++ b/BizHawk.Client.EmuHawk/CustomControls/InputRoll/InputRoll.cs @@ -90,10 +90,7 @@ namespace BizHawk.Client.EmuHawk using (var g = CreateGraphics()) using (_renderer.LockGraphics(g, Width, Height)) - { - // Set font - _renderer.PrepDrawString(_font, _foreColor); - + { // Measure width change to ignore extra padding at start/end var size1 = _renderer.MeasureString("A", _font); var size2 = _renderer.MeasureString("AA", _font); diff --git a/BizHawk.Client.EmuHawk/EmuHawkUtil.cs b/BizHawk.Client.EmuHawk/EmuHawkUtil.cs index 3bd9ea51b3..ca0879fd32 100644 --- a/BizHawk.Client.EmuHawk/EmuHawkUtil.cs +++ b/BizHawk.Client.EmuHawk/EmuHawkUtil.cs @@ -14,8 +14,8 @@ namespace BizHawk.Client.EmuHawk { static bool PromptToSwitchCore(string currentCore, string recommendedCore, Action disableCurrentCore) { - var box = new MsgBox( - $"While the {currentCore} core is faster, it is not nearly as accurate as {recommendedCore}.{Environment.NewLine}It is recommended that you switch to the {recommendedCore} core for movie recording. {Environment.NewLine}Switch to {recommendedCore}?", + using var box = new MsgBox( + $"While the {currentCore} core is faster, it is not nearly as accurate as {recommendedCore}.{Environment.NewLine}It is recommended that you switch to the {recommendedCore} core for movie recording.{Environment.NewLine}Switch to {recommendedCore}?", "Accuracy Warning", MessageBoxIcon.Warning); @@ -27,7 +27,6 @@ namespace BizHawk.Client.EmuHawk box.SetMessageToAutoSize(); var result = box.ShowDialog(); - box.Dispose(); if (result != DialogResult.Yes) { From 90724bb77762c67a5379e05ce9ff367c3015bded Mon Sep 17 00:00:00 2001 From: "J.D. Purcell" Date: Sun, 27 Oct 2019 17:55:53 -0400 Subject: [PATCH 150/166] Work on InputRoll horizontal mode a bit. --- .../InputRoll/InputRoll.Drawing.cs | 73 +++++++++++++------ .../CustomControls/InputRoll/InputRoll.cs | 4 +- .../CustomControls/InputRoll/RollColumn.cs | 14 +++- .../tools/TAStudio/TAStudio.ListView.cs | 5 +- .../tools/TAStudio/TAStudio.cs | 22 ++++-- 5 files changed, 85 insertions(+), 33 deletions(-) diff --git a/BizHawk.Client.EmuHawk/CustomControls/InputRoll/InputRoll.Drawing.cs b/BizHawk.Client.EmuHawk/CustomControls/InputRoll/InputRoll.Drawing.cs index ae84969b6c..ade2db4483 100644 --- a/BizHawk.Client.EmuHawk/CustomControls/InputRoll/InputRoll.Drawing.cs +++ b/BizHawk.Client.EmuHawk/CustomControls/InputRoll/InputRoll.Drawing.cs @@ -1,5 +1,5 @@ using System; -using System.Collections.Generic; +using System.Collections.Generic; using System.Drawing; using System.Linq; using System.Windows.Forms; @@ -167,48 +167,75 @@ namespace BizHawk.Client.EmuHawk if (HorizontalOrientation) { int startRow = FirstVisibleRow; - int range = Math.Min(LastVisibleRow, RowCount - 1) - startRow + 1; - - _renderer.PrepDrawString(_font, _foreColor); - for (int i = 0, f = 0; f < range; i++, f++) - { - f += _lagFrames[i]; - int lastVisible = LastVisibleColumnIndex; - for (int j = FirstVisibleColumn; j <= lastVisible; j++) + int range = Math.Min(LastVisibleRow, RowCount - 1) - startRow + 1; + + _renderer.PrepDrawString(_font, _foreColor); + int lastVisible = LastVisibleColumnIndex; + for (int j = FirstVisibleColumn; j <= lastVisible; j++) + { + RollColumn col = visibleColumns[j]; + + // Just a proof of concept to test auto-calculating the column height in horizontal + // mode. This would of course need to happen before any drawing because it's also + // needed for the column headers and background. + int debugColHeight = CellHeight; + if (col.Rotatable && col.RotatedHeight != null) + { + debugColHeight = Math.Max(debugColHeight, col.RotatedHeight.Value); + } + else if (col.Rotatable) + { + string text; + int strOffsetX = 0; + int strOffsetY = 0; + QueryItemText(startRow, col, out text, ref strOffsetX, ref strOffsetY); + int textWidth = _renderer.MeasureString(text, _font).Width; + debugColHeight = Math.Max(debugColHeight, strOffsetX + textWidth + (CellWidthPadding * 2)); + } + + for (int i = 0, f = 0; f < range; i++, f++) { + f += _lagFrames[i]; + Bitmap image = null; - int x; - int y; int bitmapOffsetX = 0; int bitmapOffsetY = 0; - QueryItemIcon?.Invoke(f + startRow, visibleColumns[j], ref image, ref bitmapOffsetX, ref bitmapOffsetY); + QueryItemIcon?.Invoke(f + startRow, col, ref image, ref bitmapOffsetX, ref bitmapOffsetY); if (image != null) { - x = RowsToPixels(i) + CellWidthPadding + bitmapOffsetX; - y = (j * CellHeight) + (CellHeightPadding * 2) + bitmapOffsetY; + int x = RowsToPixels(i) + CellWidthPadding + bitmapOffsetX; + int y = (j * CellHeight) + (CellHeightPadding * 2) + bitmapOffsetY; _renderer.DrawBitmap(image, new Point(x, y)); } string text; int strOffsetX = 0; int strOffsetY = 0; - QueryItemText(f + startRow, visibleColumns[j], out text, ref strOffsetX, ref strOffsetY); + QueryItemText(f + startRow, col, out text, ref strOffsetX, ref strOffsetY); - // Center Text - x = RowsToPixels(i) + ((CellWidth - (text.Length * _charSize.Width)) / 2); - y = (j * CellHeight) + CellHeightPadding - _vBar.Value; - var point = new Point(x + strOffsetX, y + strOffsetY); - - if (visibleColumns[j].Name == "FrameColumn") // TODO: don't do this hack + int baseX = RowsToPixels(i) + (col.Rotatable ? CellWidth : 0); + int baseY = j * CellHeight - _vBar.Value; + int textWidth = text.Length * _charSize.Width; + if (col.Rotatable) { + // Center Text + int textX = Math.Max(((CellHeight - textWidth) / 2), CellWidthPadding) + strOffsetX; + int textY = CellWidthPadding + strOffsetY; + var point = new Point(baseX - textY, baseY + textX); + _renderer.PrepDrawString(_font, _foreColor, rotate: true); - DrawString(text, ColumnWidth, new Point(point.X + _charSize.Height + CellWidthPadding, point.Y + CellHeightPadding)); + DrawString(text, null /* TODO */, point); _renderer.PrepDrawString(_font, _foreColor, rotate: false); } else - { + { + // Center Text + int textX = Math.Max(((CellWidth - textWidth) / 2), CellWidthPadding) + strOffsetX; + int textY = CellHeightPadding + strOffsetY; + var point = new Point(baseX + textX, baseY + textY); + DrawString(text, ColumnWidth, point); } } diff --git a/BizHawk.Client.EmuHawk/CustomControls/InputRoll/InputRoll.cs b/BizHawk.Client.EmuHawk/CustomControls/InputRoll/InputRoll.cs index b614d1bf17..5f51367ebc 100644 --- a/BizHawk.Client.EmuHawk/CustomControls/InputRoll/InputRoll.cs +++ b/BizHawk.Client.EmuHawk/CustomControls/InputRoll/InputRoll.cs @@ -1166,7 +1166,7 @@ namespace BizHawk.Client.EmuHawk { // do marker drag here } - else if (ModifierKeys == Keys.Shift && (CurrentCell.Column.Name == "FrameColumn" || CurrentCell.Column.Type == ColumnType.Text)) + else if (ModifierKeys == Keys.Shift && CurrentCell.Column.Type == ColumnType.Text) { if (_selectedItems.Any()) { @@ -1235,7 +1235,7 @@ namespace BizHawk.Client.EmuHawk SelectCell(CurrentCell); } } - else if (ModifierKeys == Keys.Control && (CurrentCell.Column.Name == "FrameColumn" || CurrentCell.Column.Type == ColumnType.Text)) + else if (ModifierKeys == Keys.Control && CurrentCell.Column.Type == ColumnType.Text) { SelectCell(CurrentCell, toggle: true); } diff --git a/BizHawk.Client.EmuHawk/CustomControls/InputRoll/RollColumn.cs b/BizHawk.Client.EmuHawk/CustomControls/InputRoll/RollColumn.cs index 1ddb5346cc..0999e9ebe6 100644 --- a/BizHawk.Client.EmuHawk/CustomControls/InputRoll/RollColumn.cs +++ b/BizHawk.Client.EmuHawk/CustomControls/InputRoll/RollColumn.cs @@ -1,4 +1,6 @@ -namespace BizHawk.Client.EmuHawk +using System; + +namespace BizHawk.Client.EmuHawk { public class RollColumn { @@ -15,5 +17,15 @@ /// Column will be drawn with an emphasized look, if true /// public bool Emphasis { get; set; } + + /// + /// Column header text will be drawn rotated, if true + /// + public bool Rotatable { get; set; } + + /// + /// If drawn rotated, specifies the desired height, or null to auto-size + /// + public int? RotatedHeight { get; set; } } } diff --git a/BizHawk.Client.EmuHawk/tools/TAStudio/TAStudio.ListView.cs b/BizHawk.Client.EmuHawk/tools/TAStudio/TAStudio.ListView.cs index 147b7b8389..1165a2cb11 100644 --- a/BizHawk.Client.EmuHawk/tools/TAStudio/TAStudio.ListView.cs +++ b/BizHawk.Client.EmuHawk/tools/TAStudio/TAStudio.ListView.cs @@ -319,7 +319,10 @@ namespace BizHawk.Client.EmuHawk } else if (columnName == FrameColumnName) { - offsetX = 7; + if (!TasView.HorizontalOrientation) + { + offsetX = 7; + } text = index.ToString().PadLeft(CurrentTasMovie.InputLogLength.ToString().Length, '0'); } else diff --git a/BizHawk.Client.EmuHawk/tools/TAStudio/TAStudio.cs b/BizHawk.Client.EmuHawk/tools/TAStudio/TAStudio.cs index 88166d2401..a2949ed6c6 100644 --- a/BizHawk.Client.EmuHawk/tools/TAStudio/TAStudio.cs +++ b/BizHawk.Client.EmuHawk/tools/TAStudio/TAStudio.cs @@ -395,7 +395,15 @@ namespace BizHawk.Client.EmuHawk { TasView.AllColumns.Clear(); AddColumn(CursorColumnName, "", 18); - AddColumn(FrameColumnName, "Frame#", 68); + AddColumn( + new RollColumn + { + Name = FrameColumnName, + Text = "Frame#", + Width = 68, + Type = ColumnType.Text, + Rotatable = true + }); var columnNames = GenerateColumnNames(); foreach (var kvp in columnNames) @@ -480,18 +488,20 @@ namespace BizHawk.Client.EmuHawk public void AddColumn(string columnName, string columnText, int columnWidth, ColumnType columnType = ColumnType.Boolean) { - if (TasView.AllColumns[columnName] == null) - { - var column = new RollColumn + AddColumn( + new RollColumn { Name = columnName, Text = columnText, Width = columnWidth, Type = columnType - }; + }); + } + private void AddColumn(RollColumn column) + { + if (TasView.AllColumns[column.Name] == null) TasView.AllColumns.Add(column); - } } private void EngageTastudio() From 5c674e5f8fc1f07374e1492648c4d152ff8ee629 Mon Sep 17 00:00:00 2001 From: adelikat Date: Sun, 27 Oct 2019 18:02:06 -0500 Subject: [PATCH 151/166] Watch UI classes - some cleanups, mostly C#7isms --- .../tools/Watch/WatchList/WatchList.cs | 20 +--- .../Lua/Libraries/EmuLuaLibrary.Client.cs | 12 +- .../tools/Watch/RamSearch.cs | 14 +-- .../tools/Watch/RamWatch.cs | 33 +----- .../tools/Watch/WatchEditor.cs | 103 +++++++++--------- .../tools/Watch/WatchValueBox.cs | 12 +- BizHawk.sln.DotSettings | 1 + 7 files changed, 72 insertions(+), 123 deletions(-) diff --git a/BizHawk.Client.Common/tools/Watch/WatchList/WatchList.cs b/BizHawk.Client.Common/tools/Watch/WatchList/WatchList.cs index 833e3595e8..96999aa9b1 100644 --- a/BizHawk.Client.Common/tools/Watch/WatchList/WatchList.cs +++ b/BizHawk.Client.Common/tools/Watch/WatchList/WatchList.cs @@ -388,15 +388,8 @@ namespace BizHawk.Client.Common /// at the specified index public Watch this[int index] { - get - { - return _watchList[index]; - } - - set - { - _watchList[index] = value; - } + get => _watchList[index]; + set => _watchList[index] = value; } #endregion IList @@ -607,14 +600,7 @@ namespace BizHawk.Client.Common CurrentFileName = path; } - if (!append) - { - Changes = false; - } - else - { - Changes = true; - } + Changes = append; return true; } diff --git a/BizHawk.Client.EmuHawk/tools/Lua/Libraries/EmuLuaLibrary.Client.cs b/BizHawk.Client.EmuHawk/tools/Lua/Libraries/EmuLuaLibrary.Client.cs index 3ebe0aeccc..f8523ea8a4 100644 --- a/BizHawk.Client.EmuHawk/tools/Lua/Libraries/EmuLuaLibrary.Client.cs +++ b/BizHawk.Client.EmuHawk/tools/Lua/Libraries/EmuLuaLibrary.Client.cs @@ -404,12 +404,12 @@ namespace BizHawk.Client.EmuHawk return GlobalWin.MainForm.DesktopLocation.Y; } - [LuaMethodExample("local incbhver = client.getversion( );")] - [LuaMethod("getversion", "Returns the current stable BizHawk version")] - public static string GetVersion() - { - return VersionInfo.Mainversion; - } + [LuaMethodExample("local incbhver = client.getversion( );")] + [LuaMethod("getversion", "Returns the current stable BizHawk version")] + public static string GetVersion() + { + return VersionInfo.Mainversion; + } [LuaMethodExample("local nlcliget = client.getavailabletools( );")] [LuaMethod("getavailabletools", "Returns a list of the tools currently open")] diff --git a/BizHawk.Client.EmuHawk/tools/Watch/RamSearch.cs b/BizHawk.Client.EmuHawk/tools/Watch/RamSearch.cs index c398b89730..6d455a25a9 100644 --- a/BizHawk.Client.EmuHawk/tools/Watch/RamSearch.cs +++ b/BizHawk.Client.EmuHawk/tools/Watch/RamSearch.cs @@ -565,15 +565,9 @@ namespace BizHawk.Client.EmuHawk private IEnumerable SelectedIndices => WatchListView.SelectedRows; - private IEnumerable SelectedItems - { - get { return SelectedIndices.Select(index => _searches[index]); } - } + private IEnumerable SelectedItems => SelectedIndices.Select(index => _searches[index]); - private IEnumerable SelectedWatches - { - get { return SelectedItems.Where(x => !x.IsSeparator); } - } + private IEnumerable SelectedWatches => SelectedItems.Where(x => !x.IsSeparator); private void SetRemovedMessage(int val) { @@ -771,8 +765,8 @@ namespace BizHawk.Client.EmuHawk private void SetReboot(bool rebootNeeded) { RebootToolBarSeparator.Visible = - RebootToolbarButton.Visible = - rebootNeeded; + RebootToolbarButton.Visible = + rebootNeeded; } private void SetToDetailedMode() diff --git a/BizHawk.Client.EmuHawk/tools/Watch/RamWatch.cs b/BizHawk.Client.EmuHawk/tools/Watch/RamWatch.cs index b29c6137e2..71b1439ea7 100644 --- a/BizHawk.Client.EmuHawk/tools/Watch/RamWatch.cs +++ b/BizHawk.Client.EmuHawk/tools/Watch/RamWatch.cs @@ -96,32 +96,11 @@ namespace BizHawk.Client.EmuHawk } private IEnumerable SelectedIndices => WatchListView.SelectedRows; + private IEnumerable SelectedItems => SelectedIndices.Select(index => _watches[index]); + private IEnumerable SelectedWatches => SelectedItems.Where(x => !x.IsSeparator); + private IEnumerable SelectedSeparators => SelectedItems.Where(x => x.IsSeparator); - private IEnumerable SelectedItems - { - get { return SelectedIndices.Select(index => _watches[index]); } - } - - private IEnumerable SelectedWatches - { - get { return SelectedItems.Where(x => !x.IsSeparator); } - } - - private IEnumerable SelectedSeparators - { - get - { - return SelectedItems.Where(x => x.IsSeparator); - } - } - - public IEnumerable Watches - { - get - { - return _watches.Where(x => !x.IsSeparator); - } - } + public IEnumerable Watches => _watches.Where(x => !x.IsSeparator); public bool UpdateBefore => false; @@ -775,8 +754,8 @@ namespace BizHawk.Client.EmuHawk private MemoryDomain CurrentDomain { - get { return _currentDomain ?? MemoryDomains.MainMemory; } - set { _currentDomain = value; } + get => _currentDomain ?? MemoryDomains.MainMemory; + set => _currentDomain = value; } private void MemoryDomainsSubMenu_DropDownOpened(object sender, EventArgs e) diff --git a/BizHawk.Client.EmuHawk/tools/Watch/WatchEditor.cs b/BizHawk.Client.EmuHawk/tools/Watch/WatchEditor.cs index 9e6a457be7..ef5484ea50 100644 --- a/BizHawk.Client.EmuHawk/tools/Watch/WatchEditor.cs +++ b/BizHawk.Client.EmuHawk/tools/Watch/WatchEditor.cs @@ -13,8 +13,6 @@ namespace BizHawk.Client.EmuHawk { public enum Mode { New, Duplicate, Edit } - private readonly List _watchList = new List(); - public Emu.IMemoryDomains MemoryDomains { get; set; } private Mode _mode = Mode.New; @@ -23,7 +21,7 @@ namespace BizHawk.Client.EmuHawk private bool _changedSize; private bool _changedDisplayType; - public List Watches => _watchList; + public List Watches { get; } = new List(); public Point InitialLocation { get; set; } = new Point(0, 0); @@ -63,7 +61,7 @@ namespace BizHawk.Client.EmuHawk break; case Mode.Duplicate: case Mode.Edit: - switch (_watchList[0].Size) + switch (Watches[0].Size) { case WatchSize.Byte: SizeDropDown.SelectedItem = SizeDropDown.Items[0]; @@ -76,28 +74,28 @@ namespace BizHawk.Client.EmuHawk break; } - var index = DisplayTypeDropDown.Items.IndexOf(Watch.DisplayTypeToString(_watchList[0].Type)); + var index = DisplayTypeDropDown.Items.IndexOf(Watch.DisplayTypeToString(Watches[0].Type)); DisplayTypeDropDown.SelectedItem = DisplayTypeDropDown.Items[index]; - if (_watchList.Count > 1) + if (Watches.Count > 1) { NotesBox.Enabled = false; NotesBox.Text = ""; AddressBox.Enabled = false; - AddressBox.Text = _watchList.Select(a => a.AddressString).Aggregate((addrStr, nextStr) => $"{addrStr},{nextStr}"); + AddressBox.Text = Watches.Select(a => a.AddressString).Aggregate((addrStr, nextStr) => $"{addrStr},{nextStr}"); BigEndianCheckBox.ThreeState = true; - if (_watchList.Select(s => s.Size).Distinct().Count() > 1) + if (Watches.Select(s => s.Size).Distinct().Count() > 1) { DisplayTypeDropDown.Enabled = false; } } else { - NotesBox.Text = _watchList[0].Notes; - AddressBox.SetFromLong(_watchList[0].Address); + NotesBox.Text = Watches[0].Notes; + AddressBox.SetFromLong(Watches[0].Address); } SetBigEndianCheckBox(); @@ -110,7 +108,7 @@ namespace BizHawk.Client.EmuHawk { if (watches != null) { - _watchList.AddRange(watches); + Watches.AddRange(watches); } _mode = mode; @@ -134,7 +132,7 @@ namespace BizHawk.Client.EmuHawk Text = "New Watch"; break; case Mode.Edit: - Text = $"Edit {(_watchList.Count == 1 ? "Watch" : "Watches")}"; + Text = $"Edit {(Watches.Count == 1 ? "Watch" : "Watches")}"; break; case Mode.Duplicate: Text = "Duplicate Watch"; @@ -188,37 +186,34 @@ namespace BizHawk.Client.EmuHawk private void SetBigEndianCheckBox() { - if (_watchList != null) + if (Watches.Count > 1) { - if (_watchList.Count > 1) - { - // Aggregate state - var hasBig = _watchList.Any(x => x.BigEndian); - var hasLittle = _watchList.Any(x => x.BigEndian == false); + // Aggregate state + var hasBig = Watches.Any(x => x.BigEndian); + var hasLittle = Watches.Any(x => x.BigEndian == false); - if (hasBig && hasLittle) - { - BigEndianCheckBox.Checked = true; - BigEndianCheckBox.CheckState = CheckState.Indeterminate; - } - else if (hasBig) - { - BigEndianCheckBox.Checked = true; - } - else - { - BigEndianCheckBox.Checked = false; - } - } - else if (_watchList.Count == 1) + if (hasBig && hasLittle) { - BigEndianCheckBox.Checked = _watchList[0].BigEndian; - return; + BigEndianCheckBox.Checked = true; + BigEndianCheckBox.CheckState = CheckState.Indeterminate; + } + else if (hasBig) + { + BigEndianCheckBox.Checked = true; + } + else + { + BigEndianCheckBox.Checked = false; } } + else if (Watches.Count == 1) + { + BigEndianCheckBox.Checked = Watches[0].BigEndian; + return; + } - var domain = MemoryDomains.FirstOrDefault(d => d.Name == DomainDropDown.SelectedItem.ToString()) ?? - MemoryDomains.MainMemory; + var domain = MemoryDomains.FirstOrDefault(d => d.Name == DomainDropDown.SelectedItem.ToString()) + ?? MemoryDomains.MainMemory; BigEndianCheckBox.Checked = domain.EndianType == Emu.MemoryDomain.Endian.Big; } @@ -246,13 +241,13 @@ namespace BizHawk.Client.EmuHawk switch (SizeDropDown.SelectedIndex) { case 0: - _watchList.Add(Watch.GenerateWatch(domain, address, WatchSize.Byte, type, bigEndian, notes)); + Watches.Add(Watch.GenerateWatch(domain, address, WatchSize.Byte, type, bigEndian, notes)); break; case 1: - _watchList.Add(Watch.GenerateWatch(domain, address, WatchSize.Word, type, bigEndian, notes)); + Watches.Add(Watch.GenerateWatch(domain, address, WatchSize.Word, type, bigEndian, notes)); break; case 2: - _watchList.Add(Watch.GenerateWatch(domain, address, WatchSize.DWord, type, bigEndian, notes)); + Watches.Add(Watch.GenerateWatch(domain, address, WatchSize.DWord, type, bigEndian, notes)); break; } @@ -262,11 +257,11 @@ namespace BizHawk.Client.EmuHawk break; case Mode.Duplicate: var tempWatchList = new List(); - tempWatchList.AddRange(_watchList); - _watchList.Clear(); + tempWatchList.AddRange(Watches); + Watches.Clear(); foreach (var watch in tempWatchList) { - _watchList.Add(Watch.GenerateWatch( + Watches.Add(Watch.GenerateWatch( watch.Domain, watch.Address, watch.Size, @@ -284,14 +279,14 @@ namespace BizHawk.Client.EmuHawk private void DoEdit() { - if (_watchList.Count == 1) + if (Watches.Count == 1) { - _watchList[0].Notes = NotesBox.Text; + Watches[0].Notes = NotesBox.Text; } if (_changedSize) { - for (var i = 0; i < _watchList.Count; i++) + for (var i = 0; i < Watches.Count; i++) { var size = WatchSize.Byte; switch (SizeDropDown.SelectedIndex) @@ -307,24 +302,24 @@ namespace BizHawk.Client.EmuHawk break; } - _watchList[i] = Watch.GenerateWatch( - _watchList[i].Domain, - _watchList.Count == 1 ? AddressBox.ToRawInt() ?? 0 : _watchList[i].Address, + Watches[i] = Watch.GenerateWatch( + Watches[i].Domain, + Watches.Count == 1 ? AddressBox.ToRawInt() ?? 0 : Watches[i].Address, size, - _watchList[i].Type, - _watchList[i].BigEndian, - _watchList[i].Notes); + Watches[i].Type, + Watches[i].BigEndian, + Watches[i].Notes); } } if (_changedDisplayType) { - _watchList.ForEach(x => x.Type = Watch.StringToDisplayType(DisplayTypeDropDown.SelectedItem.ToString())); + Watches.ForEach(x => x.Type = Watch.StringToDisplayType(DisplayTypeDropDown.SelectedItem.ToString())); } if (BigEndianCheckBox.CheckState != CheckState.Indeterminate) { - _watchList.ForEach(x => x.BigEndian = BigEndianCheckBox.Checked); + Watches.ForEach(x => x.BigEndian = BigEndianCheckBox.Checked); } } diff --git a/BizHawk.Client.EmuHawk/tools/Watch/WatchValueBox.cs b/BizHawk.Client.EmuHawk/tools/Watch/WatchValueBox.cs index 9ff28c358a..61a31de47c 100644 --- a/BizHawk.Client.EmuHawk/tools/Watch/WatchValueBox.cs +++ b/BizHawk.Client.EmuHawk/tools/Watch/WatchValueBox.cs @@ -23,10 +23,7 @@ namespace BizHawk.Client.EmuHawk public WatchSize ByteSize { - get - { - return _size; - } + get => _size; set { @@ -65,15 +62,12 @@ namespace BizHawk.Client.EmuHawk public DisplayType Type { - get - { - return _type; - } + get => _type; set { var val = ToRawInt(); - _type = value; + _type = value; SetMaxLength(); SetFromRawInt(val); } diff --git a/BizHawk.sln.DotSettings b/BizHawk.sln.DotSettings index a23de6417a..d27343588e 100644 --- a/BizHawk.sln.DotSettings +++ b/BizHawk.sln.DotSettings @@ -241,6 +241,7 @@ True True True + True True True True From 28c0586c8bd25c259ff057953675432f95866423 Mon Sep 17 00:00:00 2001 From: "J.D. Purcell" Date: Sun, 27 Oct 2019 21:00:44 -0400 Subject: [PATCH 152/166] InputRoll horizontal - WIP. --- .../InputRoll/InputRoll.Drawing.cs | 140 +++++++++++------- .../CustomControls/InputRoll/InputRoll.cs | 1 - .../tools/TAStudio/TAStudio.ListView.cs | 11 +- 3 files changed, 96 insertions(+), 56 deletions(-) diff --git a/BizHawk.Client.EmuHawk/CustomControls/InputRoll/InputRoll.Drawing.cs b/BizHawk.Client.EmuHawk/CustomControls/InputRoll/InputRoll.Drawing.cs index ade2db4483..45d51a4aa1 100644 --- a/BizHawk.Client.EmuHawk/CustomControls/InputRoll/InputRoll.Drawing.cs +++ b/BizHawk.Client.EmuHawk/CustomControls/InputRoll/InputRoll.Drawing.cs @@ -8,7 +8,9 @@ using BizHawk.Client.EmuHawk.WinFormExtensions; namespace BizHawk.Client.EmuHawk { public partial class InputRoll - { + { + private int[] _horizontalColumnHeights; + protected override void OnPaint(PaintEventArgs e) { using (_renderer.LockGraphics(e.Graphics, Width, Height)) @@ -23,6 +25,8 @@ namespace BizHawk.Client.EmuHawk var visibleColumns = _columns.VisibleColumns.ToList(); + CalculateHorizontalColumnHeights(visibleColumns); + if (visibleColumns.Any()) { DrawColumnBg(visibleColumns); @@ -64,6 +68,48 @@ namespace BizHawk.Client.EmuHawk // Do nothing, and this should never be called } + private void CalculateHorizontalColumnHeights(List visibleColumns) + { + if (!HorizontalOrientation) + { + _horizontalColumnHeights = null; + return; + } + + _horizontalColumnHeights = new int[visibleColumns.Count]; + + int startRow = FirstVisibleRow; + for (int j = 0; j < visibleColumns.Count; j++) + { + RollColumn col = visibleColumns[j]; + int height = CellHeight; + if (col.Rotatable && col.RotatedHeight != null) + { + height = Math.Max(height, col.RotatedHeight.Value); + } + else if (col.Rotatable) + { + string text; + int strOffsetX = 0; + int strOffsetY = 0; + QueryItemText(startRow, col, out text, ref strOffsetX, ref strOffsetY); + int textWidth = _renderer.MeasureString(text, _font).Width; + height = Math.Max(height, textWidth + (CellWidthPadding * 2)); + } + _horizontalColumnHeights[j] = height; + } + } + + private int HorizontalColumnsToPixels(int index) + { + int height = 0; + for (int j = 0; j < index; j++) + { + height += _horizontalColumnHeights[j]; + } + return height; + } + private void DrawColumnDrag() { if (_columnDown?.Width != null && _columnDownMoved && _currentX.HasValue && _currentY.HasValue && IsHoveringOnColumnCell) @@ -98,7 +144,6 @@ namespace BizHawk.Client.EmuHawk int x2 = x1 + _draggingCell.Column.Width.Value; int y2 = y1 + CellHeight; - _renderer.SetBrush(bgColor); _renderer.FillRectangle(x1, y1, x2 - x1, y2 - y1); _renderer.PrepDrawString(_font, _foreColor); @@ -110,13 +155,16 @@ namespace BizHawk.Client.EmuHawk { if (HorizontalOrientation) { - int start = -_vBar.Value; + int y = -_vBar.Value; _renderer.PrepDrawString(_font, _foreColor); - foreach (var column in visibleColumns) + for(int j = 0; j < visibleColumns.Count; j++) { - var point = new Point(CellWidthPadding, start + CellHeightPadding); + var column = visibleColumns[j]; + var columnHeight = _horizontalColumnHeights[j]; + var textHeight = _renderer.MeasureString(column.Text, _font).Height; + var point = new Point(CellWidthPadding, y + ((columnHeight - textHeight) / 2)); if (IsHoveringOnColumnCell && column == CurrentCell.Column) { @@ -129,7 +177,7 @@ namespace BizHawk.Client.EmuHawk DrawString(column.Text, column.Width, point); } - start += CellHeight; + y += columnHeight; } } else @@ -174,40 +222,29 @@ namespace BizHawk.Client.EmuHawk for (int j = FirstVisibleColumn; j <= lastVisible; j++) { RollColumn col = visibleColumns[j]; - - // Just a proof of concept to test auto-calculating the column height in horizontal - // mode. This would of course need to happen before any drawing because it's also - // needed for the column headers and background. - int debugColHeight = CellHeight; - if (col.Rotatable && col.RotatedHeight != null) - { - debugColHeight = Math.Max(debugColHeight, col.RotatedHeight.Value); - } - else if (col.Rotatable) - { - string text; - int strOffsetX = 0; - int strOffsetY = 0; - QueryItemText(startRow, col, out text, ref strOffsetX, ref strOffsetY); - int textWidth = _renderer.MeasureString(text, _font).Width; - debugColHeight = Math.Max(debugColHeight, strOffsetX + textWidth + (CellWidthPadding * 2)); - } + int colHeight = _horizontalColumnHeights[j]; for (int i = 0, f = 0; f < range; i++, f++) { f += _lagFrames[i]; - Bitmap image = null; - int bitmapOffsetX = 0; - int bitmapOffsetY = 0; + int baseX = RowsToPixels(i) + (col.Rotatable ? CellWidth : 0); + int baseY = HorizontalColumnsToPixels(j) - _vBar.Value; - QueryItemIcon?.Invoke(f + startRow, col, ref image, ref bitmapOffsetX, ref bitmapOffsetY); - - if (image != null) + if (!col.Rotatable) { - int x = RowsToPixels(i) + CellWidthPadding + bitmapOffsetX; - int y = (j * CellHeight) + (CellHeightPadding * 2) + bitmapOffsetY; - _renderer.DrawBitmap(image, new Point(x, y)); + Bitmap image = null; + int bitmapOffsetX = 0; + int bitmapOffsetY = 0; + + QueryItemIcon?.Invoke(f + startRow, col, ref image, ref bitmapOffsetX, ref bitmapOffsetY); + + if (image != null) + { + int x = baseX + CellWidthPadding + bitmapOffsetX; + int y = baseY + CellHeightPadding + bitmapOffsetY; + _renderer.DrawBitmap(image, new Point(x, y)); + } } string text; @@ -215,18 +252,16 @@ namespace BizHawk.Client.EmuHawk int strOffsetY = 0; QueryItemText(f + startRow, col, out text, ref strOffsetX, ref strOffsetY); - int baseX = RowsToPixels(i) + (col.Rotatable ? CellWidth : 0); - int baseY = j * CellHeight - _vBar.Value; - int textWidth = text.Length * _charSize.Width; + int textWidth = _renderer.MeasureString(text, _font).Width; if (col.Rotatable) { - // Center Text - int textX = Math.Max(((CellHeight - textWidth) / 2), CellWidthPadding) + strOffsetX; + // Center Text + int textX = Math.Max(((colHeight - textWidth) / 2), CellWidthPadding) + strOffsetX; int textY = CellWidthPadding + strOffsetY; var point = new Point(baseX - textY, baseY + textX); _renderer.PrepDrawString(_font, _foreColor, rotate: true); - DrawString(text, null /* TODO */, point); + DrawString(text, null, point); _renderer.PrepDrawString(_font, _foreColor, rotate: false); } else @@ -301,20 +336,21 @@ namespace BizHawk.Client.EmuHawk if (HorizontalOrientation) { _renderer.FillRectangle(0, 0, ColumnWidth + 1, DrawHeight + 1); - _renderer.Line(0, 0, 0, visibleColumns.Count * CellHeight + 1); - _renderer.Line(ColumnWidth, 0, ColumnWidth, visibleColumns.Count * CellHeight + 1); - int start = -_vBar.Value; - foreach (var column in visibleColumns) + int y = -_vBar.Value; + for (int j = 0; j < visibleColumns.Count; j++) { - _renderer.Line(1, start, ColumnWidth, start); - start += CellHeight; + _renderer.Line(1, y, ColumnWidth, y); + y += _horizontalColumnHeights[j]; } if (visibleColumns.Any()) { - _renderer.Line(1, start, ColumnWidth, start); + _renderer.Line(1, y, ColumnWidth, y); } + + _renderer.Line(0, 0, 0, y + 1); + _renderer.Line(ColumnWidth, 0, ColumnWidth, y + 1); } else { @@ -346,7 +382,8 @@ namespace BizHawk.Client.EmuHawk _renderer.SetBrush(SystemColors.ActiveBorder); if (HorizontalOrientation) { - _renderer.FillRectangle(1, visibleColumns.IndexOf(column) * CellHeight + 1, ColumnWidth - 1, ColumnHeight - 1); + int columnIndex = visibleColumns.IndexOf(column); + _renderer.FillRectangle(1, HorizontalColumnsToPixels(columnIndex) + 1, ColumnWidth - 1, _horizontalColumnHeights[columnIndex] - 1); } else { @@ -370,7 +407,7 @@ namespace BizHawk.Client.EmuHawk ? SystemColors.Highlight.Add(0x00222222) : SystemColors.Highlight); - _renderer.FillRectangle(1, i * CellHeight + 1, ColumnWidth - 1, ColumnHeight - 1); + _renderer.FillRectangle(1, HorizontalColumnsToPixels(i) + 1, ColumnWidth - 1, _horizontalColumnHeights[i] - 1); } } else @@ -426,7 +463,7 @@ namespace BizHawk.Client.EmuHawk // Rows for (int i = 0; i < visibleColumns.Count + 1; i++) { - int y = i * CellHeight - _vBar.Value; + int y = HorizontalColumnsToPixels(i) - _vBar.Value; _renderer.Line(RowsToPixels(0) + 1, y, DrawWidth, y); } } @@ -521,9 +558,10 @@ namespace BizHawk.Client.EmuHawk return; } + int columnIndex = visibleColumns.IndexOf(cell.Column); w = CellWidth - 1; - y = (CellHeight * visibleColumns.IndexOf(cell.Column)) + 1 - _vBar.Value; // We can't draw without row and column, so assume they exist and fail catastrophically if they don't - h = CellHeight - 1; + y = HorizontalColumnsToPixels(columnIndex) - _vBar.Value + 1; // We can't draw without row and column, so assume they exist and fail catastrophically if they don't + h = _horizontalColumnHeights[columnIndex] - 1; } else { diff --git a/BizHawk.Client.EmuHawk/CustomControls/InputRoll/InputRoll.cs b/BizHawk.Client.EmuHawk/CustomControls/InputRoll/InputRoll.cs index 5f51367ebc..2bbbd74bcc 100644 --- a/BizHawk.Client.EmuHawk/CustomControls/InputRoll/InputRoll.cs +++ b/BizHawk.Client.EmuHawk/CustomControls/InputRoll/InputRoll.cs @@ -1934,7 +1934,6 @@ namespace BizHawk.Client.EmuHawk } // The width of the largest column cell in Horizontal Orientation - private int ColumnWidth { get; set; } // The height of a column cell in Vertical Orientation. diff --git a/BizHawk.Client.EmuHawk/tools/TAStudio/TAStudio.ListView.cs b/BizHawk.Client.EmuHawk/tools/TAStudio/TAStudio.ListView.cs index 1165a2cb11..edc4fc761b 100644 --- a/BizHawk.Client.EmuHawk/tools/TAStudio/TAStudio.ListView.cs +++ b/BizHawk.Client.EmuHawk/tools/TAStudio/TAStudio.ListView.cs @@ -171,6 +171,12 @@ namespace BizHawk.Client.EmuHawk if (columnName == CursorColumnName) { + if (TasView.HorizontalOrientation) + { + offsetX = 2; + offsetY = 5; + } + if (index == Emulator.Frame && index == Mainform.PauseOnFrame) { bitmap = TasView.HorizontalOrientation ? @@ -319,10 +325,7 @@ namespace BizHawk.Client.EmuHawk } else if (columnName == FrameColumnName) { - if (!TasView.HorizontalOrientation) - { - offsetX = 7; - } + offsetX = TasView.HorizontalOrientation ? 2 : 7; text = index.ToString().PadLeft(CurrentTasMovie.InputLogLength.ToString().Length, '0'); } else From 4d2f6e902ea3e841caf1d42f4971648ad7f1e6c5 Mon Sep 17 00:00:00 2001 From: "J.D. Purcell" Date: Sun, 27 Oct 2019 22:59:42 -0400 Subject: [PATCH 153/166] InputRoll horizontal! --- .../InputRoll/InputRoll.Drawing.cs | 70 +++++++------- .../CustomControls/InputRoll/InputRoll.cs | 93 +++++++++++-------- 2 files changed, 92 insertions(+), 71 deletions(-) diff --git a/BizHawk.Client.EmuHawk/CustomControls/InputRoll/InputRoll.Drawing.cs b/BizHawk.Client.EmuHawk/CustomControls/InputRoll/InputRoll.Drawing.cs index 45d51a4aa1..106a765ab3 100644 --- a/BizHawk.Client.EmuHawk/CustomControls/InputRoll/InputRoll.Drawing.cs +++ b/BizHawk.Client.EmuHawk/CustomControls/InputRoll/InputRoll.Drawing.cs @@ -9,8 +9,6 @@ namespace BizHawk.Client.EmuHawk { public partial class InputRoll { - private int[] _horizontalColumnHeights; - protected override void OnPaint(PaintEventArgs e) { using (_renderer.LockGraphics(e.Graphics, Width, Height)) @@ -25,7 +23,7 @@ namespace BizHawk.Client.EmuHawk var visibleColumns = _columns.VisibleColumns.ToList(); - CalculateHorizontalColumnHeights(visibleColumns); + CalculateHorizontalColumnPositions(visibleColumns); if (visibleColumns.Any()) { @@ -39,8 +37,8 @@ namespace BizHawk.Client.EmuHawk // Foreground DrawData(visibleColumns); - DrawColumnDrag(); - DrawCellDrag(); + DrawColumnDrag(visibleColumns); + DrawCellDrag(visibleColumns); } } @@ -68,16 +66,19 @@ namespace BizHawk.Client.EmuHawk // Do nothing, and this should never be called } - private void CalculateHorizontalColumnHeights(List visibleColumns) + private void CalculateHorizontalColumnPositions(List visibleColumns) { if (!HorizontalOrientation) { _horizontalColumnHeights = null; + _horizontalColumnTops = null; return; } _horizontalColumnHeights = new int[visibleColumns.Count]; + _horizontalColumnTops = new int[visibleColumns.Count]; + int top = 0; int startRow = FirstVisibleRow; for (int j = 0; j < visibleColumns.Count; j++) { @@ -97,27 +98,25 @@ namespace BizHawk.Client.EmuHawk height = Math.Max(height, textWidth + (CellWidthPadding * 2)); } _horizontalColumnHeights[j] = height; + _horizontalColumnTops[j] = top; + top += height; } } - private int HorizontalColumnsToPixels(int index) - { - int height = 0; - for (int j = 0; j < index; j++) - { - height += _horizontalColumnHeights[j]; - } - return height; - } - - private void DrawColumnDrag() + private void DrawColumnDrag(List visibleColumns) { if (_columnDown?.Width != null && _columnDownMoved && _currentX.HasValue && _currentY.HasValue && IsHoveringOnColumnCell) { + int columnHeight = CellHeight; + if (HorizontalOrientation) + { + int columnIndex = visibleColumns.IndexOf(_columnDown); + columnHeight = GetHColHeight(columnIndex); + } int x1 = _currentX.Value - (_columnDown.Width.Value / 2); - int y1 = _currentY.Value - (CellHeight / 2); + int y1 = _currentY.Value - (columnHeight / 2); int x2 = x1 + _columnDown.Width.Value; - int y2 = y1 + CellHeight; + int y2 = y1 + columnHeight; _renderer.SetSolidPen(_backColor); _renderer.DrawRectangle(x1, y1, x2, y2); @@ -126,7 +125,7 @@ namespace BizHawk.Client.EmuHawk } } - private void DrawCellDrag() + private void DrawCellDrag(List visibleColumns) { if (_draggingCell != null && _draggingCell.RowIndex.HasValue && _draggingCell.Column.Width.HasValue && _currentX.HasValue && _currentY.HasValue) @@ -139,10 +138,16 @@ namespace BizHawk.Client.EmuHawk Color bgColor = _backColor; QueryItemBkColor?.Invoke(_draggingCell.RowIndex.Value, _draggingCell.Column, ref bgColor); + int columnHeight = CellHeight; + if (HorizontalOrientation) + { + int columnIndex = visibleColumns.IndexOf(_draggingCell.Column); + columnHeight = GetHColHeight(columnIndex); + } int x1 = _currentX.Value - (_draggingCell.Column.Width.Value / 2); - int y1 = _currentY.Value - (CellHeight / 2); + int y1 = _currentY.Value - (columnHeight / 2); int x2 = x1 + _draggingCell.Column.Width.Value; - int y2 = y1 + CellHeight; + int y2 = y1 + columnHeight; _renderer.SetBrush(bgColor); _renderer.FillRectangle(x1, y1, x2 - x1, y2 - y1); @@ -162,7 +167,7 @@ namespace BizHawk.Client.EmuHawk for(int j = 0; j < visibleColumns.Count; j++) { var column = visibleColumns[j]; - var columnHeight = _horizontalColumnHeights[j]; + var columnHeight = GetHColHeight(j); var textHeight = _renderer.MeasureString(column.Text, _font).Height; var point = new Point(CellWidthPadding, y + ((columnHeight - textHeight) / 2)); @@ -222,14 +227,14 @@ namespace BizHawk.Client.EmuHawk for (int j = FirstVisibleColumn; j <= lastVisible; j++) { RollColumn col = visibleColumns[j]; - int colHeight = _horizontalColumnHeights[j]; + int colHeight = GetHColHeight(j); for (int i = 0, f = 0; f < range; i++, f++) { f += _lagFrames[i]; int baseX = RowsToPixels(i) + (col.Rotatable ? CellWidth : 0); - int baseY = HorizontalColumnsToPixels(j) - _vBar.Value; + int baseY = GetHColTop(j) - _vBar.Value; if (!col.Rotatable) { @@ -341,7 +346,7 @@ namespace BizHawk.Client.EmuHawk for (int j = 0; j < visibleColumns.Count; j++) { _renderer.Line(1, y, ColumnWidth, y); - y += _horizontalColumnHeights[j]; + y += GetHColHeight(j); } if (visibleColumns.Any()) @@ -383,7 +388,7 @@ namespace BizHawk.Client.EmuHawk if (HorizontalOrientation) { int columnIndex = visibleColumns.IndexOf(column); - _renderer.FillRectangle(1, HorizontalColumnsToPixels(columnIndex) + 1, ColumnWidth - 1, _horizontalColumnHeights[columnIndex] - 1); + _renderer.FillRectangle(1, GetHColTop(columnIndex) + 1, ColumnWidth - 1, GetHColHeight(columnIndex) - 1); } else { @@ -403,11 +408,14 @@ namespace BizHawk.Client.EmuHawk continue; } + int top = GetHColTop(i) - _vBar.Value; + int height = GetHColHeight(i); + _renderer.SetBrush(CurrentCell.Column.Emphasis ? SystemColors.Highlight.Add(0x00222222) : SystemColors.Highlight); - _renderer.FillRectangle(1, HorizontalColumnsToPixels(i) + 1, ColumnWidth - 1, _horizontalColumnHeights[i] - 1); + _renderer.FillRectangle(1, top + 1, ColumnWidth - 1, height - 1); } } else @@ -463,7 +471,7 @@ namespace BizHawk.Client.EmuHawk // Rows for (int i = 0; i < visibleColumns.Count + 1; i++) { - int y = HorizontalColumnsToPixels(i) - _vBar.Value; + int y = GetHColTop(i) - _vBar.Value; _renderer.Line(RowsToPixels(0) + 1, y, DrawWidth, y); } } @@ -560,8 +568,8 @@ namespace BizHawk.Client.EmuHawk int columnIndex = visibleColumns.IndexOf(cell.Column); w = CellWidth - 1; - y = HorizontalColumnsToPixels(columnIndex) - _vBar.Value + 1; // We can't draw without row and column, so assume they exist and fail catastrophically if they don't - h = _horizontalColumnHeights[columnIndex] - 1; + y = GetHColTop(columnIndex) - _vBar.Value + 1; // We can't draw without row and column, so assume they exist and fail catastrophically if they don't + h = GetHColHeight(columnIndex) - 1; } else { diff --git a/BizHawk.Client.EmuHawk/CustomControls/InputRoll/InputRoll.cs b/BizHawk.Client.EmuHawk/CustomControls/InputRoll/InputRoll.cs index 2bbbd74bcc..701811e58b 100644 --- a/BizHawk.Client.EmuHawk/CustomControls/InputRoll/InputRoll.cs +++ b/BizHawk.Client.EmuHawk/CustomControls/InputRoll/InputRoll.cs @@ -35,7 +35,11 @@ namespace BizHawk.Client.EmuHawk private int _maxCharactersInHorizontal = 1; private int _rowCount; - private Size _charSize; + private Size _charSize; + + // Updated on paint + private int[] _horizontalColumnHeights; + private int[] _horizontalColumnTops; private RollColumn _columnDown; private RollColumn _columnResizing; @@ -148,7 +152,6 @@ namespace BizHawk.Client.EmuHawk else { var maxLength = CurrentCell.Column.Text?.Length ?? 0; - for (int i = 0; i < RowCount; i++) { @@ -829,12 +832,13 @@ namespace BizHawk.Client.EmuHawk { get { + var columnList = VisibleColumns.ToList(); + if (HorizontalOrientation) { - return _vBar.Value / CellHeight; + return Enumerable.Range(0, columnList.Count).First(i => GetHColBottom(i) > _vBar.Value); } - var columnList = VisibleColumns.ToList(); return columnList.FindIndex(c => c.Right > _hBar.Value); } } @@ -846,21 +850,14 @@ namespace BizHawk.Client.EmuHawk get { List columnList = VisibleColumns.ToList(); - int ret; + if (HorizontalOrientation) { - ret = (_vBar.Value + DrawHeight) / CellHeight; - if (ret >= columnList.Count) - { - ret = columnList.Count - 1; - } - } - else - { - ret = columnList.FindLastIndex(c => c.Left <= DrawWidth + _hBar.Value); + int count = columnList.Count; + return Enumerable.Range(0, count).Select(i => count - 1 - i).First(i => GetHColTop(i) <= DrawWidth + _hBar.Value); } - return ret; + return columnList.FindLastIndex(c => c.Left <= DrawWidth + _hBar.Value); } } @@ -1279,11 +1276,11 @@ namespace BizHawk.Client.EmuHawk } else if (e.Button == MouseButtons.Left) { - ColumnClickEvent(ColumnAtX(e.X)); + ColumnClickEvent(ColumnAtPixel(e.X)); } else if (e.Button == MouseButtons.Right) { - ColumnRightClickEvent(ColumnAtX(e.X)); + ColumnRightClickEvent(ColumnAtPixel(e.X)); } } @@ -1634,11 +1631,12 @@ namespace BizHawk.Client.EmuHawk { UpdateDrawSize(); - var columns = _columns.VisibleColumns.ToList(); + var columns = _columns.VisibleColumns.ToList(); + int iLastColumn = columns.Count - 1; if (HorizontalOrientation) { - NeedsVScrollbar = columns.Count > DrawHeight / CellHeight; + NeedsVScrollbar = GetHColBottom(iLastColumn) > DrawHeight; NeedsHScrollbar = RowCount > 1; } else @@ -1652,9 +1650,9 @@ namespace BizHawk.Client.EmuHawk { if (HorizontalOrientation) { - _vBar.LargeChange = DrawHeight / 2; - _hBar.Maximum = Math.Max((VisibleRows - 1) * CellHeight, _hBar.Maximum); - _hBar.LargeChange = (VisibleRows - 1) * CellHeight; + _hBar.Maximum = Math.Max((VisibleRows - 1) * CellWidth, _hBar.Maximum); + _hBar.LargeChange = (VisibleRows - 1) * CellWidth; + _vBar.LargeChange = Math.Max(0, DrawHeight / 2); } else { @@ -1671,7 +1669,7 @@ namespace BizHawk.Client.EmuHawk { if (HorizontalOrientation) { - _vBar.Maximum = ((columns.Count() * CellHeight) - DrawHeight) + _vBar.LargeChange; + _vBar.Maximum = GetHColBottom(iLastColumn) - DrawHeight + _vBar.LargeChange; if (_vBar.Maximum < 0) { _vBar.Maximum = 0; @@ -1680,7 +1678,6 @@ namespace BizHawk.Client.EmuHawk else { _vBar.Maximum = RowsToPixels(RowCount + 1) - (CellHeight * 3) + _vBar.LargeChange - 1; - if (_vBar.Maximum < 0) { _vBar.Maximum = 0; @@ -1841,17 +1838,12 @@ namespace BizHawk.Client.EmuHawk if (HorizontalOrientation) { newCell.RowIndex = PixelsToRows(x); - - int colIndex = (y + _vBar.Value) / CellHeight; - if (colIndex >= 0 && colIndex < columns.Count) - { - newCell.Column = columns[colIndex]; - } + newCell.Column = ColumnAtPixel(y); } else { newCell.RowIndex = PixelsToRows(y); - newCell.Column = ColumnAtX(x); + newCell.Column = ColumnAtPixel(x); } } @@ -1887,20 +1879,32 @@ namespace BizHawk.Client.EmuHawk } /// - /// Returns the RollColumn object at the specified visible x coordinate. Coordinate should be between 0 and Width of the InputRoll Control. + /// Returns the RollColumn object at the specified visible pixel coordinate. /// - /// The x coordinate. - /// RollColumn object that contains the x coordinate or null if none exists. - private RollColumn ColumnAtX(int x) + /// The pixel coordinate. + /// RollColumn object that contains the pixel coordinate or null if none exists. + private RollColumn ColumnAtPixel(int pixel) { - foreach (RollColumn column in _columns.VisibleColumns) + if (_horizontalOrientation) { - if (column.Left.Value - _hBar.Value <= x && column.Right.Value - _hBar.Value >= x) + foreach (var item in _columns.VisibleColumns.Select((n, i) => new { Column = n, Index = i })) { - return column; + if (GetHColTop(item.Index) - _vBar.Value <= pixel && GetHColBottom(item.Index) - _vBar.Value >= pixel) + { + return item.Column; + } + } + } + else + { + foreach (RollColumn column in _columns.VisibleColumns) + { + if (column.Left.Value - _hBar.Value <= pixel && column.Right.Value - _hBar.Value >= pixel) + { + return column; + } } } - return null; } @@ -1933,7 +1937,16 @@ namespace BizHawk.Client.EmuHawk return (int)Math.Floor((float)(pixels - ColumnHeight) / CellHeight); } - // The width of the largest column cell in Horizontal Orientation + private int GetHColHeight(int index) => + _horizontalColumnHeights != null && index < _horizontalColumnHeights.Length ? _horizontalColumnHeights[index] : CellHeight; + + private int GetHColTop(int index) => + _horizontalColumnTops != null && index < _horizontalColumnTops.Length ? _horizontalColumnTops[index] : (index * CellHeight); + + private int GetHColBottom(int index) => + GetHColTop(index) + GetHColHeight(index); + + // The width of the largest column cell in Horizontal Orientation private int ColumnWidth { get; set; } // The height of a column cell in Vertical Orientation. From 1b548ed92d554fac99245dd838f52172b77c1556 Mon Sep 17 00:00:00 2001 From: "J.D. Purcell" Date: Mon, 28 Oct 2019 01:35:16 -0400 Subject: [PATCH 154/166] InputRoll horizontal: Improve look of column dragging. --- .../CustomControls/InputRoll/InputRoll.Drawing.cs | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/BizHawk.Client.EmuHawk/CustomControls/InputRoll/InputRoll.Drawing.cs b/BizHawk.Client.EmuHawk/CustomControls/InputRoll/InputRoll.Drawing.cs index 106a765ab3..db18513b43 100644 --- a/BizHawk.Client.EmuHawk/CustomControls/InputRoll/InputRoll.Drawing.cs +++ b/BizHawk.Client.EmuHawk/CustomControls/InputRoll/InputRoll.Drawing.cs @@ -107,21 +107,29 @@ namespace BizHawk.Client.EmuHawk { if (_columnDown?.Width != null && _columnDownMoved && _currentX.HasValue && _currentY.HasValue && IsHoveringOnColumnCell) { + int columnWidth = _columnDown.Width.Value; int columnHeight = CellHeight; if (HorizontalOrientation) { int columnIndex = visibleColumns.IndexOf(_columnDown); + columnWidth = ColumnWidth; columnHeight = GetHColHeight(columnIndex); } - int x1 = _currentX.Value - (_columnDown.Width.Value / 2); + int x1 = _currentX.Value - (columnWidth / 2); int y1 = _currentY.Value - (columnHeight / 2); - int x2 = x1 + _columnDown.Width.Value; + int x2 = x1 + columnWidth; int y2 = y1 + columnHeight; + int textOffsetY = CellHeightPadding; + if (HorizontalOrientation) + { + int textHeight = _renderer.MeasureString(_columnDown.Text, _font).Height; + textOffsetY = (columnHeight - textHeight) / 2; + } _renderer.SetSolidPen(_backColor); _renderer.DrawRectangle(x1, y1, x2, y2); _renderer.PrepDrawString(_font, _foreColor); - _renderer.DrawString(_columnDown.Text, new Point(x1 + CellWidthPadding, y1 + CellHeightPadding)); + _renderer.DrawString(_columnDown.Text, new Point(x1 + CellWidthPadding, y1 + textOffsetY)); } } From 0b965dffc560bbaef392ad9c4b38d2ef5102524e Mon Sep 17 00:00:00 2001 From: adelikat Date: Tue, 29 Oct 2019 08:23:40 -0500 Subject: [PATCH 155/166] misc cleanups --- .../tools/Lua/LuaConsole.cs | 10 +---- .../tools/Lua/LuaFunctionsForm.cs | 15 +++---- .../tools/Lua/LuaPictureBox.cs | 4 +- .../MultiDiskBundler/MultiDiskBundler.cs | 43 +++++++------------ BizHawk.sln.DotSettings | 2 + 5 files changed, 27 insertions(+), 47 deletions(-) diff --git a/BizHawk.Client.EmuHawk/tools/Lua/LuaConsole.cs b/BizHawk.Client.EmuHawk/tools/Lua/LuaConsole.cs index 9353b10901..9d17fb6518 100644 --- a/BizHawk.Client.EmuHawk/tools/Lua/LuaConsole.cs +++ b/BizHawk.Client.EmuHawk/tools/Lua/LuaConsole.cs @@ -101,15 +101,9 @@ namespace BizHawk.Client.EmuHawk public bool UpdateBefore => true; - private IEnumerable SelectedItems - { - get { return LuaListView.SelectedRows.Select(index => LuaImp.ScriptList[index]); } - } + private IEnumerable SelectedItems => LuaListView.SelectedRows.Select(index => LuaImp.ScriptList[index]); - private IEnumerable SelectedFiles - { - get { return SelectedItems.Where(x => !x.IsSeparator); } - } + private IEnumerable SelectedFiles => SelectedItems.Where(x => !x.IsSeparator); public void NewUpdate(ToolFormUpdateType type) { } diff --git a/BizHawk.Client.EmuHawk/tools/Lua/LuaFunctionsForm.cs b/BizHawk.Client.EmuHawk/tools/Lua/LuaFunctionsForm.cs index 0f5772db3b..37965de304 100644 --- a/BizHawk.Client.EmuHawk/tools/Lua/LuaFunctionsForm.cs +++ b/BizHawk.Client.EmuHawk/tools/Lua/LuaFunctionsForm.cs @@ -119,31 +119,24 @@ namespace BizHawk.Client.EmuHawk private class Sorting { - private bool _desc; private int _column = 1; public int Column { - get - { - return _column; - } + get => _column; set { if (_column == value) { - _desc ^= true; + Descending ^= true; } _column = value; } } - public bool Descending - { - get { return _desc; } - } + public bool Descending { get; private set; } } private void FunctionView_KeyDown(object sender, KeyEventArgs e) @@ -189,7 +182,9 @@ namespace BizHawk.Client.EmuHawk } if (sb.Length > 0) + { Clipboard.SetText(sb.ToString()); + } } private void UpdateList() diff --git a/BizHawk.Client.EmuHawk/tools/Lua/LuaPictureBox.cs b/BizHawk.Client.EmuHawk/tools/Lua/LuaPictureBox.cs index 6c8bf524d5..be641ceccb 100644 --- a/BizHawk.Client.EmuHawk/tools/Lua/LuaPictureBox.cs +++ b/BizHawk.Client.EmuHawk/tools/Lua/LuaPictureBox.cs @@ -332,8 +332,8 @@ namespace BizHawk.Client.EmuHawk var f = new StringFormat(StringFormat.GenericDefault); var font = new Font(family, fontsize ?? 12, fstyle, GraphicsUnit.Pixel); var boxBackground = Graphics.FromImage(Image); - - Size sizeOfText = boxBackground.MeasureString(message, font, 0, f).ToSize(); + + Size sizeOfText = boxBackground.MeasureString(message, font, 0, f).ToSize(); if (horizalign != null) { diff --git a/BizHawk.Client.EmuHawk/tools/MultiDiskBundler/MultiDiskBundler.cs b/BizHawk.Client.EmuHawk/tools/MultiDiskBundler/MultiDiskBundler.cs index 3fd97c10cf..8216a3666b 100644 --- a/BizHawk.Client.EmuHawk/tools/MultiDiskBundler/MultiDiskBundler.cs +++ b/BizHawk.Client.EmuHawk/tools/MultiDiskBundler/MultiDiskBundler.cs @@ -1,11 +1,9 @@ using System; using System.Collections.Generic; -using System.Data; using System.Drawing; using System.IO; using System.Linq; using System.Text; -using System.Text.RegularExpressions; using System.Windows.Forms; using System.Xml.Linq; @@ -18,7 +16,7 @@ namespace BizHawk.Client.EmuHawk { public partial class MultiDiskBundler : Form, IToolFormAutoConfig { - private XElement _currentXml = null; + private XElement _currentXml; [RequiredService] public IEmulator Emulator { get; set; } @@ -35,7 +33,6 @@ namespace BizHawk.Client.EmuHawk if (!Global.Game.IsNullInstance && !GlobalWin.MainForm.CurrentlyOpenRom.EndsWith(".xml")) { - string currentRom = GlobalWin.MainForm.CurrentlyOpenRom; if (GlobalWin.MainForm.CurrentlyOpenRom.Contains("|")) { var pieces = GlobalWin.MainForm.CurrentlyOpenRom.Split('|'); @@ -50,12 +47,12 @@ namespace BizHawk.Client.EmuHawk NameBox.Text = Path.ChangeExtension(GlobalWin.MainForm.CurrentlyOpenRom, ".xml"); } - if (SystemDropDown.Items.Contains(Emulator.SystemId)) - { - SystemDropDown.SelectedItem = Emulator.SystemId; - } + if (SystemDropDown.Items.Contains(Emulator.SystemId)) + { + SystemDropDown.SelectedItem = Emulator.SystemId; + } - FileSelectors.First().SetName(GlobalWin.MainForm.CurrentlyOpenRom); + FileSelectors.First().SetName(GlobalWin.MainForm.CurrentlyOpenRom); } } @@ -83,10 +80,7 @@ namespace BizHawk.Client.EmuHawk return true; } - public bool UpdateBefore - { - get { return true; } - } + public bool UpdateBefore => true; #endregion @@ -115,8 +109,8 @@ namespace BizHawk.Client.EmuHawk DialogResult = DialogResult.OK; Close(); - var lra = new MainForm.LoadRomArgs { OpenAdvanced = new OpenAdvanced_OpenRom { Path = fileInfo.FullName } }; - GlobalWin.MainForm.LoadRom(fileInfo.FullName, lra); + var lra = new MainForm.LoadRomArgs { OpenAdvanced = new OpenAdvanced_OpenRom { Path = fileInfo.FullName } }; + GlobalWin.MainForm.LoadRom(fileInfo.FullName, lra); } } @@ -132,18 +126,18 @@ namespace BizHawk.Client.EmuHawk Anchor = AnchorStyles.Left | AnchorStyles.Right | AnchorStyles.Top }; - var mdf = new MultiDiskFileSelector - { - Location = UIHelper.Scale(new Point(7, 12)), - Width = groupBox.ClientSize.Width - UIHelper.ScaleX(13), - Anchor = AnchorStyles.Left | AnchorStyles.Right | AnchorStyles.Top + var mdf = new MultiDiskFileSelector + { + Location = UIHelper.Scale(new Point(7, 12)), + Width = groupBox.ClientSize.Width - UIHelper.ScaleX(13), + Anchor = AnchorStyles.Left | AnchorStyles.Right | AnchorStyles.Top }; mdf.NameChanged += FileSelector_NameChanged; - mdf.SystemString = SystemDropDown.SelectedText; + mdf.SystemString = SystemDropDown.SelectedText; - groupBox.Controls.Add(mdf); + groupBox.Controls.Add(mdf); FileSelectorPanel.Controls.Add(groupBox); } @@ -236,11 +230,6 @@ namespace BizHawk.Client.EmuHawk } } - private static string ConvertToTag(string name) - { - return new Regex("[^A-Za-z0-9]").Replace(name, ""); - } - private void NameBox_TextChanged(object sender, EventArgs e) { Recalculate(); diff --git a/BizHawk.sln.DotSettings b/BizHawk.sln.DotSettings index d27343588e..7e543eb96d 100644 --- a/BizHawk.sln.DotSettings +++ b/BizHawk.sln.DotSettings @@ -186,6 +186,7 @@ True True True + True True True True @@ -261,6 +262,7 @@ True True True + True True True True From d65092e96797a47fc996f536a5a1eed74b311b3b Mon Sep 17 00:00:00 2001 From: adelikat Date: Tue, 29 Oct 2019 09:27:56 -0500 Subject: [PATCH 156/166] Misc cleanups in tool dialogs - mostly the use of expression body (C#6/C#7isms) --- .../tools/NES/BarcodeEntry.cs | 20 +++-------- .../tools/NES/NESGameGenie.cs | 7 ++-- .../tools/NES/NESMusicRipper.cs | 18 ++++------ .../tools/NES/NESNameTableViewer.cs | 13 +++---- BizHawk.Client.EmuHawk/tools/NES/NESPPU.cs | 20 ++++------- .../tools/NES/PaletteViewer.cs | 7 ++-- .../tools/NES/SpriteViewer.cs | 5 +-- .../tools/PCE/PCEBGViewer.cs | 13 ++----- .../tools/PCE/PCESoundDebugger.cs | 23 ++++-------- .../tools/PCE/PCETileViewer.cs | 13 +++---- BizHawk.Client.EmuHawk/tools/SMS/VDPViewer.cs | 11 +++--- .../tools/SNES/SNESGraphicsDebugger.cs | 19 +++++----- BizHawk.Client.EmuHawk/tools/ToolManager.cs | 1 - .../tools/VirtualPads/VirtualPad.cs | 21 ++++------- .../tools/VirtualPads/VirtualpadsTool.cs | 14 +++----- .../controls/VirtualPadAnalogButton.cs | 35 ++++--------------- .../controls/VirtualPadAnalogStick.cs | 11 ++---- .../VirtualPads/controls/VirtualPadButton.cs | 10 ++---- .../VirtualPadDiscManager.Designer.cs | 1 - .../controls/VirtualPadDiscManager.cs | 25 ++++--------- .../controls/VirtualPadTargetScreen.cs | 24 +++---------- .../controls/components/AnalogStickPanel.cs | 10 ++---- BizHawk.sln.DotSettings | 3 ++ 23 files changed, 92 insertions(+), 232 deletions(-) diff --git a/BizHawk.Client.EmuHawk/tools/NES/BarcodeEntry.cs b/BizHawk.Client.EmuHawk/tools/NES/BarcodeEntry.cs index 6b4e0d07f4..5b5e514046 100644 --- a/BizHawk.Client.EmuHawk/tools/NES/BarcodeEntry.cs +++ b/BizHawk.Client.EmuHawk/tools/NES/BarcodeEntry.cs @@ -1,14 +1,6 @@ using System; -using System.Collections.Generic; -using System.ComponentModel; -using System.Data; -using System.Drawing; -using System.Linq; -using System.Text; using System.Windows.Forms; using BizHawk.Emulation.Cores.Nintendo.NES; -using BizHawk.Common; -using BizHawk.Client.Common; using BizHawk.Emulation.Common; namespace BizHawk.Client.EmuHawk @@ -16,7 +8,7 @@ namespace BizHawk.Client.EmuHawk public partial class BarcodeEntry : Form, IToolForm { [RequiredService] - private DatachBarcode reader { get; set; } + private DatachBarcode Reader { get; set; } public BarcodeEntry() { @@ -45,17 +37,13 @@ namespace BizHawk.Client.EmuHawk return true; } - public bool UpdateBefore - { - get { return false; } - } + public bool UpdateBefore => false; #endregion private void textBox1_TextChanged(object sender, EventArgs e) { - string why; - if (!DatachBarcode.ValidString(textBox1.Text, out why)) + if (!DatachBarcode.ValidString(textBox1.Text, out var why)) { label3.Text = $"Invalid: {why}"; label3.Visible = true; @@ -70,7 +58,7 @@ namespace BizHawk.Client.EmuHawk private void button1_Click(object sender, EventArgs e) { - reader.Transfer(textBox1.Text); + Reader.Transfer(textBox1.Text); } } } diff --git a/BizHawk.Client.EmuHawk/tools/NES/NESGameGenie.cs b/BizHawk.Client.EmuHawk/tools/NES/NESGameGenie.cs index 0b6912c602..516456a7f3 100644 --- a/BizHawk.Client.EmuHawk/tools/NES/NESGameGenie.cs +++ b/BizHawk.Client.EmuHawk/tools/NES/NESGameGenie.cs @@ -41,12 +41,9 @@ namespace BizHawk.Client.EmuHawk private int? _value; private int? _compare; - public int? Address { get { return _address; } } - public int? Value { get { return _value; } } - public int? Compare { get { return _compare; } } - public bool AskSaveChanges() { return true; } - public bool UpdateBefore { get { return false; } } + public bool UpdateBefore => false; + public void Restart() { if (Emulator.SystemId != "NES") diff --git a/BizHawk.Client.EmuHawk/tools/NES/NESMusicRipper.cs b/BizHawk.Client.EmuHawk/tools/NES/NESMusicRipper.cs index 2c0cfcb7ed..e5c2a12963 100644 --- a/BizHawk.Client.EmuHawk/tools/NES/NESMusicRipper.cs +++ b/BizHawk.Client.EmuHawk/tools/NES/NESMusicRipper.cs @@ -1,15 +1,9 @@ using System; -using System.Xml; using System.Xml.XPath; using System.Xml.Linq; -using System.Linq; using System.IO; -using System.Text; using System.Collections.Generic; -using System.Drawing; -using System.Drawing.Imaging; using System.Windows.Forms; -using BizHawk.Client.Common; using BizHawk.Emulation.Cores.Nintendo.NES; using BizHawk.Emulation.Common; @@ -27,7 +21,7 @@ namespace BizHawk.Client.EmuHawk } public bool AskSaveChanges() { return true; } - public bool UpdateBefore { get { return true; } } + public bool UpdateBefore => true; public void Restart() { @@ -48,12 +42,12 @@ namespace BizHawk.Client.EmuHawk //http://www.phy.mtu.edu/~suits/notefreqs.html //begins at C0. ends at B8 - static readonly float[] freqtbl = new[] {0, + static readonly float[] freqtbl = {0, 16.35f,17.32f,18.35f,19.45f,20.6f,21.83f,23.12f,24.5f,25.96f,27.5f,29.14f,30.87f,32.7f,34.65f,36.71f,38.89f,41.2f,43.65f,46.25f,49f,51.91f,55f,58.27f,61.74f,65.41f,69.3f,73.42f,77.78f,82.41f,87.31f,92.5f,98f,103.83f,110f,116.54f,123.47f,130.81f,138.59f,146.83f,155.56f,164.81f,174.61f,185f,196f,207.65f,220f,233.08f,246.94f,261.63f,277.18f,293.66f,311.13f,329.63f,349.23f,369.99f,392f,415.3f,440f,466.16f,493.88f,523.25f,554.37f,587.33f,622.25f,659.25f,698.46f,739.99f,783.99f,830.61f,880f,932.33f,987.77f,1046.5f,1108.73f,1174.66f,1244.51f,1318.51f,1396.91f,1479.98f,1567.98f,1661.22f,1760f,1864.66f,1975.53f,2093f,2217.46f,2349.32f,2489.02f,2637.02f,2793.83f,2959.96f,3135.96f,3322.44f,3520f,3729.31f,3951.07f,4186.01f,4434.92f,4698.63f,4978.03f,5274.04f,5587.65f,5919.91f,6271.93f,6644.88f,7040f,7458.62f,7902.13f, 1000000 }; - static readonly string[] noteNames = new[] { "C-", "C#", "D-", "D#", "E-", "F-", "F#", "G-", "G#", "A-", "A#", "B-" }; + static readonly string[] noteNames = { "C-", "C#", "D-", "D#", "E-", "F-", "F#", "G-", "G#", "A-", "A#", "B-" }; string NameForNote(int note) { @@ -115,8 +109,10 @@ namespace BizHawk.Client.EmuHawk private void btnExport_Click(object sender, EventArgs e) { //acquire target - var sfd = new SaveFileDialog(); - sfd.Filter = "XRNS (*.xrns)|*.xrns"; + var sfd = new SaveFileDialog + { + Filter = "XRNS (*.xrns)|*.xrns" + }; if (sfd.ShowDialog() != System.Windows.Forms.DialogResult.OK) return; diff --git a/BizHawk.Client.EmuHawk/tools/NES/NESNameTableViewer.cs b/BizHawk.Client.EmuHawk/tools/NES/NESNameTableViewer.cs index 1856b0206a..2f8d37f9fd 100644 --- a/BizHawk.Client.EmuHawk/tools/NES/NESNameTableViewer.cs +++ b/BizHawk.Client.EmuHawk/tools/NES/NESNameTableViewer.cs @@ -1,9 +1,7 @@ using System; -using System.Collections.Generic; using System.Drawing; using System.Drawing.Imaging; using System.Windows.Forms; -using BizHawk.Client.Common; using BizHawk.Emulation.Cores.Nintendo.NES; using BizHawk.Emulation.Common; @@ -21,8 +19,8 @@ namespace BizHawk.Client.EmuHawk [ConfigPersist] private int RefreshRateConfig { - get { return RefreshRate.Value; } - set { RefreshRate.Value = value; } + get => RefreshRate.Value; + set => RefreshRate.Value = value; } int scanline; @@ -40,7 +38,7 @@ namespace BizHawk.Client.EmuHawk #region Public API public bool AskSaveChanges() { return true; } - public bool UpdateBefore { get { return true; } } + public bool UpdateBefore => true; public void Restart() { @@ -238,10 +236,7 @@ namespace BizHawk.Client.EmuHawk private void NESNameTableViewer_FormClosed(object sender, FormClosedEventArgs e) { - if (_ppu != null) - { - _ppu.RemoveCallback1(); - } + _ppu?.RemoveCallback1(); } private void ScanlineTextbox_TextChanged(object sender, EventArgs e) diff --git a/BizHawk.Client.EmuHawk/tools/NES/NESPPU.cs b/BizHawk.Client.EmuHawk/tools/NES/NESPPU.cs index e4238baa17..ec28b1c2cd 100644 --- a/BizHawk.Client.EmuHawk/tools/NES/NESPPU.cs +++ b/BizHawk.Client.EmuHawk/tools/NES/NESPPU.cs @@ -1,12 +1,9 @@ using System; using System.Drawing; using System.Drawing.Imaging; -using System.Linq; using System.Windows.Forms; -using BizHawk.Client.Common; using BizHawk.Emulation.Cores.Nintendo.NES; using BizHawk.Emulation.Common; -using System.Collections.Generic; namespace BizHawk.Client.EmuHawk { @@ -33,15 +30,15 @@ namespace BizHawk.Client.EmuHawk [ConfigPersist] private int RefreshRateConfig { - get { return RefreshRate.Value; } - set { RefreshRate.Value = value; } + get => RefreshRate.Value; + set => RefreshRate.Value = value; } - private bool _chrromview = false; + private bool _chrromview; [ConfigPersist] private bool ChrRomView { - get { return _chrromview; } + get => _chrromview; set { _chrromview = value; CalculateFormSize(); } } @@ -61,7 +58,7 @@ namespace BizHawk.Client.EmuHawk #region Public API public bool AskSaveChanges() { return true; } - public bool UpdateBefore { get { return true; } } + public bool UpdateBefore => true; public void NewUpdate(ToolFormUpdateType type) { } public void UpdateValues() @@ -790,16 +787,13 @@ namespace BizHawk.Client.EmuHawk private void NesPPU_FormClosed(object sender, FormClosedEventArgs e) { - if (_ppu != null) - { - _ppu.RemoveCallback2(); - } + _ppu?.RemoveCallback2(); } #endregion MemoryDomain CHRROM; - byte[] chrromcache = new byte[8192]; + readonly byte[] chrromcache = new byte[8192]; private void cHRROMTileViewerToolStripMenuItem_Click(object sender, EventArgs e) { diff --git a/BizHawk.Client.EmuHawk/tools/NES/PaletteViewer.cs b/BizHawk.Client.EmuHawk/tools/NES/PaletteViewer.cs index 12f7a126db..0f8b22c0a7 100644 --- a/BizHawk.Client.EmuHawk/tools/NES/PaletteViewer.cs +++ b/BizHawk.Client.EmuHawk/tools/NES/PaletteViewer.cs @@ -12,12 +12,9 @@ namespace BizHawk.Client.EmuHawk { public class Palette { - public int Address { get; private set; } + public int Address { get; } public int Value { get; set; } - public Color Color - { - get { return Color.FromArgb(Value); } - } + public Color Color => Color.FromArgb(Value); public Palette(int address) { diff --git a/BizHawk.Client.EmuHawk/tools/NES/SpriteViewer.cs b/BizHawk.Client.EmuHawk/tools/NES/SpriteViewer.cs index 3ca6f07d52..fe7d3aaea5 100644 --- a/BizHawk.Client.EmuHawk/tools/NES/SpriteViewer.cs +++ b/BizHawk.Client.EmuHawk/tools/NES/SpriteViewer.cs @@ -29,10 +29,7 @@ namespace BizHawk.Client.EmuHawk private void Display(Graphics g) { - unchecked - { - g.DrawImage(sprites, 1, 1); - } + g.DrawImage(sprites, 1, 1); } private void SpriteViewer_Paint(object sender, PaintEventArgs e) diff --git a/BizHawk.Client.EmuHawk/tools/PCE/PCEBGViewer.cs b/BizHawk.Client.EmuHawk/tools/PCE/PCEBGViewer.cs index 10e69b4186..ad8ebbfc67 100644 --- a/BizHawk.Client.EmuHawk/tools/PCE/PCEBGViewer.cs +++ b/BizHawk.Client.EmuHawk/tools/PCE/PCEBGViewer.cs @@ -1,5 +1,4 @@ using System; -using System.Collections.Generic; using System.Drawing; using System.Drawing.Imaging; using System.Windows.Forms; @@ -16,14 +15,8 @@ namespace BizHawk.Client.EmuHawk [ConfigPersist] private int RefreshRateConfig { - get - { - return RefreshRate.Value; - } - set - { - RefreshRate.Value = Math.Max(Math.Min(value, RefreshRate.Maximum), RefreshRate.Minimum); - } + get => RefreshRate.Value; + set => RefreshRate.Value = Math.Max(Math.Min(value, RefreshRate.Maximum), RefreshRate.Minimum); } private int _vdcType; @@ -41,7 +34,7 @@ namespace BizHawk.Client.EmuHawk #region Public API public bool AskSaveChanges() { return true; } - public bool UpdateBefore { get { return true; } } + public bool UpdateBefore => true; public unsafe void Generate() { diff --git a/BizHawk.Client.EmuHawk/tools/PCE/PCESoundDebugger.cs b/BizHawk.Client.EmuHawk/tools/PCE/PCESoundDebugger.cs index b32faac779..95032064a9 100644 --- a/BizHawk.Client.EmuHawk/tools/PCE/PCESoundDebugger.cs +++ b/BizHawk.Client.EmuHawk/tools/PCE/PCESoundDebugger.cs @@ -1,18 +1,10 @@ using System; using System.IO; using System.Collections.Generic; -using System.ComponentModel; -using System.Data; -using System.Drawing; -using System.Linq; -using System.Text; using System.Windows.Forms; using BizHawk.Common.BufferExtensions; -using BizHawk.Client.Common; - using BizHawk.Emulation.Cores.PCEngine; -using BizHawk.Emulation.Common.Components; using BizHawk.Emulation.Common; using ICSharpCode.SharpZipLib.Zip; @@ -33,7 +25,7 @@ namespace BizHawk.Client.EmuHawk SetStyle(ControlStyles.OptimizedDoubleBuffer, true); } - byte[] waveformTemp = new byte[32 * 2]; + readonly byte[] waveformTemp = new byte[32 * 2]; protected override void OnShown(EventArgs e) { @@ -161,9 +153,9 @@ namespace BizHawk.Client.EmuHawk public short[] waveform; } - PSGEntry[] LastSamples = new PSGEntry[8]; - List PSGEntries = new List(); - Dictionary PSGEntryTable = new Dictionary(); + readonly PSGEntry[] LastSamples = new PSGEntry[8]; + readonly List PSGEntries = new List(); + readonly Dictionary PSGEntryTable = new Dictionary(); public void Restart() { @@ -174,14 +166,11 @@ namespace BizHawk.Client.EmuHawk return true; } - public bool UpdateBefore - { - get { return false; } - } + public bool UpdateBefore => false; //32*16 samples, 16bit, mono, 8khz (but we'll change the sample rate) - static readonly byte[] emptyWav = new byte[] { + static readonly byte[] emptyWav = { 0x52, 0x49, 0x46, 0x46, 0x24, 0x04, 0x00, 0x00, 0x57, 0x41, 0x56, 0x45, 0x66, 0x6D, 0x74, 0x20, 0x10, 0x00, 0x00, 0x00, 0x01, 0x00, 0x01, 0x00, 0xE0, 0x2E, 0x00, 0x00, 0xC0, 0x5D, 0x00, 0x00, 0x02, 0x00, 0x10, 0x00, 0x64, 0x61, 0x74, 0x61, 0x00, 0x04, 0x00, 0x00, diff --git a/BizHawk.Client.EmuHawk/tools/PCE/PCETileViewer.cs b/BizHawk.Client.EmuHawk/tools/PCE/PCETileViewer.cs index 2a94623389..53f00f7edb 100644 --- a/BizHawk.Client.EmuHawk/tools/PCE/PCETileViewer.cs +++ b/BizHawk.Client.EmuHawk/tools/PCE/PCETileViewer.cs @@ -1,7 +1,5 @@ using System; -using System.Collections.Generic; using System.Drawing; -using System.Linq; using System.Windows.Forms; using BizHawk.Emulation.Cores.PCEngine; @@ -50,7 +48,7 @@ namespace BizHawk.Client.EmuHawk // Do nothing } - unsafe static void Draw16x16(byte* src, int* dest, int pitch, int* pal) + static unsafe void Draw16x16(byte* src, int* dest, int pitch, int* pal) { int inc = pitch - 16; dest -= inc; @@ -62,7 +60,7 @@ namespace BizHawk.Client.EmuHawk } } - unsafe static void Draw8x8(byte* src, int* dest, int pitch, int* pal) + static unsafe void Draw8x8(byte* src, int* dest, int pitch, int* pal) { int inc = pitch - 8; dest -= inc; @@ -125,7 +123,7 @@ namespace BizHawk.Client.EmuHawk } } - unsafe static void DrawPalette(Bitmap bmp, int* pal) + static unsafe void DrawPalette(Bitmap bmp, int* pal) { var lockdata = bmp.LockBits(new Rectangle(0, 0, 256, 256), ImageLockMode.WriteOnly, PixelFormat.Format32bppArgb); @@ -165,10 +163,7 @@ namespace BizHawk.Client.EmuHawk return true; } - public bool UpdateBefore - { - get { return true; } - } + public bool UpdateBefore => true; #endregion diff --git a/BizHawk.Client.EmuHawk/tools/SMS/VDPViewer.cs b/BizHawk.Client.EmuHawk/tools/SMS/VDPViewer.cs index 760bb758b5..847ae7f61d 100644 --- a/BizHawk.Client.EmuHawk/tools/SMS/VDPViewer.cs +++ b/BizHawk.Client.EmuHawk/tools/SMS/VDPViewer.cs @@ -18,7 +18,7 @@ namespace BizHawk.Client.EmuHawk { [RequiredService] private SMS sms { get; set; } - private VDP vdp { get { return sms.Vdp; } } + private VDP vdp => sms.Vdp; int palindex = 0; @@ -31,7 +31,7 @@ namespace BizHawk.Client.EmuHawk bmpViewBG.ChangeBitmapSize(256, 256); } - unsafe static void Draw8x8(byte* src, int* dest, int pitch, int* pal) + static unsafe void Draw8x8(byte* src, int* dest, int pitch, int* pal) { int inc = pitch - 8; dest -= inc; @@ -43,7 +43,7 @@ namespace BizHawk.Client.EmuHawk } } - unsafe static void Draw8x8hv(byte* src, int* dest, int pitch, int* pal, bool hflip, bool vflip) + static unsafe void Draw8x8hv(byte* src, int* dest, int pitch, int* pal, bool hflip, bool vflip) { int incx = hflip ? -1 : 1; int incy = vflip ? -pitch : pitch; @@ -169,10 +169,7 @@ namespace BizHawk.Client.EmuHawk return true; } - public bool UpdateBefore - { - get { return true; } - } + public bool UpdateBefore => true; private void bmpViewPalette_MouseClick(object sender, MouseEventArgs e) { diff --git a/BizHawk.Client.EmuHawk/tools/SNES/SNESGraphicsDebugger.cs b/BizHawk.Client.EmuHawk/tools/SNES/SNESGraphicsDebugger.cs index 4b703e762c..7c6535b182 100644 --- a/BizHawk.Client.EmuHawk/tools/SNES/SNESGraphicsDebugger.cs +++ b/BizHawk.Client.EmuHawk/tools/SNES/SNESGraphicsDebugger.cs @@ -40,9 +40,9 @@ namespace BizHawk.Client.EmuHawk { public unsafe partial class SNESGraphicsDebugger : Form, IToolFormAutoConfig { - List displayTypeItems = new List(); + readonly List displayTypeItems = new List(); - public bool UpdateBefore { get { return false; } } + public bool UpdateBefore => false; public bool AskSaveChanges() { return true; } [RequiredService] @@ -51,8 +51,8 @@ namespace BizHawk.Client.EmuHawk [ConfigPersist] public bool UseUserBackdropColor { - get { return checkBackdropColor.Checked; } - set { checkBackdropColor.Checked = value; } + get => checkBackdropColor.Checked; + set => checkBackdropColor.Checked = value; } [ConfigPersist] public int UserBackdropColor { get; set; } @@ -116,8 +116,7 @@ namespace BizHawk.Client.EmuHawk protected override void OnClosed(EventArgs e) { base.OnClosed(e); - if (currentSnesCore != null) - currentSnesCore.ScanlineHookManager.Unregister(this); + currentSnesCore?.ScanlineHookManager.Unregister(this); currentSnesCore = null; } @@ -224,7 +223,7 @@ namespace BizHawk.Client.EmuHawk void RegenerateData() { - if (gd != null) gd.Dispose(); + gd?.Dispose(); gd = null; if (currentSnesCore == null) return; gd = NewDecoder(); @@ -345,7 +344,7 @@ namespace BizHawk.Client.EmuHawk } } - eDisplayType CurrDisplaySelection { get { return (comboDisplayType.SelectedValue as eDisplayType?).Value; } } + eDisplayType CurrDisplaySelection => (comboDisplayType.SelectedValue as eDisplayType?).Value; //todo - something smarter to cycle through bitmaps without repeatedly trashing them (use the dispose callback on the viewer) private void RenderView() @@ -527,8 +526,8 @@ namespace BizHawk.Client.EmuHawk class PaletteTypeItem { - public SnesColors.ColorType Type { get; private set; } - public string Descr { get; private set; } + public SnesColors.ColorType Type { get; } + public string Descr { get; } public PaletteTypeItem(string descr, SnesColors.ColorType type) { Type = type; diff --git a/BizHawk.Client.EmuHawk/tools/ToolManager.cs b/BizHawk.Client.EmuHawk/tools/ToolManager.cs index 86973efc73..e04f82d9f6 100644 --- a/BizHawk.Client.EmuHawk/tools/ToolManager.cs +++ b/BizHawk.Client.EmuHawk/tools/ToolManager.cs @@ -9,7 +9,6 @@ using System.Windows.Forms; using BizHawk.Client.ApiHawk; using BizHawk.Client.Common; -using BizHawk.Client.EmuHawk; using BizHawk.Client.EmuHawk.CoreExtensions; using BizHawk.Common; using BizHawk.Common.ReflectionExtensions; diff --git a/BizHawk.Client.EmuHawk/tools/VirtualPads/VirtualPad.cs b/BizHawk.Client.EmuHawk/tools/VirtualPads/VirtualPad.cs index 2f5b802fcc..b8d2103c93 100644 --- a/BizHawk.Client.EmuHawk/tools/VirtualPads/VirtualPad.cs +++ b/BizHawk.Client.EmuHawk/tools/VirtualPads/VirtualPad.cs @@ -3,7 +3,6 @@ using System.Collections.Generic; using System.Linq; using System.Windows.Forms; -using BizHawk.Client.Common; using BizHawk.Emulation.Common; using System.Drawing; @@ -19,24 +18,16 @@ namespace BizHawk.Client.EmuHawk PadControls.ForEach(c => c.UpdateValues()); } - private List PadControls - { - get - { - return PadBox.Controls - .OfType() - .ToList(); - } - } + private List PadControls => + PadBox.Controls + .OfType() + .ToList(); - public string PadSchemaDisplayName { get { return _schema.DisplayName; } } + public string PadSchemaDisplayName => _schema.DisplayName; public bool ReadOnly { - get - { - return _readOnly; - } + get => _readOnly; set { diff --git a/BizHawk.Client.EmuHawk/tools/VirtualPads/VirtualpadsTool.cs b/BizHawk.Client.EmuHawk/tools/VirtualPads/VirtualpadsTool.cs index 44ca4ac00b..4e303320bb 100644 --- a/BizHawk.Client.EmuHawk/tools/VirtualPads/VirtualpadsTool.cs +++ b/BizHawk.Client.EmuHawk/tools/VirtualPads/VirtualpadsTool.cs @@ -1,6 +1,5 @@ using System; using System.Collections.Generic; -using System.Drawing; using System.Linq; using System.Reflection; using System.Windows.Forms; @@ -23,15 +22,10 @@ namespace BizHawk.Client.EmuHawk private bool _readOnly; - private List Pads - { - get - { - return ControllerPanel.Controls - .OfType() - .ToList(); - } - } + private List Pads => + ControllerPanel.Controls + .OfType() + .ToList(); public bool Readonly { diff --git a/BizHawk.Client.EmuHawk/tools/VirtualPads/controls/VirtualPadAnalogButton.cs b/BizHawk.Client.EmuHawk/tools/VirtualPads/controls/VirtualPadAnalogButton.cs index ddc2b76b4e..617fd78021 100644 --- a/BizHawk.Client.EmuHawk/tools/VirtualPads/controls/VirtualPadAnalogButton.cs +++ b/BizHawk.Client.EmuHawk/tools/VirtualPads/controls/VirtualPadAnalogButton.cs @@ -17,10 +17,7 @@ namespace BizHawk.Client.EmuHawk private bool _isSet = false; private bool IsSet { - get - { - return _isSet; - } + get => _isSet; set { @@ -62,10 +59,7 @@ namespace BizHawk.Client.EmuHawk public bool ReadOnly { - get - { - return _readonly; - } + get => _readonly; set { @@ -102,10 +96,7 @@ namespace BizHawk.Client.EmuHawk public string DisplayName { - get - { - return _displayName; - } + get => _displayName; set { @@ -119,10 +110,7 @@ namespace BizHawk.Client.EmuHawk public int MaxValue { - get - { - return _maxValue; - } + get => _maxValue; set { @@ -137,10 +125,7 @@ namespace BizHawk.Client.EmuHawk public int MinValue { - get - { - return _minValue; - } + get => _minValue; set { @@ -155,10 +140,7 @@ namespace BizHawk.Client.EmuHawk public Orientation Orientation { - get - { - return AnalogTrackBar.Orientation; - } + get => AnalogTrackBar.Orientation; set { @@ -207,10 +189,7 @@ namespace BizHawk.Client.EmuHawk public int CurrentValue { - get - { - return AnalogTrackBar.Value; - } + get => AnalogTrackBar.Value; set { diff --git a/BizHawk.Client.EmuHawk/tools/VirtualPads/controls/VirtualPadAnalogStick.cs b/BizHawk.Client.EmuHawk/tools/VirtualPads/controls/VirtualPadAnalogStick.cs index 0237b74de7..026489f496 100644 --- a/BizHawk.Client.EmuHawk/tools/VirtualPads/controls/VirtualPadAnalogStick.cs +++ b/BizHawk.Client.EmuHawk/tools/VirtualPads/controls/VirtualPadAnalogStick.cs @@ -1,10 +1,8 @@ using System; -using System.Drawing; using System.Windows.Forms; using BizHawk.Emulation.Common; using BizHawk.Client.Common; -using System.Windows; using BizHawk.Common.NumberExtensions; namespace BizHawk.Client.EmuHawk @@ -31,8 +29,8 @@ namespace BizHawk.Client.EmuHawk manualTheta.ValueChanged += PolarNumeric_Changed; } - public float[] RangeX = new float[] { -128f, 0.0f, 127f }; - public float[] RangeY = new float[] { -128f, 0.0f, 127f }; + public float[] RangeX = { -128f, 0.0f, 127f }; + public float[] RangeY = { -128f, 0.0f, 127f }; private bool ReverseX; private bool ReverseY; @@ -112,10 +110,7 @@ namespace BizHawk.Client.EmuHawk public bool ReadOnly { - get - { - return _readonly; - } + get => _readonly; set { diff --git a/BizHawk.Client.EmuHawk/tools/VirtualPads/controls/VirtualPadButton.cs b/BizHawk.Client.EmuHawk/tools/VirtualPads/controls/VirtualPadButton.cs index 3540991722..216b902f25 100644 --- a/BizHawk.Client.EmuHawk/tools/VirtualPads/controls/VirtualPadButton.cs +++ b/BizHawk.Client.EmuHawk/tools/VirtualPads/controls/VirtualPadButton.cs @@ -57,10 +57,7 @@ namespace BizHawk.Client.EmuHawk public bool ReadOnly { - get - { - return _readonly; - } + get => _readonly; set { @@ -123,10 +120,7 @@ namespace BizHawk.Client.EmuHawk public bool RightClicked { - get - { - return !ReadOnly && _rightClicked; - } + get => !ReadOnly && _rightClicked; set { diff --git a/BizHawk.Client.EmuHawk/tools/VirtualPads/controls/VirtualPadDiscManager.Designer.cs b/BizHawk.Client.EmuHawk/tools/VirtualPads/controls/VirtualPadDiscManager.Designer.cs index a998f2e866..ca4a99c50b 100644 --- a/BizHawk.Client.EmuHawk/tools/VirtualPads/controls/VirtualPadDiscManager.Designer.cs +++ b/BizHawk.Client.EmuHawk/tools/VirtualPads/controls/VirtualPadDiscManager.Designer.cs @@ -51,7 +51,6 @@ this.groupBox1.TabIndex = 1; this.groupBox1.TabStop = false; this.groupBox1.Text = "Discs"; - this.groupBox1.Enter += new System.EventHandler(this.groupBox1_Enter); // // lvDiscs // diff --git a/BizHawk.Client.EmuHawk/tools/VirtualPads/controls/VirtualPadDiscManager.cs b/BizHawk.Client.EmuHawk/tools/VirtualPads/controls/VirtualPadDiscManager.cs index 2bdf09fc35..6366e785f8 100644 --- a/BizHawk.Client.EmuHawk/tools/VirtualPads/controls/VirtualPadDiscManager.cs +++ b/BizHawk.Client.EmuHawk/tools/VirtualPads/controls/VirtualPadDiscManager.cs @@ -1,10 +1,5 @@ using System; using System.Collections.Generic; -using System.ComponentModel; -using System.Drawing; -using System.Data; -using System.Linq; -using System.Text; using System.Windows.Forms; using BizHawk.Client.Common; @@ -29,7 +24,7 @@ namespace BizHawk.Client.EmuHawk object _ownerEmulator; public object OwnerEmulator { - get { return _ownerEmulator; } + get => _ownerEmulator; set { _ownerEmulator = value; @@ -59,8 +54,7 @@ namespace BizHawk.Client.EmuHawk int idx = 0; foreach (var button in buttons) { - var lvi = new ListViewItem(); - lvi.Text = idx.ToString(); + var lvi = new ListViewItem { Text = idx.ToString() }; lvi.SubItems.Add(button); lvDiscs.Items.Add(lvi); idx++; @@ -105,9 +99,9 @@ namespace BizHawk.Client.EmuHawk enableDiscs = btnOpen.Checked; - //since user hasnt ever needed to set the disc, make sure it's set here - //UPDATE: do it below - //Global.StickyXORAdapter.SetFloat(_discSelectName, psx.CurrentDiscIndexMounted); + // since user hasn't ever needed to set the disc, make sure it's set here + // UPDATE: do it below + //Global.StickyXORAdapter.SetFloat(_discSelectName, psx.CurrentDiscIndexMounted); } else { @@ -128,8 +122,8 @@ namespace BizHawk.Client.EmuHawk } } - //make sure we try to keep something selected here, for clarity. - //but maybe later we'll just make it so that unselecting means no disc and dont display the disc 0 + // make sure we try to keep something selected here, for clarity. + // but maybe later we'll just make it so that unselecting means no disc and don't display the disc 0 if (lvDiscs.SelectedIndices.Count == 0) lvDiscs.SelectedIndices.Add(0); } @@ -143,11 +137,6 @@ namespace BizHawk.Client.EmuHawk #endregion //IVirtualPadControl - private void groupBox1_Enter(object sender, EventArgs e) - { - - } - private void lvDiscs_SelectedIndexChanged(object sender, EventArgs e) { //not a valid way to fight unselection, it results in craptons of ping-ponging logic and eventual malfunction diff --git a/BizHawk.Client.EmuHawk/tools/VirtualPads/controls/VirtualPadTargetScreen.cs b/BizHawk.Client.EmuHawk/tools/VirtualPads/controls/VirtualPadTargetScreen.cs index 0710804b03..0ec7705863 100644 --- a/BizHawk.Client.EmuHawk/tools/VirtualPads/controls/VirtualPadTargetScreen.cs +++ b/BizHawk.Client.EmuHawk/tools/VirtualPads/controls/VirtualPadTargetScreen.cs @@ -76,10 +76,7 @@ namespace BizHawk.Client.EmuHawk public bool ReadOnly { - get - { - return _readonly; - } + get => _readonly; set { @@ -106,14 +103,11 @@ namespace BizHawk.Client.EmuHawk #endregion // Size of the extra controls to the right / bottom of the target panel at 96 DPI - private Size PaddingSize - { - get { return new Size(0, 30); } - } + private Size PaddingSize => new Size(0, 30); public Size TargetSize { - get { return TargetPanel.Size; } + get => TargetPanel.Size; set { TargetPanel.Size = value; @@ -171,11 +165,7 @@ namespace BizHawk.Client.EmuHawk public int X { - get - { - return _overrideX ?? (int)(Global.StickyXORAdapter.GetFloat(XName) / MultiplierX); - } - + get => _overrideX ?? (int)(Global.StickyXORAdapter.GetFloat(XName) / MultiplierX); set { if (value < 0) @@ -198,11 +188,7 @@ namespace BizHawk.Client.EmuHawk } public int Y { - get - { - return _overrideY ?? (int)(Global.StickyXORAdapter.GetFloat(YName) / MultiplierY); - } - + get => _overrideY ?? (int)(Global.StickyXORAdapter.GetFloat(YName) / MultiplierY); set { if (value < 0) diff --git a/BizHawk.Client.EmuHawk/tools/VirtualPads/controls/components/AnalogStickPanel.cs b/BizHawk.Client.EmuHawk/tools/VirtualPads/controls/components/AnalogStickPanel.cs index e85d267ea9..acb6c08f37 100644 --- a/BizHawk.Client.EmuHawk/tools/VirtualPads/controls/components/AnalogStickPanel.cs +++ b/BizHawk.Client.EmuHawk/tools/VirtualPads/controls/components/AnalogStickPanel.cs @@ -16,10 +16,7 @@ namespace BizHawk.Client.EmuHawk public int X { - get - { - return _x; - } + get => _x; set { _x = RangeX.Constrain(value); @@ -29,10 +26,7 @@ namespace BizHawk.Client.EmuHawk public int Y { - get - { - return _y; - } + get => _y; set { _y = RangeY.Constrain(value); diff --git a/BizHawk.sln.DotSettings b/BizHawk.sln.DotSettings index 7e543eb96d..9583238608 100644 --- a/BizHawk.sln.DotSettings +++ b/BizHawk.sln.DotSettings @@ -230,7 +230,9 @@ True True True + True True + True True True True @@ -261,6 +263,7 @@ True True True + True True True True From 0247a8f1a80f2e0b1f0753c730293dbbc53b8fef Mon Sep 17 00:00:00 2001 From: feos Date: Tue, 29 Oct 2019 18:37:27 +0300 Subject: [PATCH 157/166] mame core wip (#1705) * add MAME to OpenAdvanced * make mame launch games limited to arcades that only need rom name. other devices require machine name and rom name, and won't run. nor they are meant to be supported anyway: we have enough emulators that do the job better for particular devices. dunno if direct disk access will be avoidable, there are quite some files it might want to load other than the rom (parent rom, bios, artwork). trapping all of these might be a future task. it is also known that mame can load "romname.zip" file just as well as "romname" folder, which would represent an unarchived zip. I make use of it to send it zip name with extension. it's easy, and we're not obliged to recognize mere folder paths in the mame-advanced-loader logic. * ability to run lua code inside mame --- ...izHawkSystemIdToCoreSystemEnumConverter.cs | 3 + BizHawk.Client.Common/Api/CoreSystem.cs | 5 +- BizHawk.Client.Common/OpenAdvanced.cs | 56 +- BizHawk.Client.Common/RomLoader.cs | 17 +- BizHawk.Client.Common/SystemInfo.cs | 5 + .../BizHawk.Client.EmuHawk.csproj | 2 + .../Extensions/CoreExtensions.cs | 5 + BizHawk.Client.EmuHawk/MainForm.Events.cs | 14 +- BizHawk.Client.EmuHawk/MainForm.cs | 8 +- .../OpenAdvancedChooser.Designer.cs | 324 +++++++----- BizHawk.Client.EmuHawk/OpenAdvancedChooser.cs | 26 +- .../Properties/Resources.Designer.cs | 20 + .../Properties/Resources.resx | 6 + .../config/ControllerConfig.cs | 6 +- .../ControllerImages/ArcadeController.jpg | Bin 0 -> 118148 bytes BizHawk.Client.EmuHawk/images/mame.png | Bin 0 -> 745 bytes BizHawk.Emulation.Common/Database/Database.cs | 7 + BizHawk.Emulation.Common/Enums.cs | 12 + .../Arcades/MAME/LibMAME.cs | 76 +++ BizHawk.Emulation.Cores/Arcades/MAME/MAME.cs | 484 ++++++++++++++++++ .../BizHawk.Emulation.Cores.csproj | 2 + 21 files changed, 903 insertions(+), 175 deletions(-) create mode 100644 BizHawk.Client.EmuHawk/images/ControllerImages/ArcadeController.jpg create mode 100644 BizHawk.Client.EmuHawk/images/mame.png create mode 100644 BizHawk.Emulation.Cores/Arcades/MAME/LibMAME.cs create mode 100644 BizHawk.Emulation.Cores/Arcades/MAME/MAME.cs diff --git a/BizHawk.Client.ApiHawk/Classes/BizHawkSystemIdToCoreSystemEnumConverter.cs b/BizHawk.Client.ApiHawk/Classes/BizHawkSystemIdToCoreSystemEnumConverter.cs index dca4452785..16da2eddb0 100644 --- a/BizHawk.Client.ApiHawk/Classes/BizHawkSystemIdToCoreSystemEnumConverter.cs +++ b/BizHawk.Client.ApiHawk/Classes/BizHawkSystemIdToCoreSystemEnumConverter.cs @@ -117,6 +117,9 @@ namespace BizHawk.Client.ApiHawk case "GB4x": return CoreSystem.GB3x; + case "MAME": + return CoreSystem.MAME; + case "VB": case "NGP": case "DNGP": diff --git a/BizHawk.Client.Common/Api/CoreSystem.cs b/BizHawk.Client.Common/Api/CoreSystem.cs index ae86c41564..3fad8c8563 100644 --- a/BizHawk.Client.Common/Api/CoreSystem.cs +++ b/BizHawk.Client.Common/Api/CoreSystem.cs @@ -34,8 +34,9 @@ ZXSpectrum, AmstradCPC, GGL, - ChannelF, GB3x, - GB4x + GB4x, + ChannelF, + MAME } } diff --git a/BizHawk.Client.Common/OpenAdvanced.cs b/BizHawk.Client.Common/OpenAdvanced.cs index 251d49d89e..88fbee6689 100644 --- a/BizHawk.Client.Common/OpenAdvanced.cs +++ b/BizHawk.Client.Common/OpenAdvanced.cs @@ -36,6 +36,7 @@ namespace BizHawk.Client.Common public const string OpenRom = "OpenRom"; public const string Libretro = "Libretro"; public const string LibretroNoGame = "LibretroNoGame"; + public const string MAME = "MAME"; } @@ -55,12 +56,33 @@ namespace BizHawk.Client.Common string type = text.Substring(0, idx); string token = text.Substring(idx + 1); IOpenAdvanced ioa; - if (type == OpenAdvancedTypes.OpenRom) ioa = new OpenAdvanced_OpenRom(); - else if (type == OpenAdvancedTypes.Libretro) ioa = new OpenAdvanced_Libretro(); - else if (type == OpenAdvancedTypes.LibretroNoGame) ioa = new OpenAdvanced_LibretroNoGame(); - else ioa = null; - if (ioa == null) - throw new InvalidOperationException($"{nameof(IOpenAdvanced)} deserialization error"); + + if (type == OpenAdvancedTypes.OpenRom) + { + ioa = new OpenAdvanced_OpenRom(); + } + else if (type == OpenAdvancedTypes.Libretro) + { + ioa = new OpenAdvanced_Libretro(); + } + else if (type == OpenAdvancedTypes.LibretroNoGame) + { + ioa = new OpenAdvanced_LibretroNoGame(); + } + else if (type == OpenAdvancedTypes.MAME) + { + ioa = new OpenAdvanced_MAME(); + } + else + { + ioa = null; + } + + if (ioa == null) + { + throw new InvalidOperationException($"{nameof(IOpenAdvanced)} deserialization error"); + } + ioa.Deserialize(token); return ioa; } @@ -161,4 +183,26 @@ namespace BizHawk.Client.Common tw.Write(Path); } } + + public class OpenAdvanced_MAME : IOpenAdvanced + { + public OpenAdvanced_MAME() + { } + + public string Path; + + public string TypeName { get { return "MAME"; } } + public string DisplayName { get { return Path; } } + public string SimplePath { get { return Path; } } + + public void Deserialize(string str) + { + Path = str; + } + + public void Serialize(TextWriter tw) + { + tw.Write(Path); + } + } } \ No newline at end of file diff --git a/BizHawk.Client.Common/RomLoader.cs b/BizHawk.Client.Common/RomLoader.cs index a8e820898f..58e417333a 100644 --- a/BizHawk.Client.Common/RomLoader.cs +++ b/BizHawk.Client.Common/RomLoader.cs @@ -24,6 +24,7 @@ using BizHawk.Emulation.Cores.Sega.Saturn; using BizHawk.Emulation.Cores.Sony.PSP; using BizHawk.Emulation.Cores.Sony.PSX; using BizHawk.Emulation.Cores.Computers.SinclairSpectrum; +using BizHawk.Emulation.Cores.Arcades.MAME; using BizHawk.Emulation.DiscSystem; using GPGX64 = BizHawk.Emulation.Cores.Consoles.Sega.gpgx; @@ -171,7 +172,7 @@ namespace BizHawk.Client.Common return false; } - public bool AsLibretro { get; set; } + public AdvancedRomLoaderType AdvancedLoader { get; set; } private bool HandleArchiveBinding(HawkFile file) { @@ -268,8 +269,13 @@ namespace BizHawk.Client.Common // only try mounting a file if a filename was given if (!string.IsNullOrEmpty(path)) { - // lets not use this unless we need to - // file.NonArchiveExtensions = romExtensions; + // MAME uses these extensions for arcade ROMs, but also accepts all sorts of variations of archives, folders, and files. if we let archive loader handle this, it won't know where to stop, since it'd require MAME's ROM database (which contains ROM names and blob hashes) to look things up, and even then it might be confused by archive/folder structure + // so assume the user provides the proper ROM directly, and handle possible errors later + if (AdvancedLoader == AdvancedRomLoaderType.MAMELaunchGame) + { + file.NonArchiveExtensions = new[] { ".zip", ".7z" }; + } + file.Open(path); // if the provided file doesnt even exist, give up! @@ -289,7 +295,7 @@ namespace BizHawk.Client.Common { string ext = null; - if (AsLibretro) + if (AdvancedLoader == AdvancedRomLoaderType.LibretroLaunchGame) { string codePathPart = Path.GetFileNameWithoutExtension(nextComm.LaunchLibretroCore); @@ -1152,6 +1158,9 @@ namespace BizHawk.Client.Common nextEmulator = new Octoshock(nextComm, null, null, rom.FileData, GetCoreSettings(), GetCoreSyncSettings()); nextEmulator.CoreComm.RomStatusDetails = "PSX etc."; break; + case "Arcade": + nextEmulator = new MAME(nextComm, file.Directory, file.CanonicalName); + break; case "GEN": if (Global.Config.CoreForcingViaGameDB && game.ForcedCore?.ToLower() == "pico") { diff --git a/BizHawk.Client.Common/SystemInfo.cs b/BizHawk.Client.Common/SystemInfo.cs index 29be9a4bc5..880074f08f 100644 --- a/BizHawk.Client.Common/SystemInfo.cs +++ b/BizHawk.Client.Common/SystemInfo.cs @@ -223,6 +223,11 @@ namespace BizHawk.Client.Common /// public static SystemInfo ChannelF { get; } = new SystemInfo("Channel F", CoreSystem.ChannelF, 2); + /// + /// Gets the instance for MAME + /// + public static SystemInfo MAME { get; } = new SystemInfo("MAME", CoreSystem.MAME, 4); + #endregion Get SystemInfo /// diff --git a/BizHawk.Client.EmuHawk/BizHawk.Client.EmuHawk.csproj b/BizHawk.Client.EmuHawk/BizHawk.Client.EmuHawk.csproj index fbfcb642fe..f1ead2c24e 100644 --- a/BizHawk.Client.EmuHawk/BizHawk.Client.EmuHawk.csproj +++ b/BizHawk.Client.EmuHawk/BizHawk.Client.EmuHawk.csproj @@ -1896,6 +1896,7 @@ + @@ -2225,6 +2226,7 @@ + diff --git a/BizHawk.Client.EmuHawk/Extensions/CoreExtensions.cs b/BizHawk.Client.EmuHawk/Extensions/CoreExtensions.cs index 613d465979..07590da894 100644 --- a/BizHawk.Client.EmuHawk/Extensions/CoreExtensions.cs +++ b/BizHawk.Client.EmuHawk/Extensions/CoreExtensions.cs @@ -11,6 +11,7 @@ using BizHawk.Emulation.Cores.Nintendo.SNES9X; using BizHawk.Emulation.Cores.Sega.Saturn; using BizHawk.Emulation.Cores.Consoles.Sega.gpgx; using BizHawk.Emulation.Cores.Sony.PSP; +using BizHawk.Emulation.Cores.Arcades.MAME; using BizHawk.Client.Common; @@ -51,6 +52,10 @@ namespace BizHawk.Client.EmuHawk.CoreExtensions { return Properties.Resources.snes9x; } + else if (core is MAME) + { + return Properties.Resources.mame; + } else { return null; diff --git a/BizHawk.Client.EmuHawk/MainForm.Events.cs b/BizHawk.Client.EmuHawk/MainForm.Events.cs index 6d35453072..fb13ec3eeb 100644 --- a/BizHawk.Client.EmuHawk/MainForm.Events.cs +++ b/BizHawk.Client.EmuHawk/MainForm.Events.cs @@ -306,6 +306,7 @@ namespace BizHawk.Client.EmuHawk private void OpenRomMenuItem_Click(object sender, EventArgs e) { + AdvancedLoader = AdvancedRomLoaderType.None; OpenRom(); } @@ -317,7 +318,9 @@ namespace BizHawk.Client.EmuHawk return; } - if (oac.Result == OpenAdvancedChooser.Command.RetroLaunchNoGame) + AdvancedLoader = oac.Result; + + if (AdvancedLoader == AdvancedRomLoaderType.LibretroLaunchNoGame) { var argsNoGame = new LoadRomArgs { @@ -331,15 +334,20 @@ namespace BizHawk.Client.EmuHawk var filter = RomFilter; - if (oac.Result == OpenAdvancedChooser.Command.RetroLaunchGame) + if (AdvancedLoader == AdvancedRomLoaderType.LibretroLaunchGame) { args.OpenAdvanced = new OpenAdvanced_Libretro(); filter = oac.SuggestedExtensionFilter; } - else if (oac.Result == OpenAdvancedChooser.Command.ClassicLaunchGame) + else if (AdvancedLoader == AdvancedRomLoaderType.ClassicLaunchGame) { args.OpenAdvanced = new OpenAdvanced_OpenRom(); } + else if (AdvancedLoader == AdvancedRomLoaderType.MAMELaunchGame) + { + args.OpenAdvanced = new OpenAdvanced_MAME(); + filter = "MAME Arcade ROMs (*.zip)|*.zip"; + } else { throw new InvalidOperationException("Automatic Alpha Sanitizer"); diff --git a/BizHawk.Client.EmuHawk/MainForm.cs b/BizHawk.Client.EmuHawk/MainForm.cs index 94e6eeb07f..1661e2eca6 100644 --- a/BizHawk.Client.EmuHawk/MainForm.cs +++ b/BizHawk.Client.EmuHawk/MainForm.cs @@ -588,6 +588,8 @@ namespace BizHawk.Client.EmuHawk // runloop won't exec lua public bool SuppressLua { get; set; } + public AdvancedRomLoaderType AdvancedLoader { get; set; } + public long MouseWheelTracker { get; private set; } private int? _pauseOnFrame; @@ -610,9 +612,7 @@ namespace BizHawk.Client.EmuHawk } public bool IsSeeking => PauseOnFrame.HasValue; - private bool IsTurboSeeking => PauseOnFrame.HasValue && Global.Config.TurboSeek; - public bool IsTurboing => Global.ClientControls["Turbo"] || IsTurboSeeking; #endregion @@ -3488,15 +3488,13 @@ namespace BizHawk.Client.EmuHawk return false; } - bool asLibretro = args.OpenAdvanced is OpenAdvanced_Libretro || args.OpenAdvanced is OpenAdvanced_LibretroNoGame; - var loader = new RomLoader { ChooseArchive = LoadArchiveChooser, ChoosePlatform = ChoosePlatformForRom, Deterministic = deterministic, MessageCallback = GlobalWin.OSD.AddMessage, - AsLibretro = asLibretro + AdvancedLoader = AdvancedLoader }; Global.FirmwareManager.RecentlyServed.Clear(); diff --git a/BizHawk.Client.EmuHawk/OpenAdvancedChooser.Designer.cs b/BizHawk.Client.EmuHawk/OpenAdvancedChooser.Designer.cs index af6c2fcc75..360c49fcd4 100644 --- a/BizHawk.Client.EmuHawk/OpenAdvancedChooser.Designer.cs +++ b/BizHawk.Client.EmuHawk/OpenAdvancedChooser.Designer.cs @@ -28,147 +28,184 @@ /// private void InitializeComponent() { - this.label3 = new System.Windows.Forms.Label(); - this.label2 = new System.Windows.Forms.Label(); - this.btnLibretroLaunchNoGame = new System.Windows.Forms.Button(); - this.btnCancel = new System.Windows.Forms.Button(); - this.groupBox2 = new System.Windows.Forms.GroupBox(); - this.txtLibretroCore = new System.Windows.Forms.TextBox(); - this.btnLibretroLaunchGame = new System.Windows.Forms.Button(); - this.btnSetLibretroCore = new System.Windows.Forms.Button(); - this.groupBox3 = new System.Windows.Forms.GroupBox(); - this.btnClassicLaunchGame = new System.Windows.Forms.Button(); - this.groupBox2.SuspendLayout(); - this.groupBox3.SuspendLayout(); - this.SuspendLayout(); - // - // label3 - // - this.label3.Location = new System.Drawing.Point(6, 25); - this.label3.Name = "label3"; - this.label3.Size = new System.Drawing.Size(250, 29); - this.label3.TabIndex = 5; - this.label3.Text = "Load a rom with the classic BizHawk autodetection method. But why not just use Op" + - "en Rom?"; - // - // label2 - // - this.label2.AutoSize = true; - this.label2.Location = new System.Drawing.Point(6, 26); - this.label2.Name = "label2"; - this.label2.Size = new System.Drawing.Size(69, 13); - this.label2.TabIndex = 3; - this.label2.Text = "Current Core:"; - // - // btnLibretroLaunchNoGame - // - this.btnLibretroLaunchNoGame.Location = new System.Drawing.Point(217, 50); - this.btnLibretroLaunchNoGame.Name = "btnLibretroLaunchNoGame"; - this.btnLibretroLaunchNoGame.Size = new System.Drawing.Size(102, 23); - this.btnLibretroLaunchNoGame.TabIndex = 1; - this.btnLibretroLaunchNoGame.Text = "Launch No Game"; - this.btnLibretroLaunchNoGame.UseVisualStyleBackColor = true; - this.btnLibretroLaunchNoGame.Click += new System.EventHandler(this.btnLibretroLaunchNoGame_Click); - // - // btnCancel - // - this.btnCancel.DialogResult = System.Windows.Forms.DialogResult.Cancel; - this.btnCancel.Location = new System.Drawing.Point(370, 176); - this.btnCancel.Name = "btnCancel"; - this.btnCancel.Size = new System.Drawing.Size(75, 23); - this.btnCancel.TabIndex = 2; - this.btnCancel.Text = "Cancel"; - this.btnCancel.UseVisualStyleBackColor = true; - this.btnCancel.Click += new System.EventHandler(this.btnCancel_Click); - // - // groupBox2 - // - this.groupBox2.Controls.Add(this.txtLibretroCore); - this.groupBox2.Controls.Add(this.btnLibretroLaunchGame); - this.groupBox2.Controls.Add(this.btnSetLibretroCore); - this.groupBox2.Controls.Add(this.label2); - this.groupBox2.Controls.Add(this.btnLibretroLaunchNoGame); - this.groupBox2.Location = new System.Drawing.Point(12, 12); - this.groupBox2.Name = "groupBox2"; - this.groupBox2.Size = new System.Drawing.Size(433, 81); - this.groupBox2.TabIndex = 3; - this.groupBox2.TabStop = false; - this.groupBox2.Text = "Libretro"; - // - // txtLibretroCore - // - this.txtLibretroCore.AllowDrop = true; - this.txtLibretroCore.Location = new System.Drawing.Point(81, 23); - this.txtLibretroCore.Name = "txtLibretroCore"; - this.txtLibretroCore.ReadOnly = true; - this.txtLibretroCore.Size = new System.Drawing.Size(314, 20); - this.txtLibretroCore.TabIndex = 6; - this.txtLibretroCore.DragDrop += new System.Windows.Forms.DragEventHandler(this.txtLibretroCore_DragDrop); - this.txtLibretroCore.DragEnter += new System.Windows.Forms.DragEventHandler(this.txtLibretroCore_DragEnter); - // - // btnLibretroLaunchGame - // - this.btnLibretroLaunchGame.Location = new System.Drawing.Point(325, 50); - this.btnLibretroLaunchGame.Name = "btnLibretroLaunchGame"; - this.btnLibretroLaunchGame.Size = new System.Drawing.Size(102, 23); - this.btnLibretroLaunchGame.TabIndex = 5; - this.btnLibretroLaunchGame.Text = "Launch Game"; - this.btnLibretroLaunchGame.UseVisualStyleBackColor = true; - this.btnLibretroLaunchGame.Click += new System.EventHandler(this.btnLibretroLaunchGame_Click); - // - // btnSetLibretroCore - // - this.btnSetLibretroCore.AutoSize = true; - this.btnSetLibretroCore.AutoSizeMode = System.Windows.Forms.AutoSizeMode.GrowAndShrink; - this.btnSetLibretroCore.Location = new System.Drawing.Point(401, 21); - this.btnSetLibretroCore.Name = "btnSetLibretroCore"; - this.btnSetLibretroCore.Size = new System.Drawing.Size(26, 23); - this.btnSetLibretroCore.TabIndex = 4; - this.btnSetLibretroCore.Text = "..."; - this.btnSetLibretroCore.UseVisualStyleBackColor = true; - this.btnSetLibretroCore.Click += new System.EventHandler(this.btnSetLibretroCore_Click); - // - // groupBox3 - // - this.groupBox3.Controls.Add(this.btnClassicLaunchGame); - this.groupBox3.Controls.Add(this.label3); - this.groupBox3.Location = new System.Drawing.Point(12, 99); - this.groupBox3.Name = "groupBox3"; - this.groupBox3.Size = new System.Drawing.Size(277, 100); - this.groupBox3.TabIndex = 6; - this.groupBox3.TabStop = false; - this.groupBox3.Text = "BizHawk Classic"; - // - // btnClassicLaunchGame - // - this.btnClassicLaunchGame.Location = new System.Drawing.Point(169, 71); - this.btnClassicLaunchGame.Name = "btnClassicLaunchGame"; - this.btnClassicLaunchGame.Size = new System.Drawing.Size(102, 23); - this.btnClassicLaunchGame.TabIndex = 6; - this.btnClassicLaunchGame.Text = "Launch Game"; - this.btnClassicLaunchGame.UseVisualStyleBackColor = true; - this.btnClassicLaunchGame.Click += new System.EventHandler(this.btnClassicLaunchGame_Click); - // - // OpenAdvancedChooser - // - this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); - this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; - this.CancelButton = this.btnCancel; - this.ClientSize = new System.Drawing.Size(457, 208); - this.Controls.Add(this.groupBox3); - this.Controls.Add(this.groupBox2); - this.Controls.Add(this.btnCancel); - this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedDialog; - this.MaximizeBox = false; - this.MinimizeBox = false; - this.Name = "OpenAdvancedChooser"; - this.StartPosition = System.Windows.Forms.FormStartPosition.CenterParent; - this.Text = "Open Advanced"; - this.groupBox2.ResumeLayout(false); - this.groupBox2.PerformLayout(); - this.groupBox3.ResumeLayout(false); - this.ResumeLayout(false); - + this.label3 = new System.Windows.Forms.Label(); + this.label2 = new System.Windows.Forms.Label(); + this.btnLibretroLaunchNoGame = new System.Windows.Forms.Button(); + this.btnCancel = new System.Windows.Forms.Button(); + this.groupBox2 = new System.Windows.Forms.GroupBox(); + this.txtLibretroCore = new System.Windows.Forms.TextBox(); + this.btnLibretroLaunchGame = new System.Windows.Forms.Button(); + this.btnSetLibretroCore = new System.Windows.Forms.Button(); + this.groupBox3 = new System.Windows.Forms.GroupBox(); + this.btnClassicLaunchGame = new System.Windows.Forms.Button(); + this.groupBox1 = new System.Windows.Forms.GroupBox(); + this.label1 = new System.Windows.Forms.Label(); + this.btnMAMELaunchGame = new System.Windows.Forms.Button(); + this.groupBox2.SuspendLayout(); + this.groupBox3.SuspendLayout(); + this.groupBox1.SuspendLayout(); + this.SuspendLayout(); + // + // label3 + // + this.label3.Location = new System.Drawing.Point(6, 25); + this.label3.Name = "label3"; + this.label3.Size = new System.Drawing.Size(198, 45); + this.label3.TabIndex = 5; + this.label3.Text = "Load a ROM with the classic BizHawk autodetection method. But why not just use Op" + + "en Rom?"; + // + // label2 + // + this.label2.AutoSize = true; + this.label2.Location = new System.Drawing.Point(6, 26); + this.label2.Name = "label2"; + this.label2.Size = new System.Drawing.Size(69, 13); + this.label2.TabIndex = 3; + this.label2.Text = "Current Core:"; + // + // btnLibretroLaunchNoGame + // + this.btnLibretroLaunchNoGame.Location = new System.Drawing.Point(217, 50); + this.btnLibretroLaunchNoGame.Name = "btnLibretroLaunchNoGame"; + this.btnLibretroLaunchNoGame.Size = new System.Drawing.Size(102, 23); + this.btnLibretroLaunchNoGame.TabIndex = 1; + this.btnLibretroLaunchNoGame.Text = "Launch No Game"; + this.btnLibretroLaunchNoGame.UseVisualStyleBackColor = true; + this.btnLibretroLaunchNoGame.Click += new System.EventHandler(this.btnLibretroLaunchNoGame_Click); + // + // btnCancel + // + this.btnCancel.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right))); + this.btnCancel.DialogResult = System.Windows.Forms.DialogResult.Cancel; + this.btnCancel.Location = new System.Drawing.Point(370, 221); + this.btnCancel.Name = "btnCancel"; + this.btnCancel.Size = new System.Drawing.Size(75, 23); + this.btnCancel.TabIndex = 2; + this.btnCancel.Text = "Cancel"; + this.btnCancel.UseVisualStyleBackColor = true; + this.btnCancel.Click += new System.EventHandler(this.btnCancel_Click); + // + // groupBox2 + // + this.groupBox2.Controls.Add(this.txtLibretroCore); + this.groupBox2.Controls.Add(this.btnLibretroLaunchGame); + this.groupBox2.Controls.Add(this.btnSetLibretroCore); + this.groupBox2.Controls.Add(this.label2); + this.groupBox2.Controls.Add(this.btnLibretroLaunchNoGame); + this.groupBox2.Location = new System.Drawing.Point(12, 12); + this.groupBox2.Name = "groupBox2"; + this.groupBox2.Size = new System.Drawing.Size(433, 81); + this.groupBox2.TabIndex = 3; + this.groupBox2.TabStop = false; + this.groupBox2.Text = "Libretro"; + // + // txtLibretroCore + // + this.txtLibretroCore.AllowDrop = true; + this.txtLibretroCore.Location = new System.Drawing.Point(81, 23); + this.txtLibretroCore.Name = "txtLibretroCore"; + this.txtLibretroCore.ReadOnly = true; + this.txtLibretroCore.Size = new System.Drawing.Size(314, 20); + this.txtLibretroCore.TabIndex = 6; + this.txtLibretroCore.DragDrop += new System.Windows.Forms.DragEventHandler(this.txtLibretroCore_DragDrop); + this.txtLibretroCore.DragEnter += new System.Windows.Forms.DragEventHandler(this.txtLibretroCore_DragEnter); + // + // btnLibretroLaunchGame + // + this.btnLibretroLaunchGame.Location = new System.Drawing.Point(325, 50); + this.btnLibretroLaunchGame.Name = "btnLibretroLaunchGame"; + this.btnLibretroLaunchGame.Size = new System.Drawing.Size(102, 23); + this.btnLibretroLaunchGame.TabIndex = 5; + this.btnLibretroLaunchGame.Text = "Launch Game"; + this.btnLibretroLaunchGame.UseVisualStyleBackColor = true; + this.btnLibretroLaunchGame.Click += new System.EventHandler(this.btnLibretroLaunchGame_Click); + // + // btnSetLibretroCore + // + this.btnSetLibretroCore.AutoSize = true; + this.btnSetLibretroCore.AutoSizeMode = System.Windows.Forms.AutoSizeMode.GrowAndShrink; + this.btnSetLibretroCore.Location = new System.Drawing.Point(401, 21); + this.btnSetLibretroCore.Name = "btnSetLibretroCore"; + this.btnSetLibretroCore.Size = new System.Drawing.Size(26, 23); + this.btnSetLibretroCore.TabIndex = 4; + this.btnSetLibretroCore.Text = "..."; + this.btnSetLibretroCore.UseVisualStyleBackColor = true; + this.btnSetLibretroCore.Click += new System.EventHandler(this.btnSetLibretroCore_Click); + // + // groupBox3 + // + this.groupBox3.Controls.Add(this.btnClassicLaunchGame); + this.groupBox3.Controls.Add(this.label3); + this.groupBox3.Location = new System.Drawing.Point(235, 99); + this.groupBox3.Name = "groupBox3"; + this.groupBox3.Size = new System.Drawing.Size(210, 100); + this.groupBox3.TabIndex = 6; + this.groupBox3.TabStop = false; + this.groupBox3.Text = "BizHawk Classic"; + // + // btnClassicLaunchGame + // + this.btnClassicLaunchGame.Location = new System.Drawing.Point(102, 71); + this.btnClassicLaunchGame.Name = "btnClassicLaunchGame"; + this.btnClassicLaunchGame.Size = new System.Drawing.Size(102, 23); + this.btnClassicLaunchGame.TabIndex = 6; + this.btnClassicLaunchGame.Text = "Launch Game"; + this.btnClassicLaunchGame.UseVisualStyleBackColor = true; + this.btnClassicLaunchGame.Click += new System.EventHandler(this.btnClassicLaunchGame_Click); + // + // groupBox1 + // + this.groupBox1.Controls.Add(this.label1); + this.groupBox1.Controls.Add(this.btnMAMELaunchGame); + this.groupBox1.Location = new System.Drawing.Point(13, 99); + this.groupBox1.Name = "groupBox1"; + this.groupBox1.Size = new System.Drawing.Size(216, 100); + this.groupBox1.TabIndex = 7; + this.groupBox1.TabStop = false; + this.groupBox1.Text = "MAME Arcade"; + // + // label1 + // + this.label1.Location = new System.Drawing.Point(6, 25); + this.label1.Name = "label1"; + this.label1.Size = new System.Drawing.Size(204, 42); + this.label1.TabIndex = 1; + this.label1.Text = "Load .zip archive as MAME Arcade ROM (do not unzip)"; + this.label1.Click += new System.EventHandler(this.btnMAMELaunchGame_Click); + // + // btnMAMELaunchGame + // + this.btnMAMELaunchGame.Location = new System.Drawing.Point(108, 71); + this.btnMAMELaunchGame.Name = "btnMAMELaunchGame"; + this.btnMAMELaunchGame.Size = new System.Drawing.Size(102, 23); + this.btnMAMELaunchGame.TabIndex = 0; + this.btnMAMELaunchGame.Text = "Launch Game"; + this.btnMAMELaunchGame.UseVisualStyleBackColor = true; + this.btnMAMELaunchGame.Click += new System.EventHandler(this.btnMAMELaunchGame_Click); + // + // OpenAdvancedChooser + // + this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); + this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; + this.CancelButton = this.btnCancel; + this.ClientSize = new System.Drawing.Size(457, 256); + this.Controls.Add(this.groupBox1); + this.Controls.Add(this.groupBox3); + this.Controls.Add(this.groupBox2); + this.Controls.Add(this.btnCancel); + this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedDialog; + this.MaximizeBox = false; + this.MinimizeBox = false; + this.Name = "OpenAdvancedChooser"; + this.StartPosition = System.Windows.Forms.FormStartPosition.CenterParent; + this.Text = "Open Advanced"; + this.groupBox2.ResumeLayout(false); + this.groupBox2.PerformLayout(); + this.groupBox3.ResumeLayout(false); + this.groupBox1.ResumeLayout(false); + this.ResumeLayout(false); + } #endregion @@ -182,6 +219,9 @@ private System.Windows.Forms.TextBox txtLibretroCore; private System.Windows.Forms.Button btnLibretroLaunchGame; private System.Windows.Forms.GroupBox groupBox3; - private System.Windows.Forms.Button btnClassicLaunchGame; + private System.Windows.Forms.Button btnClassicLaunchGame; + private System.Windows.Forms.GroupBox groupBox1; + private System.Windows.Forms.Label label1; + private System.Windows.Forms.Button btnMAMELaunchGame; } } \ No newline at end of file diff --git a/BizHawk.Client.EmuHawk/OpenAdvancedChooser.cs b/BizHawk.Client.EmuHawk/OpenAdvancedChooser.cs index 8eff5a7e6e..f68d411837 100644 --- a/BizHawk.Client.EmuHawk/OpenAdvancedChooser.cs +++ b/BizHawk.Client.EmuHawk/OpenAdvancedChooser.cs @@ -7,7 +7,8 @@ using System.Drawing; using System.Linq; using System.Text; using System.Windows.Forms; - + +using BizHawk.Emulation.Common; using BizHawk.Emulation.Cores; using BizHawk.Emulation.Cores.Libretro; using BizHawk.Client.Common; @@ -20,13 +21,7 @@ namespace BizHawk.Client.EmuHawk { MainForm mainForm; - public enum Command - { - RetroLaunchNoGame, RetroLaunchGame, - ClassicLaunchGame - } - - public Command Result; + public AdvancedRomLoaderType Result; public string SuggestedExtensionFilter; public OpenAdvancedChooser(MainForm mainForm) @@ -131,21 +126,28 @@ namespace BizHawk.Client.EmuHawk filter = MainForm.FormatFilter(args.ToArray()); SuggestedExtensionFilter = filter; - Result = Command.RetroLaunchGame; + Result = AdvancedRomLoaderType.LibretroLaunchGame; DialogResult = DialogResult.OK; Close(); + } + + private void btnMAMELaunchGame_Click(object sender, EventArgs e) + { + Result = AdvancedRomLoaderType.MAMELaunchGame; + DialogResult = DialogResult.OK; + Close(); } private void btnClassicLaunchGame_Click(object sender, EventArgs e) { - Result = Command.ClassicLaunchGame; + Result = AdvancedRomLoaderType.ClassicLaunchGame; DialogResult = DialogResult.OK; Close(); } private void btnLibretroLaunchNoGame_Click(object sender, EventArgs e) { - Result = Command.RetroLaunchNoGame; + Result = AdvancedRomLoaderType.LibretroLaunchNoGame; DialogResult = DialogResult.OK; Close(); } @@ -170,6 +172,6 @@ namespace BizHawk.Client.EmuHawk var filePaths = (string[])e.Data.GetData(DataFormats.FileDrop); Global.Config.LibretroCore = filePaths[0]; RefreshLibretroCore(false); - } + } } } diff --git a/BizHawk.Client.EmuHawk/Properties/Resources.Designer.cs b/BizHawk.Client.EmuHawk/Properties/Resources.Designer.cs index 022c725cc6..0ca90c2902 100644 --- a/BizHawk.Client.EmuHawk/Properties/Resources.Designer.cs +++ b/BizHawk.Client.EmuHawk/Properties/Resources.Designer.cs @@ -120,6 +120,16 @@ namespace BizHawk.Client.EmuHawk.Properties { } } + /// + /// Looks up a localized resource of type System.Drawing.Bitmap. + /// + internal static System.Drawing.Bitmap ArcadeController { + get { + object obj = ResourceManager.GetObject("ArcadeController", resourceCulture); + return ((System.Drawing.Bitmap)(obj)); + } + } + /// /// Looks up a localized resource of type System.Drawing.Bitmap. /// @@ -870,6 +880,16 @@ namespace BizHawk.Client.EmuHawk.Properties { } } + /// + /// Looks up a localized resource of type System.Drawing.Bitmap. + /// + internal static System.Drawing.Bitmap mame { + get { + object obj = ResourceManager.GetObject("mame", resourceCulture); + return ((System.Drawing.Bitmap)(obj)); + } + } + /// /// Looks up a localized resource of type System.Drawing.Bitmap. /// diff --git a/BizHawk.Client.EmuHawk/Properties/Resources.resx b/BizHawk.Client.EmuHawk/Properties/Resources.resx index 610b6c155b..ac426a1592 100644 --- a/BizHawk.Client.EmuHawk/Properties/Resources.resx +++ b/BizHawk.Client.EmuHawk/Properties/Resources.resx @@ -1566,4 +1566,10 @@ ..\images\StopButton.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + ..\images\ControllerImages\ArcadeController.jpg;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + + ..\images\mame.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + \ No newline at end of file diff --git a/BizHawk.Client.EmuHawk/config/ControllerConfig.cs b/BizHawk.Client.EmuHawk/config/ControllerConfig.cs index b930b136be..01408593e5 100644 --- a/BizHawk.Client.EmuHawk/config/ControllerConfig.cs +++ b/BizHawk.Client.EmuHawk/config/ControllerConfig.cs @@ -49,6 +49,7 @@ namespace BizHawk.Client.EmuHawk ControllerImages.Add("Apple IIe Keyboard", Properties.Resources.AppleIIKeyboard); ControllerImages.Add("VirtualBoy Controller", Properties.Resources.VBoyController); ControllerImages.Add("NeoGeo Portable Controller", Properties.Resources.NGPController); + ControllerImages.Add("MAME Controller", Properties.Resources.ArcadeController); } private ControllerConfig() @@ -192,7 +193,10 @@ namespace BizHawk.Client.EmuHawk if (Global.Emulator.SystemId == "ZXSpectrum" || Global.Emulator.SystemId == "AmstradCPC" || Global.Emulator.SystemId == "ChannelF") return; - string tabname = (Global.Emulator.SystemId == "C64") ? "Keyboard" : "Console"; // hack + string tabname = + (Global.Emulator.SystemId == "C64") ? "Keyboard" : + (Global.Emulator.SystemId == "MAME") ? "Misc" : + "Console"; // hack tt.TabPages.Add(tabname); tt.TabPages[pageidx].Controls.Add(createpanel(settings, buckets[0], tt.Size)); } diff --git a/BizHawk.Client.EmuHawk/images/ControllerImages/ArcadeController.jpg b/BizHawk.Client.EmuHawk/images/ControllerImages/ArcadeController.jpg new file mode 100644 index 0000000000000000000000000000000000000000..d243bc8471559cf18e0e874dc887654fc2bc347d GIT binary patch literal 118148 zcmeEvbyyW!+xGw}(jZ7kN+aEDB&0(^xY*|SeNdN&60f7mD2>{L} zh>#^*EldGGULLpu0Kjzs8Q}(i1hx>se*nTQ;Oa#i0E`fb|7=?#(Erpy1a;T}kOCy& z?ufu~(Z&PY!G0FNm7linz~eW7x#2Sa&|&{^6fvJy%w{xL4>Xajxcir{t) z0qJLq*M1!b0@+{VK%o6~9Eb>i_&{Jm{L?o<=MQ&)G@$FK9Z(0}AR$l!h&TvHI0$E> z;IL88>JWs%D6b-1Y+%6W8xoi(SFT<|zK(*52ByQ`g$Mv5(jP)>0O1M(65k}KsFmC*} zg+8?65vnEuUy20eC;atMF_XqZ(IQ*aG=D!%JC!&?>vGU<<50Z zYNH9qr{Q8MH;rLj8#LF>13;$b{?Y{okwRc1p~m9`o%}O||9b>*aWjuiL39@JOElSEf!hT~0k%ByRC1sdFCk5O3=ACWPtOpl>Gy_I-TXwKA4sEi7df zeTt>H(o6ouhU?C zn=Cf=MBrPVHS(^`ok!>+k{m79B(x@0Zu%ZZ^IGXUR~lRGIG3LRV!dD(_1+A5?G3G- z@Izz9?GJs<5mmR2v_~uTjBSQG6g?OVTnDVgv3bHq%)PIA5ajKA6e%UnFzKmDtFa0Y zUMY=X7fHI3c2ydcx4?kR5>Z$8%Kf7evE_+?MLyTkxJ^&~jC{s!her5hD~#qdq<+;( zZ;2VJ~SZnhjWS$+Q}2&1WXr5c2>`BKy;= z%0A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 XTNj7kzEU3lcb@o7>R8)`UD + /// The Advanced ROM Loader type in MainForm/RomLoader/OpenAdvancedChooser + /// + public enum AdvancedRomLoaderType + { + None, + LibretroLaunchNoGame, + LibretroLaunchGame, + ClassicLaunchGame, + MAMELaunchGame + } } diff --git a/BizHawk.Emulation.Cores/Arcades/MAME/LibMAME.cs b/BizHawk.Emulation.Cores/Arcades/MAME/LibMAME.cs new file mode 100644 index 0000000000..476ddf78ef --- /dev/null +++ b/BizHawk.Emulation.Cores/Arcades/MAME/LibMAME.cs @@ -0,0 +1,76 @@ +using System; +using System.Runtime.InteropServices; + +namespace BizHawk.Emulation.Cores.Arcades.MAME +{ + public static class LibMAME + { + const string dll = "libmamearcade64.dll"; // libmamearcade64.dll libpacmansh64d.dll + const CallingConvention cc = CallingConvention.Cdecl; + + public enum OutputChannel + { + ERROR, WARNING, INFO, DEBUG, VERBOSE, LOG, COUNT + }; + + // main launcher + [DllImport(dll, CallingConvention = cc)] + public static extern UInt32 mame_launch(int argc, string[] argv); + + #region Lua API + + // execute + [DllImport(dll, CallingConvention = cc)] + public static extern void mame_lua_execute(string code); + + // get int + [DllImport(dll, CallingConvention = cc)] + public static extern int mame_lua_get_int(string code); + + // get double + [DllImport(dll, CallingConvention = cc)] + public static extern double mame_lua_get_double(string code); + + // get bool + [DllImport(dll, CallingConvention = cc)] + public static extern bool mame_lua_get_bool(string code); + + // get string + [DllImport(dll, CallingConvention = cc)] + public static extern IntPtr mame_lua_get_string(string code, out int length); + + // free string + [DllImport(dll, CallingConvention = cc)] + public static extern bool mame_lua_free_string(IntPtr pointer); + + #endregion + + #region Callbacks + + // periodic + [UnmanagedFunctionPointer(CallingConvention.Cdecl)] + public delegate void PeriodicCallbackDelegate(); + [DllImport(dll, CallingConvention = cc)] + public static extern void mame_set_periodic_callback(PeriodicCallbackDelegate cb); + + // sound + [UnmanagedFunctionPointer(CallingConvention.Cdecl)] + public delegate void SoundCallbackDelegate(); + [DllImport(dll, CallingConvention = cc)] + public static extern void mame_set_sound_callback(SoundCallbackDelegate cb); + + // boot + [UnmanagedFunctionPointer(CallingConvention.Cdecl)] + public delegate void BootCallbackDelegate(); + [DllImport(dll, CallingConvention = cc)] + public static extern void mame_set_boot_callback(BootCallbackDelegate cb); + + // log + [UnmanagedFunctionPointer(CallingConvention.Cdecl)] + public delegate void LogCallbackDelegate(OutputChannel channel, int size, string data); + [DllImport(dll, CallingConvention = cc)] + public static extern void mame_set_log_callback(LogCallbackDelegate cb); + + #endregion + } +} diff --git a/BizHawk.Emulation.Cores/Arcades/MAME/MAME.cs b/BizHawk.Emulation.Cores/Arcades/MAME/MAME.cs new file mode 100644 index 0000000000..5776c9f879 --- /dev/null +++ b/BizHawk.Emulation.Cores/Arcades/MAME/MAME.cs @@ -0,0 +1,484 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Runtime.InteropServices; +using System.Threading; +using System.Diagnostics; + +using BizHawk.Emulation.Common; +using BizHawk.Emulation.Common.IEmulatorExtensions; + +namespace BizHawk.Emulation.Cores.Arcades.MAME +{ + [Core( + name: "MAME", + author: "MAMEDev", + isPorted: true, + portedVersion: "0.214", + portedUrl: "https://github.com/mamedev/mame.git", + singleInstance: false)] + public partial class MAME : IEmulator, IVideoProvider, ISoundProvider + { + public MAME(CoreComm comm, string dir, string file) + { + ServiceProvider = new BasicServiceProvider(this); + + CoreComm = comm; + gameDirectory = dir; + gameFilename = file; + MAMEThread = new Thread(ExecuteMAMEThread); + + AsyncLaunchMAME(); + } + + #region Properties + + public CoreComm CoreComm { get; private set; } + public IEmulatorServiceProvider ServiceProvider { get; private set; } + public ControllerDefinition ControllerDefinition => MAMEController; + public string SystemId => "MAME"; + public int[] GetVideoBuffer() => frameBuffer; + public bool DeterministicEmulation => true; + public bool CanProvideAsync => false; + public SyncSoundMode SyncMode => SyncSoundMode.Sync; + public int BackgroundColor => 0; + public int Frame { get; private set; } + public int VirtualWidth { get; private set; } = 320; + public int VirtualHeight { get; private set; } = 240; + public int BufferWidth { get; private set; } = 320; + public int BufferHeight { get; private set; } = 240; + public int VsyncNumerator { get; private set; } = 60; + public int VsyncDenominator { get; private set; } = 1; + private int samplesPerFrame => (int)Math.Round(sampleRate / this.VsyncRate()); + + #endregion + + #region Fields + + private Thread MAMEThread; + private ManualResetEvent MAMEStartupComplete = new ManualResetEvent(false); + private ManualResetEvent MAMEFrameComplete = new ManualResetEvent(false); + private SortedDictionary fieldsPorts = new SortedDictionary(); + private IController Controller = NullController.Instance; + private int[] frameBuffer = new int[0]; + private short[] audioBuffer = new short[0]; + private Queue audioSamples = new Queue(); + private int sampleRate = 44100; + private bool paused = true; + private bool exiting = false; + private bool frameDone = true; + private int numSamples = 0; + private string gameDirectory; + private string gameFilename; + private LibMAME.PeriodicCallbackDelegate periodicCallback; + private LibMAME.SoundCallbackDelegate soundCallback; + private LibMAME.BootCallbackDelegate bootCallback; + private LibMAME.LogCallbackDelegate logCallback; + + #endregion + + #region IEmulator + + public bool FrameAdvance(IController controller, bool render, bool rendersound = true) + { + if (exiting) + { + return false; + } + + Controller = controller; + paused = false; + frameDone = false; + + for (; frameDone == false;) + { + MAMEFrameComplete.WaitOne(); + } + + Frame++; + + return true; + } + + public void ResetCounters() + { + Frame = 0; + } + + public void Dispose() + { + exiting = true; + MAMEThread.Join(); + } + + #endregion + + #region ISoundProvider + + public void SetSyncMode(SyncSoundMode mode) + { + if (mode == SyncSoundMode.Async) + { + throw new NotSupportedException("Async mode is not supported."); + } + } + + public void GetSamplesSync(out short[] samples, out int nsamp) + { + nsamp = samplesPerFrame; + samples = new short[samplesPerFrame * 2]; + + for (int i = 0; i < samplesPerFrame * 2; i++) + { + if (audioSamples.Any()) + { + samples[i] = audioSamples.Dequeue(); + } + else + { + samples[i] = 0; + } + } + } + + public void GetSamplesAsync(short[] samples) + { + throw new InvalidOperationException("Async mode is not supported."); + } + + public void DiscardSamples() + { + audioSamples.Clear(); + } + + #endregion + + #region Launchers + + private void AsyncLaunchMAME() + { + MAMEThread.Start(); + MAMEStartupComplete.WaitOne(); + } + + private void ExecuteMAMEThread() + { + // dodge GC + periodicCallback = MAMEPeriodicCallback; + soundCallback = MAMESoundCallback; + bootCallback = MAMEBootCallback; + logCallback = MAMELogCallback; + + LibMAME.mame_set_periodic_callback(periodicCallback); + LibMAME.mame_set_sound_callback(soundCallback); + LibMAME.mame_set_boot_callback(bootCallback); + LibMAME.mame_set_log_callback(logCallback); + + // https://docs.mamedev.org/commandline/commandline-index.html + string[] args = new string[] { + "mame" // dummy, internally discarded by index, so has to go first + , gameFilename // no dash for rom names + , "-noreadconfig" // forbid reading any config files + , "-norewind" // forbid rewind savestates (captured upon frame advance) + , "-skip_gameinfo" // forbid this blocking screen that requires user input + , "-nothrottle" // forbid throttling to "real" speed of the device + , "-update_in_pause" // ^ including frame-advancing + , "-rompath", gameDirectory // mame doesn't load roms from full paths, only from dirs to scan + , "-volume", "-32" // lowest attenuation means mame osd remains silent + , "-output", "console" // print everyting to hawk console + , "-samplerate", sampleRate.ToString() // match hawk samplerate + , "-video", "none" // forbid mame window altogether + , "-keyboardprovider", "none" + , "-mouseprovider", "none" + , "-lightgunprovider", "none" + , "-joystickprovider", "none" + }; + + LibMAME.mame_launch(args.Length, args); + } + + #endregion + + #region Updaters + + private void UpdateFramerate() + { + VsyncNumerator = 1000000000; + UInt64 refresh = (UInt64)LibMAME.mame_lua_get_double(MAMELuaCommand.GetRefresh); + VsyncDenominator = (int)(refresh / 1000000000); + } + + private void UpdateAspect() + { + int x = (int)LibMAME.mame_lua_get_double(MAMELuaCommand.GetBoundX); + int y = (int)LibMAME.mame_lua_get_double(MAMELuaCommand.GetBoundY); + VirtualHeight = BufferWidth > BufferHeight * x / y + ? BufferWidth * y / x + : BufferHeight; + VirtualWidth = VirtualHeight * x / y; + } + + private void UpdateVideo() + { + BufferWidth = LibMAME.mame_lua_get_int(MAMELuaCommand.GetWidth); + BufferHeight = LibMAME.mame_lua_get_int(MAMELuaCommand.GetHeight); + int expectedSize = BufferWidth * BufferHeight; + int bytesPerPixel = 4; + int lengthInBytes; + IntPtr ptr = LibMAME.mame_lua_get_string(MAMELuaCommand.GetPixels, out lengthInBytes); + + if (ptr == IntPtr.Zero) + { + Console.WriteLine("LibMAME ERROR: frame buffer pointer is null"); + return; + } + + if (expectedSize * bytesPerPixel != lengthInBytes) + { + Console.WriteLine( + "LibMAME ERROR: frame buffer has wrong size\n" + + $"width: { BufferWidth } pixels\n" + + $"height: { BufferHeight } pixels\n" + + $"expected: { expectedSize * bytesPerPixel } bytes\n" + + $"received: { lengthInBytes } bytes\n"); + return; + } + + frameBuffer = new int[expectedSize]; + Marshal.Copy(ptr, frameBuffer, 0, expectedSize); + + if (!LibMAME.mame_lua_free_string(ptr)) + { + Console.WriteLine("LibMAME ERROR: frame buffer wasn't freed"); + } + } + + private void UpdateInput() + { + foreach (var fieldPort in fieldsPorts) + { + LibMAME.mame_lua_execute( + "manager:machine():ioport()" + + $".ports [\"{ fieldPort.Value }\"]" + + $".fields [\"{ fieldPort.Key }\"]" + + $":set_value({ (Controller.IsPressed(fieldPort.Key) ? 1 : 0) })"); + } + } + + private void Update() + { + UpdateFramerate(); + UpdateVideo(); + UpdateAspect(); + UpdateInput(); + } + + private void CheckVersions() + { + int lengthInBytes; + IntPtr ptr = LibMAME.mame_lua_get_string(MAMELuaCommand.GetVersion, out lengthInBytes); + string MAMEVersion = Marshal.PtrToStringAnsi(ptr, lengthInBytes); + + if (!LibMAME.mame_lua_free_string(ptr)) + { + Console.WriteLine("LibMAME ERROR: string buffer wasn't freed"); + } + + string version = this.Attributes().PortedVersion; + Debug.Assert(version == MAMEVersion, + "MAME versions desync!\n\n" + + $"MAME is { MAMEVersion }\n" + + $"MAMEHawk is { version }"); + } + + #endregion + + #region Callbacks + + /* + * FrameAdvance() and MAME + * + * MAME fires the periodic callback on every video and debugger update, + * which happens every VBlank and also repeatedly at certain time + * intervals while paused. Since MAME's luaengine runs in a separate + * thread, it's only safe to update everything we need per frame during + * this callback, when it's explicitly waiting for further lua commands. + * + * If we disable throttling and pass -update_in_pause, there will be no + * delay between video updates. This allows to run at full speed while + * frame-stepping. + * + * MAME only captures new frame data once per VBlank, while unpaused. + * But it doesn't have an exclusive VBlank callback we could attach to. + * It has a LUA_ON_FRAME_DONE callback, but that fires even more + * frequently and updates all sorts of other non-video stuff, and we + * need none of that here. + * + * So we filter out all the calls that happen while paused (non-VBlank + * updates). Then, when Hawk asks us to advance a frame, we virtually + * unpause and declare the new frame unfinished. This informs MAME that + * it should advance one frame internally. Hawk starts waiting for the + * MAME thread to complete the request. + * + * After MAME's done advancing, it fires the periodic callback again. + * That's when we update everything and declare the new frame finished, + * filtering out any further updates again. Then we allow Hawk to + * complete frame-advancing. + */ + private void MAMEPeriodicCallback() + { + if (exiting) + { + LibMAME.mame_lua_execute(MAMELuaCommand.Exit); + exiting = false; + } + + int MAMEFrame = LibMAME.mame_lua_get_int(MAMELuaCommand.GetFrameNumber); + + if (!paused) + { + LibMAME.mame_lua_execute(MAMELuaCommand.Step); + frameDone = false; + paused = true; + } + else if (!frameDone) + { + Update(); + frameDone = true; + MAMEFrameComplete.Set(); + } + } + + private void MAMESoundCallback() + { + int bytesPerSample = 2; + int lengthInBytes; + IntPtr ptr = LibMAME.mame_lua_get_string(MAMELuaCommand.GetSamples, out lengthInBytes); + + if (ptr == IntPtr.Zero) + { + Console.WriteLine("LibMAME ERROR: audio buffer pointer is null"); + return; + } + + numSamples = lengthInBytes / bytesPerSample; + + unsafe + { + short* pSample = (short*)ptr.ToPointer(); + for (int i = 0; i < numSamples; i++) + { + audioSamples.Enqueue(*(pSample + i)); + } + } + + if (!LibMAME.mame_lua_free_string(ptr)) + { + Console.WriteLine("LibMAME ERROR: audio buffer wasn't freed"); + } + } + + private void MAMEBootCallback() + { + LibMAME.mame_lua_execute(MAMELuaCommand.Pause); + CheckVersions(); + GetInputFields(); + Update(); + MAMEStartupComplete.Set(); + } + + private void MAMELogCallback(LibMAME.OutputChannel channel, int size, string data) + { + // mame sends osd_output_channel casted to int, we implicitly cast is back + if (!data.Contains("pause = ")) + { + Console.WriteLine( + $"[MAME { channel.ToString() }] " + + $"{ data.Replace('\n', ' ') }"); + } + } + + #endregion + + #region Input + + public static ControllerDefinition MAMEController = new ControllerDefinition + { + Name = "MAME Controller", + BoolButtons = new List() + }; + + private void GetInputFields() + { + int lengthInBytes; + + IntPtr ptr = LibMAME.mame_lua_get_string(MAMELuaCommand.GetInputFields, out lengthInBytes); + + if (ptr == IntPtr.Zero) + { + Console.WriteLine("LibMAME ERROR: string buffer pointer is null"); + return; + } + + string inputFields = Marshal.PtrToStringAnsi(ptr, lengthInBytes); + string[] portFields = inputFields.Split(';'); + MAMEController.BoolButtons.Clear(); + + foreach (string portField in portFields) + { + if (portField != string.Empty) + { + string[] substrings = portField.Split(','); + string tag = substrings.First(); + string field = substrings.Last(); + + fieldsPorts.Add(field, tag); + MAMEController.BoolButtons.Add(field); + } + } + + if (!LibMAME.mame_lua_free_string(ptr)) + { + Console.WriteLine("LibMAME ERROR: string buffer wasn't freed"); + } + } + + #endregion + + #region Lua Commands + + private class MAMELuaCommand + { + public const string Step = "emu.step()"; + public const string Pause = "emu.pause()"; + public const string Unpause = "emu.unpause()"; + public const string Exit = "manager:machine():exit()"; + public const string GetVersion = "return emu.app_version()"; + public const string GetPixels = "return manager:machine():video():pixels()"; + public const string GetSamples = "return manager:machine():sound():samples()"; + public const string GetFrameNumber = "return select(2, next(manager:machine().screens)):frame_number()"; + public const string GetRefresh = "return select(2, next(manager:machine().screens)):refresh_attoseconds()"; + public const string GetWidth = "return (select(1, manager:machine():video():size()))"; + public const string GetHeight = "return (select(2, manager:machine():video():size()))"; + public const string GetBoundX = + "local x0,x1,y0,y1 = manager:machine():render():ui_target():view_bounds() " + + "return x1-x0"; + public const string GetBoundY = + "local x0,x1,y0,y1 = manager:machine():render():ui_target():view_bounds() " + + "return y1-y0"; + public const string GetInputFields = + "final = {} " + + "for tag, _ in pairs(manager:machine():ioport().ports) do " + + "for name, field in pairs(manager:machine():ioport().ports[tag].fields) do " + + "if field.type_class ~= \"dipswitch\" then " + + "table.insert(final, string.format(\"%s,%s;\", tag, name)) " + + "end " + + "end " + + "end " + + "table.sort(final) " + + "return table.concat(final)"; + } + + #endregion + } +} diff --git a/BizHawk.Emulation.Cores/BizHawk.Emulation.Cores.csproj b/BizHawk.Emulation.Cores/BizHawk.Emulation.Cores.csproj index 882192d4e9..157b849a24 100644 --- a/BizHawk.Emulation.Cores/BizHawk.Emulation.Cores.csproj +++ b/BizHawk.Emulation.Cores/BizHawk.Emulation.Cores.csproj @@ -103,6 +103,8 @@ VersionInfo.cs + + TI83.cs From abcda424dc6877c626e1a054653ebb64e28eb084 Mon Sep 17 00:00:00 2001 From: adelikat Date: Tue, 29 Oct 2019 12:50:18 -0500 Subject: [PATCH 158/166] fix a typo in a message box message, a few other cleanups in the vicinity --- BizHawk.Client.EmuHawk/tools/ToolManager.cs | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/BizHawk.Client.EmuHawk/tools/ToolManager.cs b/BizHawk.Client.EmuHawk/tools/ToolManager.cs index e04f82d9f6..9a382d2d11 100644 --- a/BizHawk.Client.EmuHawk/tools/ToolManager.cs +++ b/BizHawk.Client.EmuHawk/tools/ToolManager.cs @@ -147,8 +147,7 @@ namespace BizHawk.Client.EmuHawk // custom settings if (HasCustomConfig(newTool)) { - Dictionary settings; - if (!Global.Config.CustomToolSettings.TryGetValue(toolType, out settings)) + if (!Global.Config.CustomToolSettings.TryGetValue(toolType, out var settings)) { settings = new Dictionary(); Global.Config.CustomToolSettings[toolType] = settings; @@ -362,7 +361,7 @@ namespace BizHawk.Client.EmuHawk } else if (!(val is bool) && prop.PropertyType.IsPrimitive) { - // numeric constanst are similarly hosed + // numeric constants are similarly hosed val = Convert.ChangeType(val, prop.PropertyType, System.Globalization.CultureInfo.InvariantCulture); } @@ -636,7 +635,7 @@ namespace BizHawk.Client.EmuHawk { if (MessageBox.Show( "Are you sure want to load this external tool?\r\nAccept ONLY if you trust the source and if you know what you're doing. In any other case, choose no.", - "Confirmm loading", MessageBoxButtons.YesNo, MessageBoxIcon.Question) == DialogResult.Yes) + "Confirm loading", MessageBoxButtons.YesNo, MessageBoxIcon.Question) == DialogResult.Yes) { try { From c78b6df3636cb0728a635e9f43fd5981a0ecc014 Mon Sep 17 00:00:00 2001 From: adelikat Date: Tue, 29 Oct 2019 13:01:07 -0500 Subject: [PATCH 159/166] remove Autohawk tool, this doesn't do anything and never caught on as an idea --- .../BizHawk.Client.EmuHawk.csproj | 9 -- BizHawk.Client.EmuHawk/MainForm.Designer.cs | 10 -- BizHawk.Client.EmuHawk/MainForm.Events.cs | 6 - .../tools/AutoHawk.Designer.cs | 86 ------------ BizHawk.Client.EmuHawk/tools/AutoHawk.cs | 74 ----------- BizHawk.Client.EmuHawk/tools/AutoHawk.resx | 123 ------------------ 6 files changed, 308 deletions(-) delete mode 100644 BizHawk.Client.EmuHawk/tools/AutoHawk.Designer.cs delete mode 100644 BizHawk.Client.EmuHawk/tools/AutoHawk.cs delete mode 100644 BizHawk.Client.EmuHawk/tools/AutoHawk.resx diff --git a/BizHawk.Client.EmuHawk/BizHawk.Client.EmuHawk.csproj b/BizHawk.Client.EmuHawk/BizHawk.Client.EmuHawk.csproj index f1ead2c24e..b9f57f746c 100644 --- a/BizHawk.Client.EmuHawk/BizHawk.Client.EmuHawk.csproj +++ b/BizHawk.Client.EmuHawk/BizHawk.Client.EmuHawk.csproj @@ -785,12 +785,6 @@ - - Form - - - AutoHawk.cs - Form @@ -1552,9 +1546,6 @@ RomStatusPicker.cs - - AutoHawk.cs - BasicBot.cs diff --git a/BizHawk.Client.EmuHawk/MainForm.Designer.cs b/BizHawk.Client.EmuHawk/MainForm.Designer.cs index 0d8d91dfff..af23e02304 100644 --- a/BizHawk.Client.EmuHawk/MainForm.Designer.cs +++ b/BizHawk.Client.EmuHawk/MainForm.Designer.cs @@ -234,7 +234,6 @@ this.dummyExternalTool = new System.Windows.Forms.ToolStripMenuItem(); this.batchRunnerToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); this.ExperimentalToolsSubMenu = new System.Windows.Forms.ToolStripMenuItem(); - this.AutoHawkMenuItem = new System.Windows.Forms.ToolStripMenuItem(); this.NewHexEditorMenuItem = new System.Windows.Forms.ToolStripMenuItem(); this.NESSubMenu = new System.Windows.Forms.ToolStripMenuItem(); this.coreToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); @@ -2265,20 +2264,12 @@ // ExperimentalToolsSubMenu // this.ExperimentalToolsSubMenu.DropDownItems.AddRange(new System.Windows.Forms.ToolStripItem[] { - this.AutoHawkMenuItem, this.NewHexEditorMenuItem}); this.ExperimentalToolsSubMenu.Name = "ExperimentalToolsSubMenu"; this.ExperimentalToolsSubMenu.Size = new System.Drawing.Size(191, 22); this.ExperimentalToolsSubMenu.Text = "Experimental Tools"; this.ExperimentalToolsSubMenu.DropDownOpened += new System.EventHandler(this.ExperimentalToolsSubMenu_DropDownOpened); // - // AutoHawkMenuItem - // - this.AutoHawkMenuItem.Name = "AutoHawkMenuItem"; - this.AutoHawkMenuItem.Size = new System.Drawing.Size(155, 22); - this.AutoHawkMenuItem.Text = "AutoHawk"; - this.AutoHawkMenuItem.Click += new System.EventHandler(this.AutoHawkMenuItem_Click); - // // NewHexEditorMenuItem // this.NewHexEditorMenuItem.Name = "NewHexEditorMenuItem"; @@ -4748,7 +4739,6 @@ private System.Windows.Forms.ToolStripMenuItem dummyExternalTool; private System.Windows.Forms.ToolStripMenuItem RecordAVMenuItem; private System.Windows.Forms.ToolStripMenuItem ExperimentalToolsSubMenu; - private System.Windows.Forms.ToolStripMenuItem AutoHawkMenuItem; private System.Windows.Forms.ToolStripMenuItem NewHexEditorMenuItem; private System.Windows.Forms.ToolStripMenuItem SaveConfigAsMenuItem; private System.Windows.Forms.ToolStripMenuItem LoadConfigFromMenuItem; diff --git a/BizHawk.Client.EmuHawk/MainForm.Events.cs b/BizHawk.Client.EmuHawk/MainForm.Events.cs index fb13ec3eeb..6ac855a1ee 100644 --- a/BizHawk.Client.EmuHawk/MainForm.Events.cs +++ b/BizHawk.Client.EmuHawk/MainForm.Events.cs @@ -1414,7 +1414,6 @@ namespace BizHawk.Client.EmuHawk private void ExperimentalToolsSubMenu_DropDownOpened(object sender, EventArgs e) { - AutoHawkMenuItem.Enabled = GlobalWin.Tools.IsAvailable(); NewHexEditorMenuItem.Enabled = GlobalWin.Tools.IsAvailable(); } @@ -1511,11 +1510,6 @@ namespace BizHawk.Client.EmuHawk new BatchRun().ShowDialog(); } - private void AutoHawkMenuItem_Click(object sender, EventArgs e) - { - GlobalWin.Tools.Load(); - } - private void NewHexEditorMenuItem_Click(object sender, EventArgs e) { GlobalWin.Tools.Load(); diff --git a/BizHawk.Client.EmuHawk/tools/AutoHawk.Designer.cs b/BizHawk.Client.EmuHawk/tools/AutoHawk.Designer.cs deleted file mode 100644 index 5054e0208c..0000000000 --- a/BizHawk.Client.EmuHawk/tools/AutoHawk.Designer.cs +++ /dev/null @@ -1,86 +0,0 @@ -namespace BizHawk.Client.EmuHawk -{ - partial class AutoHawk - { - /// - /// Required designer variable. - /// - private System.ComponentModel.IContainer components = null; - - /// - /// Clean up any resources being used. - /// - /// true if managed resources should be disposed; otherwise, false. - protected override void Dispose(bool disposing) - { - if (disposing && (components != null)) - { - components.Dispose(); - } - base.Dispose(disposing); - } - - #region Windows Form Designer generated code - - /// - /// Required method for Designer support - do not modify - /// the contents of this method with the code editor. - /// - private void InitializeComponent() - { - this.AutoMenu = new System.Windows.Forms.MenuStrip(); - this.FileSubMenu = new System.Windows.Forms.ToolStripMenuItem(); - this.ExitMenuItem = new System.Windows.Forms.ToolStripMenuItem(); - this.AutoMenu.SuspendLayout(); - this.SuspendLayout(); - // - // AutoMenu - // - this.AutoMenu.Items.AddRange(new System.Windows.Forms.ToolStripItem[] { - this.FileSubMenu}); - this.AutoMenu.Location = new System.Drawing.Point(0, 0); - this.AutoMenu.Name = "AutoMenu"; - this.AutoMenu.Size = new System.Drawing.Size(508, 24); - this.AutoMenu.TabIndex = 2; - this.AutoMenu.Text = "menuStrip1"; - // - // FileSubMenu - // - this.FileSubMenu.DropDownItems.AddRange(new System.Windows.Forms.ToolStripItem[] { - this.ExitMenuItem}); - this.FileSubMenu.Name = "FileSubMenu"; - this.FileSubMenu.Size = new System.Drawing.Size(37, 20); - this.FileSubMenu.Text = "&File"; - // - // ExitMenuItem - // - this.ExitMenuItem.Name = "ExitMenuItem"; - this.ExitMenuItem.Size = new System.Drawing.Size(152, 22); - this.ExitMenuItem.Text = "E&xit"; - this.ExitMenuItem.Click += new System.EventHandler(this.ExitMenuItem_Click); - // - // AutoHawk - // - this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); - this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; - this.ClientSize = new System.Drawing.Size(508, 444); - this.Controls.Add(this.AutoMenu); - this.MainMenuStrip = this.AutoMenu; - this.Name = "AutoHawk"; - this.StartPosition = System.Windows.Forms.FormStartPosition.CenterParent; - this.Text = "AutoHawk"; - this.Load += new System.EventHandler(this.AutoHawk_Load); - this.AutoMenu.ResumeLayout(false); - this.AutoMenu.PerformLayout(); - this.ResumeLayout(false); - this.PerformLayout(); - - } - - #endregion - - private System.Windows.Forms.MenuStrip AutoMenu; - private System.Windows.Forms.ToolStripMenuItem FileSubMenu; - private System.Windows.Forms.ToolStripMenuItem ExitMenuItem; - } -} \ No newline at end of file diff --git a/BizHawk.Client.EmuHawk/tools/AutoHawk.cs b/BizHawk.Client.EmuHawk/tools/AutoHawk.cs deleted file mode 100644 index c1674db0ee..0000000000 --- a/BizHawk.Client.EmuHawk/tools/AutoHawk.cs +++ /dev/null @@ -1,74 +0,0 @@ -using System; -using System.Collections.Generic; -using System.ComponentModel; -using System.Data; -using System.Drawing; -using System.Linq; -using System.Text; -using System.Windows.Forms; - -using BizHawk.Emulation.Common; - -namespace BizHawk.Client.EmuHawk -{ - [Tool(released: false, supportedSystems: null)] - public partial class AutoHawk : Form, IToolFormAutoConfig - { - public AutoHawk() - { - InitializeComponent(); - } - - private void AutoHawk_Load(object sender, EventArgs e) - { - - } - - [RequiredService] - public IMemoryDomains MemoryDomains { get; set; } - - [RequiredService] - public IStatable StatableCore { get; set; } - - [ConfigPersist] - public ConfigVariables Config { get; set; } - - public class ConfigVariables - { - // anything that needs to be saved in config.ini should go here - } - - #region IToolForm Implementation - - public void NewUpdate(ToolFormUpdateType type) { } - - public void UpdateValues() - { - // TODO: per frame stuff goes here - } - - public void FastUpdate() - { - // TODO: when the user is turboing this will be called, slow things like updating graphics should be avoided, but critical operations must still be done here - } - - public void Restart() - { - // When the user changes to a new ROM, closes a ROM, starts a movie, etc, this will be called - } - - public bool UpdateBefore { get { return true; } } - - public bool AskSaveChanges() - { - return true; - } - - #endregion - - private void ExitMenuItem_Click(object sender, EventArgs e) - { - Close(); - } - } -} diff --git a/BizHawk.Client.EmuHawk/tools/AutoHawk.resx b/BizHawk.Client.EmuHawk/tools/AutoHawk.resx deleted file mode 100644 index 435c368278..0000000000 --- a/BizHawk.Client.EmuHawk/tools/AutoHawk.resx +++ /dev/null @@ -1,123 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - text/microsoft-resx - - - 2.0 - - - System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - - System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - - 17, 17 - - \ No newline at end of file From 2b7cb1bb7d01c0acd29c955e80ef9e06c075a1e9 Mon Sep 17 00:00:00 2001 From: adelikat Date: Tue, 29 Oct 2019 13:59:08 -0500 Subject: [PATCH 160/166] BizHawk.Emulation.Common - cleanups -> C#6/7isms, fix some typos, variable naming, spaces to tabs --- .../BasicServiceProvider.cs | 11 +- .../Base Implementations/CodeDataLog.cs | 16 +- .../ControllerDefinition.cs | 24 +- .../MemoryCallbackSystem.cs | 12 +- .../Base Implementations/MemoryDomainImpls.cs | 23 +- .../Base Implementations/MemoryDomainList.cs | 34 +- .../Base Implementations/NullEmulator.cs | 4 +- .../Base Implementations/NullSound.cs | 2 +- .../Base Implementations/TraceBuffer.cs | 7 +- BizHawk.Emulation.Common/CoreAttribute.cs | 14 +- BizHawk.Emulation.Common/CoreComms.cs | 6 +- BizHawk.Emulation.Common/DSKIdentifier.cs | 772 +++++++++--------- BizHawk.Emulation.Common/Database/Database.cs | 50 +- .../EmulationExceptions.cs | 22 +- BizHawk.Emulation.Common/Extensions.cs | 100 +-- .../Interfaces/Services/ICycleTiming.cs | 9 +- .../Interfaces/Services/IDebuggable.cs | 4 +- .../Interfaces/Services/IDisassemblable.cs | 6 +- .../Interfaces/Services/ISaveRam.cs | 4 +- .../Interfaces/Services/ISettable.cs | 8 +- .../Properties/AssemblyInfo.cs | 1 - BizHawk.Emulation.Common/SaveController.cs | 4 +- BizHawk.Emulation.Common/ServiceAttributes.cs | 2 +- BizHawk.Emulation.Common/ServiceInjector.cs | 16 +- .../Sound/Utilities/DCFilter.cs | 47 +- .../Utilities/ISynchronizingAudioBuffer.cs | 3 +- BizHawk.Emulation.Common/SystemLookup.cs | 18 +- BizHawk.sln.DotSettings | 12 + 28 files changed, 550 insertions(+), 681 deletions(-) diff --git a/BizHawk.Emulation.Common/Base Implementations/BasicServiceProvider.cs b/BizHawk.Emulation.Common/Base Implementations/BasicServiceProvider.cs index 3e3414dac7..52df2946eb 100644 --- a/BizHawk.Emulation.Common/Base Implementations/BasicServiceProvider.cs +++ b/BizHawk.Emulation.Common/Base Implementations/BasicServiceProvider.cs @@ -66,8 +66,7 @@ namespace BizHawk.Emulation.Common public object GetService(Type t) { - object service; - if (_services.TryGetValue(t, out service)) + if (_services.TryGetValue(t, out var service)) { return service; } @@ -86,12 +85,6 @@ namespace BizHawk.Emulation.Common return _services.ContainsKey(t); } - public IEnumerable AvailableServices - { - get - { - return _services.Select(d => d.Key); - } - } + public IEnumerable AvailableServices =>_services.Select(d => d.Key); } } diff --git a/BizHawk.Emulation.Common/Base Implementations/CodeDataLog.cs b/BizHawk.Emulation.Common/Base Implementations/CodeDataLog.cs index 626354c7b7..b7051b3ab7 100644 --- a/BizHawk.Emulation.Common/Base Implementations/CodeDataLog.cs +++ b/BizHawk.Emulation.Common/Base Implementations/CodeDataLog.cs @@ -62,9 +62,9 @@ namespace BizHawk.Emulation.Common /// /// Whether the CDL is tracking a block with the given name /// - public bool Has(string blockname) + public bool Has(string blockName) { - return ContainsKey(blockname); + return ContainsKey(blockName); } /// @@ -121,17 +121,17 @@ namespace BizHawk.Emulation.Common foreach (var kvp in other) { - byte[] fromdata = kvp.Value; - byte[] todata = this[kvp.Key]; + byte[] fromData = kvp.Value; + byte[] toData = this[kvp.Key]; - if (fromdata.Length != todata.Length) + if (fromData.Length != toData.Length) { throw new InvalidDataException("Memory regions must be the same size!"); } - for (int i = 0; i < todata.Length; i++) + for (int i = 0; i < toData.Length; i++) { - todata[i] |= fromdata[i]; + toData[i] |= fromData[i]; } } } @@ -201,7 +201,7 @@ namespace BizHawk.Emulation.Common } else { - throw new InvalidDataException("File is not a Bizhawk CDL file!"); + throw new InvalidDataException("File is not a BizHawk CDL file!"); } int count = br.ReadInt32(); diff --git a/BizHawk.Emulation.Common/Base Implementations/ControllerDefinition.cs b/BizHawk.Emulation.Common/Base Implementations/ControllerDefinition.cs index f6488b134a..00fd8c1ba0 100644 --- a/BizHawk.Emulation.Common/Base Implementations/ControllerDefinition.cs +++ b/BizHawk.Emulation.Common/Base Implementations/ControllerDefinition.cs @@ -82,23 +82,23 @@ namespace BizHawk.Emulation.Common { case AxisConstraintType.Circular: { - string xaxis = constraint.Params[0] as string; - string yaxis = constraint.Params[1] as string; + string xAxis = constraint.Params[0] as string ?? ""; + string yAxis = constraint.Params[1] as string ?? ""; float range = (float)constraint.Params[2]; - if (!floatButtons.ContainsKey(xaxis)) break; - if (!floatButtons.ContainsKey(yaxis)) break; - double xval = floatButtons[xaxis]; - double yval = floatButtons[yaxis]; - double length = Math.Sqrt((xval * xval) + (yval * yval)); + if (!floatButtons.ContainsKey(xAxis)) break; + if (!floatButtons.ContainsKey(yAxis)) break; + double xVal = floatButtons[xAxis]; + double yVal = floatButtons[yAxis]; + double length = Math.Sqrt((xVal * xVal) + (yVal * yVal)); if (length > range) { double ratio = range / length; - xval *= ratio; - yval *= ratio; + xVal *= ratio; + yVal *= ratio; } - floatButtons[xaxis] = (float)xval; - floatButtons[yaxis] = (float)yval; + floatButtons[xAxis] = (float)xVal; + floatButtons[yAxis] = (float)yVal; break; } } @@ -167,7 +167,7 @@ namespace BizHawk.Emulation.Common List list = new List(FloatControls); list.AddRange(BoolButtons); - // starts with console buttons, then each plasyer's buttons individually + // starts with console buttons, then each player's buttons individually List[] ret = new List[PlayerCount + 1]; for (int i = 0; i < ret.Length; i++) { diff --git a/BizHawk.Emulation.Common/Base Implementations/MemoryCallbackSystem.cs b/BizHawk.Emulation.Common/Base Implementations/MemoryCallbackSystem.cs index 3b984eedde..b612eb6861 100644 --- a/BizHawk.Emulation.Common/Base Implementations/MemoryCallbackSystem.cs +++ b/BizHawk.Emulation.Common/Base Implementations/MemoryCallbackSystem.cs @@ -70,11 +70,11 @@ namespace BizHawk.Emulation.Common private static void Call(ObservableCollection cbs, uint addr, uint value, uint flags, string scope) { - for (int i = 0; i < cbs.Count; i++) + foreach (var cb in cbs) { - if (!cbs[i].Address.HasValue || (cbs[i].Scope == scope && cbs[i].Address == (addr & cbs[i].AddressMask))) + if (!cb.Address.HasValue || (cb.Scope == scope && cb.Address == (addr & cb.AddressMask))) { - cbs[i].Callback(addr, value, flags); + cb.Callback(addr, value, flags); } } } @@ -134,17 +134,17 @@ namespace BizHawk.Emulation.Common public bool HasReadsForScope(string scope) { - return _reads.Where(e => e.Scope == scope).Any(); + return _reads.Any(e => e.Scope == scope); } public bool HasWritesForScope(string scope) { - return _writes.Where(e => e.Scope == scope).Any(); + return _writes.Any(e => e.Scope == scope); } public bool HasExecutesForScope(string scope) { - return _execs.Where(e => e.Scope == scope).Any(); + return _execs.Any(e => e.Scope == scope); } private bool UpdateHasVariables() diff --git a/BizHawk.Emulation.Common/Base Implementations/MemoryDomainImpls.cs b/BizHawk.Emulation.Common/Base Implementations/MemoryDomainImpls.cs index 6a80b62c62..d7f0f22453 100644 --- a/BizHawk.Emulation.Common/Base Implementations/MemoryDomainImpls.cs +++ b/BizHawk.Emulation.Common/Base Implementations/MemoryDomainImpls.cs @@ -5,22 +5,13 @@ namespace BizHawk.Emulation.Common { public class MemoryDomainDelegate : MemoryDomain { - private Func _peek; private Action _poke; - public Func Peek - { - get { return _peek; } - set { _peek = value; } - } + public Func Peek { get; set; } public Action Poke { - get - { - return _poke; - } - + get => _poke; set { _poke = value; @@ -30,7 +21,7 @@ namespace BizHawk.Emulation.Common public override byte PeekByte(long addr) { - return _peek(addr); + return Peek(addr); } public override void PokeByte(long addr, byte val) @@ -43,7 +34,7 @@ namespace BizHawk.Emulation.Common Name = name; EndianType = endian; Size = size; - _peek = peek; + Peek = peek; _poke = poke; Writable = poke != null; WordSize = wordSize; @@ -56,11 +47,7 @@ namespace BizHawk.Emulation.Common public byte[] Data { - get - { - return _data; - } - + get => _data; set { _data = value; diff --git a/BizHawk.Emulation.Common/Base Implementations/MemoryDomainList.cs b/BizHawk.Emulation.Common/Base Implementations/MemoryDomainList.cs index dfb67ec775..6def6abe23 100644 --- a/BizHawk.Emulation.Common/Base Implementations/MemoryDomainList.cs +++ b/BizHawk.Emulation.Common/Base Implementations/MemoryDomainList.cs @@ -24,13 +24,7 @@ namespace BizHawk.Emulation.Common { } - public MemoryDomain this[string name] - { - get - { - return this.FirstOrDefault(x => x.Name == name); - } - } + public MemoryDomain this[string name] => this.FirstOrDefault(x => x.Name == name); public MemoryDomain MainMemory { @@ -44,24 +38,10 @@ namespace BizHawk.Emulation.Common return this.First(); } - set - { - _mainMemory = value; - } + set => _mainMemory = value; } - public bool HasSystemBus - { - get - { - if (_systemBus != null) - { - return true; - } - - return this.Any(x => x.Name == "System Bus"); - } - } + public bool HasSystemBus => _systemBus != null || this.Any(x => x.Name == "System Bus"); public MemoryDomain SystemBus { @@ -82,10 +62,7 @@ namespace BizHawk.Emulation.Common return MainMemory; } - set - { - _systemBus = value; - } + set => _systemBus = value; } /// @@ -96,8 +73,7 @@ namespace BizHawk.Emulation.Common var domains = this.ToDictionary(m => m.Name); foreach (var src in other) { - MemoryDomain dst; - if (domains.TryGetValue(src.Name, out dst)) + if (domains.TryGetValue(src.Name, out var dst)) { TryMerge(dst, src, (d, s) => d.Data = s.Data); TryMerge(dst, src, (d, s) => d.Data = s.Data); diff --git a/BizHawk.Emulation.Common/Base Implementations/NullEmulator.cs b/BizHawk.Emulation.Common/Base Implementations/NullEmulator.cs index 0983f9651c..3792f583f1 100644 --- a/BizHawk.Emulation.Common/Base Implementations/NullEmulator.cs +++ b/BizHawk.Emulation.Common/Base Implementations/NullEmulator.cs @@ -33,7 +33,7 @@ namespace BizHawk.Emulation.Common public ControllerDefinition ControllerDefinition => NullController.Instance.Definition; - public bool FrameAdvance(IController controller, bool render, bool rendersound) + public bool FrameAdvance(IController controller, bool render, bool renderSound) { if (render == false) { @@ -249,7 +249,7 @@ namespace BizHawk.Emulation.Common var ms = new MemoryStream(); gz.CopyTo(ms); _data = ms.ToArray(); - for (int i = 0; i < 3800; i++) // compenstate for sample start point + for (int i = 0; i < 3800; i++) // compensate for sample start point { Next(); } diff --git a/BizHawk.Emulation.Common/Base Implementations/NullSound.cs b/BizHawk.Emulation.Common/Base Implementations/NullSound.cs index 27afd57ecc..1598dd5d1f 100644 --- a/BizHawk.Emulation.Common/Base Implementations/NullSound.cs +++ b/BizHawk.Emulation.Common/Base Implementations/NullSound.cs @@ -27,7 +27,7 @@ namespace BizHawk.Emulation.Common : this() { _spfNumerator = spf; - _spfDenominator = 1; + _spfDenominator = 1; } /// diff --git a/BizHawk.Emulation.Common/Base Implementations/TraceBuffer.cs b/BizHawk.Emulation.Common/Base Implementations/TraceBuffer.cs index 75d64f56c9..3f288cdce6 100644 --- a/BizHawk.Emulation.Common/Base Implementations/TraceBuffer.cs +++ b/BizHawk.Emulation.Common/Base Implementations/TraceBuffer.cs @@ -6,12 +6,7 @@ /// public class TraceBuffer : ITraceable { - public TraceBuffer() - { - Header = "Instructions"; - } - - public string Header { get; set; } + public string Header { get; set; } = "Instructions"; public ITraceSink Sink { private get; set; } diff --git a/BizHawk.Emulation.Common/CoreAttribute.cs b/BizHawk.Emulation.Common/CoreAttribute.cs index 5d6ddcc496..d0b7012fb7 100644 --- a/BizHawk.Emulation.Common/CoreAttribute.cs +++ b/BizHawk.Emulation.Common/CoreAttribute.cs @@ -23,12 +23,12 @@ namespace BizHawk.Emulation.Common SingleInstance = singleInstance; } - public string CoreName { get; private set; } - public string Author { get; private set; } - public bool Ported { get; private set; } - public bool Released { get; private set; } - public string PortedVersion { get; private set; } - public string PortedUrl { get; private set; } - public bool SingleInstance { get; private set; } + public string CoreName { get; } + public string Author { get; } + public bool Ported { get; } + public bool Released { get; } + public string PortedVersion { get; } + public string PortedUrl { get; } + public bool SingleInstance { get; } } } diff --git a/BizHawk.Emulation.Common/CoreComms.cs b/BizHawk.Emulation.Common/CoreComms.cs index 04a124cd26..9259c6b479 100644 --- a/BizHawk.Emulation.Common/CoreComms.cs +++ b/BizHawk.Emulation.Common/CoreComms.cs @@ -36,16 +36,16 @@ namespace BizHawk.Emulation.Common /// /// Gets a message to show. reasonably annoying (dialog box), shouldn't be used most of the time /// - public Action ShowMessage { get; private set; } + public Action ShowMessage { get; } /// /// Gets a message to show. less annoying (OSD message). Should be used for ignorable helpful messages /// - public Action Notify { get; private set; } + public Action Notify { get; } public Func RequestGLContext { get; set; } public Action ReleaseGLContext { get; set; } public Action ActivateGLContext { get; set; } - public Action DeactivateGLContext { get; set; } // this shouldnt be necessary.. frontend should be changing context before it does anything.. but for now.. + public Action DeactivateGLContext { get; set; } // this shouldn't be necessary.. frontend should be changing context before it does anything.. but for now.. } } diff --git a/BizHawk.Emulation.Common/DSKIdentifier.cs b/BizHawk.Emulation.Common/DSKIdentifier.cs index b40c6ffdf5..6a3e85a0a6 100644 --- a/BizHawk.Emulation.Common/DSKIdentifier.cs +++ b/BizHawk.Emulation.Common/DSKIdentifier.cs @@ -1,421 +1,417 @@ - -using System.Linq; -using System.Text; +using System.Text; namespace BizHawk.Emulation.Common { - /// - /// A slightly convoluted way of determining the required System based on a *.dsk file - /// This is here because (for probably good reason) there does not appear to be a route - /// to BizHawk.Emulation.Cores from Bizhawk.Emultion.Common - /// - public class DSKIdentifier - { - /// - /// Default fallthrough to AppleII - /// - public string IdentifiedSystem = "AppleII"; - private string PossibleIdent = ""; + /// + /// A slightly convoluted way of determining the required System based on a *.dsk file + /// This is here because (for probably good reason) there does not appear to be a route + /// to BizHawk.Emulation.Cores from BizHawk.Emulation.Common + /// + public class DSKIdentifier + { + /// + /// Default fallthrough to AppleII + /// + public string IdentifiedSystem = "AppleII"; + private string PossibleIdent = ""; - private byte[] data; - - // dsk header - public byte NumberOfTracks { get; set; } - public byte NumberOfSides { get; set; } - public int[] TrackSizes { get; set; } + private readonly byte[] data; - // state - public int CylinderCount; - public int SideCount; - public int BytesPerTrack; + // dsk header + public byte NumberOfTracks { get; set; } + public byte NumberOfSides { get; set; } + public int[] TrackSizes { get; set; } - public Track[] Tracks = null; + // state + public int CylinderCount; + public int SideCount; + public int BytesPerTrack; - public DSKIdentifier(byte[] imageData) - { - data = imageData; - ParseDskImage(); - } + public Track[] Tracks = null; - private void ParseDskImage() - { - string ident = Encoding.ASCII.GetString(data, 0, 16).ToUpper(); - if (ident.Contains("MV - CPC")) - { - ParseDSK(); - } - else if (ident.Contains("EXTENDED CPC DSK")) - { - ParseEDSK(); - } - else - { - // fall through - return; - } + public DSKIdentifier(byte[] imageData) + { + data = imageData; + ParseDskImage(); + } - CalculateFormat(); - } + private void ParseDskImage() + { + string ident = Encoding.ASCII.GetString(data, 0, 16).ToUpper(); + if (ident.Contains("MV - CPC")) + { + ParseDSK(); + } + else if (ident.Contains("EXTENDED CPC DSK")) + { + ParseEDSK(); + } + else + { + // fall through + return; + } - private void CalculateFormat() - { - // uses some of the work done here: https://github.com/damieng/DiskImageManager - var trk = Tracks[0]; + CalculateFormat(); + } - // look for standard speccy bootstart - if (trk.Sectors[0].SectorData != null && trk.Sectors[0].SectorData.Length > 0) - { - if (trk.Sectors[0].SectorData[0] == 0 && trk.Sectors[0].SectorData[1] == 0 - && trk.Sectors[0].SectorData[2] == 40) - { - PossibleIdent = "ZXSpectrum"; - } - } + private void CalculateFormat() + { + // uses some of the work done here: https://github.com/damieng/DiskImageManager + var trk = Tracks[0]; - // search for PLUS3DOS string - foreach (var t in Tracks) - { - foreach (var s in t.Sectors) - { - if (s.SectorData == null || s.SectorData.Length == 0) - continue; + // look for standard speccy bootstart + if (trk.Sectors[0].SectorData != null && trk.Sectors[0].SectorData.Length > 0) + { + if (trk.Sectors[0].SectorData[0] == 0 && trk.Sectors[0].SectorData[1] == 0 + && trk.Sectors[0].SectorData[2] == 40) + { + PossibleIdent = "ZXSpectrum"; + } + } - string str = Encoding.ASCII.GetString(s.SectorData, 0, s.SectorData.Length).ToUpper(); - if (str.Contains("PLUS3DOS")) - { - IdentifiedSystem = "ZXSpectrum"; - return; - } - } - } + // search for PLUS3DOS string + foreach (var t in Tracks) + { + foreach (var s in t.Sectors) + { + if (s.SectorData == null || s.SectorData.Length == 0) + continue; - // check for bootable status - if (trk.Sectors[0].SectorData != null && trk.Sectors[0].SectorData.Length > 0) - { - int chksm = trk.Sectors[0].GetChecksum256(); + string str = Encoding.ASCII.GetString(s.SectorData, 0, s.SectorData.Length).ToUpper(); + if (str.Contains("PLUS3DOS")) + { + IdentifiedSystem = "ZXSpectrum"; + return; + } + } + } - switch(chksm) - { - case 3: - IdentifiedSystem = "ZXSpectrum"; - return; - case 1: - case 255: - // different Amstrad PCW boot records - // just return CPC for now - IdentifiedSystem = "AmstradCPC"; - return; - } + // check for bootable status + if (trk.Sectors[0].SectorData != null && trk.Sectors[0].SectorData.Length > 0) + { + int chksm = trk.Sectors[0].GetChecksum256(); - switch(trk.GetLowestSectorID()) - { - case 65: - case 193: - IdentifiedSystem = "AmstradCPC"; - return; - } - } + switch (chksm) + { + case 3: + IdentifiedSystem = "ZXSpectrum"; + return; + case 1: + case 255: + // different Amstrad PCW boot records + // just return CPC for now + IdentifiedSystem = "AmstradCPC"; + return; + } - // at this point the disk is not standard bootable - // try format analysis - if (trk.Sectors.Length == 9 && trk.Sectors[0].SectorSize == 2) - { - switch(trk.GetLowestSectorID()) - { - case 1: - switch(trk.Sectors[0].GetChecksum256()) - { - case 3: - IdentifiedSystem = "ZXSpectrum"; - return; - case 1: - case 255: - // different Amstrad PCW checksums - // just return CPC for now - IdentifiedSystem = "AmstradCPC"; - return; - } - break; - case 65: - case 193: - IdentifiedSystem = "AmstradCPC"; - return; - } - } + switch (trk.GetLowestSectorID()) + { + case 65: + case 193: + IdentifiedSystem = "AmstradCPC"; + return; + } + } - // could be an odd format disk - switch (trk.GetLowestSectorID()) - { - case 1: - if (trk.Sectors.Length == 8) - { - // CPC IBM - IdentifiedSystem = "AmstradCPC"; - return; - } - break; - case 65: - case 193: - // possible CPC custom - PossibleIdent = "AmstradCPC"; - break; - } + // at this point the disk is not standard bootable + // try format analysis + if (trk.Sectors.Length == 9 && trk.Sectors[0].SectorSize == 2) + { + switch (trk.GetLowestSectorID()) + { + case 1: + switch (trk.Sectors[0].GetChecksum256()) + { + case 3: + IdentifiedSystem = "ZXSpectrum"; + return; + case 1: + case 255: + // different Amstrad PCW checksums + // just return CPC for now + IdentifiedSystem = "AmstradCPC"; + return; + } + break; + case 65: + case 193: + IdentifiedSystem = "AmstradCPC"; + return; + } + } - // other custom ZX Spectrum formats - if (NumberOfSides == 1 && trk.Sectors.Length == 10) - { - if (trk.Sectors[0].SectorData.Length > 10) - { - if (trk.Sectors[0].SectorData[2] == 42 && trk.Sectors[0].SectorData[8] == 12) - { - switch (trk.Sectors[0].SectorData[5]) - { - case 0: - if (trk.Sectors[1].SectorID == 8) - { - switch (Tracks[1].Sectors[0].SectorID) - { - case 7: - IdentifiedSystem = "ZXSpectrum"; - return; - default: - PossibleIdent = "ZXSpectrum"; - break; - } - } - else - { - PossibleIdent = "ZXSpectrum"; - } - break; - case 1: - if (trk.Sectors[1].SectorID == 8) - { - switch (Tracks[1].Sectors[0].SectorID) - { - case 7: - case 1: - IdentifiedSystem = "ZXSpectrum"; - return; - } - } - else - { - PossibleIdent = "ZXSpectrum"; - } - break; - } - } + // could be an odd format disk + switch (trk.GetLowestSectorID()) + { + case 1: + if (trk.Sectors.Length == 8) + { + // CPC IBM + IdentifiedSystem = "AmstradCPC"; + return; + } + break; + case 65: + case 193: + // possible CPC custom + PossibleIdent = "AmstradCPC"; + break; + } - if (trk.Sectors[0].SectorData[7] == 3 && - trk.Sectors[0].SectorData[9] == 23 && - trk.Sectors[0].SectorData[2] == 40) - { - IdentifiedSystem = "ZXSpectrum"; - return; - } - } - } + // other custom ZX Spectrum formats + if (NumberOfSides == 1 && trk.Sectors.Length == 10) + { + if (trk.Sectors[0].SectorData.Length > 10) + { + if (trk.Sectors[0].SectorData[2] == 42 && trk.Sectors[0].SectorData[8] == 12) + { + switch (trk.Sectors[0].SectorData[5]) + { + case 0: + if (trk.Sectors[1].SectorID == 8) + { + switch (Tracks[1].Sectors[0].SectorID) + { + case 7: + IdentifiedSystem = "ZXSpectrum"; + return; + default: + PossibleIdent = "ZXSpectrum"; + break; + } + } + else + { + PossibleIdent = "ZXSpectrum"; + } + break; + case 1: + if (trk.Sectors[1].SectorID == 8) + { + switch (Tracks[1].Sectors[0].SectorID) + { + case 7: + case 1: + IdentifiedSystem = "ZXSpectrum"; + return; + } + } + else + { + PossibleIdent = "ZXSpectrum"; + } + break; + } + } - // last chance. use the possible value - if (IdentifiedSystem == "AppleII" && PossibleIdent != "") - { - IdentifiedSystem = "ZXSpectrum"; - } - } + if (trk.Sectors[0].SectorData[7] == 3 && + trk.Sectors[0].SectorData[9] == 23 && + trk.Sectors[0].SectorData[2] == 40) + { + IdentifiedSystem = "ZXSpectrum"; + return; + } + } + } - private void ParseDSK() - { - NumberOfTracks = data[0x30]; - NumberOfSides = data[0x31]; - TrackSizes = new int[NumberOfTracks * NumberOfSides]; - Tracks = new Track[NumberOfTracks * NumberOfSides]; - int pos = 0x32; - for (int i = 0; i < NumberOfTracks * NumberOfSides; i++) - { - TrackSizes[i] = (ushort)(data[pos] | data[pos + 1] << 8); - } - pos = 0x100; - for (int i = 0; i < NumberOfTracks * NumberOfSides; i++) - { - if (TrackSizes[i] == 0) - { - Tracks[i] = new Track(); - Tracks[i].Sectors = new Sector[0]; - continue; - } - int p = pos; - Tracks[i] = new Track(); - Tracks[i].TrackIdent = Encoding.ASCII.GetString(data, p, 12); - p += 16; - Tracks[i].TrackNumber = data[p++]; - Tracks[i].SideNumber = data[p++]; - p += 2; - Tracks[i].SectorSize = data[p++]; - Tracks[i].NumberOfSectors = data[p++]; - Tracks[i].GAP3Length = data[p++]; - Tracks[i].FillerByte = data[p++]; - int dpos = pos + 0x100; - Tracks[i].Sectors = new Sector[Tracks[i].NumberOfSectors]; - for (int s = 0; s < Tracks[i].NumberOfSectors; s++) - { - Tracks[i].Sectors[s] = new Sector(); + // last chance. use the possible value + if (IdentifiedSystem == "AppleII" && PossibleIdent != "") + { + IdentifiedSystem = "ZXSpectrum"; + } + } - Tracks[i].Sectors[s].TrackNumber = data[p++]; - Tracks[i].Sectors[s].SideNumber = data[p++]; - Tracks[i].Sectors[s].SectorID = data[p++]; - Tracks[i].Sectors[s].SectorSize = data[p++]; - Tracks[i].Sectors[s].Status1 = data[p++]; - Tracks[i].Sectors[s].Status2 = data[p++]; - Tracks[i].Sectors[s].ActualDataByteLength = (ushort)(data[p] | data[p + 1] << 8); - p += 2; - if (Tracks[i].Sectors[s].SectorSize == 0) - { - Tracks[i].Sectors[s].ActualDataByteLength = TrackSizes[i]; - } - else if (Tracks[i].Sectors[s].SectorSize > 6) - { - Tracks[i].Sectors[s].ActualDataByteLength = TrackSizes[i]; - } - else if (Tracks[i].Sectors[s].SectorSize == 6) - { - Tracks[i].Sectors[s].ActualDataByteLength = 0x1800; - } - else - { - Tracks[i].Sectors[s].ActualDataByteLength = 0x80 << Tracks[i].Sectors[s].SectorSize; - } - Tracks[i].Sectors[s].SectorData = new byte[Tracks[i].Sectors[s].ActualDataByteLength]; - for (int b = 0; b < Tracks[i].Sectors[s].ActualDataByteLength; b++) - { - Tracks[i].Sectors[s].SectorData[b] = data[dpos + b]; - } - dpos += Tracks[i].Sectors[s].ActualDataByteLength; - } - pos += TrackSizes[i]; - } - } + private void ParseDSK() + { + NumberOfTracks = data[0x30]; + NumberOfSides = data[0x31]; + TrackSizes = new int[NumberOfTracks * NumberOfSides]; + Tracks = new Track[NumberOfTracks * NumberOfSides]; + int pos = 0x32; + for (int i = 0; i < NumberOfTracks * NumberOfSides; i++) + { + TrackSizes[i] = (ushort)(data[pos] | data[pos + 1] << 8); + } + pos = 0x100; + for (int i = 0; i < NumberOfTracks * NumberOfSides; i++) + { + if (TrackSizes[i] == 0) + { + Tracks[i] = new Track(); + Tracks[i].Sectors = new Sector[0]; + continue; + } + int p = pos; + Tracks[i] = new Track(); + Tracks[i].TrackIdent = Encoding.ASCII.GetString(data, p, 12); + p += 16; + Tracks[i].TrackNumber = data[p++]; + Tracks[i].SideNumber = data[p++]; + p += 2; + Tracks[i].SectorSize = data[p++]; + Tracks[i].NumberOfSectors = data[p++]; + Tracks[i].GAP3Length = data[p++]; + Tracks[i].FillerByte = data[p++]; + int dpos = pos + 0x100; + Tracks[i].Sectors = new Sector[Tracks[i].NumberOfSectors]; + for (int s = 0; s < Tracks[i].NumberOfSectors; s++) + { + Tracks[i].Sectors[s] = new Sector(); - private void ParseEDSK() - { - NumberOfTracks = data[0x30]; - NumberOfSides = data[0x31]; - TrackSizes = new int[NumberOfTracks * NumberOfSides]; - Tracks = new Track[NumberOfTracks * NumberOfSides]; - int pos = 0x34; - for (int i = 0; i < NumberOfTracks * NumberOfSides; i++) - { - TrackSizes[i] = data[pos++] * 256; - } - pos = 0x100; - for (int i = 0; i < NumberOfTracks * NumberOfSides; i++) - { - if (TrackSizes[i] == 0) - { - Tracks[i] = new Track(); - Tracks[i].Sectors = new Sector[0]; - continue; - } - int p = pos; - Tracks[i] = new Track(); - Tracks[i].TrackIdent = Encoding.ASCII.GetString(data, p, 12); - p += 16; - Tracks[i].TrackNumber = data[p++]; - Tracks[i].SideNumber = data[p++]; - Tracks[i].DataRate = data[p++]; - Tracks[i].RecordingMode = data[p++]; - Tracks[i].SectorSize = data[p++]; - Tracks[i].NumberOfSectors = data[p++]; - Tracks[i].GAP3Length = data[p++]; - Tracks[i].FillerByte = data[p++]; - int dpos = pos + 0x100; - Tracks[i].Sectors = new Sector[Tracks[i].NumberOfSectors]; - for (int s = 0; s < Tracks[i].NumberOfSectors; s++) - { - Tracks[i].Sectors[s] = new Sector(); + Tracks[i].Sectors[s].TrackNumber = data[p++]; + Tracks[i].Sectors[s].SideNumber = data[p++]; + Tracks[i].Sectors[s].SectorID = data[p++]; + Tracks[i].Sectors[s].SectorSize = data[p++]; + Tracks[i].Sectors[s].Status1 = data[p++]; + Tracks[i].Sectors[s].Status2 = data[p++]; + Tracks[i].Sectors[s].ActualDataByteLength = (ushort)(data[p] | data[p + 1] << 8); + p += 2; + if (Tracks[i].Sectors[s].SectorSize == 0) + { + Tracks[i].Sectors[s].ActualDataByteLength = TrackSizes[i]; + } + else if (Tracks[i].Sectors[s].SectorSize > 6) + { + Tracks[i].Sectors[s].ActualDataByteLength = TrackSizes[i]; + } + else if (Tracks[i].Sectors[s].SectorSize == 6) + { + Tracks[i].Sectors[s].ActualDataByteLength = 0x1800; + } + else + { + Tracks[i].Sectors[s].ActualDataByteLength = 0x80 << Tracks[i].Sectors[s].SectorSize; + } + Tracks[i].Sectors[s].SectorData = new byte[Tracks[i].Sectors[s].ActualDataByteLength]; + for (int b = 0; b < Tracks[i].Sectors[s].ActualDataByteLength; b++) + { + Tracks[i].Sectors[s].SectorData[b] = data[dpos + b]; + } + dpos += Tracks[i].Sectors[s].ActualDataByteLength; + } + pos += TrackSizes[i]; + } + } - Tracks[i].Sectors[s].TrackNumber = data[p++]; - Tracks[i].Sectors[s].SideNumber = data[p++]; - Tracks[i].Sectors[s].SectorID = data[p++]; - Tracks[i].Sectors[s].SectorSize = data[p++]; - Tracks[i].Sectors[s].Status1 = data[p++]; - Tracks[i].Sectors[s].Status2 = data[p++]; - Tracks[i].Sectors[s].ActualDataByteLength = (ushort)(data[p] | data[p + 1] << 8); - p += 2; - Tracks[i].Sectors[s].SectorData = new byte[Tracks[i].Sectors[s].ActualDataByteLength]; - for (int b = 0; b < Tracks[i].Sectors[s].ActualDataByteLength; b++) - { - Tracks[i].Sectors[s].SectorData[b] = data[dpos + b]; - } - if (Tracks[i].Sectors[s].SectorSize <= 7) - { - int specifiedSize = 0x80 << Tracks[i].Sectors[s].SectorSize; - if (specifiedSize < Tracks[i].Sectors[s].ActualDataByteLength) - { - if (Tracks[i].Sectors[s].ActualDataByteLength % specifiedSize != 0) - { - Tracks[i].Sectors[s].ContainsMultipleWeakSectors = true; - } - } - } - dpos += Tracks[i].Sectors[s].ActualDataByteLength; - } - pos += TrackSizes[i]; - } - } + private void ParseEDSK() + { + NumberOfTracks = data[0x30]; + NumberOfSides = data[0x31]; + TrackSizes = new int[NumberOfTracks * NumberOfSides]; + Tracks = new Track[NumberOfTracks * NumberOfSides]; + int pos = 0x34; + for (int i = 0; i < NumberOfTracks * NumberOfSides; i++) + { + TrackSizes[i] = data[pos++] * 256; + } + pos = 0x100; + for (int i = 0; i < NumberOfTracks * NumberOfSides; i++) + { + if (TrackSizes[i] == 0) + { + Tracks[i] = new Track(); + Tracks[i].Sectors = new Sector[0]; + continue; + } + int p = pos; + Tracks[i] = new Track(); + Tracks[i].TrackIdent = Encoding.ASCII.GetString(data, p, 12); + p += 16; + Tracks[i].TrackNumber = data[p++]; + Tracks[i].SideNumber = data[p++]; + Tracks[i].DataRate = data[p++]; + Tracks[i].RecordingMode = data[p++]; + Tracks[i].SectorSize = data[p++]; + Tracks[i].NumberOfSectors = data[p++]; + Tracks[i].GAP3Length = data[p++]; + Tracks[i].FillerByte = data[p++]; + int dpos = pos + 0x100; + Tracks[i].Sectors = new Sector[Tracks[i].NumberOfSectors]; + for (int s = 0; s < Tracks[i].NumberOfSectors; s++) + { + Tracks[i].Sectors[s] = new Sector(); - #region Internal Classes + Tracks[i].Sectors[s].TrackNumber = data[p++]; + Tracks[i].Sectors[s].SideNumber = data[p++]; + Tracks[i].Sectors[s].SectorID = data[p++]; + Tracks[i].Sectors[s].SectorSize = data[p++]; + Tracks[i].Sectors[s].Status1 = data[p++]; + Tracks[i].Sectors[s].Status2 = data[p++]; + Tracks[i].Sectors[s].ActualDataByteLength = (ushort)(data[p] | data[p + 1] << 8); + p += 2; + Tracks[i].Sectors[s].SectorData = new byte[Tracks[i].Sectors[s].ActualDataByteLength]; + for (int b = 0; b < Tracks[i].Sectors[s].ActualDataByteLength; b++) + { + Tracks[i].Sectors[s].SectorData[b] = data[dpos + b]; + } + if (Tracks[i].Sectors[s].SectorSize <= 7) + { + int specifiedSize = 0x80 << Tracks[i].Sectors[s].SectorSize; + if (specifiedSize < Tracks[i].Sectors[s].ActualDataByteLength) + { + if (Tracks[i].Sectors[s].ActualDataByteLength % specifiedSize != 0) + { + Tracks[i].Sectors[s].ContainsMultipleWeakSectors = true; + } + } + } + dpos += Tracks[i].Sectors[s].ActualDataByteLength; + } + pos += TrackSizes[i]; + } + } - public class Track - { - public string TrackIdent { get; set; } - public byte TrackNumber { get; set; } - public byte SideNumber { get; set; } - public byte DataRate { get; set; } - public byte RecordingMode { get; set; } - public byte SectorSize { get; set; } - public byte NumberOfSectors { get; set; } - public byte GAP3Length { get; set; } - public byte FillerByte { get; set; } - public Sector[] Sectors { get; set; } + #region Internal Classes - public byte GetLowestSectorID() - { - byte res = 0xFF; - foreach (var s in Sectors) - { - if (s.SectorID < res) - res = s.SectorID; - } - return res; - } - } + public class Track + { + public string TrackIdent { get; set; } + public byte TrackNumber { get; set; } + public byte SideNumber { get; set; } + public byte DataRate { get; set; } + public byte RecordingMode { get; set; } + public byte SectorSize { get; set; } + public byte NumberOfSectors { get; set; } + public byte GAP3Length { get; set; } + public byte FillerByte { get; set; } + public Sector[] Sectors { get; set; } - public class Sector - { - public byte TrackNumber { get; set; } - public byte SideNumber { get; set; } - public byte SectorID { get; set; } - public byte SectorSize { get; set; } - public byte Status1 { get; set; } - public byte Status2 { get; set; } - public int ActualDataByteLength { get; set; } - public byte[] SectorData { get; set; } - public bool ContainsMultipleWeakSectors { get; set; } + public byte GetLowestSectorID() + { + byte res = 0xFF; + foreach (var s in Sectors) + { + if (s.SectorID < res) + res = s.SectorID; + } + return res; + } + } - public int GetChecksum256() - { - int res = 0; - for (int i = 0; i < SectorData.Length; i++) - { - res += SectorData[i] % 256; - } - return res; - } - } + public class Sector + { + public byte TrackNumber { get; set; } + public byte SideNumber { get; set; } + public byte SectorID { get; set; } + public byte SectorSize { get; set; } + public byte Status1 { get; set; } + public byte Status2 { get; set; } + public int ActualDataByteLength { get; set; } + public byte[] SectorData { get; set; } + public bool ContainsMultipleWeakSectors { get; set; } - #endregion + public int GetChecksum256() + { + int res = 0; + for (int i = 0; i < SectorData.Length; i++) + { + res += SectorData[i] % 256; + } + return res; + } + } - - } + #endregion + } } diff --git a/BizHawk.Emulation.Common/Database/Database.cs b/BizHawk.Emulation.Common/Database/Database.cs index dabf010125..efdd513bb3 100644 --- a/BizHawk.Emulation.Common/Database/Database.cs +++ b/BizHawk.Emulation.Common/Database/Database.cs @@ -117,7 +117,7 @@ namespace BizHawk.Emulation.Common var line = reader.ReadLine() ?? ""; try { - if (line.StartsWith(";")) + if (line.StartsWith(";")) { continue; // comment } @@ -140,7 +140,7 @@ namespace BizHawk.Emulation.Common Hash = RemoveHashType(items[0].ToUpper()) }; - // remove a hash type identifier. well don't really need them for indexing (theyre just there for human purposes) + // remove a hash type identifier. well don't really need them for indexing (they're just there for human purposes) switch (items[1].Trim()) { case "B": @@ -238,8 +238,8 @@ namespace BizHawk.Emulation.Common break; case ".SFC": - case ".SMC": - game.System = "SNES"; + case ".SMC": + game.System = "SNES"; break; case ".GB": @@ -299,30 +299,30 @@ namespace BizHawk.Emulation.Common case ".D64": case ".T64": case ".G64": - case ".CRT": + case ".CRT": game.System = "C64"; break; - case ".TZX": - case ".PZX": - case ".CSW": - case ".WAV": - game.System = "ZXSpectrum"; - break; + case ".TZX": + case ".PZX": + case ".CSW": + case ".WAV": + game.System = "ZXSpectrum"; + break; - case ".CDT": - game.System = "AmstradCPC"; - break; + case ".CDT": + game.System = "AmstradCPC"; + break; - case ".TAP": - byte[] head = romData.Take(8).ToArray(); - if (System.Text.Encoding.Default.GetString(head).Contains("C64-TAPE")) - game.System = "C64"; - else - game.System = "ZXSpectrum"; - break; + case ".TAP": + byte[] head = romData.Take(8).ToArray(); + if (System.Text.Encoding.Default.GetString(head).Contains("C64-TAPE")) + game.System = "C64"; + else + game.System = "ZXSpectrum"; + break; - case ".Z64": + case ".Z64": case ".V64": case ".N64": game.System = "N64"; @@ -346,9 +346,9 @@ namespace BizHawk.Emulation.Common break; case ".DSK": - var dId = new DSKIdentifier(romData); - game.System = dId.IdentifiedSystem; - break; + var dId = new DSKIdentifier(romData); + game.System = dId.IdentifiedSystem; + break; case ".PO": case ".DO": diff --git a/BizHawk.Emulation.Common/EmulationExceptions.cs b/BizHawk.Emulation.Common/EmulationExceptions.cs index e61d82bf38..585dafc742 100644 --- a/BizHawk.Emulation.Common/EmulationExceptions.cs +++ b/BizHawk.Emulation.Common/EmulationExceptions.cs @@ -20,19 +20,19 @@ namespace BizHawk.Emulation.Common } } - public class NoAvailableCoreException : Exception - { - public NoAvailableCoreException() - : base("System is currently NOT emulated") - { - } + public class NoAvailableCoreException : Exception + { + public NoAvailableCoreException() + : base("System is currently NOT emulated") + { + } - public NoAvailableCoreException(string message) - : base ($"System is currently NOT emulated: {message}") - { + public NoAvailableCoreException(string message) + : base($"System is currently NOT emulated: {message}") + { - } - } + } + } public class CGBNotSupportedException : Exception { diff --git a/BizHawk.Emulation.Common/Extensions.cs b/BizHawk.Emulation.Common/Extensions.cs index 75e9a5d69b..d732222a88 100644 --- a/BizHawk.Emulation.Common/Extensions.cs +++ b/BizHawk.Emulation.Common/Extensions.cs @@ -44,12 +44,7 @@ namespace BizHawk.Emulation.Common.IEmulatorExtensions public static bool HasSoundProvider(this IEmulator core) { - if (core == null) - { - return false; - } - - return core.ServiceProvider.HasService(); + return core != null && core.ServiceProvider.HasService(); } public static ISoundProvider AsSoundProvider(this IEmulator core) @@ -70,12 +65,7 @@ namespace BizHawk.Emulation.Common.IEmulatorExtensions public static bool HasMemoryDomains(this IEmulator core) { - if (core == null) - { - return false; - } - - return core.ServiceProvider.HasService(); + return core != null && core.ServiceProvider.HasService(); } public static IMemoryDomains AsMemoryDomains(this IEmulator core) @@ -85,12 +75,7 @@ namespace BizHawk.Emulation.Common.IEmulatorExtensions public static bool HasSaveRam(this IEmulator core) { - if (core == null) - { - return false; - } - - return core.ServiceProvider.HasService(); + return core != null && core.ServiceProvider.HasService(); } public static ISaveRam AsSaveRam(this IEmulator core) @@ -100,12 +85,7 @@ namespace BizHawk.Emulation.Common.IEmulatorExtensions public static bool HasSavestates(this IEmulator core) { - if (core == null) - { - return false; - } - - return core.ServiceProvider.HasService(); + return core != null && core.ServiceProvider.HasService(); } public static IStatable AsStatable(this IEmulator core) @@ -115,12 +95,7 @@ namespace BizHawk.Emulation.Common.IEmulatorExtensions public static bool CanPollInput(this IEmulator core) { - if (core == null) - { - return false; - } - - return core.ServiceProvider.HasService(); + return core != null && core.ServiceProvider.HasService(); } public static IInputPollable AsInputPollable(this IEmulator core) @@ -130,13 +105,8 @@ namespace BizHawk.Emulation.Common.IEmulatorExtensions public static bool InputCallbacksAvailable(this IEmulator core) { - if (core == null) - { - return false; - } - // TODO: this is a pretty ugly way to handle this - var pollable = core.ServiceProvider.GetService(); + var pollable = core?.ServiceProvider.GetService(); if (pollable != null) { try @@ -155,12 +125,7 @@ namespace BizHawk.Emulation.Common.IEmulatorExtensions public static bool HasDriveLight(this IEmulator core) { - if (core == null) - { - return false; - } - - return core.ServiceProvider.HasService(); + return core != null && core.ServiceProvider.HasService(); } public static IDriveLight AsDriveLight(this IEmulator core) @@ -170,12 +135,7 @@ namespace BizHawk.Emulation.Common.IEmulatorExtensions public static bool CanDebug(this IEmulator core) { - if (core == null) - { - return false; - } - - return core.ServiceProvider.HasService(); + return core != null && core.ServiceProvider.HasService(); } public static IDebuggable AsDebuggable(this IEmulator core) @@ -185,12 +145,7 @@ namespace BizHawk.Emulation.Common.IEmulatorExtensions public static bool CpuTraceAvailable(this IEmulator core) { - if (core == null) - { - return false; - } - - return core.ServiceProvider.HasService(); + return core != null && core.ServiceProvider.HasService(); } public static ITraceable AsTracer(this IEmulator core) @@ -200,13 +155,8 @@ namespace BizHawk.Emulation.Common.IEmulatorExtensions public static bool MemoryCallbacksAvailable(this IEmulator core) { - if (core == null) - { - return false; - } - // TODO: this is a pretty ugly way to handle this - var debuggable = (IDebuggable)core.ServiceProvider.GetService(); + var debuggable = (IDebuggable) core?.ServiceProvider.GetService(); if (debuggable != null) { try @@ -251,7 +201,7 @@ namespace BizHawk.Emulation.Common.IEmulatorExtensions return core.ServiceProvider.HasService(); } - public static IDisassemblable AsDissassembler(this IEmulator core) + public static IDisassemblable AsDisassembler(this IEmulator core) { return core.ServiceProvider.GetService(); } @@ -284,12 +234,7 @@ namespace BizHawk.Emulation.Common.IEmulatorExtensions public static bool CanCDLog(this IEmulator core) { - if (core == null) - { - return false; - } - - return core.ServiceProvider.HasService(); + return core != null && core.ServiceProvider.HasService(); } public static ICodeDataLogger AsCodeDataLogger(this IEmulator core) @@ -304,22 +249,12 @@ namespace BizHawk.Emulation.Common.IEmulatorExtensions public static bool UsesLinkCable(this IEmulator core) { - if (core == null) - { - return false; - } - - return core.ServiceProvider.HasService(); + return core != null && core.ServiceProvider.HasService(); } public static bool CanGenerateGameDBEntries(this IEmulator core) { - if (core == null) - { - return false; - } - - return core.ServiceProvider.HasService(); + return core != null && core.ServiceProvider.HasService(); } public static ICreateGameDBEntries AsGameDBEntryGenerator(this IEmulator core) @@ -329,12 +264,7 @@ namespace BizHawk.Emulation.Common.IEmulatorExtensions public static bool HasBoardInfo(this IEmulator core) { - if (core == null) - { - return false; - } - - return core.ServiceProvider.HasService(); + return core != null && core.ServiceProvider.HasService(); } public static IBoardInfo AsBoardInfo(this IEmulator core) diff --git a/BizHawk.Emulation.Common/Interfaces/Services/ICycleTiming.cs b/BizHawk.Emulation.Common/Interfaces/Services/ICycleTiming.cs index 5fd648e9f7..9982216981 100644 --- a/BizHawk.Emulation.Common/Interfaces/Services/ICycleTiming.cs +++ b/BizHawk.Emulation.Common/Interfaces/Services/ICycleTiming.cs @@ -1,10 +1,4 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; - -namespace BizHawk.Emulation.Common +namespace BizHawk.Emulation.Common { public interface ICycleTiming { @@ -12,6 +6,7 @@ namespace BizHawk.Emulation.Common /// Total elapsed emulation time relative to /// long CycleCount { get; } + /// /// Clock Rate in hz for /// diff --git a/BizHawk.Emulation.Common/Interfaces/Services/IDebuggable.cs b/BizHawk.Emulation.Common/Interfaces/Services/IDebuggable.cs index 977ff10ae8..748d93fe90 100644 --- a/BizHawk.Emulation.Common/Interfaces/Services/IDebuggable.cs +++ b/BizHawk.Emulation.Common/Interfaces/Services/IDebuggable.cs @@ -46,8 +46,8 @@ namespace BizHawk.Emulation.Common public class RegisterValue { - public ulong Value { get; private set; } - public byte BitSize { get; private set; } + public ulong Value { get; } + public byte BitSize { get; } public RegisterValue(ulong val, byte bitSize) { diff --git a/BizHawk.Emulation.Common/Interfaces/Services/IDisassemblable.cs b/BizHawk.Emulation.Common/Interfaces/Services/IDisassemblable.cs index a95ed0d625..378b7090e2 100644 --- a/BizHawk.Emulation.Common/Interfaces/Services/IDisassemblable.cs +++ b/BizHawk.Emulation.Common/Interfaces/Services/IDisassemblable.cs @@ -42,11 +42,7 @@ namespace BizHawk.Emulation.Common public virtual string Cpu { - get - { - return _cpu; - } - + get => _cpu; set { if (!AvailableCpus.Contains(value)) diff --git a/BizHawk.Emulation.Common/Interfaces/Services/ISaveRam.cs b/BizHawk.Emulation.Common/Interfaces/Services/ISaveRam.cs index a1e7b1e2b9..0415e61bd5 100644 --- a/BizHawk.Emulation.Common/Interfaces/Services/ISaveRam.cs +++ b/BizHawk.Emulation.Common/Interfaces/Services/ISaveRam.cs @@ -22,9 +22,9 @@ /// /// Gets a value indicating whether or not SaveRAM has been modified since the last save /// TODO: This is not the best interface. What defines a "save"? I suppose a Clone(), right? at least specify that here. - /// Clone() should probably take an optionthat says whether to clear the dirty flag. + /// Clone() should probably take an option that says whether to clear the dirty flag. /// And anyway, cores might not know if they can even track a functional dirty flag -- we should convey that fact somehow - /// (reminder: do that with flags, so we dont have to change the interface 10000 times) + /// (reminder: do that with flags, so we don't have to change the interface 10000 times) /// Dirty SaveRAM can in principle be determined by the frontend in that case, but it could possibly be too slow for the file menu dropdown or other things /// bool SaveRamModified { get; } diff --git a/BizHawk.Emulation.Common/Interfaces/Services/ISettable.cs b/BizHawk.Emulation.Common/Interfaces/Services/ISettable.cs index fcfaa211dc..ec92488bf1 100644 --- a/BizHawk.Emulation.Common/Interfaces/Services/ISettable.cs +++ b/BizHawk.Emulation.Common/Interfaces/Services/ISettable.cs @@ -71,10 +71,10 @@ namespace BizHawk.Emulation.Common else { var tt = impl.GetGenericArguments(); - var settingtype = tt[0]; - var synctype = tt[1]; - HasSettings = settingtype != typeof(object); // object is used for a placeholder where an emu doesn't have both s and ss - HasSyncSettings = synctype != typeof(object); + var settingType = tt[0]; + var syncType = tt[1]; + HasSettings = settingType != typeof(object); // object is used for a placeholder where an emu doesn't have both s and ss + HasSyncSettings = syncType != typeof(object); if (HasSettings) { diff --git a/BizHawk.Emulation.Common/Properties/AssemblyInfo.cs b/BizHawk.Emulation.Common/Properties/AssemblyInfo.cs index 454bd38dfc..35d9fed2fb 100644 --- a/BizHawk.Emulation.Common/Properties/AssemblyInfo.cs +++ b/BizHawk.Emulation.Common/Properties/AssemblyInfo.cs @@ -1,5 +1,4 @@ using System.Reflection; -using System.Runtime.CompilerServices; using System.Runtime.InteropServices; // General Information about an assembly is controlled through the following diff --git a/BizHawk.Emulation.Common/SaveController.cs b/BizHawk.Emulation.Common/SaveController.cs index d54e99f62c..8db556f656 100644 --- a/BizHawk.Emulation.Common/SaveController.cs +++ b/BizHawk.Emulation.Common/SaveController.cs @@ -45,8 +45,8 @@ namespace BizHawk.Emulation.Common public void DeSerialize(BinaryReader b) { _buttons.Clear(); - int numbuttons = b.ReadInt32(); - for (int i = 0; i < numbuttons; i++) + int numButtons = b.ReadInt32(); + for (int i = 0; i < numButtons; i++) { string k = b.ReadString(); float v = b.ReadSingle(); diff --git a/BizHawk.Emulation.Common/ServiceAttributes.cs b/BizHawk.Emulation.Common/ServiceAttributes.cs index f2a5ec87ad..768539b0ae 100644 --- a/BizHawk.Emulation.Common/ServiceAttributes.cs +++ b/BizHawk.Emulation.Common/ServiceAttributes.cs @@ -28,6 +28,6 @@ namespace BizHawk.Emulation.Common NotApplicableTypes = types?.AsEnumerable() ?? Enumerable.Empty(); } - public IEnumerable NotApplicableTypes { get; private set; } + public IEnumerable NotApplicableTypes { get; } } } diff --git a/BizHawk.Emulation.Common/ServiceInjector.cs b/BizHawk.Emulation.Common/ServiceInjector.cs index 15ffb76f85..a80973a932 100644 --- a/BizHawk.Emulation.Common/ServiceInjector.cs +++ b/BizHawk.Emulation.Common/ServiceInjector.cs @@ -18,11 +18,11 @@ namespace BizHawk.Emulation.Common Type targetType = target.GetType(); object[] tmp = new object[1]; - foreach (var propinfo in + foreach (var propInfo in targetType.GetPropertiesWithAttrib(typeof(RequiredServiceAttribute)) .Concat(targetType.GetPropertiesWithAttrib(typeof(OptionalServiceAttribute)))) { - propinfo.GetSetMethod(true).Invoke(target, tmp); + propInfo.GetSetMethod(true).Invoke(target, tmp); } } @@ -35,21 +35,21 @@ namespace BizHawk.Emulation.Common Type targetType = target.GetType(); object[] tmp = new object[1]; - foreach (var propinfo in targetType.GetPropertiesWithAttrib(typeof(RequiredServiceAttribute))) + foreach (var propInfo in targetType.GetPropertiesWithAttrib(typeof(RequiredServiceAttribute))) { - tmp[0] = source.GetService(propinfo.PropertyType); + tmp[0] = source.GetService(propInfo.PropertyType); if (tmp[0] == null) { return false; } - propinfo.GetSetMethod(true).Invoke(target, tmp); + propInfo.GetSetMethod(true).Invoke(target, tmp); } - foreach (var propinfo in targetType.GetPropertiesWithAttrib(typeof(OptionalServiceAttribute))) + foreach (var propInfo in targetType.GetPropertiesWithAttrib(typeof(OptionalServiceAttribute))) { - tmp[0] = source.GetService(propinfo.PropertyType); - propinfo.GetSetMethod(true).Invoke(target, tmp); + tmp[0] = source.GetService(propInfo.PropertyType); + propInfo.GetSetMethod(true).Invoke(target, tmp); } return true; diff --git a/BizHawk.Emulation.Common/Sound/Utilities/DCFilter.cs b/BizHawk.Emulation.Common/Sound/Utilities/DCFilter.cs index 19067916d7..0fb52e423a 100644 --- a/BizHawk.Emulation.Common/Sound/Utilities/DCFilter.cs +++ b/BizHawk.Emulation.Common/Sound/Utilities/DCFilter.cs @@ -15,44 +15,44 @@ namespace BizHawk.Emulation.Common private int _accumL; private int _accumR; - private static int DepthFromFilterwidth(int filterwidth) + private static int DepthFromFilterWidth(int filterWidth) { int ret = -2; - while (filterwidth > 0) + while (filterWidth > 0) { - filterwidth >>= 1; + filterWidth >>= 1; ret++; } return ret; } - public DCFilter(ISoundProvider input, int filterwidth) + public DCFilter(ISoundProvider input, int filterWidth) { if (input == null) { throw new ArgumentNullException(); } - if (filterwidth < 8 || filterwidth > 65536) + if (filterWidth < 8 || filterWidth > 65536) { throw new ArgumentOutOfRangeException(); } - _depth = DepthFromFilterwidth(filterwidth); + _depth = DepthFromFilterWidth(filterWidth); _soundProvider = input; } // Detached mode - public DCFilter(int filterwidth) + public DCFilter(int filterWidth) { - if (filterwidth < 8 || filterwidth > 65536) + if (filterWidth < 8 || filterWidth > 65536) { throw new ArgumentOutOfRangeException(); } - _depth = DepthFromFilterwidth(filterwidth); + _depth = DepthFromFilterWidth(filterWidth); _soundProvider = null; } @@ -67,12 +67,12 @@ namespace BizHawk.Emulation.Common PushThroughSamples(samples, samples, length); } - private void PushThroughSamples(short[] samplesin, short[] samplesout, int length) + private void PushThroughSamples(short[] samplesIn, short[] samplesOut, int length) { for (int i = 0; i < length; i += 2) { - int l = samplesin[i] << 12; - int r = samplesin[i + 1] << 12; + int l = samplesIn[i] << 12; + int r = samplesIn[i + 1] << 12; _accumL -= _accumL >> _depth; _accumR -= _accumR >> _depth; _accumL += l - _latchL; @@ -86,28 +86,28 @@ namespace BizHawk.Emulation.Common // check for clipping if (bigL > 32767) { - samplesout[i] = 32767; + samplesOut[i] = 32767; } else if (bigL < -32768) { - samplesout[i] = -32768; + samplesOut[i] = -32768; } else { - samplesout[i] = (short)bigL; + samplesOut[i] = (short)bigL; } if (bigR > 32767) { - samplesout[i + 1] = 32767; + samplesOut[i + 1] = 32767; } else if (bigR < -32768) { - samplesout[i + 1] = -32768; + samplesOut[i + 1] = -32768; } else { - samplesout[i + 1] = (short)bigR; + samplesOut[i + 1] = (short)bigR; } } } @@ -125,15 +125,12 @@ namespace BizHawk.Emulation.Common public void GetSamplesSync(out short[] samples, out int nsamp) { - short[] sampin; - int nsampin; + _soundProvider.GetSamplesSync(out var sampIn, out var nsampIn); - _soundProvider.GetSamplesSync(out sampin, out nsampin); - - short[] ret = new short[nsampin * 2]; - PushThroughSamples(sampin, ret, nsampin * 2); + short[] ret = new short[nsampIn * 2]; + PushThroughSamples(sampIn, ret, nsampIn * 2); samples = ret; - nsamp = nsampin; + nsamp = nsampIn; } public SyncSoundMode SyncMode => _soundProvider.SyncMode; diff --git a/BizHawk.Emulation.Common/Sound/Utilities/ISynchronizingAudioBuffer.cs b/BizHawk.Emulation.Common/Sound/Utilities/ISynchronizingAudioBuffer.cs index 28558763d5..06f782f64f 100644 --- a/BizHawk.Emulation.Common/Sound/Utilities/ISynchronizingAudioBuffer.cs +++ b/BizHawk.Emulation.Common/Sound/Utilities/ISynchronizingAudioBuffer.cs @@ -75,8 +75,7 @@ namespace BizHawk.Emulation.Common } done++; - short left, right; - _adjustobuf.Dequeue(out left, out right); + _adjustobuf.Dequeue(out var left, out var right); buf[ctr++] = left; buf[ctr++] = right; } diff --git a/BizHawk.Emulation.Common/SystemLookup.cs b/BizHawk.Emulation.Common/SystemLookup.cs index 88f7fe8e6c..929abce021 100644 --- a/BizHawk.Emulation.Common/SystemLookup.cs +++ b/BizHawk.Emulation.Common/SystemLookup.cs @@ -22,19 +22,19 @@ namespace BizHawk.Emulation.Common new SystemInfo { SystemId = "PSX", FullName = "Playstation" }, new SystemInfo { SystemId = "SMS", FullName = "Sega Master System" }, - new SystemInfo { SystemId = "GEN", FullName = "Sega Genesis/Megadrive" }, + new SystemInfo { SystemId = "GEN", FullName = "Sega Genesis/Mega Drive" }, new SystemInfo { SystemId = "SAT", FullName = "Sega Saturn" }, new SystemInfo { SystemId = "PCE", FullName = "PC Engine/TurboGrafx 16" }, - new SystemInfo { SystemId = "Coleco", FullName = "Colecovision" }, + new SystemInfo { SystemId = "Coleco", FullName = "ColecoVision" }, new SystemInfo { SystemId = "TI83", FullName = "TI-83 Calculator" }, new SystemInfo { SystemId = "WSWAN", FullName = "WonderSwan" }, new SystemInfo { SystemId = "C64", FullName = "Commodore 64" }, new SystemInfo { SystemId = "AppleII", FullName = "Apple II" }, - new SystemInfo { SystemId = "INTV", FullName = "Intellivision" }, - new SystemInfo { SystemId = "ZXSpectrum", FullName = "Sinclair ZX Spectrum" }, - new SystemInfo { SystemId = "AmstradCPC", FullName = "Amstrad CPC" }, + new SystemInfo { SystemId = "INTV", FullName = "IntelliVision" }, + new SystemInfo { SystemId = "ZXSpectrum", FullName = "Sinclair ZX Spectrum" }, + new SystemInfo { SystemId = "AmstradCPC", FullName = "Amstrad CPC" }, new SystemInfo { SystemId = "ChannelF", FullName = "Fairchild Channel F"}, }; @@ -43,13 +43,7 @@ namespace BizHawk.Emulation.Common get { var system = _systems.FirstOrDefault(s => s.SystemId == systemId); - - if (system != null) - { - return system; - } - - return new SystemInfo { SystemId = "Unknown", FullName = "Unknown" }; + return system ?? new SystemInfo { SystemId = "Unknown", FullName = "Unknown" }; } } diff --git a/BizHawk.sln.DotSettings b/BizHawk.sln.DotSettings index 9583238608..1473f6e06c 100644 --- a/BizHawk.sln.DotSettings +++ b/BizHawk.sln.DotSettings @@ -183,6 +183,7 @@ True True True + True True True True @@ -194,14 +195,18 @@ True True True + True True True True + True True + True True True True True + True True True True @@ -212,6 +217,7 @@ True True True + True True True True @@ -232,6 +238,7 @@ True True True + True True True True @@ -241,6 +248,9 @@ True True True + True + True + True True True True @@ -251,11 +261,13 @@ True True True + True True True True True True + True True True True From f8379d9fd4bdbbd83d4d228324cd99db481d14ba Mon Sep 17 00:00:00 2001 From: YoshiRulz Date: Thu, 31 Oct 2019 03:30:00 +1000 Subject: [PATCH 161/166] Bump ReSharper analysis to C# 8.0 --- .../BizHawk.Client.ApiHawk.csproj.DotSettings | 2 +- BizHawk.Client.Common/BizHawk.Client.Common.csproj.DotSettings | 2 +- BizHawk.Client.DBMan/BizHawk.Client.DBMan.csproj.DotSettings | 2 +- .../BizHawk.Client.DiscoHawk.csproj.DotSettings | 2 +- .../BizHawk.Client.EmuHawk.csproj.DotSettings | 2 +- BizHawk.Common/BizHawk.Common.csproj.DotSettings | 2 +- .../BizHawk.Emulation.Common.csproj.DotSettings | 2 +- .../BizHawk.Emulation.Cores.csproj.DotSettings | 2 +- .../BizHawk.Emulation.DiscSystem.csproj.DotSettings | 2 +- .../BizHawk.Bizware.BizwareGL.GdiPlus.csproj.DotSettings | 2 +- .../BizHawk.Bizware.BizwareGL.OpenTK.csproj.DotSettings | 2 +- .../BizHawk.Bizware.BizwareGL.SlimDX.csproj.DotSettings | 2 +- .../BizHawk.Bizware.BizwareGL.csproj.DotSettings | 2 +- Version/Version.csproj.DotSettings | 2 +- 14 files changed, 14 insertions(+), 14 deletions(-) diff --git a/BizHawk.Client.ApiHawk/BizHawk.Client.ApiHawk.csproj.DotSettings b/BizHawk.Client.ApiHawk/BizHawk.Client.ApiHawk.csproj.DotSettings index c54c126d26..b9fd6ee4f5 100644 --- a/BizHawk.Client.ApiHawk/BizHawk.Client.ApiHawk.csproj.DotSettings +++ b/BizHawk.Client.ApiHawk/BizHawk.Client.ApiHawk.csproj.DotSettings @@ -1,2 +1,2 @@  - CSharp70 \ No newline at end of file + CSharp80 \ No newline at end of file diff --git a/BizHawk.Client.Common/BizHawk.Client.Common.csproj.DotSettings b/BizHawk.Client.Common/BizHawk.Client.Common.csproj.DotSettings index c54c126d26..b9fd6ee4f5 100644 --- a/BizHawk.Client.Common/BizHawk.Client.Common.csproj.DotSettings +++ b/BizHawk.Client.Common/BizHawk.Client.Common.csproj.DotSettings @@ -1,2 +1,2 @@  - CSharp70 \ No newline at end of file + CSharp80 \ No newline at end of file diff --git a/BizHawk.Client.DBMan/BizHawk.Client.DBMan.csproj.DotSettings b/BizHawk.Client.DBMan/BizHawk.Client.DBMan.csproj.DotSettings index c54c126d26..b9fd6ee4f5 100644 --- a/BizHawk.Client.DBMan/BizHawk.Client.DBMan.csproj.DotSettings +++ b/BizHawk.Client.DBMan/BizHawk.Client.DBMan.csproj.DotSettings @@ -1,2 +1,2 @@  - CSharp70 \ No newline at end of file + CSharp80 \ No newline at end of file diff --git a/BizHawk.Client.DiscoHawk/BizHawk.Client.DiscoHawk.csproj.DotSettings b/BizHawk.Client.DiscoHawk/BizHawk.Client.DiscoHawk.csproj.DotSettings index c54c126d26..b9fd6ee4f5 100644 --- a/BizHawk.Client.DiscoHawk/BizHawk.Client.DiscoHawk.csproj.DotSettings +++ b/BizHawk.Client.DiscoHawk/BizHawk.Client.DiscoHawk.csproj.DotSettings @@ -1,2 +1,2 @@  - CSharp70 \ No newline at end of file + CSharp80 \ No newline at end of file diff --git a/BizHawk.Client.EmuHawk/BizHawk.Client.EmuHawk.csproj.DotSettings b/BizHawk.Client.EmuHawk/BizHawk.Client.EmuHawk.csproj.DotSettings index c54c126d26..b9fd6ee4f5 100644 --- a/BizHawk.Client.EmuHawk/BizHawk.Client.EmuHawk.csproj.DotSettings +++ b/BizHawk.Client.EmuHawk/BizHawk.Client.EmuHawk.csproj.DotSettings @@ -1,2 +1,2 @@  - CSharp70 \ No newline at end of file + CSharp80 \ No newline at end of file diff --git a/BizHawk.Common/BizHawk.Common.csproj.DotSettings b/BizHawk.Common/BizHawk.Common.csproj.DotSettings index c54c126d26..b9fd6ee4f5 100644 --- a/BizHawk.Common/BizHawk.Common.csproj.DotSettings +++ b/BizHawk.Common/BizHawk.Common.csproj.DotSettings @@ -1,2 +1,2 @@  - CSharp70 \ No newline at end of file + CSharp80 \ No newline at end of file diff --git a/BizHawk.Emulation.Common/BizHawk.Emulation.Common.csproj.DotSettings b/BizHawk.Emulation.Common/BizHawk.Emulation.Common.csproj.DotSettings index c54c126d26..b9fd6ee4f5 100644 --- a/BizHawk.Emulation.Common/BizHawk.Emulation.Common.csproj.DotSettings +++ b/BizHawk.Emulation.Common/BizHawk.Emulation.Common.csproj.DotSettings @@ -1,2 +1,2 @@  - CSharp70 \ No newline at end of file + CSharp80 \ No newline at end of file diff --git a/BizHawk.Emulation.Cores/BizHawk.Emulation.Cores.csproj.DotSettings b/BizHawk.Emulation.Cores/BizHawk.Emulation.Cores.csproj.DotSettings index ae23115e0a..c3052f1709 100644 --- a/BizHawk.Emulation.Cores/BizHawk.Emulation.Cores.csproj.DotSettings +++ b/BizHawk.Emulation.Cores/BizHawk.Emulation.Cores.csproj.DotSettings @@ -1,5 +1,5 @@  - CSharp70 + CSharp80 DO_NOT_SHOW \ No newline at end of file diff --git a/BizHawk.Emulation.DiscSystem/BizHawk.Emulation.DiscSystem.csproj.DotSettings b/BizHawk.Emulation.DiscSystem/BizHawk.Emulation.DiscSystem.csproj.DotSettings index c54c126d26..b9fd6ee4f5 100644 --- a/BizHawk.Emulation.DiscSystem/BizHawk.Emulation.DiscSystem.csproj.DotSettings +++ b/BizHawk.Emulation.DiscSystem/BizHawk.Emulation.DiscSystem.csproj.DotSettings @@ -1,2 +1,2 @@  - CSharp70 \ No newline at end of file + CSharp80 \ No newline at end of file diff --git a/Bizware/BizHawk.Bizware.BizwareGL.GdiPlus/BizHawk.Bizware.BizwareGL.GdiPlus.csproj.DotSettings b/Bizware/BizHawk.Bizware.BizwareGL.GdiPlus/BizHawk.Bizware.BizwareGL.GdiPlus.csproj.DotSettings index c54c126d26..b9fd6ee4f5 100644 --- a/Bizware/BizHawk.Bizware.BizwareGL.GdiPlus/BizHawk.Bizware.BizwareGL.GdiPlus.csproj.DotSettings +++ b/Bizware/BizHawk.Bizware.BizwareGL.GdiPlus/BizHawk.Bizware.BizwareGL.GdiPlus.csproj.DotSettings @@ -1,2 +1,2 @@  - CSharp70 \ No newline at end of file + CSharp80 \ No newline at end of file diff --git a/Bizware/BizHawk.Bizware.BizwareGL.OpenTK/BizHawk.Bizware.BizwareGL.OpenTK.csproj.DotSettings b/Bizware/BizHawk.Bizware.BizwareGL.OpenTK/BizHawk.Bizware.BizwareGL.OpenTK.csproj.DotSettings index c54c126d26..b9fd6ee4f5 100644 --- a/Bizware/BizHawk.Bizware.BizwareGL.OpenTK/BizHawk.Bizware.BizwareGL.OpenTK.csproj.DotSettings +++ b/Bizware/BizHawk.Bizware.BizwareGL.OpenTK/BizHawk.Bizware.BizwareGL.OpenTK.csproj.DotSettings @@ -1,2 +1,2 @@  - CSharp70 \ No newline at end of file + CSharp80 \ No newline at end of file diff --git a/Bizware/BizHawk.Bizware.BizwareGL.SlimDX/BizHawk.Bizware.BizwareGL.SlimDX.csproj.DotSettings b/Bizware/BizHawk.Bizware.BizwareGL.SlimDX/BizHawk.Bizware.BizwareGL.SlimDX.csproj.DotSettings index c54c126d26..b9fd6ee4f5 100644 --- a/Bizware/BizHawk.Bizware.BizwareGL.SlimDX/BizHawk.Bizware.BizwareGL.SlimDX.csproj.DotSettings +++ b/Bizware/BizHawk.Bizware.BizwareGL.SlimDX/BizHawk.Bizware.BizwareGL.SlimDX.csproj.DotSettings @@ -1,2 +1,2 @@  - CSharp70 \ No newline at end of file + CSharp80 \ No newline at end of file diff --git a/Bizware/BizHawk.Bizware.BizwareGL/BizHawk.Bizware.BizwareGL.csproj.DotSettings b/Bizware/BizHawk.Bizware.BizwareGL/BizHawk.Bizware.BizwareGL.csproj.DotSettings index c54c126d26..b9fd6ee4f5 100644 --- a/Bizware/BizHawk.Bizware.BizwareGL/BizHawk.Bizware.BizwareGL.csproj.DotSettings +++ b/Bizware/BizHawk.Bizware.BizwareGL/BizHawk.Bizware.BizwareGL.csproj.DotSettings @@ -1,2 +1,2 @@  - CSharp70 \ No newline at end of file + CSharp80 \ No newline at end of file diff --git a/Version/Version.csproj.DotSettings b/Version/Version.csproj.DotSettings index c54c126d26..b9fd6ee4f5 100644 --- a/Version/Version.csproj.DotSettings +++ b/Version/Version.csproj.DotSettings @@ -1,2 +1,2 @@  - CSharp70 \ No newline at end of file + CSharp80 \ No newline at end of file From 41caf0e61617b6b052b7197b0296eb7d99ed9b47 Mon Sep 17 00:00:00 2001 From: YoshiRulz Date: Thu, 31 Oct 2019 03:32:29 +1000 Subject: [PATCH 162/166] Reduce "pause lag" on Paper Mario (#558) by using CopyColorToRDRAM = 1 --- Assets/gamedb/gamedb_n64.txt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Assets/gamedb/gamedb_n64.txt b/Assets/gamedb/gamedb_n64.txt index 511260f3b2..ecc5fc9b51 100644 --- a/Assets/gamedb/gamedb_n64.txt +++ b/Assets/gamedb/gamedb_n64.txt @@ -555,8 +555,8 @@ A5359E35839B40C414EAE498CA633B28176629AA G Olympic Hockey 98 (Japan) N64 Glide_ 7592F4C16B8E040539B5DCC201FAB2965A5E8C8D G Onegai Monsters (Japan) N64 133F17162B2734286F9E94F64ACB1538B11506B2 G Operation WinBack (Europe) (En,Fr,De,Es,It) N64 B8F29E8EFCF51EE9A6A16E2A1E60442B4F304950 G Pachinko 365 Nichi (Japan) N64 -2111D39265A317414D359E35A7D971C4DFA5F9E1 G Paper Mario (Europe) (En,Fr,De,Es) N64 Glide_enable_hacks_for_game=15;Glide_fb_hires_buf_clear=false;Glide_fb_optimize_texrect=false;Glide_swapmode=2;Glide_fb_smart=true;Glide_fb_read_alpha=true;Glide64mk2_enable_hacks_for_game=20;Glide64mk2_hires_buf_clear=false;Glide64mk2_optimize_texrect=false;Glide64mk2_filtering=1;Glide64mk2_swapmode=2;Glide64mk2_fb_smart=true;Glide64mk2_fb_read_alpha=true;Jabo_Clear_Frame=1;GLideN64_CopyColorToRDRAM=2 -3837F44CDA784B466C9A2D99DF70D77C322B97A0 G Paper Mario (USA) N64 RiceFrameBufferOption=3;RiceRenderToTextureOption=3;RiceScreenUpdateSettingHack=4;Glide_enable_hacks_for_game=15;Glide_fb_hires_buf_clear=false;Glide_fb_optimize_texrect=false;Glide_swapmode=2;Glide_fb_smart=true;Glide_fb_read_alpha=true;Glide64mk2_enable_hacks_for_game=20;Glide64mk2_hires_buf_clear=false;Glide64mk2_optimize_texrect=false;Glide64mk2_filtering=1;Glide64mk2_swapmode=2;Glide64mk2_fb_smart=true;Glide64mk2_fb_read_alpha=true;Jabo_Clear_Frame=1;GLideN64_CopyColorToRDRAM=2 +2111D39265A317414D359E35A7D971C4DFA5F9E1 G Paper Mario (Europe) (En,Fr,De,Es) N64 Glide_enable_hacks_for_game=15;Glide_fb_hires_buf_clear=false;Glide_fb_optimize_texrect=false;Glide_swapmode=2;Glide_fb_smart=true;Glide_fb_read_alpha=true;Glide64mk2_enable_hacks_for_game=20;Glide64mk2_hires_buf_clear=false;Glide64mk2_optimize_texrect=false;Glide64mk2_filtering=1;Glide64mk2_swapmode=2;Glide64mk2_fb_smart=true;Glide64mk2_fb_read_alpha=true;Jabo_Clear_Frame=1;GLideN64_CopyColorToRDRAM=1 +3837F44CDA784B466C9A2D99DF70D77C322B97A0 G Paper Mario (USA) N64 RiceFrameBufferOption=3;RiceRenderToTextureOption=3;RiceScreenUpdateSettingHack=4;Glide_enable_hacks_for_game=15;Glide_fb_hires_buf_clear=false;Glide_fb_optimize_texrect=false;Glide_swapmode=2;Glide_fb_smart=true;Glide_fb_read_alpha=true;Glide64mk2_enable_hacks_for_game=20;Glide64mk2_hires_buf_clear=false;Glide64mk2_optimize_texrect=false;Glide64mk2_filtering=1;Glide64mk2_swapmode=2;Glide64mk2_fb_smart=true;Glide64mk2_fb_read_alpha=true;Jabo_Clear_Frame=1;GLideN64_CopyColorToRDRAM=1 7DB4808042B9651B47592E814AC4C125B51D4D2F G Paperboy (Europe) N64 B043C47B9758FA6BB289CA7DBA2068BDA6CAFA3A G Paperboy (USA) N64 9887A0E4BFE3C5E85E31638853574069F6C41CD3 G Parlor! Pro 64 - Pachinko Jikki Simulation Game (Japan) N64 Glide_force_microcheck=true;Glide64mk2_force_microcheck=true;Glide64mk2_filtering=1 From 520ba97caaeebb5a3624aab3edd9879d7ff428a4 Mon Sep 17 00:00:00 2001 From: alyosha-tas Date: Thu, 31 Oct 2019 09:43:25 -0400 Subject: [PATCH 163/166] O2Hawk start --- Assets/gamedb/gamedb_nes.txt | 1 - .../BizHawk.Emulation.Cores.csproj | 39 ++ .../CPUs/Intel8048/Disassembler.cs | 494 ++++++++++++++++++ .../CPUs/Intel8048/Execute.cs | 285 ++++++++++ .../CPUs/Intel8048/I8048.cs | 369 +++++++++++++ .../CPUs/Intel8048/Interrupts.cs | 30 ++ .../CPUs/Intel8048/OP_Tables.cs | 113 ++++ .../CPUs/Intel8048/Operations.cs | 291 +++++++++++ .../CPUs/Intel8048/ReadMe.txt | 1 + .../CPUs/Intel8048/Registers.cs | 86 +++ BizHawk.Emulation.Cores/CPUs/MC6800/MC6800.cs | 13 +- BizHawk.Emulation.Cores/CPUs/MC6809/MC6809.cs | 132 +++-- .../Atari/2600/Atari2600.IStatable.cs | 5 +- .../Consoles/Magnavox/Odyssey2/Audio.cs | 220 ++++++++ .../Magnavox/Odyssey2/HW_Registers.cs | 291 +++++++++++ .../Magnavox/Odyssey2/Mappers/MapperBase.cs | 64 +++ .../Odyssey2/Mappers/Mapper_Default.cs | 80 +++ .../Magnavox/Odyssey2/Mappers/ReadMe.txt | 3 + .../Consoles/Magnavox/Odyssey2/MemoryMap.cs | 59 +++ .../Magnavox/Odyssey2/O2Hawk.ICodeDataLog.cs | 64 +++ .../Magnavox/Odyssey2/O2Hawk.IDebuggable.cs | 77 +++ .../Magnavox/Odyssey2/O2Hawk.IEmulator.cs | 197 +++++++ .../Odyssey2/O2Hawk.IInputPollable.cs | 24 + .../Odyssey2/O2Hawk.IMemoryDomains.cs | 69 +++ .../Magnavox/Odyssey2/O2Hawk.ISaveRam.cs | 37 ++ .../Magnavox/Odyssey2/O2Hawk.ISettable.cs | 92 ++++ .../Magnavox/Odyssey2/O2Hawk.IStatable.cs | 91 ++++ .../Consoles/Magnavox/Odyssey2/O2Hawk.cs | 144 +++++ .../Magnavox/Odyssey2/O2HawkControllerDeck.cs | 81 +++ .../Magnavox/Odyssey2/O2HawkControllers.cs | 217 ++++++++ .../Consoles/Magnavox/Odyssey2/PPU.cs | 272 ++++++++++ .../Consoles/Magnavox/Odyssey2/ReadMe.txt | 1 + .../Consoles/Magnavox/Odyssey2/SerialPort.cs | 150 ++++++ 33 files changed, 4035 insertions(+), 57 deletions(-) create mode 100644 BizHawk.Emulation.Cores/CPUs/Intel8048/Disassembler.cs create mode 100644 BizHawk.Emulation.Cores/CPUs/Intel8048/Execute.cs create mode 100644 BizHawk.Emulation.Cores/CPUs/Intel8048/I8048.cs create mode 100644 BizHawk.Emulation.Cores/CPUs/Intel8048/Interrupts.cs create mode 100644 BizHawk.Emulation.Cores/CPUs/Intel8048/OP_Tables.cs create mode 100644 BizHawk.Emulation.Cores/CPUs/Intel8048/Operations.cs create mode 100644 BizHawk.Emulation.Cores/CPUs/Intel8048/ReadMe.txt create mode 100644 BizHawk.Emulation.Cores/CPUs/Intel8048/Registers.cs create mode 100644 BizHawk.Emulation.Cores/Consoles/Magnavox/Odyssey2/Audio.cs create mode 100644 BizHawk.Emulation.Cores/Consoles/Magnavox/Odyssey2/HW_Registers.cs create mode 100644 BizHawk.Emulation.Cores/Consoles/Magnavox/Odyssey2/Mappers/MapperBase.cs create mode 100644 BizHawk.Emulation.Cores/Consoles/Magnavox/Odyssey2/Mappers/Mapper_Default.cs create mode 100644 BizHawk.Emulation.Cores/Consoles/Magnavox/Odyssey2/Mappers/ReadMe.txt create mode 100644 BizHawk.Emulation.Cores/Consoles/Magnavox/Odyssey2/MemoryMap.cs create mode 100644 BizHawk.Emulation.Cores/Consoles/Magnavox/Odyssey2/O2Hawk.ICodeDataLog.cs create mode 100644 BizHawk.Emulation.Cores/Consoles/Magnavox/Odyssey2/O2Hawk.IDebuggable.cs create mode 100644 BizHawk.Emulation.Cores/Consoles/Magnavox/Odyssey2/O2Hawk.IEmulator.cs create mode 100644 BizHawk.Emulation.Cores/Consoles/Magnavox/Odyssey2/O2Hawk.IInputPollable.cs create mode 100644 BizHawk.Emulation.Cores/Consoles/Magnavox/Odyssey2/O2Hawk.IMemoryDomains.cs create mode 100644 BizHawk.Emulation.Cores/Consoles/Magnavox/Odyssey2/O2Hawk.ISaveRam.cs create mode 100644 BizHawk.Emulation.Cores/Consoles/Magnavox/Odyssey2/O2Hawk.ISettable.cs create mode 100644 BizHawk.Emulation.Cores/Consoles/Magnavox/Odyssey2/O2Hawk.IStatable.cs create mode 100644 BizHawk.Emulation.Cores/Consoles/Magnavox/Odyssey2/O2Hawk.cs create mode 100644 BizHawk.Emulation.Cores/Consoles/Magnavox/Odyssey2/O2HawkControllerDeck.cs create mode 100644 BizHawk.Emulation.Cores/Consoles/Magnavox/Odyssey2/O2HawkControllers.cs create mode 100644 BizHawk.Emulation.Cores/Consoles/Magnavox/Odyssey2/PPU.cs create mode 100644 BizHawk.Emulation.Cores/Consoles/Magnavox/Odyssey2/ReadMe.txt create mode 100644 BizHawk.Emulation.Cores/Consoles/Magnavox/Odyssey2/SerialPort.cs diff --git a/Assets/gamedb/gamedb_nes.txt b/Assets/gamedb/gamedb_nes.txt index b837ef1be5..ec808e4165 100644 --- a/Assets/gamedb/gamedb_nes.txt +++ b/Assets/gamedb/gamedb_nes.txt @@ -305,7 +305,6 @@ sha1:17473C223453D2D80FCB9DCFA317947287DC5C52 Xing He Zhan Shi (China) (Unl) NE sha1:B1C74236FD17FAB4AB9AA6AB28E38864C66D6255 Pocahontus (UNL) NES board=MAPPER182;PRG=256;CHR=256;WRAM=8;PAD_H=1 sha1:5FA23F88432006DCF6874EA36E9E7DA8934427BE Super Donkey Kong (Unl) NES board=MAPPER182;PRG=128;CHR=128;WRAM=8;PAD_H=1 sha1:8A7DAB8B78DA1C5EA159BA9EEC00FF97742245F1 B Super Donkey Kong (Unl) [b1] NES board=MAPPER182;PRG=128;CHR=128;WRAM=8;PAD_H=1 -sha1:8A7DAB8B78DA1C5EA159BA9EEC00FF97742245F1 O Super Donkey Kong (Unl) [o1] NES board=MAPPER182;PRG=128;CHR=128;WRAM=8;PAD_H=1 ;wrong vram info sha1:32D71DD6C5A8D78A918FE1B9D6D6C4A570D9652D Oeka Kids Anpanman no Hiragana Daisuki (J) NES board=MAPPER096;VRAM=32 diff --git a/BizHawk.Emulation.Cores/BizHawk.Emulation.Cores.csproj b/BizHawk.Emulation.Cores/BizHawk.Emulation.Cores.csproj index 157b849a24..0e551be12f 100644 --- a/BizHawk.Emulation.Cores/BizHawk.Emulation.Cores.csproj +++ b/BizHawk.Emulation.Cores/BizHawk.Emulation.Cores.csproj @@ -709,6 +709,38 @@ + + + + + O2Hawk.cs + + + O2Hawk.cs + + + O2Hawk.cs + + + O2Hawk.cs + + + O2Hawk.cs + + + O2Hawk.cs + + + O2Hawk.cs + + + + + + + + + @@ -1607,6 +1639,13 @@ + + + + + + + diff --git a/BizHawk.Emulation.Cores/CPUs/Intel8048/Disassembler.cs b/BizHawk.Emulation.Cores/CPUs/Intel8048/Disassembler.cs new file mode 100644 index 0000000000..bd325ae77d --- /dev/null +++ b/BizHawk.Emulation.Cores/CPUs/Intel8048/Disassembler.cs @@ -0,0 +1,494 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace BizHawk.Emulation.Common.Components.I8048 +{ + public sealed partial class I8048 + { + static string[] table = + { + "NEG DP+i8", // 00 + "???", // 01 + "???", // 02 + "COM DP+i8", // 03 + "LSR DP+i8", // 04 + "???", // 05 + "ROR DP+i8", // 06 + "ASR DP+i8", // 07 + "ASL DP+i8", // 08 + "ROL DP+i8", // 09 + "DEC DP+i8", // 0a + "???", // 0b + "INC DP+i8", // 0c + "TST DP+i8", // 0d + "JMP DP+i8", // 0e + "CLR DP+i8", // 0f + "PAGE 2", // 10 + "PAGE 3", // 11 + "NOP", // 12 + "SYNC", // 13 + "???", // 14 + "???", // 15 + "LBRA i16", // 16 + "LBSR i16", // 17 + "???", // 18 + "DAA", // 19 + "ORCC i8", // 1a + "???", // 1b + "ANDCC i8", // 1c + "SEX", // 1d + "EXG i8", // 1e + "TFR i8", // 1f + "BRA i8", // 20 + "BRN i8", // 21 + "BHI i8", // 22 + "BLS i8", // 23 + "BHS i8", // 24 + "BLO i8", // 25 + "BNE i8", // 26 + "BEQ i8", // 27 + "BVC i8", // 28 + "BVS i8", // 29 + "BPL i8", // 2a + "BMI i8", // 2b + "BGE i8", // 2c + "BLT i8", // 2d + "BGT i8", // 2e + "BLE i8", // 2f + "LEAX ix16", // 30 + "LEAY ix16", // 31 + "LEAS ix16", // 32 + "LEAU ix16", // 33 + "PSHS i8", // 34 + "PULS i8", // 35 + "PSHU i8", // 36 + "PULU i8", // 37 + "???", // 38 + "RTS", // 39 + "ABX", // 3a + "RTI", // 3b + "CWAI i8", // 3c + "MUL", // 3d + "???", // 3e + "SWI1", // 3f + "NEG A", // 40 + "???", // 41 + "???", // 42 + "COM A", // 43 + "LSR A", // 44 + "???", // 45 + "ROR A", // 46 + "ASR A", // 47 + "ASL A", // 48 + "ROL A", // 49 + "DEC A", // 4a + "???", // 4b + "INC A", // 4c + "TST A", // 4d + "???", // 4e + "CLR A", // 4f + "NEG B", // 50 + "???", // 51 + "???", // 52 + "COM B", // 53 + "LSR B", // 54 + "???", // 55 + "ROR B", // 56 + "ASR B", // 57 + "ASL B", // 58 + "ROL B", // 59 + "DEC B", // 5a + "???", // 5b + "INC B", // 5c + "TST B", // 5d + "???", // 5e + "CLR B", // 5f + "NEG ix16", // 60 + "???", // 61 + "???", // 62 + "COM ix16", // 63 + "LSR ix16", // 64 + "???", // 65 + "ROR ix16", // 66 + "ASR ix16", // 67 + "ASL ix16", // 68 + "ROL ix16", // 69 + "DEC ix16", // 6a + "???", // 6b + "INC ix16", // 6c + "TST ix16", // 6d + "JMP ix16", // 6e + "CLR ix16", // 6f + "NEG ex16", // 70 + "???", // 71 + "???", // 72 + "COM ex16", // 73 + "LSR ex16", // 74 + "???", // 75 + "ROR ex16", // 76 + "ASR ex16", // 77 + "ASL ex16", // 78 + "ROL ex16", // 79 + "DEC ex16", // 7a + "???", // 7b + "INC ex16", // 7c + "TST ex16", // 7d + "JMP ex16", // 7e + "CLR ex16", // 7f + "SUB A,i8", // 80 + "CMP A,i8", // 81 + "SBC A,i8", // 82 + "SUB D,i16", // 83 + "AND A,i8", // 84 + "BIT A,i8", // 85 + "LD A,i8", // 86 + "???", // 87 + "EOR A,i8", // 88 + "ADC A,i8", // 89 + "OR A,i8", // 8a + "ADD A,i8", // 8b + "CMP X,i16", // 8c + "BSR i8", // 8d + "LD X,i16", // 8e + "???", // 8f + "SUB A,DP+i8", // 90 + "CMP A,DP+i8", // 91 + "SBC A,DP+i8", // 92 + "SUB D,DP+i8", // 93 + "AND A,DP+i8", // 94 + "BIT A,DP+i8", // 95 + "LD A,DP+i8", // 96 + "ST A,DP+i8", // 97 + "EOR A,DP+i8", // 98 + "ADC A,DP+i8", // 99 + "OR A,DP+i8", // 9a + "ADD A,DP+i8", // 9b + "CMP X,DP+i8", // 9c + "JSR DP+i8", // 9d + "LD X,DP+i8", // 9e + "ST X,DP+i8", // 9f + "SUB A,ix16", // a0 + "CMP A,ix16", // a1 + "SBC A,ix16", // a2 + "SUB D,ix16", // a3 + "AND A,ix16", // a4 + "BIT A,ix16", // a5 + "LD A,ix16", // a6 + "ST A,ix16", // a7 + "EOR A,ix16", // a8 + "ADC A,ix16", // a9 + "OR A,ix16", // aa + "ADD A,ix16", // ab + "CMP X,ix16", // ac + "JSR ix16", // ad + "LD X,ix16", // ae + "ST X,ix16", // af + "SUB A,ex16", // b0 + "CMP A,ex16", // b1 + "SBC A,ex16", // b2 + "SUB D,ex16", // b3 + "AND A,ex16", // b4 + "BIT A,ex16", // b5 + "LD A,ex16", // b6 + "ST A,ex16", // b7 + "EOR A,ex16", // b8 + "ADC A,ex16", // b9 + "OR A,ex16", // ba + "ADD A,ex16", // bb + "CMP X,ex16", // bc + "JSR ex16", // bd + "LD X,ex16", // be + "ST X,ex16", // bf + "SUB B,i8", // c0 + "CMP B,i8", // c1 + "SBC B,i8", // c2 + "ADD D,i16", // c3 + "AND B,i8", // c4 + "BIT B,i8", // c5 + "LD B,i8", // c6 + "???", // c7 + "EOR B,i8", // c8 + "ADC B,i8", // c9 + "OR B,i8", // ca + "ADD B,i8", // cb + "LD D,i16", // cc + "???", // cd + "LD U,i16", // ce + "???", // cf + "SUB B,DP+i8", // d0 + "CMP B,DP+i8", // d1 + "SBC B,DP+i8", // d2 + "ADD D,DP+i8", // d3 + "AND B,DP+i8", // d4 + "BIT B,DP+i8", // d5 + "LD B,DP+i8", // d6 + "ST B,DP+i8", // d7 + "EOR B,DP+i8", // d8 + "ADC B,DP+i8", // d9 + "OR B,DP+i8", // da + "ADD B,DP+i8", // db + "LD D,DP+i8", // dc + "ST D,DP+i8", // dd + "LD U,DP+i8", // de + "ST U,DP+i8", // df + "SUB B,ix16", // e0 + "CMP B,ix16", // e1 + "SBC B,ix16", // e2 + "ADD D,ix16", // e3 + "AND B,ix16", // e4 + "BIT B,ix16", // e5 + "LD B,ix16", // e6 + "ST B,ix16", // e7 + "EOR B,ix16", // e8 + "ADC B,ix16", // e9 + "OR B,ix16", // ea + "ADD B,ix16", // eb + "LD D,ix16", // ec + "ST D,ix16", // ed + "LD U,ix16", // ee + "ST U,ix16", // ef + "SUB B,ex16", // f0 + "CMP B,ex16", // f1 + "SBC B,ex16", // f2 + "ADD D,ex16", // f3 + "AND B,ex16", // f4 + "BIT B,ex16", // f5 + "LD B,ex16", // f6 + "ST B,ex16", // f7 + "EOR B,ex16", // f8 + "ADC B,ex16", // f9 + "OR B,ex16", // fa + "ADD B,ex16", // fb + "LD D,ex16", // fc + "ST D,ex16", // fd + "LD U,ex16", // fe + "ST U,ex16", // ff + }; + + public static string Disassemble(ushort addr, Func reader, out ushort size) + { + ushort origaddr = addr; + List bytes = new List(); + bytes.Add(reader(addr++)); + + string result = table[bytes[0]]; + + if (result.Contains("i8")) + { + byte d = reader(addr++); + bytes.Add(d); + result = result.Replace("i8", string.Format("#{0:X2}h", d)); + } + else if (result.Contains("i16")) + { + byte dhi = reader(addr++); + byte dlo = reader(addr++); + bytes.Add(dhi); + bytes.Add(dlo); + result = result.Replace("i16", string.Format("#{0:X2}{1:X2}h", dhi, dlo)); + } + else if (result.Contains("ex16")) + { + byte dhi = reader(addr++); + byte dlo = reader(addr++); + bytes.Add(dhi); + bytes.Add(dlo); + result = result.Replace("ex16", "(" + string.Format("#{0:X2}{1:X2}h", dhi, dlo) + ")"); + } + else if (result.Contains("ix16")) + { + byte d = reader(addr++); + bytes.Add(d); + + string temp_reg = ""; + + switch ((d >> 5) & 3) + { + case 0: temp_reg = "X"; break; + case 1: temp_reg = "Y"; break; + case 2: temp_reg = "US"; break; + case 3: temp_reg = "SP"; break; + } + + if ((d & 0x80) == 0) + { + short tempdis = (short)(d & 0x1F); + if (tempdis >= 16) + tempdis -= 32; + + result = result.Replace("ix16", temp_reg + " + ea"); + result = result.Replace("ea", string.Format("{0:N}h", tempdis)); + } + else + { + if ((d & 0x10) == 0x10) + { + switch (d & 0xF) + { + case 0x0: + result = result.Replace("ix16", "???"); + break; + case 0x1: + result = result.Replace("ix16","(" + temp_reg + ")++"); + break; + case 0x2: + result = result.Replace("ix16", "???"); + break; + case 0x3: + result = result.Replace("ix16", "--(" + temp_reg + ")"); + break; + case 0x4: + result = result.Replace("ix16", "(" + temp_reg + ")"); + break; + case 0x5: + result = result.Replace("ix16", "(" + temp_reg + " + B)"); + break; + case 0x6: + result = result.Replace("ix16", "(" + temp_reg + " + A)"); + break; + case 0x7: + result = result.Replace("ix16", "???"); + break; + case 0x8: + byte e = reader(addr++); + bytes.Add(e); + result = result.Replace("ix16", "(" + temp_reg + " + ea)"); + result = result.Replace("ea", string.Format("{0:X2}h", e)); + break; + case 0x9: + byte f = reader(addr++); + bytes.Add(f); + byte g = reader(addr++); + bytes.Add(g); + result = result.Replace("ix16", "(" + temp_reg + " + ea)"); + result = result.Replace("ea", string.Format("{0:X2}{1:X2}h", f, g)); + break; + case 0xA: + result = result.Replace("ix16", "???"); + break; + case 0xB: + result = result.Replace("ix16", "(" + temp_reg + " + D)"); + break; + case 0xC: + temp_reg = "PC"; + byte h = reader(addr++); + bytes.Add(h); + result = result.Replace("ix16", "(" + temp_reg + " + ea)"); + result = result.Replace("ea", string.Format("{0:X2}h", h)); + break; + case 0xD: + temp_reg = "PC"; + byte i = reader(addr++); + bytes.Add(i); + byte j = reader(addr++); + bytes.Add(j); + result = result.Replace("ix16", "(" + temp_reg + " + ea)"); + result = result.Replace("ea", string.Format("{0:X2}{1:X2}h", i, j)); + break; + case 0xE: + result = result.Replace("ix16", "???"); + break; + case 0xF: + if (((d >> 5) & 3) == 0) + { + byte k = reader(addr++); + bytes.Add(k); + byte l = reader(addr++); + bytes.Add(l); + result = result.Replace("ix16", "(" + string.Format("{0:X2}{1:X2}h", k, l) + ")"); + } + else + { + result = result.Replace("ix16", "???"); + } + break; + } + } + else + { + switch (d & 0xF) + { + case 0x0: + result = result.Replace("ix16", temp_reg + "+"); + break; + case 0x1: + result = result.Replace("ix16", temp_reg + "++"); + break; + case 0x2: + result = result.Replace("ix16", "-" + temp_reg); + break; + case 0x3: + result = result.Replace("ix16", "--" + temp_reg); + break; + case 0x4: + result = result.Replace("ix16", temp_reg); + break; + case 0x5: + result = result.Replace("ix16", temp_reg + " + B"); + break; + case 0x6: + result = result.Replace("ix16", temp_reg + " + A"); + break; + case 0x7: + result = result.Replace("ix16", "???"); + break; + case 0x8: + byte e = reader(addr++); + bytes.Add(e); + result = result.Replace("ix16", temp_reg + " + ea"); + result = result.Replace("ea", string.Format("{0:X2}h", e)); + break; + case 0x9: + byte f = reader(addr++); + bytes.Add(f); + byte g = reader(addr++); + bytes.Add(g); + result = result.Replace("ix16", temp_reg + " + ea"); + result = result.Replace("ea", string.Format("{0:X2}{1:X2}h", f, g)); + break; + case 0xA: + result = result.Replace("ix16", "???"); + break; + case 0xB: + result = result.Replace("ix16", temp_reg + " + D"); + break; + case 0xC: + temp_reg = "PC"; + byte h = reader(addr++); + bytes.Add(h); + result = result.Replace("ix16", temp_reg + " + ea"); + result = result.Replace("ea", string.Format("{0:X2}h", h)); + break; + case 0xD: + temp_reg = "PC"; + byte i = reader(addr++); + bytes.Add(i); + byte j = reader(addr++); + bytes.Add(j); + result = result.Replace("ix16", temp_reg + " + ea"); + result = result.Replace("ea", string.Format("{0:X2}{1:X2}h", i, j)); + break; + case 0xE: + result = result.Replace("ix16", "???"); + break; + case 0xF: + result = result.Replace("ix16", "???"); + break; + } + } + } + } + + StringBuilder ret = new StringBuilder(); + ret.Append(string.Format("{0:X4}: ", origaddr)); + foreach (var b in bytes) + ret.Append(string.Format("{0:X2} ", b)); + while (ret.Length < 22) + ret.Append(' '); + ret.Append(result); + size = (ushort)(addr - origaddr); + return ret.ToString(); + } + } +} diff --git a/BizHawk.Emulation.Cores/CPUs/Intel8048/Execute.cs b/BizHawk.Emulation.Cores/CPUs/Intel8048/Execute.cs new file mode 100644 index 0000000000..279b9b1d54 --- /dev/null +++ b/BizHawk.Emulation.Cores/CPUs/Intel8048/Execute.cs @@ -0,0 +1,285 @@ +using System; + +namespace BizHawk.Emulation.Common.Components.I8048 +{ + public partial class I8048 + { + public ulong TotalExecutedCycles; + + // variables for executing instructions + public int instr_pntr = 0; + public ushort[] cur_instr = new ushort[60]; + public int opcode_see; + + public int IRQS; + public int irq_pntr; + + ushort reg_d_ad; + ushort reg_h_ad; + ushort reg_l_ad; + + public void FetchInstruction(byte opcode) + { + opcode_see = opcode; + switch (opcode) + { + case 0x00: OP_IMP(IDLE); break; // NOP + case 0x01: ILLEGAL(); break; // ILLEGAL + case 0x02: ILLEGAL(); break; // ILLEGAL + case 0x03: OP_A_DIR(ADD8); break; // ADD A,# + case 0x04: ILLEGAL(); break; // LSR (Direct) + case 0x05: OP_IMP(EI); break; // EI + case 0x06: ILLEGAL(); break; // ROR (Direct) + case 0x07: OP_IMP(DECA); break; // DEC A + case 0x08: ILLEGAL(); break; // ASL , LSL (Direct) + case 0x09: ILLEGAL(); break; // ROL (Direct) + case 0x0A: ILLEGAL(); break; // DEC (Direct) + case 0x0B: ILLEGAL(); break; // ILLEGAL + case 0x0C: ILLEGAL(); break; // INC (Direct) + case 0x0D: ILLEGAL(); break; // TST (Direct) + case 0x0E: ILLEGAL(); break; // JMP (Direct) + case 0x0F: ILLEGAL(); break; // CLR (Direct) + case 0x10: ILLEGAL(); break; // Page 2 + case 0x11: ILLEGAL(); break; // Page 3 + case 0x12: ILLEGAL(); break; // NOP (Inherent) + case 0x13: OP_A_DIR(ADC8); break; // ADC A,# + case 0x14: CALL(0); break; // CALL + case 0x15: OP_IMP(DI); break; // DI + case 0x16: ILLEGAL(); break; // LBRA (Relative) + case 0x17: OP_IMP(INCA); break; // INC A + case 0x18: ILLEGAL(); break; // ILLEGAL + case 0x19: ILLEGAL(); break; // DAA (Inherent) + case 0x1A: ILLEGAL(); break; // ORCC (Immediate) + case 0x1B: ILLEGAL(); break; // ILLEGAL + case 0x1C: ILLEGAL(); break; // ANDCC (Immediate) + case 0x1D: ILLEGAL(); break; // SEX (Inherent) + case 0x1E: ILLEGAL(); break; // EXG (Immediate) + case 0x1F: ILLEGAL(); break; // TFR (Immediate) + case 0x20: ILLEGAL(); break; // BRA (Relative) + case 0x21: ILLEGAL(); break; // BRN (Relative) + case 0x22: ILLEGAL(); break; // BHI (Relative) + case 0x23: ILLEGAL(); break; // BLS (Relative) + case 0x24: ILLEGAL(); break; // BHS , BCC (Relative) + case 0x25: OP_IMP(EN); break; // EN + case 0x26: ILLEGAL(); break; // BNE (Relative) + case 0x27: OP_IMP(CLR); break; // CLR A + case 0x28: ILLEGAL(); break; // BVC (Relative) + case 0x29: ILLEGAL(); break; // BVS (Relative) + case 0x2A: ILLEGAL(); break; // BPL (Relative) + case 0x2B: ILLEGAL(); break; // BMI (Relative) + case 0x2C: ILLEGAL(); break; // BGE (Relative) + case 0x2D: ILLEGAL(); break; // BLT (Relative) + case 0x2E: ILLEGAL(); break; // BGT (Relative) + case 0x2F: ILLEGAL(); break; // BLE (Relative) + case 0x30: ILLEGAL(); break; // LEAX (Indexed) + case 0x31: ILLEGAL(); break; // LEAY (Indexed) + case 0x32: ILLEGAL(); break; // LEAS (Indexed) + case 0x33: ILLEGAL(); break; // LEAU (Indexed) + case 0x34: CALL(1); break; // CALL + case 0x35: OP_IMP(DN); break; // DN + case 0x36: ILLEGAL(); break; // PSHU (Immediate) + case 0x37: OP_IMP(COM); break; // COM A + case 0x38: ILLEGAL(); break; // ILLEGAL + case 0x39: ILLEGAL(); break; // RTS (Inherent) + case 0x3A: ILLEGAL(); break; // ABX (Inherent) + case 0x3B: ILLEGAL(); break; // RTI (Inherent) + case 0x3C: ILLEGAL(); break; // CWAI (Inherent) + case 0x3D: ILLEGAL(); break; // MUL (Inherent) + case 0x3E: ILLEGAL(); break; // ILLEGAL + case 0x3F: ILLEGAL(); break; // SWI (Inherent) + case 0x40: OP_A_R(OR8RAM, R0); break; // OR A,@R0 + case 0x41: OP_A_R(OR8RAM, R1); break; // OR A,@R1 + case 0x42: ILLEGAL(); break; // ILLEGAL + case 0x43: OP_A_DIR(OR8); break; // OR A,# + case 0x44: ILLEGAL(); break; // LSRA (Inherent) + case 0x45: ILLEGAL(); break; // ILLEGAL + case 0x46: ILLEGAL(); break; // RORA (Inherent) + case 0x47: OP_IMP(SWP); break; // SWP + case 0x48: OP_A_R(OR8, R0); break; // OR A,R0 + case 0x49: OP_A_R(OR8, R1); break; // OR A,R1 + case 0x4A: OP_A_R(OR8, R2); break; // OR A,R2 + case 0x4B: OP_A_R(OR8, R3); break; // OR A,R3 + case 0x4C: OP_A_R(OR8, R4); break; // OR A,R4 + case 0x4D: OP_A_R(OR8, R5); break; // OR A,R5 + case 0x4E: OP_A_R(OR8, R6); break; // OR A,R6 + case 0x4F: OP_A_R(OR8, R7); break; // OR A,R7 + case 0x50: OP_A_R(AND8RAM, R0); break; // AND A,@R0 + case 0x51: OP_A_R(AND8RAM, R1); break; // AND A,@R1 + case 0x52: ILLEGAL(); break; // ILLEGAL + case 0x53: OP_A_DIR(AND8); break; // AND A,# + case 0x54: CALL(2); break; // CALL + case 0x55: ILLEGAL(); break; // ILLEGAL + case 0x56: ILLEGAL(); break; // RORB (Inherent) + case 0x57: OP_IMP(DA); break; // DA A + case 0x58: OP_A_R(AND8, R0); break; // AND A,R0 + case 0x59: OP_A_R(AND8, R1); break; // AND A,R1 + case 0x5A: OP_A_R(AND8, R2); break; // AND A,R2 + case 0x5B: OP_A_R(AND8, R3); break; // AND A,R3 + case 0x5C: OP_A_R(AND8, R4); break; // AND A,R4 + case 0x5D: OP_A_R(AND8, R5); break; // AND A,R5 + case 0x5E: OP_A_R(AND8, R6); break; // AND A,R6 + case 0x5F: OP_A_R(AND8, R7); break; // AND A,R7 + case 0x60: OP_A_R(ADD8RAM, R0); break; // ADD A,@R0 + case 0x61: OP_A_R(ADD8RAM, R1); break; // ADD A,@R1 + case 0x62: ILLEGAL(); break; // ILLEGAL + case 0x63: ILLEGAL(); break; // COM (Indexed) + case 0x64: ILLEGAL(); break; // LSR (Indexed) + case 0x65: ILLEGAL(); break; // ILLEGAL + case 0x66: ILLEGAL(); break; // ROR (Indexed) + case 0x67: OP_IMP(RRC); break; // RRC + case 0x68: OP_A_R(ADD8, R0); break; // ADD A,R0 + case 0x69: OP_A_R(ADD8, R1); break; // ADD A,R1 + case 0x6A: OP_A_R(ADD8, R2); break; // ADD A,R2 + case 0x6B: OP_A_R(ADD8, R3); break; // ADD A,R3 + case 0x6C: OP_A_R(ADD8, R4); break; // ADD A,R4 + case 0x6D: OP_A_R(ADD8, R5); break; // ADD A,R5 + case 0x6E: OP_A_R(ADD8, R6); break; // ADD A,R6 + case 0x6F: OP_A_R(ADD8, R7); break; // ADD A,R7 + case 0x70: OP_A_R(ADC8RAM, R0); break; // ADC A,@R0 + case 0x71: OP_A_R(ADC8RAM, R1); break; // ADC A,@R1 + case 0x72: ILLEGAL(); break; // ILLEGAL + case 0x73: ILLEGAL(); break; // COM (Extended) + case 0x74: CALL(3); break; // CALL + case 0x75: ILLEGAL(); break; // ILLEGAL + case 0x76: ILLEGAL(); break; // ROR (Extended) + case 0x77: OP_IMP(ROR); break; // ROR + case 0x78: OP_A_R(ADC8, R0); break; // ADC A,R0 + case 0x79: OP_A_R(ADC8, R1); break; // ADC A,R1 + case 0x7A: OP_A_R(ADC8, R2); break; // ADC A,R2 + case 0x7B: OP_A_R(ADC8, R3); break; // ADC A,R3 + case 0x7C: OP_A_R(ADC8, R4); break; // ADC A,R4 + case 0x7D: OP_A_R(ADC8, R5); break; // ADC A,R5 + case 0x7E: OP_A_R(ADC8, R6); break; // ADC A,R6 + case 0x7F: OP_A_R(ADC8, R7); break; // ADC A,R7 + case 0x80: ILLEGAL(); break; // SUBA (Immediate) + case 0x81: ILLEGAL(); break; // CMPA (Immediate) + case 0x82: ILLEGAL(); break; // SBCA (Immediate) + case 0x83: ILLEGAL(); break; // SUBD (Immediate) + case 0x84: ILLEGAL(); break; // ANDA (Immediate) + case 0x85: OP_IMP(CL0); break; // CLR F0 + case 0x86: ILLEGAL(); break; // LDA (Immediate) + case 0x87: ILLEGAL(); break; // ILLEGAL + case 0x88: OP_PB_DIR(OR8, BUS); break; // OR BUS,# + case 0x89: OP_PB_DIR(OR8, P1); break; // OR P1,# + case 0x8A: OP_PB_DIR(OR8, P2); break; // OR P2,# + case 0x8B: ILLEGAL(); break; // ILLEGAL + case 0x8C: OP_EXP_A(OR8, P4); break; // OR P4,A + case 0x8D: OP_EXP_A(OR8, P5); break; // OR P5,A + case 0x8E: OP_EXP_A(OR8, P6); break; // OR P6,A + case 0x8F: OP_EXP_A(OR8, P7); break; // OR P7,A + case 0x90: ILLEGAL(); break; // SUBA (Direct) + case 0x91: ILLEGAL(); break; // CMPA (Direct) + case 0x92: ILLEGAL(); break; // SBCA (Direct) + case 0x93: ILLEGAL(); break; // SUBD (Direct) + case 0x94: CALL(4); break; // CALL + case 0x95: OP_IMP(CM0); break; // COM F0 + case 0x96: ILLEGAL(); break; // LDA (Direct) + case 0x97: OP_IMP(CLC); break; // CLR C + case 0x98: OP_PB_DIR(AND8, BUS); break; // AND BUS,# + case 0x99: OP_PB_DIR(AND8, P1); break; // AND P1,# + case 0x9A: OP_PB_DIR(AND8, P2); break; // AND P2,# + case 0x9B: ILLEGAL(); break; // ILLEGAL + case 0x9C: OP_EXP_A(AND8, P4); break; // AND P4,A + case 0x9D: OP_EXP_A(AND8, P5); break; // AND P5,A + case 0x9E: OP_EXP_A(AND8, P6); break; // AND P6,A + case 0x9F: OP_EXP_A(AND8, P7); break; // AND P7,A + case 0xA0: ILLEGAL(); break; // SUBA (Indexed) + case 0xA1: ILLEGAL(); break; // CMPA (Indexed) + case 0xA2: ILLEGAL(); break; // SBCA (Indexed) + case 0xA3: ILLEGAL(); break; // SUBD (Indexed) + case 0xA4: ILLEGAL(); break; // ANDA (Indexed) + case 0xA5: OP_IMP(CL1); break; // CLR F1 + case 0xA6: ILLEGAL(); break; // LDA (Indexed) + case 0xA7: OP_IMP(CMC); break; // COM C + case 0xA8: ILLEGAL(); break; // EORA (Indexed) + case 0xA9: ILLEGAL(); break; // ADCA (Indexed) + case 0xAA: ILLEGAL(); break; // ORA (Indexed) + case 0xAB: ILLEGAL(); break; // ADDA (Indexed) + case 0xAC: ILLEGAL(); break; // CMPX (Indexed) + case 0xAD: ILLEGAL(); break; // JSR (Indexed) + case 0xAE: ILLEGAL(); break; // LDX (Indexed) + case 0xAF: ILLEGAL(); break; // STX (Indexed) + case 0xB0: ILLEGAL(); break; // SUBA (Extended) + case 0xB1: ILLEGAL(); break; // CMPA (Extended) + case 0xB2: ILLEGAL(); break; // SBCA (Extended) + case 0xB3: ILLEGAL(); break; // SUBD (Extended) + case 0xB4: CALL(5); break; // CALL + case 0xB5: OP_IMP(CM1); break; // COM F1 + case 0xB6: ILLEGAL(); break; // LDA (Extended) + case 0xB7: ILLEGAL(); break; // STA (Extended) + case 0xB8: ILLEGAL(); break; // EORA (Extended) + case 0xB9: ILLEGAL(); break; // ADCA (Extended) + case 0xBA: ILLEGAL(); break; // ORA (Extended) + case 0xBB: ILLEGAL(); break; // ADDA (Extended) + case 0xBC: ILLEGAL(); break; // CMPX (Extended) + case 0xBD: ILLEGAL(); break; // JSR (Extended) + case 0xBE: ILLEGAL(); break; // LDX (Extended) + case 0xBF: ILLEGAL(); break; // STX (Extended) + case 0xC0: ILLEGAL(); break; // SUBB (Immediate) + case 0xC1: ILLEGAL(); break; // CMPB (Immediate) + case 0xC2: ILLEGAL(); break; // SBCB (Immediate) + case 0xC3: ILLEGAL(); break; // ADDD (Immediate) + case 0xC4: ILLEGAL(); break; // ANDB (Immediate) + case 0xC5: ILLEGAL(); break; // BITB (Immediate) + case 0xC6: ILLEGAL(); break; // LDB (Immediate) + case 0xC7: ILLEGAL(); break; // ILLEGAL + case 0xC8: OP_R_IMP(DEC8, R0); break; // DEC R0 + case 0xC9: OP_R_IMP(DEC8, R1); break; // DEC R1 + case 0xCA: OP_R_IMP(DEC8, R2); break; // DEC R2 + case 0xCB: OP_R_IMP(DEC8, R3); break; // DEC R3 + case 0xCC: OP_R_IMP(DEC8, R4); break; // DEC R4 + case 0xCD: OP_R_IMP(DEC8, R5); break; // DEC R5 + case 0xCE: OP_R_IMP(DEC8, R6); break; // DEC R6 + case 0xCF: OP_R_IMP(DEC8, R7); break; // DEC R7 + case 0xD0: OP_A_R(XOR8RAM, R0); break; // XOR A,@R0 + case 0xD1: OP_A_R(XOR8RAM, R1); break; // XOR A,@R1 + case 0xD2: ILLEGAL(); break; // ILLEGAL + case 0xD3: OP_A_DIR(XOR8); break; // XOR A,# + case 0xD4: CALL(6); break; // CALL + case 0xD5: ILLEGAL(); break; // BITB (Direct) + case 0xD6: ILLEGAL(); break; // LDB (Direct) + case 0xD7: ILLEGAL(); break; // STB (Direct) + case 0xD8: OP_A_R(XOR8, R0); break; // XOR A,R0 + case 0xD9: OP_A_R(XOR8, R1); break; // XOR A,R1 + case 0xDA: OP_A_R(XOR8, R2); break; // XOR A,R2 + case 0xDB: OP_A_R(XOR8, R3); break; // XOR A,R3 + case 0xDC: OP_A_R(XOR8, R4); break; // XOR A,R4 + case 0xDD: OP_A_R(XOR8, R5); break; // XOR A,R5 + case 0xDE: OP_A_R(XOR8, R6); break; // XOR A,R6 + case 0xDF: OP_A_R(XOR8, R7); break; // XOR A,R7 + case 0xE0: ILLEGAL(); break; // SUBB (Indexed) + case 0xE1: ILLEGAL(); break; // CMPB (Indexed) + case 0xE2: ILLEGAL(); break; // SBCB (Indexed) + case 0xE3: ILLEGAL(); break; // ADDD (Indexed) + case 0xE4: ILLEGAL(); break; // ANDB (Indexed) + case 0xE5: ILLEGAL(); break; // BITB (Indexed) + case 0xE6: ILLEGAL(); break; // LDB (Indexed) + case 0xE7: OP_IMP(ROL); break; // ROL + case 0xE8: ILLEGAL(); break; // EORB (Indexed) + case 0xE9: ILLEGAL(); break; // ADCB (Indexed) + case 0xEA: ILLEGAL(); break; // ORB (Indexed) + case 0xEB: ILLEGAL(); break; // ADDB (Indexed) + case 0xEC: ILLEGAL(); break; // LDD (Indexed) + case 0xED: ILLEGAL(); break; // STD (Indexed) + case 0xEE: ILLEGAL(); break; // LDU (Indexed) + case 0xEF: ILLEGAL(); break; // STU (Indexed) + case 0xF0: ILLEGAL(); break; // SUBB (Extended) + case 0xF1: ILLEGAL(); break; // CMPB (Extended) + case 0xF2: ILLEGAL(); break; // SBCB (Extended) + case 0xF3: ILLEGAL(); break; // ADDD (Extended) + case 0xF4: CALL(7); break; // CALL + case 0xF5: ILLEGAL(); break; // BITB (Extended) + case 0xF6: ILLEGAL(); break; // LDB (Extended) + case 0xF7: OP_IMP(RLC); break; // RLC + case 0xF8: ILLEGAL(); break; // EORB (Extended) + case 0xF9: ILLEGAL(); break; // ADCB (Extended) + case 0xFA: ILLEGAL(); break; // ORB (Extended) + case 0xFB: ILLEGAL(); break; // ADDB (Extended) + case 0xFC: ILLEGAL(); break; // LDD (Extended) + case 0xFD: ILLEGAL(); break; // STD (Extended) + case 0xFE: ILLEGAL(); break; // LDU (Extended) + case 0xFF: ILLEGAL(); break; // STU (Extended) + } + } + } +} \ No newline at end of file diff --git a/BizHawk.Emulation.Cores/CPUs/Intel8048/I8048.cs b/BizHawk.Emulation.Cores/CPUs/Intel8048/I8048.cs new file mode 100644 index 0000000000..28ffdd7633 --- /dev/null +++ b/BizHawk.Emulation.Cores/CPUs/Intel8048/I8048.cs @@ -0,0 +1,369 @@ +using System; + +using BizHawk.Common; + +// Intel Corp 8048 +namespace BizHawk.Emulation.Common.Components.I8048 +{ + public sealed partial class I8048 + { + // operations that can take place in an instruction + public const ushort IDLE = 0; + public const ushort OP = 1; + public const ushort RD = 2; + public const ushort WR = 3; + public const ushort TR = 4; + public const ushort ADD16BR = 5; + public const ushort ADD8 = 6; + public const ushort ADD8RAM = 7; + public const ushort ADC8 = 8; + public const ushort ADC8RAM = 9; + public const ushort INC16 = 10; + public const ushort INC8 = 11; + public const ushort INCA = 12; + public const ushort DEC16 = 13; + public const ushort DEC8 = 14; + public const ushort DECA = 15; + public const ushort ROL = 16; + public const ushort ROR = 17; + public const ushort RLC = 18; + public const ushort RRC = 19; + public const ushort SWP = 20; + public const ushort COM = 21; + public const ushort CMC = 22; + public const ushort CM0 = 23; + public const ushort CM1 = 24; + public const ushort DA = 25; + public const ushort AND8 = 26; + public const ushort AND8RAM = 27; + public const ushort XOR8 = 28; + public const ushort XOR8RAM = 29; + public const ushort OR8 = 30; + public const ushort OR8RAM = 31; + public const ushort ASL = 32; + public const ushort ASR = 33; + public const ushort LSR = 34; + public const ushort BIT = 35; + public const ushort RD_INC = 36; + public const ushort SET_ADDR = 37; + public const ushort NEG = 38; + public const ushort TST = 39; + public const ushort CLR = 40; + public const ushort CLC = 41; + public const ushort CL0 = 42; + public const ushort CL1 = 43; + public const ushort EI = 44; + public const ushort EN = 45; + public const ushort DI = 46; + public const ushort DN = 47; + public const ushort TFR = 48; + public const ushort ADD8BR = 49; + public const ushort ABX = 50; + public const ushort JPE = 51; + public const ushort MSK = 52; + public const ushort CMP8 = 53; + public const ushort SUB16 = 54; + public const ushort ADD16 = 55; + public const ushort CMP16 = 56; + public const ushort CMP16D = 57; + public const ushort CLR_E = 63; + + public I8048() + { + Reset(); + } + + public void Reset() + { + ResetRegisters(); + ResetInterrupts(); + TotalExecutedCycles = 0; + Regs[PC] = 0xFFFE; + PopulateCURINSTR(IDLE, + IDLE, + IDLE, + RD_INC, ALU, PC, + RD_INC, ALU2, PC, + SET_ADDR, PC, ALU, ALU2); + + IRQS = 6; + instr_pntr = irq_pntr = 0; + } + + // Memory Access + + public Func ReadMemory; + public Action WriteMemory; + public Func PeekMemory; + public Func DummyReadMemory; + + //this only calls when the first byte of an instruction is fetched. + public Action OnExecFetch; + + public void UnregisterMemoryMapper() + { + ReadMemory = null; + ReadMemory = null; + PeekMemory = null; + DummyReadMemory = null; + } + + public void SetCallbacks + ( + Func ReadMemory, + Func DummyReadMemory, + Func PeekMemory, + Action WriteMemory + ) + { + this.ReadMemory = ReadMemory; + this.DummyReadMemory = DummyReadMemory; + this.PeekMemory = PeekMemory; + this.WriteMemory = WriteMemory; + } + + //a little CDL related stuff + public delegate void DoCDLCallbackType(ushort addr, I8048.eCDLogMemFlags flags); + + public DoCDLCallbackType CDLCallback; + + public enum eCDLogMemFlags + { + FetchFirst = 1, + FetchOperand = 2, + Data = 4, + Write = 8 + }; + + // Execute instructions + public void ExecuteOne() + { + //Console.Write(opcode_see + " "); + //Console.WriteLine(Regs[PC] + " "); + switch (cur_instr[instr_pntr++]) + { + case IDLE: + // do nothing + break; + case OP: + // Read the opcode of the next instruction + if (OnExecFetch != null) OnExecFetch(PC); + if (TraceCallback != null) TraceCallback(State()); + if (CDLCallback != null) CDLCallback(PC, eCDLogMemFlags.FetchFirst); + FetchInstruction(ReadMemory(Regs[PC]++)); + instr_pntr = 0; + irq_pntr = -1; + break; + case RD: + Read_Func(cur_instr[instr_pntr++], cur_instr[instr_pntr++]); + break; + case RD_INC: + Read_Inc_Func(cur_instr[instr_pntr++], cur_instr[instr_pntr++]); + break; + case WR: + Write_Func(cur_instr[instr_pntr++], cur_instr[instr_pntr++]); + break; + case TR: + TR_Func(cur_instr[instr_pntr++], cur_instr[instr_pntr++]); + break; + case TFR: + TFR_Func(cur_instr[instr_pntr++]); + break; + case SET_ADDR: + reg_d_ad = cur_instr[instr_pntr++]; + reg_h_ad = cur_instr[instr_pntr++]; + reg_l_ad = cur_instr[instr_pntr++]; + + // Console.WriteLine(reg_d_ad + " " + reg_h_ad + " " + reg_l_ad); + // Console.WriteLine(Regs[reg_d_ad] + " " + Regs[reg_h_ad] + " " + Regs[reg_l_ad]); + + Regs[reg_d_ad] = (ushort)((Regs[reg_h_ad] << 8) | Regs[reg_l_ad]); + break; + case TST: + TST_Func(cur_instr[instr_pntr++]); + break; + case CLR: + CLR_Func(cur_instr[instr_pntr++]); + break; + case CLR_E: + + break; + case ADD16BR: + ADD16BR_Func(cur_instr[instr_pntr++], cur_instr[instr_pntr++]); + break; + case ADD8BR: + ADD8BR_Func(cur_instr[instr_pntr++], cur_instr[instr_pntr++]); + break; + case ADD8: + ADD8_Func(cur_instr[instr_pntr++], cur_instr[instr_pntr++]); + break; + case ADC8: + ADC8_Func(cur_instr[instr_pntr++], cur_instr[instr_pntr++]); + break; + case CMP8: + CMP8_Func(cur_instr[instr_pntr++], cur_instr[instr_pntr++]); + break; + case INC16: + INC16_Func(cur_instr[instr_pntr++]); + break; + case INC8: + INC8_Func(cur_instr[instr_pntr++]); + break; + case DEC16: + DEC16_Func(cur_instr[instr_pntr++]); + break; + case CMP16: + CMP16_Func(cur_instr[instr_pntr++], cur_instr[instr_pntr++]); + break; + case DEC8: + DEC8_Func(cur_instr[instr_pntr++]); + break; + case ROL: + ROL_Func(cur_instr[instr_pntr++]); + break; + case ROR: + ROR_Func(cur_instr[instr_pntr++]); + break; + case COM: + COM_Func(cur_instr[instr_pntr++]); + break; + case DA: + DA_Func(cur_instr[instr_pntr++]); + break; + case AND8: + AND8_Func(cur_instr[instr_pntr++], cur_instr[instr_pntr++]); + break; + case XOR8: + XOR8_Func(cur_instr[instr_pntr++], cur_instr[instr_pntr++]); + break; + case OR8: + OR8_Func(cur_instr[instr_pntr++], cur_instr[instr_pntr++]); + break; + case ASL: + ASL_Func(cur_instr[instr_pntr++]); + break; + case ASR: + ASR_Func(cur_instr[instr_pntr++]); + break; + case LSR: + LSR_Func(cur_instr[instr_pntr++]); + break; + case BIT: + BIT_Func(cur_instr[instr_pntr++], cur_instr[instr_pntr++]); + break; + } + + if (++irq_pntr == IRQS) + { + // then regular IRQ + if (IRQPending && IntEn) + { + IRQPending = false; + + if (TraceCallback != null) { TraceCallback(new TraceInfo { Disassembly = "====IRQ====", RegisterInfo = "" }); } + + IRQ_(); + IRQCallback(); + instr_pntr = irq_pntr = 0; + } + // otherwise start the next instruction + else + { + PopulateCURINSTR(OP); + instr_pntr = irq_pntr = 0; + IRQS = -1; + } + } + + TotalExecutedCycles++; + } + + // tracer stuff + + public Action TraceCallback; + + public string TraceHeader + { + get { return "MC6809: PC, machine code, mnemonic, operands, registers (A, B, X, Y, US, SP, DP, CC), Cy, flags (EFHINZVC)"; } + } + + public TraceInfo State(bool disassemble = true) + { + ushort notused; + + return new TraceInfo + { + Disassembly = $"{(disassemble ? Disassemble(Regs[PC], ReadMemory, out notused) : "---")} ".PadRight(50), + RegisterInfo = string.Format( + "A:{0:X2} R0:{1:X2} R1:{2:X2} R2:{3:X2} R3:{4:X2} R4:{5:X2} R5:{6:X2} R6:{7:X2} R7:{8:X2} PSW:{9:X4} Cy:{10} {11}{12}{13}{14} {15}{16}{17}{18}", + Regs[A], + Regs[R0], + Regs[R1], + Regs[R2], + Regs[R3], + Regs[R4], + Regs[R5], + Regs[R6], + Regs[R7], + Regs[PSW], + TotalExecutedCycles, + FlagC ? "C" : "c", + FlagAC ? "A" : "a", + FlagF0 ? "F" : "f", + FlagBS ? "B" : "b", + IntEn ? "I" : "i", + F1 ? "F" : "f", + T0 ? "T" : "t", + T1 ? "T" : "t" + ) + }; + } + + /// + /// Optimization method to set cur_instr + /// + private void PopulateCURINSTR(ushort d0 = 0, ushort d1 = 0, ushort d2 = 0, ushort d3 = 0, ushort d4 = 0, ushort d5 = 0, ushort d6 = 0, ushort d7 = 0, ushort d8 = 0, + ushort d9 = 0, ushort d10 = 0, ushort d11 = 0, ushort d12 = 0, ushort d13 = 0, ushort d14 = 0, ushort d15 = 0, ushort d16 = 0, ushort d17 = 0, ushort d18 = 0, + ushort d19 = 0, ushort d20 = 0, ushort d21 = 0, ushort d22 = 0, ushort d23 = 0, ushort d24 = 0, ushort d25 = 0, ushort d26 = 0, ushort d27 = 0, ushort d28 = 0, + ushort d29 = 0, ushort d30 = 0, ushort d31 = 0, ushort d32 = 0, ushort d33 = 0, ushort d34 = 0, ushort d35 = 0, ushort d36 = 0, ushort d37 = 0, ushort d38 = 0) + { + cur_instr[0] = d0; cur_instr[1] = d1; cur_instr[2] = d2; + cur_instr[3] = d3; cur_instr[4] = d4; cur_instr[5] = d5; + cur_instr[6] = d6; cur_instr[7] = d7; cur_instr[8] = d8; + cur_instr[9] = d9; cur_instr[10] = d10; cur_instr[11] = d11; + cur_instr[12] = d12; cur_instr[13] = d13; cur_instr[14] = d14; + cur_instr[15] = d15; cur_instr[16] = d16; cur_instr[17] = d17; + cur_instr[18] = d18; cur_instr[19] = d19; cur_instr[20] = d20; + cur_instr[21] = d21; cur_instr[22] = d22; cur_instr[23] = d23; + cur_instr[24] = d24; cur_instr[25] = d25; cur_instr[26] = d26; + cur_instr[27] = d27; cur_instr[28] = d28; cur_instr[29] = d29; + cur_instr[30] = d30; cur_instr[31] = d31; cur_instr[32] = d32; + cur_instr[33] = d33; cur_instr[34] = d34; cur_instr[35] = d35; + cur_instr[36] = d36; cur_instr[37] = d37; cur_instr[38] = d38; + } + + // State Save/Load + public void SyncState(Serializer ser) + { + ser.BeginSection("MC6809"); + + ser.Sync(nameof(IntEn), ref IntEn); + ser.Sync(nameof(IRQPending), ref IRQPending); + + ser.Sync(nameof(instr_pntr), ref instr_pntr); + ser.Sync(nameof(cur_instr), ref cur_instr, false); + ser.Sync(nameof(opcode_see), ref opcode_see); + ser.Sync(nameof(IRQS), ref IRQS); + ser.Sync(nameof(irq_pntr), ref irq_pntr); + + ser.Sync(nameof(Regs), ref Regs, false); + ser.Sync(nameof(RAM), ref RAM, false); + ser.Sync(nameof(F1), ref F1); + ser.Sync(nameof(T0), ref T0); + ser.Sync(nameof(T1), ref T1); + ser.Sync(nameof(TotalExecutedCycles), ref TotalExecutedCycles); + + ser.EndSection(); + } + } +} diff --git a/BizHawk.Emulation.Cores/CPUs/Intel8048/Interrupts.cs b/BizHawk.Emulation.Cores/CPUs/Intel8048/Interrupts.cs new file mode 100644 index 0000000000..ca157fb333 --- /dev/null +++ b/BizHawk.Emulation.Cores/CPUs/Intel8048/Interrupts.cs @@ -0,0 +1,30 @@ +using System; + +namespace BizHawk.Emulation.Common.Components.I8048 +{ + public partial class I8048 + { + private void IRQ_() + { + Regs[ADDR] = 0xFFF8; + PopulateCURINSTR(IDLE, + IDLE, + IDLE, + RD_INC, ALU, ADDR, + RD_INC, ALU2, ADDR, + SET_ADDR, PC, ALU, ALU2); + + IRQS = 19; + } + + public bool IRQPending; + public bool IntEn; + + public Action IRQCallback = delegate () { }; + + private void ResetInterrupts() + { + IntEn = true; + } + } +} \ No newline at end of file diff --git a/BizHawk.Emulation.Cores/CPUs/Intel8048/OP_Tables.cs b/BizHawk.Emulation.Cores/CPUs/Intel8048/OP_Tables.cs new file mode 100644 index 0000000000..d122a47d61 --- /dev/null +++ b/BizHawk.Emulation.Cores/CPUs/Intel8048/OP_Tables.cs @@ -0,0 +1,113 @@ +using System; +using BizHawk.Common.NumberExtensions; + +namespace BizHawk.Emulation.Common.Components.I8048 +{ + public partial class I8048 + { + // this contains the vectors of instrcution operations + // NOTE: This list is NOT confirmed accurate for each individual cycle + public void ILLEGAL() + { + PopulateCURINSTR(IDLE, + IDLE, + IDLE, + IDLE); + + IRQS = 4; + } + + public void OP_IMP(ushort oper) + { + PopulateCURINSTR(IDLE, + IDLE, + IDLE, + oper); + + IRQS = 4; + } + + public void OP_R_IMP(ushort oper, ushort reg) + { + PopulateCURINSTR(IDLE, + IDLE, + IDLE, + oper, reg); + + IRQS = 4; + } + + + public void OP_A_R(ushort oper, ushort reg) + { + PopulateCURINSTR(IDLE, + IDLE, + IDLE, + oper,A,reg); + + IRQS = 4; + } + + public void OP_A_DIR(ushort oper) + { + PopulateCURINSTR(IDLE, + IDLE, + IDLE, + RD, ALU, PC, + INC16, PC, + IDLE, + IDLE, + IDLE, + oper, A, ALU); + + IRQS = 9; + } + + public void OP_PB_DIR(ushort oper, ushort reg) + { + PopulateCURINSTR(IDLE, + IDLE, + IDLE, + RD, ALU, PC, + INC16, PC, + IDLE, + IDLE, + IDLE, + oper, reg, ALU); + + IRQS = 9; + } + + public void OP_EXP_A(ushort oper, ushort reg) + { + // Lower 4 bits only + PopulateCURINSTR(IDLE, + IDLE, + IDLE, + TR, ALU, A, + IDLE, + IDLE, + MSK, ALU, + IDLE, + oper, reg, ALU); + + IRQS = 9; + } + + public void CALL(ushort dest_h) + { + // Lower 4 bits only + PopulateCURINSTR(IDLE, + IDLE, + IDLE, + TR, ALU, A, + IDLE, + IDLE, + MSK, ALU, + IDLE, + ALU); + + IRQS = 9; + } + } +} diff --git a/BizHawk.Emulation.Cores/CPUs/Intel8048/Operations.cs b/BizHawk.Emulation.Cores/CPUs/Intel8048/Operations.cs new file mode 100644 index 0000000000..24f54091c9 --- /dev/null +++ b/BizHawk.Emulation.Cores/CPUs/Intel8048/Operations.cs @@ -0,0 +1,291 @@ +using System; +using BizHawk.Common.NumberExtensions; + +namespace BizHawk.Emulation.Common.Components.I8048 +{ + public partial class I8048 + { + public void Read_Func(ushort dest, ushort src) + { + if (CDLCallback != null) + { + if (src == PC) CDLCallback(Regs[src], eCDLogMemFlags.FetchOperand); + else CDLCallback(Regs[src], eCDLogMemFlags.Data); + } + Regs[dest] = ReadMemory(Regs[src]); + } + + public void Read_Inc_Func(ushort dest, ushort src) + { + if (CDLCallback != null) + { + if (src == PC) CDLCallback(Regs[src], eCDLogMemFlags.FetchOperand); + else CDLCallback(Regs[src], eCDLogMemFlags.Data); + } + //Console.WriteLine(dest + " " + src + " " + opcode_see); + + Regs[dest] = ReadMemory(Regs[src]); + + Regs[src]++; + } + + public void Write_Func(ushort dest, ushort src) + { + if (CDLCallback != null) CDLCallback(Regs[dest], eCDLogMemFlags.Write | eCDLogMemFlags.Data); + WriteMemory(Regs[dest], (byte)Regs[src]); + } + + public void TR_Func(ushort dest, ushort src) + { + Regs[dest] = Regs[src]; + } + + public void LD_8_Func(ushort dest, ushort src) + { + Regs[dest] = Regs[src]; + } + + public void TST_Func(ushort src) + { + + } + + public void CLR_Func(ushort src) + { + Regs[src] = 0; + + FlagC = false; + } + + // source is considered a 16 bit signed value, used for long relative branch + // no flags used + public void ADD16BR_Func(ushort dest, ushort src) + { + Regs[dest] = (ushort)(Regs[dest] + (short)Regs[src]); + } + + public void ADD8BR_Func(ushort dest, ushort src) + { + if (Regs[src] > 127) { Regs[src] |= 0xFF00; } + Regs[dest] = (ushort)(Regs[dest] + (short)Regs[src]); + } + + public void ADD8_Func(ushort dest, ushort src) + { + int Reg16_d = Regs[dest]; + Reg16_d += Regs[src]; + + FlagC = Reg16_d.Bit(8); + + ushort ans = (ushort)(Reg16_d & 0xFF); + + // redo for half carry flag + Reg16_d = Regs[dest] & 0xF; + Reg16_d += (Regs[src] & 0xF); + + Regs[dest] = ans; + } + + public void SUB8_Func(ushort dest, ushort src) + { + int Reg16_d = Regs[dest]; + Reg16_d -= Regs[src]; + + FlagC = Reg16_d.Bit(8); + + ushort ans = (ushort)(Reg16_d & 0xFF); + + // redo for half carry flag + Reg16_d = Regs[dest] & 0xF; + Reg16_d -= (Regs[src] & 0xF); + + Regs[dest] = ans; + } + + // same as SUB8 but result not stored + public void CMP8_Func(ushort dest, ushort src) + { + int Reg16_d = Regs[dest]; + Reg16_d -= Regs[src]; + + FlagC = Reg16_d.Bit(8); + + ushort ans = (ushort)(Reg16_d & 0xFF); + + // redo for half carry flag + Reg16_d = Regs[dest] & 0xF; + Reg16_d -= (Regs[src] & 0xF); + } + + public void BIT_Func(ushort dest, ushort src) + { + ushort ans = (ushort)(Regs[dest] & Regs[src]); + } + + public void ASL_Func(ushort src) + { + FlagC = Regs[src].Bit(7); + + Regs[src] = (ushort)((Regs[src] << 1) & 0xFF); + } + + public void ASR_Func(ushort src) + { + FlagC = Regs[src].Bit(0); + + ushort temp = (ushort)(Regs[src] & 0x80); // MSB doesn't change in this operation + + Regs[src] = (ushort)((Regs[src] >> 1) | temp); + } + + public void LSR_Func(ushort src) + { + FlagC = Regs[src].Bit(0); + + Regs[src] = (ushort)(Regs[src] >> 1); + } + + public void COM_Func(ushort src) + { + Regs[src] = (ushort)((~Regs[src]) & 0xFF); + + FlagC = true; + } + + public void AND8_Func(ushort dest, ushort src) + { + Regs[dest] = (ushort)(Regs[dest] & Regs[src]); + } + + public void OR8_Func(ushort dest, ushort src) + { + Regs[dest] = (ushort)(Regs[dest] | Regs[src]); + } + + public void XOR8_Func(ushort dest, ushort src) + { + Regs[dest] = (ushort)(Regs[dest] ^ Regs[src]); + } + + public void ROR_Func(ushort src) + { + ushort c = (ushort)(FlagC ? 0x80 : 0); + + FlagC = Regs[src].Bit(0); + + Regs[src] = (ushort)(c | (Regs[src] >> 1)); + } + + public void ROL_Func(ushort src) + { + ushort c = (ushort)(FlagC ? 1 : 0); + FlagC = Regs[src].Bit(7); + + Regs[src] = (ushort)(((Regs[src] << 1) & 0xFF) | c); + } + + public void RRC_Func(ushort src) + { + ushort c = (ushort)(FlagC ? 0x80 : 0); + + FlagC = Regs[src].Bit(0); + + Regs[src] = (ushort)(c | (Regs[src] >> 1)); + } + + public void RLC_Func(ushort src) + { + ushort c = (ushort)(FlagC ? 1 : 0); + FlagC = Regs[src].Bit(7); + + Regs[src] = (ushort)(((Regs[src] << 1) & 0xFF) | c); + } + + public void INC8_Func(ushort src) + { + Regs[src] = (ushort)((Regs[src] + 1) & 0xFF); + } + + public void DEC8_Func(ushort src) + { + Regs[src] = (ushort)((Regs[src] - 1) & 0xFF); + } + + public void INC16_Func(ushort src) + { + Regs[src] += 1; + } + + public void DEC16_Func(ushort src) + { + Regs[src] -= 1; + } + + public void ADC8_Func(ushort dest, ushort src) + { + int Reg16_d = Regs[dest]; + int c = FlagC ? 1 : 0; + + Reg16_d += (Regs[src] + c); + + FlagC = Reg16_d.Bit(8); + + ushort ans = (ushort)(Reg16_d & 0xFF); + + // redo for half carry flag + Reg16_d = Regs[dest] & 0xF; + Reg16_d += ((Regs[src] & 0xF) + c); + + Regs[dest] = ans; + } + + public void DA_Func(ushort src) + { + int a = Regs[src]; + + byte CF = 0; + if (FlagC || ((a & 0xF) > 9)) + { + CF = 6; + } + if (FlagC || (((a >> 4) & 0xF) > 9) || ((((a >> 4) & 0xF) > 8) && ((a & 0xF) > 9))) + { + CF |= (byte)(6 << 4); + } + + a += CF; + + if ((a > 0xFF) || FlagC) + { + FlagC = true; + } + else + { + FlagC = false; + } + Regs[src] = (byte)a; + } + + public void CMP16_Func(ushort dest, ushort src) + { + int Reg16_d = Regs[dest]; + int Reg16_s = Regs[src]; + + Reg16_d -= Reg16_s; + + FlagC = Reg16_d.Bit(16); + + ushort ans = (ushort)(Reg16_d & 0xFFFF); + } + + public void EXG_Func(ushort sel) + { + + } + + public void TFR_Func(ushort sel) + { + + } + } +} diff --git a/BizHawk.Emulation.Cores/CPUs/Intel8048/ReadMe.txt b/BizHawk.Emulation.Cores/CPUs/Intel8048/ReadMe.txt new file mode 100644 index 0000000000..115b568cb8 --- /dev/null +++ b/BizHawk.Emulation.Cores/CPUs/Intel8048/ReadMe.txt @@ -0,0 +1 @@ +TODO: STOP for second byte nonzero diff --git a/BizHawk.Emulation.Cores/CPUs/Intel8048/Registers.cs b/BizHawk.Emulation.Cores/CPUs/Intel8048/Registers.cs new file mode 100644 index 0000000000..7db008df57 --- /dev/null +++ b/BizHawk.Emulation.Cores/CPUs/Intel8048/Registers.cs @@ -0,0 +1,86 @@ +using System; + +namespace BizHawk.Emulation.Common.Components.I8048 +{ + public partial class I8048 + { + // registers + public ushort[] Regs = new ushort[21]; + + // 64 bytes of onboard ram + public ushort[] RAM = new ushort[64]; + + // The 8048 has 2 flags that can be used for conditionals + // F0 is on the PSW, F1 is seperate + public bool F1; + + // The 8048 has 2 test lines which can be used for conditionals, T0 can be used as an output + public bool T0, T1; + + public const ushort PC = 0; + public const ushort PSW = 1; + public const ushort BUS = 2; + public const ushort A = 3; + public const ushort R0 = 4; + public const ushort R1 = 5; + public const ushort R2 = 6; + public const ushort R3 = 7; + public const ushort R4 = 8; + public const ushort R5 = 9; + public const ushort R6 = 10; + public const ushort R7 = 11; + public const ushort ADDR = 12; // internal + public const ushort ALU = 13; // internal + public const ushort ALU2 = 14; // internal + public const ushort P1 = 15; + public const ushort P2 = 16; + public const ushort P4 = 17; + public const ushort P5 = 18; + public const ushort P6 = 19; + public const ushort P7 = 20; + + public bool Flag3 + { + get { return (Regs[PSW] & 0x08) != 0; } + set { Regs[PSW] = (byte)((Regs[PSW] & ~0x08) | 0x08); } + } + + public bool FlagBS + { + get { return (Regs[PSW] & 0x10) != 0; } + set { Regs[PSW] = (byte)((Regs[PSW] & ~0x10) | (value ? 0x10 : 0x00)); } + } + + public bool FlagF0 + { + get { return (Regs[PSW] & 0x20) != 0; } + set { Regs[PSW] = (byte)((Regs[PSW] & ~0x20) | (value ? 0x20 : 0x00)); } + } + + public bool FlagAC + { + get { return (Regs[PSW] & 0x40) != 0; } + set { Regs[PSW] = (byte)((Regs[PSW] & ~0x40) | (value ? 0x40 : 0x00)); } + } + + public bool FlagC + { + get { return (Regs[PSW] & 0x80) != 0; } + set { Regs[PSW] = (byte)((Regs[PSW] & ~0x80) | (value ? 0x80 : 0x00)); } + } + + private void ResetRegisters() + { + for (int i = 0; i < 21; i++) + { + Regs[i] = 0; + } + + F1 = false; + + T0 = T1 = false; + + Flag3 = true; + } + } +} \ No newline at end of file diff --git a/BizHawk.Emulation.Cores/CPUs/MC6800/MC6800.cs b/BizHawk.Emulation.Cores/CPUs/MC6800/MC6800.cs index 69dc1b2339..84b29f164f 100644 --- a/BizHawk.Emulation.Cores/CPUs/MC6800/MC6800.cs +++ b/BizHawk.Emulation.Cores/CPUs/MC6800/MC6800.cs @@ -473,16 +473,13 @@ namespace BizHawk.Emulation.Common.Components.MC6800 // then regular IRQ else if (IRQPending && !FlagI) { - if (!FlagI) - { - IRQPending = false; + IRQPending = false; - if (TraceCallback != null) { TraceCallback(new TraceInfo { Disassembly = "====IRQ====", RegisterInfo = "" }); } + if (TraceCallback != null) { TraceCallback(new TraceInfo { Disassembly = "====IRQ====", RegisterInfo = "" }); } - IRQ_(); - IRQCallback(); - instr_pntr = irq_pntr = 0; - } + IRQ_(); + IRQCallback(); + instr_pntr = irq_pntr = 0; } // otherwise start the next instruction else diff --git a/BizHawk.Emulation.Cores/CPUs/MC6809/MC6809.cs b/BizHawk.Emulation.Cores/CPUs/MC6809/MC6809.cs index 14dfc124f4..4551374220 100644 --- a/BizHawk.Emulation.Cores/CPUs/MC6809/MC6809.cs +++ b/BizHawk.Emulation.Cores/CPUs/MC6809/MC6809.cs @@ -503,16 +503,85 @@ namespace BizHawk.Emulation.Common.Components.MC6809 else { PopulateCURINSTR(CWAI); - irq_pntr = 0; + irq_pntr = instr_pntr = 0; IRQS = -1; } instr_pntr = 0; break; case SYNC: - IN_SYNC = true; - IRQS = 1; - instr_pntr = irq_pntr = 0; - PopulateCURINSTR(SYNC); + if (NMIPending) + { + NMIPending = false; + IN_SYNC = false; + + Regs[ADDR] = 0xFFFC; + PopulateCURINSTR(RD_INC, ALU, ADDR, + RD_INC, ALU2, ADDR, + SET_ADDR, PC, ALU, ALU2); + irq_pntr = -1; + IRQS = 3; + + if (TraceCallback != null) { TraceCallback(new TraceInfo { Disassembly = "====SYNC NMI====", RegisterInfo = "" }); } + } + else if (FIRQPending) + { + if (!FlagF) + { + FIRQPending = false; + + Regs[ADDR] = 0xFFF6; + PopulateCURINSTR(RD_INC, ALU, ADDR, + RD_INC, ALU2, ADDR, + SET_ADDR, PC, ALU, ALU2); + irq_pntr = -1; + IRQS = 3; + + if (TraceCallback != null) { TraceCallback(new TraceInfo { Disassembly = "====SYNC FIRQ====", RegisterInfo = "" }); } + } + else + { + FIRQPending = false; + IN_SYNC = false; + IRQS = 2; + instr_pntr = irq_pntr = 0; + PopulateCURINSTR(IDLE, + IDLE); + } + } + else if (IRQPending) + { + if (!FlagI) + { + IRQPending = false; + IN_SYNC = false; + + Regs[ADDR] = 0xFFF8; + PopulateCURINSTR(RD_INC, ALU, ADDR, + RD_INC, ALU2, ADDR, + SET_ADDR, PC, ALU, ALU2); + irq_pntr = -1; + IRQS = 3; + + if (TraceCallback != null) { TraceCallback(new TraceInfo { Disassembly = "====SYNC IRQ====", RegisterInfo = "" }); } + } + else + { + FIRQPending = false; + IN_SYNC = false; + IRQS = 2; + instr_pntr = irq_pntr = 0; + PopulateCURINSTR(IDLE, + IDLE); + } + } + else + { + IN_SYNC = true; + IRQS = -1; + instr_pntr = irq_pntr = 0; + PopulateCURINSTR(SYNC); + } + break; } @@ -525,62 +594,31 @@ namespace BizHawk.Emulation.Common.Components.MC6809 if (TraceCallback != null) { TraceCallback(new TraceInfo { Disassembly = "====NMI====", RegisterInfo = "" }); } - IN_SYNC = false; NMI_(); NMICallback(); instr_pntr = irq_pntr = 0; } // fast IRQ has next priority - else if (FIRQPending) + else if (FIRQPending && !FlagF) { - if (!FlagF) - { - FIRQPending = false; + FIRQPending = false; - if (TraceCallback != null) { TraceCallback(new TraceInfo { Disassembly = "====FIRQ====", RegisterInfo = "" }); } + if (TraceCallback != null) { TraceCallback(new TraceInfo { Disassembly = "====FIRQ====", RegisterInfo = "" }); } - IN_SYNC = false; - FIRQ_(); - FIRQCallback(); - instr_pntr = irq_pntr = 0; - } - else if (IN_SYNC) - { - FIRQPending = false; - - if (TraceCallback != null) { TraceCallback(new TraceInfo { Disassembly = "====SYNC====", RegisterInfo = "" }); } - - IN_SYNC = false; - IRQS = 1; - instr_pntr = irq_pntr = 0; - PopulateCURINSTR(IDLE); - } + FIRQ_(); + FIRQCallback(); + instr_pntr = irq_pntr = 0; } // then regular IRQ else if (IRQPending && !FlagI) { - if (!FlagI) - { - IRQPending = false; + IRQPending = false; - if (TraceCallback != null) { TraceCallback(new TraceInfo { Disassembly = "====IRQ====", RegisterInfo = "" }); } + if (TraceCallback != null) { TraceCallback(new TraceInfo { Disassembly = "====IRQ====", RegisterInfo = "" }); } - IN_SYNC = false; - IRQ_(); - IRQCallback(); - instr_pntr = irq_pntr = 0; - } - else if (IN_SYNC) - { - IRQPending = false; - - if (TraceCallback != null) { TraceCallback(new TraceInfo { Disassembly = "====SYNC====", RegisterInfo = "" }); } - - IN_SYNC = false; - IRQS = 1; - instr_pntr = irq_pntr = 0; - PopulateCURINSTR(IDLE); - } + IRQ_(); + IRQCallback(); + instr_pntr = irq_pntr = 0; } // otherwise start the next instruction else diff --git a/BizHawk.Emulation.Cores/Consoles/Atari/2600/Atari2600.IStatable.cs b/BizHawk.Emulation.Cores/Consoles/Atari/2600/Atari2600.IStatable.cs index eabaf20fdc..7751a535f5 100644 --- a/BizHawk.Emulation.Cores/Consoles/Atari/2600/Atari2600.IStatable.cs +++ b/BizHawk.Emulation.Cores/Consoles/Atari/2600/Atari2600.IStatable.cs @@ -7,7 +7,10 @@ namespace BizHawk.Emulation.Cores.Atari.Atari2600 { public partial class Atari2600 : IStatable { - public bool BinarySaveStatesPreferred => false; + public bool BinarySaveStatesPreferred + { + get { return true; } + } public void SaveStateText(TextWriter writer) { diff --git a/BizHawk.Emulation.Cores/Consoles/Magnavox/Odyssey2/Audio.cs b/BizHawk.Emulation.Cores/Consoles/Magnavox/Odyssey2/Audio.cs new file mode 100644 index 0000000000..9a459bf8f5 --- /dev/null +++ b/BizHawk.Emulation.Cores/Consoles/Magnavox/Odyssey2/Audio.cs @@ -0,0 +1,220 @@ +using System; + +using BizHawk.Common; +using BizHawk.Common.BufferExtensions; +using BizHawk.Emulation.Common; +using BizHawk.Common.NumberExtensions; + +namespace BizHawk.Emulation.Cores.Nintendo.O2Hawk +{ + // Audio Emulation + public class Audio : ISoundProvider + { + public O2Hawk Core { get; set; } + + private BlipBuffer _blip_L = new BlipBuffer(15000); + private BlipBuffer _blip_R = new BlipBuffer(15000); + + public const int NR10 = 0; + public const int NR11 = 1; + public const int NR12 = 2; + public const int NR13 = 3; + public const int NR14 = 4; + public const int NR21 = 5; + public const int NR22 = 6; + public const int NR23 = 7; + public const int NR24 = 8; + public const int NR30 = 9; + public const int NR31 = 10; + public const int NR32 = 11; + public const int NR33 = 12; + public const int NR34 = 13; + public const int NR41 = 14; + public const int NR42 = 15; + public const int NR43 = 16; + public const int NR44 = 17; + public const int NR50 = 18; + public const int NR51 = 19; + public const int NR52 = 20; + + + public byte[] Audio_Regs = new byte[21]; + + // Contol Variables + public bool AUD_CTRL_vin_L_en; + public bool AUD_CTRL_vin_R_en; + public bool AUD_CTRL_sq1_L_en; + public bool AUD_CTRL_sq2_L_en; + public bool AUD_CTRL_wave_L_en; + public bool AUD_CTRL_noise_L_en; + public bool AUD_CTRL_sq1_R_en; + public bool AUD_CTRL_sq2_R_en; + public bool AUD_CTRL_wave_R_en; + public bool AUD_CTRL_noise_R_en; + public bool AUD_CTRL_power; + public byte AUD_CTRL_vol_L; + public byte AUD_CTRL_vol_R; + + public byte sample; + + public uint master_audio_clock; + + public int latched_sample_L, latched_sample_R; + + public byte ReadReg(int addr) + { + byte ret = 0; + + switch (addr) + { + case 0xFF10: ret = (byte)(Audio_Regs[NR10]); break; // NR10 (sweep) + case 0xFF11: ret = (byte)(Audio_Regs[NR11]); break; // NR11 (sound length / wave pattern duty %) + case 0xFF12: ret = (byte)(Audio_Regs[NR12]); break; // NR12 (envelope) + case 0xFF13: ret = (byte)(Audio_Regs[NR13]); break; // NR13 (freq low) + } + + return ret; + } + + public void WriteReg(int addr, byte value) + { + + } + + public void tick() + { + + // add up components to each channel + int L_final = 0; + int R_final = 0; + + if (AUD_CTRL_sq1_L_en) { L_final += 0; } + + + if (AUD_CTRL_sq1_R_en) { R_final += 0; } + + L_final *= (AUD_CTRL_vol_L + 1) * 40; + R_final *= (AUD_CTRL_vol_R + 1) * 40; + + if (L_final != latched_sample_L) + { + _blip_L.AddDelta(master_audio_clock, L_final - latched_sample_L); + latched_sample_L = L_final; + } + + if (R_final != latched_sample_R) + { + _blip_R.AddDelta(master_audio_clock, R_final - latched_sample_R); + latched_sample_R = R_final; + } + + master_audio_clock++; + } + + public void power_off() + { + for (int i = 0; i < 0x16; i++) + { + WriteReg(0xFF10 + i, 0); + } + } + + public void Reset() + { + Audio_Regs = new byte[21]; + + master_audio_clock = 0; + + sample = 0; + + _blip_L.SetRates(4194304, 44100); + _blip_R.SetRates(4194304, 44100); + } + + public void SyncState(Serializer ser) + { + ser.Sync(nameof(Audio_Regs), ref Audio_Regs, false); + + ser.Sync(nameof(master_audio_clock), ref master_audio_clock); + + ser.Sync(nameof(sample), ref sample); + ser.Sync(nameof(latched_sample_L), ref latched_sample_L); + ser.Sync(nameof(latched_sample_R), ref latched_sample_R); + + ser.Sync(nameof(AUD_CTRL_vin_L_en), ref AUD_CTRL_vin_L_en); + ser.Sync(nameof(AUD_CTRL_vin_R_en), ref AUD_CTRL_vin_R_en); + ser.Sync(nameof(AUD_CTRL_sq1_L_en), ref AUD_CTRL_sq1_L_en); + ser.Sync(nameof(AUD_CTRL_sq2_L_en), ref AUD_CTRL_sq2_L_en); + ser.Sync(nameof(AUD_CTRL_wave_L_en), ref AUD_CTRL_wave_L_en); + ser.Sync(nameof(AUD_CTRL_noise_L_en), ref AUD_CTRL_noise_L_en); + ser.Sync(nameof(AUD_CTRL_sq1_R_en), ref AUD_CTRL_sq1_R_en); + ser.Sync(nameof(AUD_CTRL_sq2_R_en), ref AUD_CTRL_sq2_R_en); + ser.Sync(nameof(AUD_CTRL_wave_R_en), ref AUD_CTRL_wave_R_en); + ser.Sync(nameof(AUD_CTRL_noise_R_en), ref AUD_CTRL_noise_R_en); + ser.Sync(nameof(AUD_CTRL_power), ref AUD_CTRL_power); + ser.Sync(nameof(AUD_CTRL_vol_L), ref AUD_CTRL_vol_L); + ser.Sync(nameof(AUD_CTRL_vol_R), ref AUD_CTRL_vol_R); + } + + #region audio + + public bool CanProvideAsync => false; + + public void SetSyncMode(SyncSoundMode mode) + { + if (mode != SyncSoundMode.Sync) + { + throw new InvalidOperationException("Only Sync mode is supported_"); + } + } + + public SyncSoundMode SyncMode => SyncSoundMode.Sync; + + public void GetSamplesSync(out short[] samples, out int nsamp) + { + _blip_L.EndFrame(master_audio_clock); + _blip_R.EndFrame(master_audio_clock); + + nsamp = _blip_L.SamplesAvailable(); + + samples = new short[nsamp * 2]; + + if (nsamp != 0) + { + _blip_L.ReadSamplesLeft(samples, nsamp); + _blip_R.ReadSamplesRight(samples, nsamp); + } + + master_audio_clock = 0; + } + + public void GetSamplesAsync(short[] samples) + { + throw new NotSupportedException("Async is not available"); + } + + public void DiscardSamples() + { + _blip_L.Clear(); + _blip_R.Clear(); + master_audio_clock = 0; + } + + private void GetSamples(short[] samples) + { + + } + + public void DisposeSound() + { + _blip_L.Clear(); + _blip_R.Clear(); + _blip_L.Dispose(); + _blip_R.Dispose(); + _blip_L = null; + _blip_R = null; + } + + #endregion + } +} \ No newline at end of file diff --git a/BizHawk.Emulation.Cores/Consoles/Magnavox/Odyssey2/HW_Registers.cs b/BizHawk.Emulation.Cores/Consoles/Magnavox/Odyssey2/HW_Registers.cs new file mode 100644 index 0000000000..3181a60936 --- /dev/null +++ b/BizHawk.Emulation.Cores/Consoles/Magnavox/Odyssey2/HW_Registers.cs @@ -0,0 +1,291 @@ +using System; +using BizHawk.Common.NumberExtensions; + +namespace BizHawk.Emulation.Cores.Nintendo.O2Hawk +{ + public partial class O2Hawk + { + public byte Read_Registers(int addr) + { + byte ret = 0; + + switch (addr) + { + // Read Input + case 0xFF00: + _islag = false; + ret = input_register; + break; + + // Serial data port + case 0xFF01: + ret = serialport.ReadReg(addr); + break; + + // Serial port control + case 0xFF02: + ret = serialport.ReadReg(addr); + break; + + // Interrupt flags + case 0xFF0F: + + break; + + // audio regs + case 0xFF10: + case 0xFF11: + case 0xFF12: + case 0xFF13: + case 0xFF14: + case 0xFF16: + case 0xFF17: + case 0xFF18: + case 0xFF19: + case 0xFF1A: + case 0xFF1B: + case 0xFF1C: + case 0xFF1D: + case 0xFF1E: + case 0xFF20: + case 0xFF21: + case 0xFF22: + case 0xFF23: + case 0xFF24: + case 0xFF25: + case 0xFF26: + case 0xFF30: + case 0xFF31: + case 0xFF32: + case 0xFF33: + case 0xFF34: + case 0xFF35: + case 0xFF36: + case 0xFF37: + case 0xFF38: + case 0xFF39: + case 0xFF3A: + case 0xFF3B: + case 0xFF3C: + case 0xFF3D: + case 0xFF3E: + case 0xFF3F: + ret = audio.ReadReg(addr); + break; + + // PPU Regs + case 0xFF40: + case 0xFF41: + case 0xFF42: + case 0xFF43: + case 0xFF44: + case 0xFF45: + case 0xFF46: + case 0xFF47: + case 0xFF48: + case 0xFF49: + case 0xFF4A: + case 0xFF4B: + ret = ppu.ReadReg(addr); + break; + + // Speed Control for GBC + case 0xFF4D: + + break; + + case 0xFF4F: // VBK + + break; + + // Bios control register. Not sure if it is readable + case 0xFF50: + ret = 0xFF; + break; + + // PPU Regs for GBC + case 0xFF51: + case 0xFF52: + case 0xFF53: + case 0xFF54: + case 0xFF55: + + break; + + case 0xFF56: + + break; + + case 0xFF68: + case 0xFF69: + case 0xFF6A: + case 0xFF6B: + + break; + + // Speed Control for GBC + case 0xFF70: + + break; + + case 0xFF6C: + case 0xFF72: + case 0xFF73: + case 0xFF74: + case 0xFF75: + case 0xFF76: + case 0xFF77: + + break; + + // interrupt control register + case 0xFFFF: + + break; + + default: + ret = 0xFF; + break; + + } + return ret; + } + + public void Write_Registers(int addr, byte value) + { + switch (addr) + { + // select input + case 0xFF00: + + break; + + // Serial data port + case 0xFF01: + serialport.WriteReg(addr, value); + break; + + // Serial port control + case 0xFF02: + serialport.WriteReg(addr, value); + break; + + // Interrupt flags + case 0xFF0F: + + break; + + // audio regs + case 0xFF10: + case 0xFF11: + case 0xFF12: + case 0xFF13: + case 0xFF14: + case 0xFF16: + case 0xFF17: + case 0xFF18: + case 0xFF19: + case 0xFF1A: + case 0xFF1B: + case 0xFF1C: + case 0xFF1D: + case 0xFF1E: + case 0xFF20: + case 0xFF21: + case 0xFF22: + case 0xFF23: + case 0xFF24: + case 0xFF25: + case 0xFF26: + case 0xFF30: + case 0xFF31: + case 0xFF32: + case 0xFF33: + case 0xFF34: + case 0xFF35: + case 0xFF36: + case 0xFF37: + case 0xFF38: + case 0xFF39: + case 0xFF3A: + case 0xFF3B: + case 0xFF3C: + case 0xFF3D: + case 0xFF3E: + case 0xFF3F: + audio.WriteReg(addr, value); + break; + + // PPU Regs + case 0xFF40: + case 0xFF41: + case 0xFF42: + case 0xFF43: + case 0xFF44: + case 0xFF45: + case 0xFF46: + case 0xFF47: + case 0xFF48: + case 0xFF49: + case 0xFF4A: + case 0xFF4B: + ppu.WriteReg(addr, value); + break; + + // GBC compatibility register (I think) + case 0xFF4C: + + break; + + // Speed Control for GBC + case 0xFF4D: + + break; + + // VBK + case 0xFF4F: + + break; + + // Bios control register. Writing 1 permanently disables BIOS until a power cycle occurs + case 0xFF50: + + break; + + // PPU Regs for GBC + case 0xFF51: + case 0xFF52: + case 0xFF53: + case 0xFF54: + case 0xFF55: + + break; + + case 0xFF56: + + break; + + case 0xFF68: + case 0xFF69: + case 0xFF6A: + case 0xFF6B: + //if (GBC_compat) + //{ + ppu.WriteReg(addr, value); + //} + break; + + default: + Console.Write(addr); + Console.Write(" "); + Console.WriteLine(value); + break; + } + } + + public void Register_Reset() + { + input_register = 0xCF; // not reading any input + } + } +} diff --git a/BizHawk.Emulation.Cores/Consoles/Magnavox/Odyssey2/Mappers/MapperBase.cs b/BizHawk.Emulation.Cores/Consoles/Magnavox/Odyssey2/Mappers/MapperBase.cs new file mode 100644 index 0000000000..0094f1d4da --- /dev/null +++ b/BizHawk.Emulation.Cores/Consoles/Magnavox/Odyssey2/Mappers/MapperBase.cs @@ -0,0 +1,64 @@ +using BizHawk.Common; +using System; + +using BizHawk.Emulation.Common.Components.I8048; + +namespace BizHawk.Emulation.Cores.Nintendo.O2Hawk +{ + public class MapperBase + { + public O2Hawk Core { get; set; } + + public virtual byte ReadMemory(ushort addr) + { + return 0; + } + + public virtual byte PeekMemory(ushort addr) + { + return 0; + } + + public virtual void WriteMemory(ushort addr, byte value) + { + } + + public virtual void PokeMemory(ushort addr, byte value) + { + } + + public virtual void SyncState(Serializer ser) + { + } + + public virtual void Dispose() + { + } + + public virtual void Initialize() + { + } + + public virtual void Mapper_Tick() + { + } + + public virtual void RTC_Get(int value, int index) + { + } + + public virtual void MapCDL(ushort addr, I8048.eCDLogMemFlags flags) + { + } + + protected void SetCDLROM(I8048.eCDLogMemFlags flags, int cdladdr) + { + Core.SetCDL(flags, "ROM", cdladdr); + } + + protected void SetCDLRAM(I8048.eCDLogMemFlags flags, int cdladdr) + { + Core.SetCDL(flags, "CartRAM", cdladdr); + } + } +} diff --git a/BizHawk.Emulation.Cores/Consoles/Magnavox/Odyssey2/Mappers/Mapper_Default.cs b/BizHawk.Emulation.Cores/Consoles/Magnavox/Odyssey2/Mappers/Mapper_Default.cs new file mode 100644 index 0000000000..657c02779f --- /dev/null +++ b/BizHawk.Emulation.Cores/Consoles/Magnavox/Odyssey2/Mappers/Mapper_Default.cs @@ -0,0 +1,80 @@ +using BizHawk.Common; +using BizHawk.Common.NumberExtensions; +using System; + +using BizHawk.Emulation.Common.Components.I8048; + +namespace BizHawk.Emulation.Cores.Nintendo.O2Hawk +{ + // Default mapper with no bank switching + public class MapperDefault : MapperBase + { + public override void Initialize() + { + // nothing to initialize + } + + public override byte ReadMemory(ushort addr) + { + if (addr < 0x8000) + { + return Core._rom[addr]; + } + else + { + if (Core.cart_RAM != null) + { + return Core.cart_RAM[addr - 0xA000]; + } + else + { + return 0; + } + } + } + + public override void MapCDL(ushort addr, I8048.eCDLogMemFlags flags) + { + if (addr < 0x8000) + { + SetCDLROM(flags, addr); + } + else + { + if (Core.cart_RAM != null) + { + SetCDLRAM(flags, addr - 0xA000); + } + else + { + return; + } + } + } + + public override byte PeekMemory(ushort addr) + { + return ReadMemory(addr); + } + + public override void WriteMemory(ushort addr, byte value) + { + if (addr < 0x8000) + { + // no mapping hardware available + } + else + { + if (Core.cart_RAM != null) + { + Core.cart_RAM[addr - 0xA000] = value; + } + } + } + + public override void PokeMemory(ushort addr, byte value) + { + WriteMemory(addr, value); + } + } +} diff --git a/BizHawk.Emulation.Cores/Consoles/Magnavox/Odyssey2/Mappers/ReadMe.txt b/BizHawk.Emulation.Cores/Consoles/Magnavox/Odyssey2/Mappers/ReadMe.txt new file mode 100644 index 0000000000..0c94c8272c --- /dev/null +++ b/BizHawk.Emulation.Cores/Consoles/Magnavox/Odyssey2/Mappers/ReadMe.txt @@ -0,0 +1,3 @@ +TODO: +Official Mappers +Unofficial Mappers diff --git a/BizHawk.Emulation.Cores/Consoles/Magnavox/Odyssey2/MemoryMap.cs b/BizHawk.Emulation.Cores/Consoles/Magnavox/Odyssey2/MemoryMap.cs new file mode 100644 index 0000000000..ac20bf4d07 --- /dev/null +++ b/BizHawk.Emulation.Cores/Consoles/Magnavox/Odyssey2/MemoryMap.cs @@ -0,0 +1,59 @@ +using System; + +using BizHawk.Common.BufferExtensions; +using BizHawk.Emulation.Common; + +/* + $0400-$0FFF Cartridge (Only 2K accessible, bit 10 not mapped to cart) + $0000-$03FF BIOS +*/ + +namespace BizHawk.Emulation.Cores.Nintendo.O2Hawk +{ + public partial class O2Hawk + { + public byte ReadMemory(ushort addr) + { + uint flags = (uint)(MemoryCallbackFlags.AccessRead); + MemoryCallbacks.CallMemoryCallbacks(addr, 0, flags, "System Bus"); + addr_access = addr; + + if (addr < 0x400) + { + return _bios[addr]; + } + else + { + return mapper.ReadMemory(addr); + } + } + + public void WriteMemory(ushort addr, byte value) + { + uint flags = (uint)(MemoryCallbackFlags.AccessWrite); + MemoryCallbacks.CallMemoryCallbacks(addr, value, flags, "System Bus"); + addr_access = addr; + + if (addr < 0x400) + { + + } + else + { + mapper.WriteMemory(addr, value); + } + } + + public byte PeekMemory(ushort addr) + { + if (addr < 0x400) + { + return _bios[addr]; + } + else + { + return mapper.PeekMemory(addr); + } + } + } +} diff --git a/BizHawk.Emulation.Cores/Consoles/Magnavox/Odyssey2/O2Hawk.ICodeDataLog.cs b/BizHawk.Emulation.Cores/Consoles/Magnavox/Odyssey2/O2Hawk.ICodeDataLog.cs new file mode 100644 index 0000000000..ac77428216 --- /dev/null +++ b/BizHawk.Emulation.Cores/Consoles/Magnavox/Odyssey2/O2Hawk.ICodeDataLog.cs @@ -0,0 +1,64 @@ +using System; +using System.IO; +using System.Collections.Generic; + +using BizHawk.Emulation.Common; +using BizHawk.Emulation.Common.Components.I8048; + +namespace BizHawk.Emulation.Cores.Nintendo.O2Hawk +{ + public partial class O2Hawk : ICodeDataLogger + { + private ICodeDataLog _cdl; + + public void SetCDL(ICodeDataLog cdl) + { + _cdl = cdl; + if (cdl == null) + this.cpu.CDLCallback = null; + else this.cpu.CDLCallback = CDLCpuCallback; + } + + public void NewCDL(ICodeDataLog cdl) + { + cdl["ROM"] = new byte[MemoryDomains["ROM"].Size]; + cdl["HRAM"] = new byte[MemoryDomains["Zero Page RAM"].Size]; + + cdl["WRAM"] = new byte[MemoryDomains["Main RAM"].Size]; + + if (MemoryDomains.Has("Cart RAM")) + { + cdl["CartRAM"] = new byte[MemoryDomains["Cart RAM"].Size]; + } + + cdl.SubType = "O2"; + cdl.SubVer = 0; + } + + [FeatureNotImplemented] + void ICodeDataLogger.DisassembleCDL(Stream s, ICodeDataLog cdl) + { + } + + public void SetCDL(I8048.eCDLogMemFlags flags, string type, int cdladdr) + { + if (type == null) return; + byte val = (byte)flags; + _cdl[type][cdladdr] |= (byte)flags; + } + + void CDLCpuCallback(ushort addr, I8048.eCDLogMemFlags flags) + { + + if (addr < 0x400) + { + + } + else + { + mapper.MapCDL(addr, flags); + return; + } + } + } +} \ No newline at end of file diff --git a/BizHawk.Emulation.Cores/Consoles/Magnavox/Odyssey2/O2Hawk.IDebuggable.cs b/BizHawk.Emulation.Cores/Consoles/Magnavox/Odyssey2/O2Hawk.IDebuggable.cs new file mode 100644 index 0000000000..45f9f3e543 --- /dev/null +++ b/BizHawk.Emulation.Cores/Consoles/Magnavox/Odyssey2/O2Hawk.IDebuggable.cs @@ -0,0 +1,77 @@ +using System; +using System.Collections.Generic; + +using BizHawk.Emulation.Common; + +namespace BizHawk.Emulation.Cores.Nintendo.O2Hawk +{ + public partial class O2Hawk : IDebuggable + { + public IDictionary GetCpuFlagsAndRegisters() + { + return new Dictionary + { + /* + ["A"] = cpu.A, + ["X"] = cpu.X, + ["Y"] = cpu.Y, + ["S"] = cpu.S, + ["PC"] = cpu.PC, + ["Flag C"] = cpu.FlagC, + ["Flag Z"] = cpu.FlagZ, + ["Flag I"] = cpu.FlagI, + ["Flag D"] = cpu.FlagD, + ["Flag B"] = cpu.FlagB, + ["Flag V"] = cpu.FlagV, + ["Flag N"] = cpu.FlagN, + ["Flag T"] = cpu.FlagT + */ + }; + } + + public void SetCpuRegister(string register, int value) + { + switch (register) + { + default: + throw new InvalidOperationException(); + case "A": + //cpu.A = (byte)value; + break; + case "X": + //cpu.X = (byte)value; + break; + case "Y": + //cpu.Y = (byte)value; + break; + case "S": + //cpu.S = (byte)value; + break; + case "PC": + //cpu.PC = (ushort)value; + break; + case "Flag I": + //cpu.FlagI = value > 0; + break; + } + } + + public IMemoryCallbackSystem MemoryCallbacks { get; } = new MemoryCallbackSystem(new[] { "System Bus" }); + + public bool CanStep(StepType type) + { + return false; + } + + [FeatureNotImplemented] + public void Step(StepType type) + { + throw new NotImplementedException(); + } + + public long TotalExecutedCycles + { + get { return (long)cpu.TotalExecutedCycles; } + } + } +} diff --git a/BizHawk.Emulation.Cores/Consoles/Magnavox/Odyssey2/O2Hawk.IEmulator.cs b/BizHawk.Emulation.Cores/Consoles/Magnavox/Odyssey2/O2Hawk.IEmulator.cs new file mode 100644 index 0000000000..c9452702a4 --- /dev/null +++ b/BizHawk.Emulation.Cores/Consoles/Magnavox/Odyssey2/O2Hawk.IEmulator.cs @@ -0,0 +1,197 @@ +using BizHawk.Common.NumberExtensions; +using BizHawk.Emulation.Common; +using System; +using System.Collections.Generic; +using System.Runtime.InteropServices; + +namespace BizHawk.Emulation.Cores.Nintendo.O2Hawk +{ + public partial class O2Hawk : IEmulator, IVideoProvider + { + public IEmulatorServiceProvider ServiceProvider { get; } + + public ControllerDefinition ControllerDefinition => _controllerDeck.Definition; + + public byte controller_state; + public ushort Acc_X_state; + public ushort Acc_Y_state; + public bool in_vblank_old; + public bool in_vblank; + public bool vblank_rise; + + public bool FrameAdvance(IController controller, bool render, bool rendersound) + { + //Console.WriteLine("-----------------------FRAME-----------------------"); + + if (_tracer.Enabled) + { + cpu.TraceCallback = s => _tracer.Put(s); + } + else + { + cpu.TraceCallback = null; + } + + _frame++; + + if (controller.IsPressed("Power")) + { + HardReset(); + } + + _islag = true; + + do_frame(controller); + + if (_islag) + { + _lagcount++; + } + + return true; + } + + public void do_frame(IController controller) + { + for (int i = 0; i < 70224; i++) + { + audio.tick(); + ppu.tick(); + ppu.DMA_tick(); + serialport.serial_transfer_tick(); + cpu.ExecuteOne(); + + if (in_vblank && !in_vblank_old) + { + // update the controller state on VBlank + GetControllerState(controller); + + // check if controller state caused interrupt + do_controller_check(); + + // send the image on VBlank + SendVideoBuffer(); + } + + in_vblank_old = in_vblank; + } + + // turn off the screen so the image doesnt persist + // but dont turn off blank_frame yet, it still needs to be true until the next VBL + // this doesn't run for GBC, some games, ex MIB the series 2, rely on the screens persistence while off to make video look smooth. + // But some GB gams, ex Battletoads, turn off the screen for a long time from the middle of the frame, so need to be cleared. + if (ppu.clear_screen) + { + for (int j = 0; j < frame_buffer.Length; j++) { frame_buffer[j] = (int)color_palette[0]; } + ppu.clear_screen = false; + } + } + + public void do_single_step() + { + audio.tick(); + ppu.tick(); + ppu.DMA_tick(); + serialport.serial_transfer_tick(); + cpu.ExecuteOne(); + } + + public void do_controller_check() + { + // check if new input changed the input register and triggered IRQ + byte contr_prev = input_register; + + input_register &= 0xF0; + if ((input_register & 0x30) == 0x20) + { + input_register |= (byte)(controller_state & 0xF); + } + else if ((input_register & 0x30) == 0x10) + { + input_register |= (byte)((controller_state & 0xF0) >> 4); + } + else if ((input_register & 0x30) == 0x00) + { + // if both polls are set, then a bit is zero if either or both pins are zero + byte temp = (byte)((controller_state & 0xF) & ((controller_state & 0xF0) >> 4)); + input_register |= temp; + } + else + { + input_register |= 0xF; + } + } + + public void GetControllerState(IController controller) + { + InputCallbacks.Call(); + controller_state = _controllerDeck.ReadPort1(controller); + + Acc_X_state = _controllerDeck.ReadAccX1(controller); + Acc_Y_state = _controllerDeck.ReadAccY1(controller); + } + + public int Frame => _frame; + + public string SystemId => "O2"; + + public bool DeterministicEmulation { get; set; } + + public void ResetCounters() + { + _frame = 0; + _lagcount = 0; + _islag = false; + } + + public CoreComm CoreComm { get; } + + public void Dispose() + { + audio.DisposeSound(); + } + + #region Video provider + + public int _frameHz = 60; + + public int[] _vidbuffer; + + public int[] frame_buffer; + + public int[] GetVideoBuffer() + { + return frame_buffer; + } + + public void SendVideoBuffer() + { + if (ppu.blank_frame) + { + for (int i = 0; i < _vidbuffer.Length; i++) + { + _vidbuffer[i] = (int)color_palette[0]; + } + } + + for (int j = 0; j < frame_buffer.Length; j++) { frame_buffer[j] = _vidbuffer[j]; } + + ppu.blank_frame = false; + } + + public int VirtualWidth => 160; + public int VirtualHeight => 144; + public int BufferWidth => 160; + public int BufferHeight => 144; + public int BackgroundColor => unchecked((int)0xFF000000); + public int VsyncNumerator => _frameHz; + public int VsyncDenominator => 1; + + public static readonly uint[] color_palette_BW = { 0xFFFFFFFF , 0xFFAAAAAA, 0xFF555555, 0xFF000000 }; + public static readonly uint[] color_palette_Gr = { 0xFFA4C505, 0xFF88A905, 0xFF1D551D, 0xFF052505 }; + + public uint[] color_palette = new uint[4]; + + #endregion + } +} diff --git a/BizHawk.Emulation.Cores/Consoles/Magnavox/Odyssey2/O2Hawk.IInputPollable.cs b/BizHawk.Emulation.Cores/Consoles/Magnavox/Odyssey2/O2Hawk.IInputPollable.cs new file mode 100644 index 0000000000..252cf6418d --- /dev/null +++ b/BizHawk.Emulation.Cores/Consoles/Magnavox/Odyssey2/O2Hawk.IInputPollable.cs @@ -0,0 +1,24 @@ +using BizHawk.Emulation.Common; + +namespace BizHawk.Emulation.Cores.Nintendo.O2Hawk +{ + public partial class O2Hawk : IInputPollable + { + public int LagCount + { + get { return _lagcount; } + set { _lagcount = value; } + } + + public bool IsLagFrame + { + get { return _islag; } + set { _islag = value; } + } + + public IInputCallbackSystem InputCallbacks { get; } = new InputCallbackSystem(); + + public bool _islag = true; + private int _lagcount; + } +} diff --git a/BizHawk.Emulation.Cores/Consoles/Magnavox/Odyssey2/O2Hawk.IMemoryDomains.cs b/BizHawk.Emulation.Cores/Consoles/Magnavox/Odyssey2/O2Hawk.IMemoryDomains.cs new file mode 100644 index 0000000000..24f66c0ec1 --- /dev/null +++ b/BizHawk.Emulation.Cores/Consoles/Magnavox/Odyssey2/O2Hawk.IMemoryDomains.cs @@ -0,0 +1,69 @@ +using System; +using System.Collections.Generic; +using System.Linq; + +using BizHawk.Emulation.Common; + +namespace BizHawk.Emulation.Cores.Nintendo.O2Hawk +{ + public partial class O2Hawk + { + private IMemoryDomains MemoryDomains; + + public void SetupMemoryDomains() + { + var domains = new List + { + new MemoryDomainDelegate( + "Main RAM", + RAM.Length, + MemoryDomain.Endian.Little, + addr => RAM[addr], + (addr, value) => RAM[addr] = value, + 1), + new MemoryDomainDelegate( + "System Bus", + 0X1000, + MemoryDomain.Endian.Little, + addr => PeekSystemBus(addr), + (addr, value) => PokeSystemBus(addr, value), + 1), + new MemoryDomainDelegate( + "ROM", + _rom.Length, + MemoryDomain.Endian.Little, + addr => _rom[addr], + (addr, value) => _rom[addr] = value, + 1), + new MemoryDomainDelegate( + "VRAM", + VRAM.Length, + MemoryDomain.Endian.Little, + addr => VRAM[addr], + (addr, value) => VRAM[addr] = value, + 1) + }; + + if (cart_RAM != null) + { + var CartRam = new MemoryDomainByteArray("Cart RAM", MemoryDomain.Endian.Little, cart_RAM, true, 1); + domains.Add(CartRam); + } + + MemoryDomains = new MemoryDomainList(domains); + (ServiceProvider as BasicServiceProvider).Register(MemoryDomains); + } + + private byte PeekSystemBus(long addr) + { + ushort addr2 = (ushort)(addr & 0xFFF); + return PeekMemory(addr2); + } + + private void PokeSystemBus(long addr, byte value) + { + ushort addr2 = (ushort)(addr & 0xFFF); + WriteMemory(addr2, value); + } + } +} diff --git a/BizHawk.Emulation.Cores/Consoles/Magnavox/Odyssey2/O2Hawk.ISaveRam.cs b/BizHawk.Emulation.Cores/Consoles/Magnavox/Odyssey2/O2Hawk.ISaveRam.cs new file mode 100644 index 0000000000..130f51b497 --- /dev/null +++ b/BizHawk.Emulation.Cores/Consoles/Magnavox/Odyssey2/O2Hawk.ISaveRam.cs @@ -0,0 +1,37 @@ +using System; +using BizHawk.Emulation.Common; + +namespace BizHawk.Emulation.Cores.Nintendo.O2Hawk +{ + public partial class O2Hawk : ISaveRam + { + public byte[] CloneSaveRam() + { + if (cart_RAM != null) + { + return (byte[])cart_RAM.Clone(); + } + else + { + return null; + } + } + + public void StoreSaveRam(byte[] data) + { + if (_syncSettings.Use_SRAM) + { + Buffer.BlockCopy(data, 0, cart_RAM, 0, data.Length); + Console.WriteLine("loading SRAM here"); + } + } + + public bool SaveRamModified + { + get + { + return has_bat & _syncSettings.Use_SRAM; + } + } + } +} diff --git a/BizHawk.Emulation.Cores/Consoles/Magnavox/Odyssey2/O2Hawk.ISettable.cs b/BizHawk.Emulation.Cores/Consoles/Magnavox/Odyssey2/O2Hawk.ISettable.cs new file mode 100644 index 0000000000..11025b254a --- /dev/null +++ b/BizHawk.Emulation.Cores/Consoles/Magnavox/Odyssey2/O2Hawk.ISettable.cs @@ -0,0 +1,92 @@ +using System; +using System.ComponentModel; + +using Newtonsoft.Json; + +using BizHawk.Common; +using BizHawk.Emulation.Common; + +namespace BizHawk.Emulation.Cores.Nintendo.O2Hawk +{ + public partial class O2Hawk : IEmulator, IStatable, ISettable + { + public O2Settings GetSettings() + { + return _settings.Clone(); + } + + public O2SyncSettings GetSyncSettings() + { + return _syncSettings.Clone(); + } + + public bool PutSettings(O2Settings o) + { + _settings = o; + return false; + } + + public bool PutSyncSettings(O2SyncSettings o) + { + bool ret = O2SyncSettings.NeedsReboot(_syncSettings, o); + _syncSettings = o; + return ret; + } + + private O2Settings _settings = new O2Settings(); + public O2SyncSettings _syncSettings = new O2SyncSettings(); + + public class O2Settings + { + public O2Settings Clone() + { + return (O2Settings)MemberwiseClone(); + } + } + + public class O2SyncSettings + { + [JsonIgnore] + public string Port1 = O2HawkControllerDeck.DefaultControllerName; + + public enum ControllerType + { + Default, + Tilt + } + + [JsonIgnore] + private ControllerType _O2Controller; + + [DisplayName("Controller")] + [Description("Select Controller Type")] + [DefaultValue(ControllerType.Default)] + public ControllerType O2Controller + { + get { return _O2Controller; } + set + { + if (value == ControllerType.Default) { Port1 = O2HawkControllerDeck.DefaultControllerName; } + else { Port1 = "Gameboy Controller + Tilt"; } + + _O2Controller = value; + } + } + + [DisplayName("Use Existing SaveRAM")] + [Description("When true, existing SaveRAM will be loaded at boot up")] + [DefaultValue(false)] + public bool Use_SRAM { get; set; } + + public O2SyncSettings Clone() + { + return (O2SyncSettings)MemberwiseClone(); + } + + public static bool NeedsReboot(O2SyncSettings x, O2SyncSettings y) + { + return !DeepEquality.DeepEquals(x, y); + } + } + } +} diff --git a/BizHawk.Emulation.Cores/Consoles/Magnavox/Odyssey2/O2Hawk.IStatable.cs b/BizHawk.Emulation.Cores/Consoles/Magnavox/Odyssey2/O2Hawk.IStatable.cs new file mode 100644 index 0000000000..5d1f0b840f --- /dev/null +++ b/BizHawk.Emulation.Cores/Consoles/Magnavox/Odyssey2/O2Hawk.IStatable.cs @@ -0,0 +1,91 @@ +using System.IO; + +using BizHawk.Common; +using BizHawk.Emulation.Common; + +namespace BizHawk.Emulation.Cores.Nintendo.O2Hawk +{ + public partial class O2Hawk : IStatable + { + public bool BinarySaveStatesPreferred => true; + + public void SaveStateText(TextWriter writer) + { + SyncState(new Serializer(writer)); + } + + public void LoadStateText(TextReader reader) + { + SyncState(new Serializer(reader)); + } + + public void SaveStateBinary(BinaryWriter bw) + { + SyncState(new Serializer(bw)); + } + + public void LoadStateBinary(BinaryReader br) + { + SyncState(new Serializer(br)); + } + + public byte[] SaveStateBinary() + { + MemoryStream ms = new MemoryStream(); + BinaryWriter bw = new BinaryWriter(ms); + SaveStateBinary(bw); + bw.Flush(); + return ms.ToArray(); + } + + private void SyncState(Serializer ser) + { + byte[] core = null; + if (ser.IsWriter) + { + var ms = new MemoryStream(); + ms.Close(); + core = ms.ToArray(); + } + cpu.SyncState(ser); + mapper.SyncState(ser); + ppu.SyncState(ser); + serialport.SyncState(ser); + audio.SyncState(ser); + + ser.BeginSection("Odyssey2"); + ser.Sync(nameof(core), ref core, false); + ser.Sync("Lag", ref _lagcount); + ser.Sync("Frame", ref _frame); + ser.Sync("IsLag", ref _islag); + _controllerDeck.SyncState(ser); + + ser.Sync(nameof(controller_state), ref controller_state); + ser.Sync(nameof(Acc_X_state), ref Acc_X_state); + ser.Sync(nameof(Acc_Y_state), ref Acc_Y_state); + ser.Sync(nameof(in_vblank), ref in_vblank); + ser.Sync(nameof(in_vblank_old), ref in_vblank_old); + ser.Sync(nameof(vblank_rise), ref vblank_rise); + ser.Sync(nameof(input_register), ref input_register); + + // memory domains + ser.Sync(nameof(RAM), ref RAM, false); + ser.Sync(nameof(VRAM), ref VRAM, false); + ser.Sync(nameof(OAM), ref OAM, false); + ser.Sync(nameof(_bios), ref _bios, false); + ser.Sync(nameof(RAM_Bank), ref RAM_Bank); + ser.Sync(nameof(addr_access), ref addr_access); + + ser.Sync(nameof(frame_buffer), ref frame_buffer, false); + ser.Sync(nameof(_vidbuffer), ref _vidbuffer, false); + + // probably a better way to do this + if (cart_RAM != null) + { + ser.Sync(nameof(cart_RAM), ref cart_RAM, false); + } + + ser.EndSection(); + } + } +} diff --git a/BizHawk.Emulation.Cores/Consoles/Magnavox/Odyssey2/O2Hawk.cs b/BizHawk.Emulation.Cores/Consoles/Magnavox/Odyssey2/O2Hawk.cs new file mode 100644 index 0000000000..39a4593eb3 --- /dev/null +++ b/BizHawk.Emulation.Cores/Consoles/Magnavox/Odyssey2/O2Hawk.cs @@ -0,0 +1,144 @@ +using System; + +using BizHawk.Common.BufferExtensions; +using BizHawk.Emulation.Common; +using BizHawk.Emulation.Common.Components.I8048; + +using System.Runtime.InteropServices; + +namespace BizHawk.Emulation.Cores.Nintendo.O2Hawk +{ + [Core( + "O2Hawk", + "", + isPorted: false, + isReleased: false)] + [ServiceNotApplicable(typeof(IDriveLight))] + public partial class O2Hawk : IEmulator, ISaveRam, IDebuggable, IStatable, IInputPollable, IRegionable, ISettable + { + public byte input_register; + + // memory domains + public byte[] RAM = new byte[0x80]; + + public byte[] VRAM = new byte[0x4000]; + public byte[] OAM = new byte[0xA0]; + + public int RAM_Bank; + + public byte[] _bios; + public readonly byte[] _rom; + public readonly byte[] header = new byte[0x50]; + + public byte[] cart_RAM; + public bool has_bat; + + private int _frame = 0; + + public ushort addr_access; + + public MapperBase mapper; + + private readonly ITraceable _tracer; + + public I8048 cpu; + public PPU ppu; + public Audio audio; + public SerialPort serialport; + + [CoreConstructor("O2")] + public O2Hawk(CoreComm comm, GameInfo game, byte[] rom, /*string gameDbFn,*/ object settings, object syncSettings) + { + var ser = new BasicServiceProvider(this); + + cpu = new I8048 + { + ReadMemory = ReadMemory, + WriteMemory = WriteMemory, + PeekMemory = PeekMemory, + DummyReadMemory = ReadMemory, + OnExecFetch = ExecFetch, + }; + + audio = new Audio(); + serialport = new SerialPort(); + + CoreComm = comm; + + _settings = (O2Settings)settings ?? new O2Settings(); + _syncSettings = (O2SyncSettings)syncSettings ?? new O2SyncSettings(); + _controllerDeck = new O2HawkControllerDeck(_syncSettings.Port1); + + byte[] Bios = null; + + Bios = comm.CoreFileProvider.GetFirmware("O2", "World", true, "BIOS Not Found, Cannot Load"); + ppu = new PPU(); + + if (Bios == null) + { + throw new MissingFirmwareException("Missing Odyssey2 Bios"); + } + + _bios = Bios; + + Buffer.BlockCopy(rom, 0x100, header, 0, 0x50); + + Console.WriteLine("MD5: " + rom.HashMD5(0, rom.Length)); + Console.WriteLine("SHA1: " + rom.HashSHA1(0, rom.Length)); + _rom = rom; + Setup_Mapper(); + + _frameHz = 60; + + audio.Core = this; + ppu.Core = this; + serialport.Core = this; + + ser.Register(this); + ser.Register(audio); + ServiceProvider = ser; + + _settings = (O2Settings)settings ?? new O2Settings(); + _syncSettings = (O2SyncSettings)syncSettings ?? new O2SyncSettings(); + + _tracer = new TraceBuffer { Header = cpu.TraceHeader }; + ser.Register(_tracer); + + SetupMemoryDomains(); + HardReset(); + } + + public DisplayType Region => DisplayType.NTSC; + + private readonly O2HawkControllerDeck _controllerDeck; + + public void HardReset() + { + in_vblank = true; // we start off in vblank since the LCD is off + in_vblank_old = true; + + RAM_Bank = 1; // RAM bank always starts as 1 (even writing zero still sets 1) + + Register_Reset(); + ppu.Reset(); + audio.Reset(); + serialport.Reset(); + + cpu.SetCallbacks(ReadMemory, PeekMemory, PeekMemory, WriteMemory); + + _vidbuffer = new int[VirtualWidth * VirtualHeight]; + frame_buffer = new int[VirtualWidth * VirtualHeight]; + } + + private void ExecFetch(ushort addr) + { + uint flags = (uint)(MemoryCallbackFlags.AccessRead); + MemoryCallbacks.CallMemoryCallbacks(addr, 0, flags, "System Bus"); + } + + private void Setup_Mapper() + { + + } + } +} diff --git a/BizHawk.Emulation.Cores/Consoles/Magnavox/Odyssey2/O2HawkControllerDeck.cs b/BizHawk.Emulation.Cores/Consoles/Magnavox/Odyssey2/O2HawkControllerDeck.cs new file mode 100644 index 0000000000..83c92a6f2c --- /dev/null +++ b/BizHawk.Emulation.Cores/Consoles/Magnavox/Odyssey2/O2HawkControllerDeck.cs @@ -0,0 +1,81 @@ +using System; +using System.Collections.Generic; +using System.Linq; + +using BizHawk.Common; +using BizHawk.Common.ReflectionExtensions; +using BizHawk.Emulation.Common; + +namespace BizHawk.Emulation.Cores.Nintendo.O2Hawk +{ + public class O2HawkControllerDeck + { + public O2HawkControllerDeck(string controller1Name) + { + if (!ValidControllerTypes.ContainsKey(controller1Name)) + { + throw new InvalidOperationException("Invalid controller type: " + controller1Name); + } + + Port1 = (IPort)Activator.CreateInstance(ValidControllerTypes[controller1Name], 1); + + Definition = new ControllerDefinition + { + Name = Port1.Definition.Name, + BoolButtons = Port1.Definition.BoolButtons + .ToList() + }; + + Definition.FloatControls.AddRange(Port1.Definition.FloatControls); + + Definition.FloatRanges.AddRange(Port1.Definition.FloatRanges); + } + + public byte ReadPort1(IController c) + { + return Port1.Read(c); + } + + public ushort ReadAccX1(IController c) + { + return Port1.ReadAccX(c); + } + + public ushort ReadAccY1(IController c) + { + return Port1.ReadAccY(c); + } + + public ControllerDefinition Definition { get; } + + public void SyncState(Serializer ser) + { + ser.BeginSection(nameof(Port1)); + Port1.SyncState(ser); + ser.EndSection(); + } + + private readonly IPort Port1; + + private static Dictionary _controllerTypes; + + public static Dictionary ValidControllerTypes + { + get + { + if (_controllerTypes == null) + { + _controllerTypes = typeof(O2HawkControllerDeck).Assembly + .GetTypes() + .Where(t => typeof(IPort).IsAssignableFrom(t)) + .Where(t => !t.IsAbstract && !t.IsInterface) + .ToDictionary(tkey => tkey.DisplayName()); + } + + return _controllerTypes; + } + } + + public static string DefaultControllerName => typeof(StandardControls).DisplayName(); + } +} diff --git a/BizHawk.Emulation.Cores/Consoles/Magnavox/Odyssey2/O2HawkControllers.cs b/BizHawk.Emulation.Cores/Consoles/Magnavox/Odyssey2/O2HawkControllers.cs new file mode 100644 index 0000000000..8af8abcdd9 --- /dev/null +++ b/BizHawk.Emulation.Cores/Consoles/Magnavox/Odyssey2/O2HawkControllers.cs @@ -0,0 +1,217 @@ +using System; +using System.Collections.Generic; +using System.ComponentModel; +using System.Linq; + +using BizHawk.Common; +using BizHawk.Emulation.Common; + +namespace BizHawk.Emulation.Cores.Nintendo.O2Hawk +{ + /// + /// Represents a O2 add on + /// + public interface IPort + { + byte Read(IController c); + + ushort ReadAccX(IController c); + + ushort ReadAccY(IController c); + + ControllerDefinition Definition { get; } + + void SyncState(Serializer ser); + + int PortNum { get; } + } + + [DisplayName("Gameboy Controller")] + public class StandardControls : IPort + { + public StandardControls(int portNum) + { + PortNum = portNum; + Definition = new ControllerDefinition + { + Name = "Gameboy Controller H", + BoolButtons = BaseDefinition + .Select(b => "P" + PortNum + " " + b) + .ToList() + }; + } + + public int PortNum { get; } + + public ControllerDefinition Definition { get; } + + public byte Read(IController c) + { + byte result = 0xFF; + + if (c.IsPressed(Definition.BoolButtons[0])) + { + result -= 4; + } + if (c.IsPressed(Definition.BoolButtons[1])) + { + result -= 8; + } + if (c.IsPressed(Definition.BoolButtons[2])) + { + result -= 2; + } + if (c.IsPressed(Definition.BoolButtons[3])) + { + result -= 1; + } + if (c.IsPressed(Definition.BoolButtons[4])) + { + result -= 128; + } + if (c.IsPressed(Definition.BoolButtons[5])) + { + result -= 64; + } + if (c.IsPressed(Definition.BoolButtons[6])) + { + result -= 32; + } + if (c.IsPressed(Definition.BoolButtons[7])) + { + result -= 16; + } + + return result; + } + + public ushort ReadAccX(IController c) + { + return 0; + } + + public ushort ReadAccY(IController c) + { + return 0; + } + + private static readonly string[] BaseDefinition = + { + "Up", "Down", "Left", "Right", "Start", "Select", "B", "A", "Power" + }; + + public void SyncState(Serializer ser) + { + //nothing + } + } + + [DisplayName("Gameboy Controller + Tilt")] + public class StandardTilt : IPort + { + public StandardTilt(int portNum) + { + PortNum = portNum; + Definition = new ControllerDefinition + { + Name = "Gameboy Controller + Tilt", + BoolButtons = BaseDefinition + .Select(b => "P" + PortNum + " " + b) + .ToList(), + FloatControls = { "P" + PortNum + " Tilt X", "P" + PortNum + " Tilt Y" }, + FloatRanges = { new[] { -45.0f, 0, 45.0f }, new[] { -45.0f, 0, 45.0f } } + }; + } + + public int PortNum { get; } + + public float theta, phi, theta_prev, phi_prev; + + public ControllerDefinition Definition { get; } + + public byte Read(IController c) + { + byte result = 0xFF; + + if (c.IsPressed(Definition.BoolButtons[0])) + { + result -= 4; + } + if (c.IsPressed(Definition.BoolButtons[1])) + { + result -= 8; + } + if (c.IsPressed(Definition.BoolButtons[2])) + { + result -= 2; + } + if (c.IsPressed(Definition.BoolButtons[3])) + { + result -= 1; + } + if (c.IsPressed(Definition.BoolButtons[4])) + { + result -= 128; + } + if (c.IsPressed(Definition.BoolButtons[5])) + { + result -= 64; + } + if (c.IsPressed(Definition.BoolButtons[6])) + { + result -= 32; + } + if (c.IsPressed(Definition.BoolButtons[7])) + { + result -= 16; + } + + return result; + } + + // acc x is the result of rotating around body y AFTER rotating around body x + // therefore this control scheme gives decreasing sensitivity in X as Y rotation inscreases + public ushort ReadAccX(IController c) + { + theta_prev = theta; + phi_prev = phi; + + theta = (float)(c.GetFloat(Definition.FloatControls[1]) * Math.PI / 180.0); + phi = (float)(c.GetFloat(Definition.FloatControls[0]) * Math.PI / 180.0); + + float temp = (float)(Math.Cos(theta) * Math.Sin(phi)); + + // here we add in rates of change parameters. + // a typical rate of change for a fast rotation is guessed at 0.5 rad / frame + // since rotations about X have less of a moment arm compared to by, we take 1/5 of the effect as a baseline + float temp2 = (float)((phi - phi_prev) / 0.5 * 25); + + return (ushort)(0x81D0 - Math.Floor(temp * 125) - temp2); + } + + // acc y is just the sine of the angle + // we assume that ReadAccX is called first, which updates the the states + public ushort ReadAccY(IController c) + { + float temp = (float)Math.Sin(theta); + + // here we add in rates of change parameters. + // a typical rate of change for a fast rotation is guessed at 0.5 rad / frame + // further it will be assumed that the resulting acceleration is roughly eqvuivalent to gravity + float temp2 = (float)((theta - theta_prev)/0.5 * 125); + + return (ushort)(0x81D0 - Math.Floor(temp * 125) + temp2); + } + + private static readonly string[] BaseDefinition = + { + "Up", "Down", "Left", "Right", "Start", "Select", "B", "A", "Power" + }; + + public void SyncState(Serializer ser) + { + // since we need rate of change of angle, need to savestate them + ser.Sync(nameof(theta), ref theta); + } + } +} \ No newline at end of file diff --git a/BizHawk.Emulation.Cores/Consoles/Magnavox/Odyssey2/PPU.cs b/BizHawk.Emulation.Cores/Consoles/Magnavox/Odyssey2/PPU.cs new file mode 100644 index 0000000000..d48456cb4f --- /dev/null +++ b/BizHawk.Emulation.Cores/Consoles/Magnavox/Odyssey2/PPU.cs @@ -0,0 +1,272 @@ +using System; +using BizHawk.Common; + +namespace BizHawk.Emulation.Cores.Nintendo.O2Hawk +{ + public class PPU + { + public O2Hawk Core { get; set; } + + public uint[] BG_palette = new uint[32]; + public uint[] OBJ_palette = new uint[32]; + + public bool HDMA_active; + public bool clear_screen; + + // register variables + public byte LCDC; + public byte STAT; + public byte scroll_y; + public byte scroll_x; + public byte LY; + public byte LY_actual; + public byte LY_inc; + public byte LYC; + public byte DMA_addr; + public byte BGP; + public byte obj_pal_0; + public byte obj_pal_1; + public byte window_y; + public byte window_x; + public bool DMA_start; + public int DMA_clock; + public int DMA_inc; + public byte DMA_byte; + + // state variables + public int cycle; + public bool LYC_INT; + public bool HBL_INT; + public bool VBL_INT; + public bool OAM_INT; + public bool LCD_was_off; + public bool stat_line; + public bool stat_line_old; + // OAM scan + public bool DMA_OAM_access; + public bool OAM_access_read; + public bool OAM_access_write; + public int OAM_scan_index; + public int SL_sprites_index; + public int[] SL_sprites = new int[40]; + public int write_sprite; + public bool no_scan; + // render + public bool VRAM_access_read; + public bool VRAM_access_write; + public int read_case; + public int internal_cycle; + public int y_tile; + public int y_scroll_offset; + public int x_tile; + public int x_scroll_offset; + public int tile_byte; + public int sprite_fetch_cycles; + public bool fetch_sprite; + public bool going_to_fetch; + public bool first_fetch; + public int sprite_fetch_counter; + public byte[] sprite_attr_list = new byte[160]; + public byte[] sprite_pixel_list = new byte[160]; + public byte[] sprite_present_list = new byte[160]; + public int temp_fetch; + public int tile_inc; + public bool pre_render; + public bool pre_render_2; + public byte[] tile_data = new byte[3]; + public byte[] tile_data_latch = new byte[3]; + public int latch_counter; + public bool latch_new_data; + public int render_counter; + public int render_offset; + public int pixel_counter; + public int pixel; + public byte[] sprite_data = new byte[2]; + public byte[] sprite_sel = new byte[2]; + public int sl_use_index; + public bool no_sprites; + public int[] SL_sprites_ordered = new int[40]; // (x_end, data_low, data_high, attr) + public int evaled_sprites; + public int sprite_ordered_index; + public bool blank_frame; + public bool window_latch; + public int consecutive_sprite; + public int last_eval; + + public int total_counter; + // windowing state + public int window_counter; + public bool window_pre_render; + public bool window_started; + public bool window_is_reset; + public int window_tile_inc; + public int window_y_tile; + public int window_x_tile; + public int window_y_tile_inc; + public int window_x_latch; + public int window_y_latch; + + public int hbl_countdown; + + public byte ReadReg(int addr) + { + byte ret = 0; + + switch (addr) + { + + } + + return ret; + } + + public void WriteReg(int addr, byte value) + { + + } + + public void tick() + { + + } + + // might be needed, not sure yet + public void latch_delay() + { + + } + + public void render(int render_cycle) + { + + } + + public void process_sprite() + { + + } + + // normal DMA moves twice as fast in double speed mode on GBC + // So give it it's own function so we can seperate it from PPU tick + public void DMA_tick() + { + + } + + public void OAM_scan(int OAM_cycle) + { + + } + + public void Reset() + { + + } + + // order sprites according to x coordinate + // note that for sprites of equal x coordinate, priority goes to first on the list + public void reorder_and_assemble_sprites() + { + + } + + public void SyncState(Serializer ser) + { + ser.Sync(nameof(BG_palette), ref BG_palette, false); + ser.Sync(nameof(OBJ_palette), ref OBJ_palette, false); + ser.Sync(nameof(HDMA_active), ref HDMA_active); + ser.Sync(nameof(clear_screen), ref clear_screen); + + ser.Sync(nameof(LCDC), ref LCDC); + ser.Sync(nameof(STAT), ref STAT); + ser.Sync(nameof(scroll_y), ref scroll_y); + ser.Sync(nameof(scroll_x), ref scroll_x); + ser.Sync(nameof(LY), ref LY); + ser.Sync(nameof(LY_actual), ref LY_actual); + ser.Sync(nameof(LY_inc), ref LY_inc); + ser.Sync(nameof(LYC), ref LYC); + ser.Sync(nameof(DMA_addr), ref DMA_addr); + ser.Sync(nameof(BGP), ref BGP); + ser.Sync(nameof(obj_pal_0), ref obj_pal_0); + ser.Sync(nameof(obj_pal_1), ref obj_pal_1); + ser.Sync(nameof(window_y), ref window_y); + ser.Sync(nameof(window_x), ref window_x); + ser.Sync(nameof(DMA_start), ref DMA_start); + ser.Sync(nameof(DMA_clock), ref DMA_clock); + ser.Sync(nameof(DMA_inc), ref DMA_inc); + ser.Sync(nameof(DMA_byte), ref DMA_byte); + + ser.Sync(nameof(cycle), ref cycle); + ser.Sync(nameof(LYC_INT), ref LYC_INT); + ser.Sync(nameof(HBL_INT), ref HBL_INT); + ser.Sync(nameof(VBL_INT), ref VBL_INT); + ser.Sync(nameof(OAM_INT), ref OAM_INT); + ser.Sync(nameof(stat_line), ref stat_line); + ser.Sync(nameof(stat_line_old), ref stat_line_old); + ser.Sync(nameof(LCD_was_off), ref LCD_was_off); + ser.Sync(nameof(OAM_scan_index), ref OAM_scan_index); + ser.Sync(nameof(SL_sprites_index), ref SL_sprites_index); + ser.Sync(nameof(SL_sprites), ref SL_sprites, false); + ser.Sync(nameof(write_sprite), ref write_sprite); + ser.Sync(nameof(no_scan), ref no_scan); + + ser.Sync(nameof(DMA_OAM_access), ref DMA_OAM_access); + ser.Sync(nameof(OAM_access_read), ref OAM_access_read); + ser.Sync(nameof(OAM_access_write), ref OAM_access_write); + ser.Sync(nameof(VRAM_access_read), ref VRAM_access_read); + ser.Sync(nameof(VRAM_access_write), ref VRAM_access_write); + + ser.Sync(nameof(read_case), ref read_case); + ser.Sync(nameof(internal_cycle), ref internal_cycle); + ser.Sync(nameof(y_tile), ref y_tile); + ser.Sync(nameof(y_scroll_offset), ref y_scroll_offset); + ser.Sync(nameof(x_tile), ref x_tile); + ser.Sync(nameof(x_scroll_offset), ref x_scroll_offset); + ser.Sync(nameof(tile_byte), ref tile_byte); + ser.Sync(nameof(sprite_fetch_cycles), ref sprite_fetch_cycles); + ser.Sync(nameof(fetch_sprite), ref fetch_sprite); + ser.Sync(nameof(going_to_fetch), ref going_to_fetch); + ser.Sync(nameof(first_fetch), ref first_fetch); + ser.Sync(nameof(sprite_fetch_counter), ref sprite_fetch_counter); + ser.Sync(nameof(sprite_attr_list), ref sprite_attr_list, false); + ser.Sync(nameof(sprite_pixel_list), ref sprite_pixel_list, false); + ser.Sync(nameof(sprite_present_list), ref sprite_present_list, false); + ser.Sync(nameof(temp_fetch), ref temp_fetch); + ser.Sync(nameof(tile_inc), ref tile_inc); + ser.Sync(nameof(pre_render), ref pre_render); + ser.Sync(nameof(pre_render_2), ref pre_render_2); + ser.Sync(nameof(tile_data), ref tile_data, false); + ser.Sync(nameof(tile_data_latch), ref tile_data_latch, false); + ser.Sync(nameof(latch_counter), ref latch_counter); + ser.Sync(nameof(latch_new_data), ref latch_new_data); + ser.Sync(nameof(render_counter), ref render_counter); + ser.Sync(nameof(render_offset), ref render_offset); + ser.Sync(nameof(pixel_counter), ref pixel_counter); + ser.Sync(nameof(pixel), ref pixel); + ser.Sync(nameof(sprite_data), ref sprite_data, false); + ser.Sync(nameof(sl_use_index), ref sl_use_index); + ser.Sync(nameof(sprite_sel), ref sprite_sel, false); + ser.Sync(nameof(no_sprites), ref no_sprites); + ser.Sync(nameof(evaled_sprites), ref evaled_sprites); + ser.Sync(nameof(SL_sprites_ordered), ref SL_sprites_ordered, false); + ser.Sync(nameof(sprite_ordered_index), ref sprite_ordered_index); + ser.Sync(nameof(blank_frame), ref blank_frame); + ser.Sync(nameof(window_latch), ref window_latch); + ser.Sync(nameof(consecutive_sprite), ref consecutive_sprite); + ser.Sync(nameof(last_eval), ref last_eval); + + ser.Sync(nameof(window_counter), ref window_counter); + ser.Sync(nameof(window_pre_render), ref window_pre_render); + ser.Sync(nameof(window_started), ref window_started); + ser.Sync(nameof(window_is_reset), ref window_is_reset); + ser.Sync(nameof(window_tile_inc), ref window_tile_inc); + ser.Sync(nameof(window_y_tile), ref window_y_tile); + ser.Sync(nameof(window_x_tile), ref window_x_tile); + ser.Sync(nameof(window_y_tile_inc), ref window_y_tile_inc); + ser.Sync(nameof(window_x_latch), ref window_x_latch); + ser.Sync(nameof(window_y_latch), ref window_y_latch); + + ser.Sync(nameof(hbl_countdown), ref hbl_countdown); + } + } +} diff --git a/BizHawk.Emulation.Cores/Consoles/Magnavox/Odyssey2/ReadMe.txt b/BizHawk.Emulation.Cores/Consoles/Magnavox/Odyssey2/ReadMe.txt new file mode 100644 index 0000000000..bc60bf4b01 --- /dev/null +++ b/BizHawk.Emulation.Cores/Consoles/Magnavox/Odyssey2/ReadMe.txt @@ -0,0 +1 @@ +TODO: diff --git a/BizHawk.Emulation.Cores/Consoles/Magnavox/Odyssey2/SerialPort.cs b/BizHawk.Emulation.Cores/Consoles/Magnavox/Odyssey2/SerialPort.cs new file mode 100644 index 0000000000..e67b722df3 --- /dev/null +++ b/BizHawk.Emulation.Cores/Consoles/Magnavox/Odyssey2/SerialPort.cs @@ -0,0 +1,150 @@ +using System; +using BizHawk.Emulation.Common; +using BizHawk.Common.NumberExtensions; +using BizHawk.Common; + +namespace BizHawk.Emulation.Cores.Nintendo.O2Hawk +{ + public class SerialPort + { + public O2Hawk Core { get; set; } + + public byte serial_control; + public byte serial_data; + public bool serial_start; + public bool can_pulse; + public int serial_clock; + public int serial_bits; + public int clk_rate; + public byte going_out; + public byte coming_in; + + public byte ReadReg(int addr) + { + switch (addr) + { + case 0xFF01: + return serial_data; + case 0xFF02: + return serial_control; + } + + return 0xFF; + } + + public void WriteReg(int addr, byte value) + { + switch (addr) + { + case 0xFF01: + serial_data = value; + break; + + case 0xFF02: + if (((value & 0x80) > 0) && !serial_start) + { + serial_start = true; + serial_bits = 8; + if ((value & 1) > 0) + { + if (((value & 2) > 0)) + { + clk_rate = 16; + } + else + { + clk_rate = 512; + } + serial_clock = clk_rate; + can_pulse = true; + } + else + { + clk_rate = -1; + serial_clock = clk_rate; + can_pulse = false; + } + } + else if (serial_start) + { + if ((value & 1) > 0) + { + if (((value & 2) > 0)) + { + clk_rate = 16; + } + else + { + clk_rate = 512; + } + serial_clock = clk_rate; + can_pulse = true; + } + else + { + clk_rate = -1; + serial_clock = clk_rate; + can_pulse = false; + } + } + + serial_control = (byte)(0x7E | (value & 0x81)); // middle six bits always 1 + + break; + } + } + + + public void serial_transfer_tick() + { + if (serial_start) + { + if (serial_clock > 0) { serial_clock--; } + + if (serial_clock == 0) + { + if (serial_bits > 0) + { + byte temp = coming_in; + serial_data = (byte)((serial_data << 1) | temp); + + serial_bits--; + + if (serial_bits == 0) + { + serial_control &= 0x7F; + serial_start = false; + } + else + { + serial_clock = clk_rate; + if (clk_rate > 0) { can_pulse = true; } + } + } + } + } + } + + public void Reset() + { + serial_control = 0x7E; + serial_start = false; + serial_data = 0x00; + going_out = 0; + coming_in = 1; + } + + public void SyncState(Serializer ser) + { + ser.Sync(nameof(serial_control), ref serial_control); + ser.Sync(nameof(serial_data), ref serial_data); + ser.Sync(nameof(serial_start), ref serial_start); + ser.Sync(nameof(serial_clock), ref serial_clock); + ser.Sync(nameof(serial_bits), ref serial_bits); + ser.Sync(nameof(clk_rate), ref clk_rate); + ser.Sync(nameof(going_out), ref going_out); + ser.Sync(nameof(coming_in), ref coming_in); + ser.Sync(nameof(can_pulse), ref can_pulse); + } + } +} From d6f46104dd298d3a4b4b222343c00dc1f7ab40a4 Mon Sep 17 00:00:00 2001 From: alyosha-tas Date: Thu, 31 Oct 2019 13:29:18 -0400 Subject: [PATCH 164/166] O2hawk: internal graphics table --- .../Consoles/Magnavox/Odyssey2/PPU.cs | 66 +++++++++++++++++++ 1 file changed, 66 insertions(+) diff --git a/BizHawk.Emulation.Cores/Consoles/Magnavox/Odyssey2/PPU.cs b/BizHawk.Emulation.Cores/Consoles/Magnavox/Odyssey2/PPU.cs index d48456cb4f..9fd91d3c11 100644 --- a/BizHawk.Emulation.Cores/Consoles/Magnavox/Odyssey2/PPU.cs +++ b/BizHawk.Emulation.Cores/Consoles/Magnavox/Odyssey2/PPU.cs @@ -170,6 +170,72 @@ namespace BizHawk.Emulation.Cores.Nintendo.O2Hawk } + public static readonly byte[] Internal_Graphics = { 0x3C, 0x66, 0x66, 0x66, 0x66, 0x66, 0x3C, // 0 0x00 + 0x18, 0x38, 0x18, 0x18, 0x18, 0x18, 0x3C, // 1 0x01 + 0x3C, 0x66, 0x0C, 0x18, 0x30, 0x60, 0x7E, // 2 0x02 + 0x3C, 0x66, 0x06, 0x1C, 0x06, 0x66, 0x3C, // 3 0x03 + 0xCC, 0xCC, 0xCC, 0xFE, 0x0C, 0x0C, 0x0C, // 4 0x04 + 0x7E, 0x60, 0x60, 0x3C, 0x60, 0x66, 0x3C, // 5 0x05 + 0x3C, 0x66, 0x60, 0x7C, 0x66, 0x66, 0x3C, // 6 0x06 + 0xFE, 0x06, 0x0C, 0x18, 0x30, 0x60, 0xC0, // 7 0x07 + 0x3C, 0x66, 0x66, 0x3C, 0x66, 0x66, 0x3C, // 8 0x08 + 0x3C, 0x66, 0x66, 0x3E, 0x02, 0x66, 0x3C, // 9 0x09 + 0x00, 0x18, 0x18, 0x00, 0x18, 0x18, 0x00, // : 0x0A + 0x18, 0x7E, 0x58, 0x7E, 0x1A, 0x7E, 0x18, // $ 0x0B + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0x0C + 0x3C, 0x66, 0x0C, 0x18, 0x18, 0x00, 0x18, // ? 0x0D + 0x60, 0x60, 0x60, 0x60, 0x60, 0x60, 0x7E, // L 0x0E + 0x7C, 0x66, 0x66, 0x7C, 0x60, 0x60, 0x60, // P 0x0F + 0x00, 0x18, 0x18, 0x7E, 0x18, 0x18, 0x00, // + 0x10 + 0xC6, 0xC6, 0xC6, 0xD6, 0xFE, 0xEE, 0xC6, // W 0x11 + 0x7E, 0x60, 0x60, 0x7C, 0x60, 0x60, 0x7E, // E 0x12 + 0xFC, 0xC6, 0xC6, 0xFC, 0xD8, 0xCC, 0xC6, // R 0x13 + 0x7E, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, // T 0x14 + 0xC6, 0xC6, 0xC6, 0xC6, 0xC6, 0xC6, 0x7C, // U 0x15 + 0x3C, 0x18, 0x18, 0x18, 0x18, 0x18, 0x3C, // I 0x16 + 0x7C, 0xC6, 0xC6, 0xC6, 0xC6, 0xC6, 0x7C, // O 0x17 + 0x7C, 0xC6, 0xC6, 0xC6, 0xD7, 0xCC, 0x76, // Q 0x18 + 0x3C, 0x66, 0x60, 0x3C, 0x06, 0x66, 0x3C, // S 0x19 + 0x7C, 0x66, 0x66, 0x66, 0x66, 0x66, 0x7C, // D 0x1A + 0xFE, 0xC0, 0xC0, 0xF8, 0xC0, 0xC0, 0xC0, // F 0x1B + 0x7C, 0xC6, 0xC0, 0xC0, 0xCE, 0xC6, 0x7E, // G 0x1C + 0xC6, 0xC6, 0xC6, 0xFE, 0xC6, 0xC6, 0xC6, // H 0x1D + 0x06, 0x06, 0x06, 0x06, 0x06, 0xC6, 0x7C, // J 0x1E + 0xC6, 0xCC, 0xD8, 0xF0, 0xD8, 0xCC, 0xC6, // K 0x1F + 0x38, 0x6C, 0xC6, 0xC6, 0xF7, 0xC6, 0xC6, // A 0x20 + 0x7E, 0x06, 0x0C, 0x18, 0x30, 0x60, 0x7E, // Z 0x21 + 0xC6, 0xC6, 0x6C, 0x38, 0x6C, 0xC6, 0xC6, // X 0x22 + 0x7C, 0xC6, 0xC0, 0xC0, 0xC0, 0xC6, 0x7C, // C 0x23 + 0xC6, 0xC6, 0xC6, 0xC6, 0xC6, 0x6C, 0x38, // V 0x24 + 0x7C, 0x66, 0x66, 0x7C, 0x66, 0x66, 0x7C, // B 0x25 + 0xC6, 0xEE, 0xFE, 0xD6, 0xC6, 0xC6, 0xC6, // M 0x26 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x38, 0x38, // . 0x27 + 0x00, 0x00, 0x00, 0x7E, 0x00, 0x00, 0x00, // - 0x28 + 0x00, 0x66, 0x3C, 0x18, 0x3C, 0x66, 0x00, // x 0x29 + 0x00, 0x18, 0x00, 0x7E, 0x00, 0x18, 0x00, // (div) 0x2A + 0x00, 0x00, 0x7E, 0x00, 0x7E, 0x00, 0x00, // = 0x2B + 0x66, 0x66, 0x66, 0x3C, 0x18, 0x18, 0x18, // Y 0x2C + 0xC6, 0xE6, 0xF6, 0xFE, 0xDE, 0xCE, 0xC6, // N 0x2D + 0x03, 0x06, 0xC0, 0x18, 0x30, 0x60, 0xC0, // / 0x2E + 0x7E, 0x7E, 0x7E, 0x7E, 0x7E, 0x7E, 0x7E, // (box) 0x2F + 0xCE, 0xDB, 0xDB, 0xDB, 0xDB, 0xDB, 0xCE, // 10 0x30 + 0x00, 0x00, 0x3C, 0x7E, 0x7E, 0x7E, 0x3C, // (ball) 0x31 + 0x38, 0x38, 0x30, 0x3C, 0x30, 0x30, 0x38, // (person R) 0x32 + 0x38, 0x38, 0x30, 0x3C, 0x30, 0x68, 0x4C, // (runner R) 0x33 + 0x38, 0x38, 0x18, 0x78, 0x18, 0x2C, 0x64, // (runner L) 0x34 + 0x38, 0x38, 0x18, 0x78, 0x18, 0x18, 0x38, // (person L) 0x35 + 0x00, 0x18, 0xC0, 0xF7, 0xC0, 0x18, 0x00, // (arrow R) 0x36 + 0x18, 0x3C, 0x7E, 0xFF, 0xFF, 0x18, 0x18, // (tree) 0x37 + 0x01, 0x03, 0x07, 0x0F, 0x1F, 0x3F, 0x7F, // (ramp R) 0x38 + 0x80, 0xC0, 0xE0, 0xF0, 0xF8, 0xFC, 0xFE, // (ramp L) 0x39 + 0x38, 0x38, 0x12, 0xFE, 0xB8, 0x28, 0x6C, // (person F) 0x3A + 0xC0, 0x60, 0x30, 0x18, 0x0C, 0x06, 0x03, // \ 0x3B + 0x00, 0x00, 0x18, 0x10, 0x10, 0xF7, 0x7C, // (boat 1) 0x3C + 0x00, 0x03, 0x63, 0xFF, 0xFF, 0x18, 0x08, // (plane) 0x3D + 0x00, 0x00, 0x00, 0x01, 0x38, 0xFF, 0x7E, // (boat 2) 0x3E + 0x00, 0x00, 0x00, 0x54, 0x54, 0xFF, 0x7E, // (boat 3 unk) 0x3F + }; + public void SyncState(Serializer ser) { ser.Sync(nameof(BG_palette), ref BG_palette, false); From 3b25fdc8ca2db0842078eaac9d57492c54040fdd Mon Sep 17 00:00:00 2001 From: adelikat Date: Tue, 29 Oct 2019 17:18:17 -0500 Subject: [PATCH 165/166] simplify some movie import code --- .../conversions/MovieConversionExtensions.cs | 2 +- .../movie/import/IMovieImport.cs | 12 ++--- .../movie/import/MovieImport.cs | 46 +++++++------------ BizHawk.sln.DotSettings | 2 + 4 files changed, 22 insertions(+), 40 deletions(-) diff --git a/BizHawk.Client.Common/movie/conversions/MovieConversionExtensions.cs b/BizHawk.Client.Common/movie/conversions/MovieConversionExtensions.cs index a1450bf56a..6fe710524f 100644 --- a/BizHawk.Client.Common/movie/conversions/MovieConversionExtensions.cs +++ b/BizHawk.Client.Common/movie/conversions/MovieConversionExtensions.cs @@ -338,7 +338,7 @@ namespace BizHawk.Client.Common.MovieConversionExtensions if (Global.Emulator is SMS && (Global.Emulator as SMS).IsSG1000) { movie.HeaderEntries.Add("IsSGMode", "1"); - } + } if (Global.Emulator is SMS && (Global.Emulator as SMS).IsGameGear) { diff --git a/BizHawk.Client.Common/movie/import/IMovieImport.cs b/BizHawk.Client.Common/movie/import/IMovieImport.cs index 91191b7342..c35caddca8 100644 --- a/BizHawk.Client.Common/movie/import/IMovieImport.cs +++ b/BizHawk.Client.Common/movie/import/IMovieImport.cs @@ -68,14 +68,8 @@ namespace BizHawk.Client.Common public class ImportResult { - public ImportResult() - { - Warnings = new List(); - Errors = new List(); - } - - public IList Warnings { get; private set; } - public IList Errors { get; } + public IList Warnings { get; } = new List(); + public IList Errors { get; } = new List(); public Bk2Movie Movie { get; set; } } @@ -88,6 +82,6 @@ namespace BizHawk.Client.Common Extension = extension; } - public string Extension { get; private set; } + public string Extension { get; } } } diff --git a/BizHawk.Client.Common/movie/import/MovieImport.cs b/BizHawk.Client.Common/movie/import/MovieImport.cs index 6f16c63120..0b0a6ae201 100644 --- a/BizHawk.Client.Common/movie/import/MovieImport.cs +++ b/BizHawk.Client.Common/movie/import/MovieImport.cs @@ -42,23 +42,16 @@ namespace BizHawk.Client.Common public static void ProcessMovieImport(string fn, Action conversionErrorCallback, Action messageCallback) { var d = PathManager.MakeAbsolutePath(Global.Config.PathEntries.MoviesPathFragment, null); - string errorMsg; - string warningMsg; - var m = ImportFile(fn, out errorMsg, out warningMsg); + var m = ImportFile(fn, out var errorMsg, out var warningMsg); if (!string.IsNullOrWhiteSpace(errorMsg)) { conversionErrorCallback(errorMsg); } - if (!string.IsNullOrWhiteSpace(warningMsg)) - { - messageCallback(warningMsg); - } - else - { - messageCallback($"{Path.GetFileName(fn)} imported as {m.Filename}"); - } + messageCallback(!string.IsNullOrWhiteSpace(warningMsg) + ? warningMsg + : $"{Path.GetFileName(fn)} imported as {m.Filename}"); if (!Directory.Exists(d)) { @@ -118,25 +111,15 @@ namespace BizHawk.Client.Common private static IEnumerable ImportersForExtension(string ext) { - var info = typeof(MovieImport).Module; - var importers = from t in info.GetTypes() - where typeof(IMovieImport).IsAssignableFrom(t) - && TypeImportsExtension(t, ext) - select t; - - return importers; + return typeof(MovieImport).Module + .GetTypes() + .Where(t => typeof(IMovieImport).IsAssignableFrom(t)); } private static bool TypeImportsExtension(Type t, string ext) { var attrs = (ImportExtensionAttribute[])t.GetCustomAttributes(typeof(ImportExtensionAttribute), inherit: false); - - if (attrs.Any(a => a.Extension.ToUpper() == ext.ToUpper())) - { - return true; - } - - return false; + return attrs.Any(a => a.Extension.ToUpper() == ext.ToUpper()); } private static BkmMovie LegacyImportFile(string ext, string path, out string errorMsg, out string warningMsg) @@ -252,9 +235,12 @@ namespace BizHawk.Client.Common private static IController EmptyLmsvFrame(string line) { - var emptyController = new SimpleController { Definition = new ControllerDefinition { Name = "SNES Controller" } }; - emptyController["Reset"] = false; - emptyController["Power"] = false; + var emptyController = new SimpleController + { + Definition = new ControllerDefinition { Name = "SNES Controller" } + , ["Reset"] = false + , ["Power"] = false + }; string[] buttons = { "B", "Y", "Select", "Start", "Up", "Down", "Left", "Right", "A", "X", "L", "R" }; string[] sections = line.Split('|'); @@ -263,9 +249,9 @@ namespace BizHawk.Client.Common int player = section - 1; // We start with 1 string prefix = $"P{player} "; // "P1" - for (int button = 0; button < buttons.Length; button++) + foreach (var b in buttons) { - emptyController[prefix + buttons[button]] = false; + emptyController[prefix + b] = false; } } diff --git a/BizHawk.sln.DotSettings b/BizHawk.sln.DotSettings index 1473f6e06c..759dbd9b23 100644 --- a/BizHawk.sln.DotSettings +++ b/BizHawk.sln.DotSettings @@ -226,6 +226,7 @@ True True True + True True True True @@ -262,6 +263,7 @@ True True True + True True True True From 7d554f06d349598f068ea16f5c6f9c0c69f1104d Mon Sep 17 00:00:00 2001 From: adelikat Date: Tue, 29 Oct 2019 17:19:44 -0500 Subject: [PATCH 166/166] return an IMovie instead of Bk2Movie from ImportFile --- BizHawk.Client.Common/movie/import/MovieImport.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/BizHawk.Client.Common/movie/import/MovieImport.cs b/BizHawk.Client.Common/movie/import/MovieImport.cs index 0b0a6ae201..89152ab11d 100644 --- a/BizHawk.Client.Common/movie/import/MovieImport.cs +++ b/BizHawk.Client.Common/movie/import/MovieImport.cs @@ -60,7 +60,7 @@ namespace BizHawk.Client.Common } // Attempt to import another type of movie file into a movie object. - public static Bk2Movie ImportFile(string path, out string errorMsg, out string warningMsg) + public static IMovie ImportFile(string path, out string errorMsg, out string warningMsg) { errorMsg = ""; warningMsg = "";