Some checks failed
Cargo Build & Test / Rust project - latest (stable) (push) Has been cancelled
- Bit instruction now sets Z flag correctly - DMA is no longer handled by cpu.rs
668 lines
22 KiB
Rust
668 lines
22 KiB
Rust
use std::rc::Rc;
|
|
|
|
use iced::{
|
|
Element,
|
|
Length::{self, Fill},
|
|
Point, Renderer, Size,
|
|
advanced::{
|
|
Widget,
|
|
layout::Node,
|
|
widget::{
|
|
Tree,
|
|
tree::{State, Tag},
|
|
},
|
|
},
|
|
mouse,
|
|
widget::{
|
|
self, Canvas, Text, button,
|
|
canvas::{Frame, Program},
|
|
checkbox, column,
|
|
container::bordered_box,
|
|
hex_input, image, number_input, row,
|
|
rule::horizontal,
|
|
scrollable, text,
|
|
},
|
|
};
|
|
|
|
use crate::{Break, CycleResult, NES, PPU, mem::Mapped};
|
|
|
|
#[derive(Debug, Clone)]
|
|
pub struct DebuggerState {
|
|
ppu_cycles: usize,
|
|
cpu_cycles: usize,
|
|
instructions: usize,
|
|
scan_lines: usize,
|
|
to_scan_line: usize,
|
|
frames: usize,
|
|
breakpoint: usize,
|
|
}
|
|
|
|
#[derive(Debug, Clone)]
|
|
pub enum DebuggerMessage {
|
|
Run,
|
|
Pause,
|
|
SetPPUCycles(usize),
|
|
RunPPUCycles,
|
|
SetCPUCycles(usize),
|
|
RunCPUCycles,
|
|
SetInstructions(usize),
|
|
RunInstructions,
|
|
SetScanLines(usize),
|
|
RunScanLines,
|
|
SetToScanLine(usize),
|
|
RunToScanLine,
|
|
SetFrames(usize),
|
|
RunFrames,
|
|
SetBreakpoint(usize),
|
|
RunBreakpoint,
|
|
}
|
|
|
|
pub fn hex16<'a, Theme, Renderer>(val: u16) -> Text<'a, Theme, Renderer>
|
|
where
|
|
Theme: text::Catalog + 'a,
|
|
Renderer: iced::advanced::text::Renderer,
|
|
{
|
|
text(format!("{val:04X}"))
|
|
}
|
|
pub fn hex8<'a, Theme, Renderer>(val: u8) -> Text<'a, Theme, Renderer>
|
|
where
|
|
Theme: text::Catalog + 'a,
|
|
Renderer: iced::advanced::text::Renderer,
|
|
{
|
|
text(format!("{val:02X}"))
|
|
}
|
|
pub fn bin8<'a, Theme, Renderer>(val: u8) -> Text<'a, Theme, Renderer>
|
|
where
|
|
Theme: text::Catalog + 'a,
|
|
Renderer: iced::advanced::text::Renderer,
|
|
{
|
|
text(format!("{val:08b}"))
|
|
}
|
|
pub fn bin32<'a, Theme, Renderer>(val: u32) -> Text<'a, Theme, Renderer>
|
|
where
|
|
Theme: text::Catalog + 'a,
|
|
Renderer: iced::advanced::text::Renderer,
|
|
{
|
|
text(format!("{val:032b}"))
|
|
}
|
|
|
|
impl DebuggerState {
|
|
pub fn new() -> Self {
|
|
Self {
|
|
ppu_cycles: 1,
|
|
cpu_cycles: 1,
|
|
instructions: 1,
|
|
scan_lines: 1,
|
|
to_scan_line: 1,
|
|
frames: 1,
|
|
breakpoint: 0xEA5A,
|
|
// cpu_cycles: 1,
|
|
}
|
|
}
|
|
|
|
pub fn view<'s>(&'s self, nes: &'s NES) -> Element<'s, DebuggerMessage> {
|
|
column![
|
|
row![
|
|
button(image("./images/ic_fluent_play_24_filled.png"))
|
|
.on_press(DebuggerMessage::Run),
|
|
button(image("./images/ic_fluent_pause_24_filled.png"))
|
|
.on_press(DebuggerMessage::Pause),
|
|
],
|
|
iced::widget::rule::horizontal(2.),
|
|
row![column![
|
|
text("Status"),
|
|
row![
|
|
labelled("A:", text(format!("{:02X}", nes.cpu.a))),
|
|
labelled("X:", text(format!("{:02X}", nes.cpu.x))),
|
|
labelled("Y:", text(format!("{:02X}", nes.cpu.y))),
|
|
labelled("PC:", text(format!("{:04X}", nes.cpu.pc))),
|
|
labelled("Cycle:", text(format!("{}", nes.cpu_cycle()))),
|
|
labelled("SP:", text(format!("{:02X}", nes.cpu.sp))),
|
|
]
|
|
.spacing(5.),
|
|
row![
|
|
labelled("P:", text(format!("{:02X}", nes.cpu.status.0))),
|
|
labelled_box("Carry", nes.cpu.status.carry()),
|
|
labelled_box("Zero", nes.cpu.status.zero()),
|
|
labelled_box("Interrupt", nes.cpu.status.interrupt_disable()),
|
|
labelled_box("--", false),
|
|
labelled_box("--", false),
|
|
labelled_box("Overflow", nes.cpu.status.overflow()),
|
|
labelled_box("Negative", nes.cpu.status.negative()),
|
|
]
|
|
.spacing(5.),
|
|
row![
|
|
text("IRQs:"),
|
|
labelled_box("NMI", nes.peek_nmi()),
|
|
labelled_box("Cart", false),
|
|
labelled_box("Frame Counter", nes.apu().peek_irq()),
|
|
labelled_box("DMC", false),
|
|
]
|
|
.spacing(5.),
|
|
row![
|
|
column![
|
|
labelled("Cycle", text(nes.ppu().pixel)),
|
|
labelled("Scanline", text(nes.ppu().scanline)),
|
|
labelled("PPU Cycle", text(nes.ppu().cycle)),
|
|
labelled("Frame", text(nes.ppu().frame_count)),
|
|
labelled("V:", hex16(nes.ppu().background.v)),
|
|
labelled("T:", hex16(nes.ppu().background.t)),
|
|
labelled("X:", hex8(nes.ppu().background.x)),
|
|
text(""),
|
|
labelled("NT:", hex8(nes.ppu().background.cur_nametable)),
|
|
labelled2(
|
|
"AT:",
|
|
hex8(nes.ppu().background.next_attr),
|
|
hex16(
|
|
0x23C0
|
|
| (nes.ppu().background.v & 0x0C00)
|
|
| ((nes.ppu().background.v >> 4) & 0x38)
|
|
| ((nes.ppu().background.v >> 2) & 0x07)
|
|
)
|
|
),
|
|
labelled("AT:", hex8(nes.ppu().background.cur_attr)),
|
|
labelled("HI:", bin32(nes.ppu().background.cur_shift_high)),
|
|
labelled("LO:", bin32(nes.ppu().background.cur_shift_low)),
|
|
],
|
|
column![
|
|
labelled_box("Sprite 0 Hit", false),
|
|
labelled_box("Sprite 0 Overflow", false),
|
|
labelled_box("Vertical Blank", nes.ppu().vblank),
|
|
labelled_box("Write Toggle", nes.ppu().background.w),
|
|
text(""),
|
|
labelled_box("Large Sprites", false),
|
|
labelled_box("Vertical Write", nes.ppu().background.vram_column),
|
|
labelled_box("NMI on VBlank", nes.ppu().nmi_on_vblank()),
|
|
labelled_box("BG at $1000", nes.ppu().background.second_pattern),
|
|
labelled_box("Sprites at $1000", false),
|
|
],
|
|
column![
|
|
labelled_box("Even frame", nes.ppu().even),
|
|
labelled_box("BG Enabled", nes.ppu().mask.enable_background),
|
|
labelled_box("Sprites Enabled", nes.ppu().mask.enable_sprites),
|
|
labelled_box("BG Mask", nes.ppu().mask.background_on_left_edge),
|
|
labelled_box("Sprites Mask", nes.ppu().mask.sprites_on_left_edge),
|
|
labelled_box("Grayscale", nes.ppu().mask.grayscale),
|
|
labelled_box("Intensify Red", nes.ppu().mask.em_red),
|
|
labelled_box("Intensify Green", nes.ppu().mask.em_green),
|
|
labelled_box("Intensify Blue", nes.ppu().mask.em_blue),
|
|
],
|
|
column![
|
|
run_type(
|
|
"PPU Cycles:",
|
|
self.ppu_cycles,
|
|
DebuggerMessage::SetPPUCycles,
|
|
DebuggerMessage::RunPPUCycles
|
|
),
|
|
run_type(
|
|
"CPU Cycles:",
|
|
self.cpu_cycles,
|
|
DebuggerMessage::SetCPUCycles,
|
|
DebuggerMessage::RunCPUCycles
|
|
),
|
|
run_type(
|
|
"Instructions:",
|
|
self.instructions,
|
|
DebuggerMessage::SetInstructions,
|
|
DebuggerMessage::RunInstructions
|
|
),
|
|
run_type(
|
|
"Scanlines:",
|
|
self.scan_lines,
|
|
DebuggerMessage::SetScanLines,
|
|
DebuggerMessage::RunScanLines
|
|
),
|
|
run_type(
|
|
"To Scanline:",
|
|
self.to_scan_line,
|
|
DebuggerMessage::SetToScanLine,
|
|
DebuggerMessage::RunToScanLine
|
|
),
|
|
run_type(
|
|
"Frames:",
|
|
self.frames,
|
|
DebuggerMessage::SetFrames,
|
|
DebuggerMessage::RunFrames
|
|
),
|
|
run_type_hex(
|
|
"To Address:",
|
|
self.breakpoint,
|
|
DebuggerMessage::SetBreakpoint,
|
|
DebuggerMessage::RunBreakpoint
|
|
),
|
|
],
|
|
]
|
|
.spacing(5.),
|
|
horizontal(2),
|
|
scrollable(
|
|
column(
|
|
nes.debug_log()
|
|
.history()
|
|
.into_iter()
|
|
.rev()
|
|
.map(|s| text(s).line_height(0.9).into())
|
|
)
|
|
.spacing(0)
|
|
)
|
|
.width(Fill),
|
|
],],
|
|
]
|
|
.width(Fill)
|
|
.height(Fill)
|
|
.into()
|
|
}
|
|
|
|
fn run_n_clock_cycles(nes: &mut NES, n: usize) {
|
|
for _ in 0..n {
|
|
if nes.run_one_clock_cycle(&Break::default()).dbg_int || nes.halted() {
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
fn run_until(
|
|
nes: &mut NES,
|
|
br: &Break,
|
|
mut f: impl FnMut(CycleResult, &NES) -> bool,
|
|
// mut count: usize,
|
|
) {
|
|
// Always run at least 1 cycle
|
|
let mut res = nes.run_one_clock_cycle(&Break::default());
|
|
while !nes.halted() && !res.dbg_int && !f(res, nes) {
|
|
// if res.dbg_int || f(res, nes) {
|
|
// count -= 1;
|
|
// if count <= 0 {
|
|
// break;
|
|
// }
|
|
// }
|
|
// if nes.halted() {
|
|
// break;
|
|
// }
|
|
res = nes.run_one_clock_cycle(br);
|
|
}
|
|
}
|
|
fn run_until_n(
|
|
nes: &mut NES,
|
|
br: &Break,
|
|
mut f: impl FnMut(CycleResult, &NES) -> bool,
|
|
mut count: usize,
|
|
) {
|
|
while count > 0 {
|
|
Self::run_until(nes, br, &mut f);
|
|
count -= 1;
|
|
}
|
|
}
|
|
|
|
pub fn update(&mut self, message: DebuggerMessage, nes: &mut NES) {
|
|
match message {
|
|
DebuggerMessage::SetPPUCycles(n) => self.ppu_cycles = n,
|
|
DebuggerMessage::SetCPUCycles(n) => self.cpu_cycles = n,
|
|
DebuggerMessage::SetInstructions(n) => self.instructions = n,
|
|
DebuggerMessage::SetScanLines(n) => self.scan_lines = n,
|
|
DebuggerMessage::SetToScanLine(n) => self.to_scan_line = n.min(261), // Max scanline is 261
|
|
DebuggerMessage::SetFrames(n) => self.frames = n,
|
|
DebuggerMessage::SetBreakpoint(n) => self.breakpoint = n,
|
|
DebuggerMessage::RunPPUCycles => Self::run_n_clock_cycles(nes, self.ppu_cycles),
|
|
DebuggerMessage::RunCPUCycles => Self::run_n_clock_cycles(nes, self.cpu_cycles * 3),
|
|
// DebuggerMessage::RunInstructions => Self::run_until_n(
|
|
// nes,
|
|
// &Break {
|
|
// cpu_exec: true,
|
|
// ..Break::default()
|
|
// },
|
|
// |_, _| false,
|
|
// self.instructions,
|
|
// ),
|
|
DebuggerMessage::RunInstructions => Self::run_until_n(
|
|
nes,
|
|
&Break {
|
|
..Break::default()
|
|
},
|
|
|res, _| res.cpu_exec,
|
|
self.instructions,
|
|
),
|
|
DebuggerMessage::RunScanLines => Self::run_n_clock_cycles(nes, self.scan_lines * 341),
|
|
DebuggerMessage::RunToScanLine => Self::run_until(
|
|
nes,
|
|
&Break {
|
|
ppu_scanline: true,
|
|
..Break::default()
|
|
},
|
|
|_, n| n.ppu.scanline == self.to_scan_line,
|
|
),
|
|
DebuggerMessage::RunFrames => Self::run_n_clock_cycles(nes, self.frames * 341 * 262),
|
|
DebuggerMessage::RunBreakpoint => Self::run_until(
|
|
nes,
|
|
&Break {
|
|
break_points: vec![self.breakpoint as u16],
|
|
..Break::default()
|
|
},
|
|
|_, nes| nes.cpu.pc as usize == self.breakpoint,
|
|
),
|
|
DebuggerMessage::Run => {
|
|
Self::run_until(nes, &Break { ..Break::default() }, |_, nes| nes.halted())
|
|
}
|
|
DebuggerMessage::Pause => todo!(),
|
|
}
|
|
}
|
|
}
|
|
|
|
fn run_type<'a, Message: Clone + 'a>(
|
|
label: &'a str,
|
|
val: usize,
|
|
update: impl Fn(usize) -> Message + 'a,
|
|
run: Message,
|
|
) -> Element<'a, Message> {
|
|
row![
|
|
widget::container(text(label)).padding(2.),
|
|
widget::container(number_input(val).on_input(update).on_submit(run.clone())).padding(2.),
|
|
widget::container(button(image("./images/ic_fluent_play_24_filled.png")).on_press(run))
|
|
.padding(2.),
|
|
]
|
|
.spacing(1.)
|
|
.into()
|
|
}
|
|
fn run_type_hex<'a, Message: Clone + 'a>(
|
|
label: &'a str,
|
|
val: usize,
|
|
update: impl Fn(usize) -> Message + 'a,
|
|
run: Message,
|
|
) -> Element<'a, Message> {
|
|
row![
|
|
widget::container(text(label)).padding(2.),
|
|
widget::container(hex_input(val).on_input(update).on_submit(run.clone())).padding(2.),
|
|
widget::container(button(image("./images/ic_fluent_play_24_filled.png")).on_press(run))
|
|
.padding(2.),
|
|
]
|
|
.spacing(1.)
|
|
.into()
|
|
}
|
|
|
|
pub fn labelled<'a, Message: 'a>(
|
|
label: &'a str,
|
|
content: impl Into<Element<'a, Message>>,
|
|
) -> Element<'a, Message> {
|
|
row![
|
|
widget::container(text(label)).padding(2.),
|
|
widget::container(content).style(bordered_box).padding(2.),
|
|
]
|
|
.spacing(1.)
|
|
.into()
|
|
}
|
|
|
|
pub fn labelled2<'a, Message: 'a>(
|
|
label: &'a str,
|
|
content: impl Into<Element<'a, Message>>,
|
|
content2: impl Into<Element<'a, Message>>,
|
|
) -> Element<'a, Message> {
|
|
row![
|
|
widget::container(text(label)).padding(2.),
|
|
widget::container(content).style(bordered_box).padding(2.),
|
|
widget::container(content2).style(bordered_box).padding(2.),
|
|
]
|
|
.spacing(1.)
|
|
.into()
|
|
}
|
|
|
|
pub fn labelled_box<'a, Message: 'a>(label: &'a str, value: bool) -> Element<'a, Message> {
|
|
row![checkbox(value), widget::container(text(label)),]
|
|
.spacing(1.)
|
|
.into()
|
|
}
|
|
|
|
#[derive(Clone, Copy)]
|
|
pub enum DbgImage<'a> {
|
|
NameTable(&'a Mapped, &'a PPU),
|
|
PatternTable(&'a Mapped, &'a PPU),
|
|
Palette(&'a Mapped, &'a PPU),
|
|
}
|
|
|
|
impl<Message, T> Program<Message, T> for DbgImage<'_> {
|
|
type State = ();
|
|
|
|
fn draw(
|
|
&self,
|
|
_state: &Self::State,
|
|
renderer: &Renderer,
|
|
_theme: &T,
|
|
_bounds: iced::Rectangle,
|
|
_cursor: mouse::Cursor,
|
|
) -> Vec<iced::widget::canvas::Geometry<Renderer>> {
|
|
// const SIZE: f32 = 2.;
|
|
let mut name_table_frame =
|
|
Frame::new(renderer, Size::new(256. * 4. + 260. * 2., 256. * 4.));
|
|
name_table_frame.scale(2.);
|
|
// println!("Position: {:?}", cursor.position());
|
|
match self {
|
|
DbgImage::NameTable(mem, ppu) => ppu.render_name_table(mem, &mut name_table_frame),
|
|
DbgImage::PatternTable(mem, ppu) => {
|
|
ppu.render_pattern_tables(mem, &mut name_table_frame)
|
|
}
|
|
DbgImage::Palette(_, ppu) => ppu.render_palette(&mut name_table_frame),
|
|
};
|
|
vec![name_table_frame.into_geometry()]
|
|
}
|
|
}
|
|
|
|
impl DbgImage<'_> {
|
|
fn width(&self) -> Length {
|
|
match self {
|
|
DbgImage::NameTable(_, _) => Length::Fixed(512. * 2.),
|
|
DbgImage::PatternTable(_, _) => Length::Fixed(16. * 8. * 2.),
|
|
DbgImage::Palette(_, _) => Length::Fixed(40. * 2.),
|
|
}
|
|
}
|
|
fn height(&self) -> Length {
|
|
match self {
|
|
DbgImage::NameTable(_, _) => Length::Fixed(512. * 2.),
|
|
DbgImage::PatternTable(_, _) => Length::Fixed(16. * 8. * 2. * 2.),
|
|
DbgImage::Palette(_, _) => Length::Fixed(80. * 2.),
|
|
}
|
|
}
|
|
fn help(&self, cursor: Point) -> Option<String> {
|
|
match self {
|
|
DbgImage::NameTable(mem, ppu) => ppu.name_cursor_info(mem, cursor),
|
|
DbgImage::PatternTable(_, ppu) => ppu.pattern_cursor_info(cursor),
|
|
DbgImage::Palette(_, ppu) => ppu.palette_cursor_info(cursor),
|
|
}
|
|
}
|
|
}
|
|
|
|
struct DbgImageSetup<'a, M, T: text::Catalog> {
|
|
dbg: DbgImage<'a>,
|
|
image: Canvas<DbgImage<'a>, M, T>,
|
|
text: Text<'a, T>,
|
|
padding: f32,
|
|
drawn: bool,
|
|
// image: DbgImage<'a>,
|
|
// text: te,
|
|
}
|
|
|
|
// pub trait Container<Message, Theme, Renderer> {
|
|
// // Not ideal
|
|
// fn children(&self) -> &[&dyn Widget<Message, Theme, Renderer>];
|
|
// }
|
|
|
|
impl<'s, Message, Theme> Widget<Message, Theme, Renderer> for DbgImageSetup<'s, Message, Theme>
|
|
where
|
|
Theme: text::Catalog + 's,
|
|
{
|
|
fn size(&self) -> Size<iced::Length> {
|
|
// self.
|
|
Size::new(Fill, Fill)
|
|
}
|
|
|
|
fn layout(
|
|
&mut self,
|
|
tree: &mut Tree,
|
|
renderer: &Renderer,
|
|
limits: &iced::advanced::layout::Limits,
|
|
) -> Node {
|
|
let img_node = self.image.layout(&mut tree.children[0], renderer, limits);
|
|
let txt_node = Widget::<Message, Theme, _>::layout(
|
|
&mut self.text,
|
|
&mut tree.children[1],
|
|
renderer,
|
|
&limits.shrink(Size::new(
|
|
img_node.size().width + self.padding * 2.,
|
|
self.padding * 2.,
|
|
)),
|
|
)
|
|
.move_to(Point::new(
|
|
img_node.size().width + self.padding,
|
|
self.padding,
|
|
));
|
|
Node::with_children(limits.max(), vec![img_node, txt_node])
|
|
}
|
|
|
|
fn draw(
|
|
&self,
|
|
tree: &Tree,
|
|
renderer: &mut Renderer,
|
|
theme: &Theme,
|
|
style: &iced::advanced::renderer::Style,
|
|
layout: iced::advanced::Layout<'_>,
|
|
cursor: iced::advanced::mouse::Cursor,
|
|
viewport: &iced::Rectangle,
|
|
) {
|
|
self.image.draw(
|
|
&tree.children[0],
|
|
renderer,
|
|
theme,
|
|
style,
|
|
layout.child(0),
|
|
cursor,
|
|
viewport,
|
|
);
|
|
Widget::<Message, Theme, _>::draw(
|
|
&self.text,
|
|
&tree.children[1],
|
|
renderer,
|
|
theme,
|
|
style,
|
|
layout.child(1),
|
|
cursor,
|
|
viewport,
|
|
)
|
|
}
|
|
|
|
fn tag(&self) -> Tag {
|
|
Tag::of::<Rc<String>>()
|
|
}
|
|
|
|
fn state(&self) -> State {
|
|
State::new(Rc::new(String::new()))
|
|
}
|
|
|
|
fn children(&self) -> Vec<Tree> {
|
|
vec![
|
|
Tree::new(&self.image as &dyn Widget<Message, Theme, Renderer>),
|
|
Tree::new(&self.text as &dyn Widget<Message, Theme, Renderer>),
|
|
]
|
|
}
|
|
|
|
fn diff(&self, tree: &mut Tree) {
|
|
tree.diff_children(&[
|
|
&self.image as &dyn Widget<Message, Theme, Renderer>,
|
|
&self.text as &dyn Widget<Message, Theme, Renderer>,
|
|
]);
|
|
}
|
|
|
|
fn operate(
|
|
&mut self,
|
|
tree: &mut Tree,
|
|
layout: iced::advanced::Layout<'_>,
|
|
renderer: &Renderer,
|
|
operation: &mut dyn iced::advanced::widget::Operation,
|
|
) {
|
|
operation.container(None, layout.bounds());
|
|
operation.traverse(&mut |op| {
|
|
self.image
|
|
.operate(&mut tree.children[0], layout.child(0), renderer, op);
|
|
Widget::<Message, Theme, _>::operate(
|
|
&mut self.text,
|
|
&mut tree.children[1],
|
|
layout.child(1),
|
|
renderer,
|
|
op,
|
|
);
|
|
});
|
|
}
|
|
|
|
fn update(
|
|
&mut self,
|
|
tree: &mut Tree,
|
|
event: &iced::Event,
|
|
layout: iced::advanced::Layout<'_>,
|
|
cursor: iced::advanced::mouse::Cursor,
|
|
renderer: &Renderer,
|
|
clipboard: &mut dyn iced::advanced::Clipboard,
|
|
shell: &mut iced::advanced::Shell<'_, Message>,
|
|
viewport: &iced::Rectangle,
|
|
) {
|
|
self.image.update(
|
|
&mut tree.children[0],
|
|
event,
|
|
layout.child(0),
|
|
cursor,
|
|
renderer,
|
|
clipboard,
|
|
shell,
|
|
viewport,
|
|
);
|
|
if matches!(event, iced::Event::Mouse(mouse::Event::CursorMoved { .. })) || !self.drawn {
|
|
if let Some(help) = cursor
|
|
.position_in(layout.child(0).bounds())
|
|
.and_then(|pos| self.dbg.help(Point::new(pos.x / 2., pos.y / 2.)))
|
|
{
|
|
self.text = text(help);
|
|
shell.invalidate_layout();
|
|
shell.request_redraw();
|
|
}
|
|
self.drawn = true;
|
|
}
|
|
Widget::<Message, Theme, _>::update(
|
|
&mut self.text,
|
|
&mut tree.children[1],
|
|
event,
|
|
layout.child(1),
|
|
cursor,
|
|
renderer,
|
|
clipboard,
|
|
shell,
|
|
viewport,
|
|
);
|
|
}
|
|
|
|
fn mouse_interaction(
|
|
&self,
|
|
_tree: &iced::advanced::widget::Tree,
|
|
_layout: iced::advanced::Layout<'_>,
|
|
_cursor: iced::advanced::mouse::Cursor,
|
|
_viewport: &iced::Rectangle,
|
|
_renderer: &Renderer,
|
|
) -> iced::advanced::mouse::Interaction {
|
|
iced::advanced::mouse::Interaction::default()
|
|
}
|
|
|
|
fn overlay<'a>(
|
|
&'a mut self,
|
|
_tree: &'a mut iced::advanced::widget::Tree,
|
|
_layout: iced::advanced::Layout<'a>,
|
|
_renderer: &Renderer,
|
|
_viewport: &iced::Rectangle,
|
|
_translation: iced::Vector,
|
|
) -> Option<iced::advanced::overlay::Element<'a, Message, Theme, Renderer>> {
|
|
None
|
|
}
|
|
}
|
|
|
|
pub fn dbg_image<'a, Message: 'a>(img: DbgImage<'a>) -> Element<'a, Message> {
|
|
Element::new(DbgImageSetup {
|
|
dbg: img,
|
|
image: Canvas::new(img).width(img.width()).height(img.height()),
|
|
text: text(""),
|
|
padding: 10.,
|
|
drawn: false,
|
|
})
|
|
}
|