VIP inspection tooling #4
			
				
			
		
		
		
	| 
						 | 
				
			
			@ -1,9 +1,10 @@
 | 
			
		|||
use std::{
 | 
			
		||||
    fmt::Display,
 | 
			
		||||
    fmt::{Display, UpperHex},
 | 
			
		||||
    ops::{Bound, RangeBounds},
 | 
			
		||||
    str::FromStr,
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
use atoi::FromRadix16;
 | 
			
		||||
use egui::{
 | 
			
		||||
    ecolor::HexColor, Align, Color32, CursorIcon, Event, Frame, Key, Layout, Margin, Rect,
 | 
			
		||||
    Response, RichText, Rounding, Sense, Shape, Stroke, TextEdit, Ui, UiBuilder, Vec2, Widget,
 | 
			
		||||
| 
						 | 
				
			
			@ -38,7 +39,12 @@ impl UiExt for Ui {
 | 
			
		|||
        let mut frame = Frame::group(self.style());
 | 
			
		||||
        frame.outer_margin.top += 10.0;
 | 
			
		||||
        frame.inner_margin.top += 2.0;
 | 
			
		||||
        let res = self.push_id(&title, |ui| frame.show(ui, add_contents));
 | 
			
		||||
        let res = self.push_id(&title, |ui| {
 | 
			
		||||
            frame.show(ui, |ui| {
 | 
			
		||||
                ui.set_min_width(ui.available_width());
 | 
			
		||||
                add_contents(ui);
 | 
			
		||||
            })
 | 
			
		||||
        });
 | 
			
		||||
        let text = RichText::new(title).background_color(self.style().visuals.panel_fill);
 | 
			
		||||
        let old_rect = res.response.rect;
 | 
			
		||||
        let mut text_rect = old_rect;
 | 
			
		||||
| 
						 | 
				
			
			@ -98,11 +104,35 @@ enum Direction {
 | 
			
		|||
}
 | 
			
		||||
 | 
			
		||||
pub trait Number:
 | 
			
		||||
    Copy + One + CheckedAdd + CheckedSub + Eq + Ord + Display + FromStr + Send + Sync + 'static
 | 
			
		||||
    Copy
 | 
			
		||||
    + One
 | 
			
		||||
    + CheckedAdd
 | 
			
		||||
    + CheckedSub
 | 
			
		||||
    + Eq
 | 
			
		||||
    + Ord
 | 
			
		||||
    + Display
 | 
			
		||||
    + FromStr
 | 
			
		||||
    + FromRadix16
 | 
			
		||||
    + UpperHex
 | 
			
		||||
    + Send
 | 
			
		||||
    + Sync
 | 
			
		||||
    + 'static
 | 
			
		||||
{
 | 
			
		||||
}
 | 
			
		||||
impl<
 | 
			
		||||
        T: Copy + One + CheckedAdd + CheckedSub + Eq + Ord + Display + FromStr + Send + Sync + 'static,
 | 
			
		||||
        T: Copy
 | 
			
		||||
            + One
 | 
			
		||||
            + CheckedAdd
 | 
			
		||||
            + CheckedSub
 | 
			
		||||
            + Eq
 | 
			
		||||
            + Ord
 | 
			
		||||
            + Display
 | 
			
		||||
            + FromStr
 | 
			
		||||
            + FromRadix16
 | 
			
		||||
            + UpperHex
 | 
			
		||||
            + Send
 | 
			
		||||
            + Sync
 | 
			
		||||
            + 'static,
 | 
			
		||||
    > Number for T
 | 
			
		||||
{
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -113,6 +143,8 @@ pub struct NumberEdit<'a, T: Number> {
 | 
			
		|||
    precision: usize,
 | 
			
		||||
    min: Option<T>,
 | 
			
		||||
    max: Option<T>,
 | 
			
		||||
    arrows: bool,
 | 
			
		||||
    hex: bool,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl<'a, T: Number> NumberEdit<'a, T> {
 | 
			
		||||
| 
						 | 
				
			
			@ -123,6 +155,8 @@ impl<'a, T: Number> NumberEdit<'a, T> {
 | 
			
		|||
            precision: 3,
 | 
			
		||||
            min: None,
 | 
			
		||||
            max: None,
 | 
			
		||||
            arrows: true,
 | 
			
		||||
            hex: false,
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -143,12 +177,35 @@ impl<'a, T: Number> NumberEdit<'a, T> {
 | 
			
		|||
        };
 | 
			
		||||
        Self { min, max, ..self }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    pub fn arrows(self, arrows: bool) -> Self {
 | 
			
		||||
        Self { arrows, ..self }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    pub fn hex(self, hex: bool) -> Self {
 | 
			
		||||
        Self { hex, ..self }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl<T: Number> Widget for NumberEdit<'_, T> {
 | 
			
		||||
    fn ui(self, ui: &mut Ui) -> Response {
 | 
			
		||||
        let id = ui.id();
 | 
			
		||||
        let to_string = |val: &T| format!("{val:.0$}", self.precision);
 | 
			
		||||
        let to_string = |val: &T| {
 | 
			
		||||
            if self.hex {
 | 
			
		||||
                format!("{val:.0$X}", self.precision)
 | 
			
		||||
            } else {
 | 
			
		||||
                format!("{val:.0$}", self.precision)
 | 
			
		||||
            }
 | 
			
		||||
        };
 | 
			
		||||
        let from_string = |val: &str| {
 | 
			
		||||
            if self.hex {
 | 
			
		||||
                let bytes = val.as_bytes();
 | 
			
		||||
                let (result, consumed) = T::from_radix_16(bytes);
 | 
			
		||||
                (consumed == bytes.len()).then_some(result)
 | 
			
		||||
            } else {
 | 
			
		||||
                val.parse::<T>().ok()
 | 
			
		||||
            }
 | 
			
		||||
        };
 | 
			
		||||
 | 
			
		||||
        let (last_value, mut str, focus) = ui.memory(|m| {
 | 
			
		||||
            let (lv, s) = m
 | 
			
		||||
| 
						 | 
				
			
			@ -163,7 +220,7 @@ impl<T: Number> Widget for NumberEdit<'_, T> {
 | 
			
		|||
            str = to_string(self.value);
 | 
			
		||||
            stale = true;
 | 
			
		||||
        }
 | 
			
		||||
        let valid = str.parse().is_ok_and(|v: T| v == *self.value);
 | 
			
		||||
        let valid = from_string(&str).is_some_and(|v: T| v == *self.value);
 | 
			
		||||
        let mut up_pressed = false;
 | 
			
		||||
        let mut down_pressed = false;
 | 
			
		||||
        if focus {
 | 
			
		||||
| 
						 | 
				
			
			@ -194,17 +251,25 @@ impl<T: Number> Widget for NumberEdit<'_, T> {
 | 
			
		|||
            .id(id)
 | 
			
		||||
            .margin(Margin {
 | 
			
		||||
                left: 4.0,
 | 
			
		||||
                right: 20.0,
 | 
			
		||||
                right: if self.arrows { 20.0 } else { 4.0 },
 | 
			
		||||
                top: 2.0,
 | 
			
		||||
                bottom: 2.0,
 | 
			
		||||
            });
 | 
			
		||||
        let res = if valid {
 | 
			
		||||
        let mut res = if valid {
 | 
			
		||||
            ui.add(text)
 | 
			
		||||
        } else {
 | 
			
		||||
            let message = match (self.min, self.max) {
 | 
			
		||||
                (Some(min), Some(max)) => format!("Please enter a number between {min} and {max}."),
 | 
			
		||||
                (Some(min), None) => format!("Please enter a number greater than {min}."),
 | 
			
		||||
                (None, Some(max)) => format!("Please enter a number less than {max}."),
 | 
			
		||||
                (Some(min), Some(max)) => format!(
 | 
			
		||||
                    "Please enter a number between {} and {}.",
 | 
			
		||||
                    to_string(&min),
 | 
			
		||||
                    to_string(&max)
 | 
			
		||||
                ),
 | 
			
		||||
                (Some(min), None) => {
 | 
			
		||||
                    format!("Please enter a number greater than {}.", to_string(&min))
 | 
			
		||||
                }
 | 
			
		||||
                (None, Some(max)) => {
 | 
			
		||||
                    format!("Please enter a number less than {}.", to_string(&max))
 | 
			
		||||
                }
 | 
			
		||||
                (None, None) => "Please enter a number.".to_string(),
 | 
			
		||||
            };
 | 
			
		||||
            ui.scope(|ui| {
 | 
			
		||||
| 
						 | 
				
			
			@ -218,26 +283,28 @@ impl<T: Number> Widget for NumberEdit<'_, T> {
 | 
			
		|||
            .on_hover_text(message)
 | 
			
		||||
        };
 | 
			
		||||
 | 
			
		||||
        let arrow_left = res.rect.max.x + 4.0;
 | 
			
		||||
        let arrow_right = res.rect.max.x + 20.0;
 | 
			
		||||
        let arrow_top = res.rect.min.y - 2.0;
 | 
			
		||||
        let arrow_middle = (res.rect.min.y + res.rect.max.y) / 2.0;
 | 
			
		||||
        let arrow_bottom = res.rect.max.y + 2.0;
 | 
			
		||||
 | 
			
		||||
        let mut delta = None;
 | 
			
		||||
        let top_arrow_rect = Rect {
 | 
			
		||||
            min: (arrow_left, arrow_top).into(),
 | 
			
		||||
            max: (arrow_right, arrow_middle).into(),
 | 
			
		||||
        };
 | 
			
		||||
        if draw_arrow(ui, top_arrow_rect, true).clicked_or_dragged() || up_pressed {
 | 
			
		||||
            delta = Some(Direction::Up);
 | 
			
		||||
        }
 | 
			
		||||
        let bottom_arrow_rect = Rect {
 | 
			
		||||
            min: (arrow_left, arrow_middle).into(),
 | 
			
		||||
            max: (arrow_right, arrow_bottom).into(),
 | 
			
		||||
        };
 | 
			
		||||
        if draw_arrow(ui, bottom_arrow_rect, false).clicked_or_dragged() || down_pressed {
 | 
			
		||||
            delta = Some(Direction::Down);
 | 
			
		||||
        if self.arrows {
 | 
			
		||||
            let arrow_left = res.rect.max.x + 4.0;
 | 
			
		||||
            let arrow_right = res.rect.max.x + 20.0;
 | 
			
		||||
            let arrow_top = res.rect.min.y - 2.0;
 | 
			
		||||
            let arrow_middle = (res.rect.min.y + res.rect.max.y) / 2.0;
 | 
			
		||||
            let arrow_bottom = res.rect.max.y + 2.0;
 | 
			
		||||
 | 
			
		||||
            let top_arrow_rect = Rect {
 | 
			
		||||
                min: (arrow_left, arrow_top).into(),
 | 
			
		||||
                max: (arrow_right, arrow_middle).into(),
 | 
			
		||||
            };
 | 
			
		||||
            if draw_arrow(ui, top_arrow_rect, true).clicked_or_dragged() || up_pressed {
 | 
			
		||||
                delta = Some(Direction::Up);
 | 
			
		||||
            }
 | 
			
		||||
            let bottom_arrow_rect = Rect {
 | 
			
		||||
                min: (arrow_left, arrow_middle).into(),
 | 
			
		||||
                max: (arrow_right, arrow_bottom).into(),
 | 
			
		||||
            };
 | 
			
		||||
            if draw_arrow(ui, bottom_arrow_rect, false).clicked_or_dragged() || down_pressed {
 | 
			
		||||
                delta = Some(Direction::Down);
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        let in_range =
 | 
			
		||||
| 
						 | 
				
			
			@ -248,12 +315,18 @@ impl<T: Number> Widget for NumberEdit<'_, T> {
 | 
			
		|||
                Direction::Down => self.value.checked_sub(&self.increment),
 | 
			
		||||
            };
 | 
			
		||||
            if let Some(new_value) = value.filter(in_range) {
 | 
			
		||||
                if *self.value != new_value {
 | 
			
		||||
                    res.mark_changed();
 | 
			
		||||
                }
 | 
			
		||||
                *self.value = new_value;
 | 
			
		||||
            }
 | 
			
		||||
            str = to_string(self.value);
 | 
			
		||||
            stale = true;
 | 
			
		||||
        } else if res.changed {
 | 
			
		||||
            if let Some(new_value) = str.parse().ok().filter(in_range) {
 | 
			
		||||
            if let Some(new_value) = from_string(&str).filter(in_range) {
 | 
			
		||||
                if *self.value != new_value {
 | 
			
		||||
                    res.mark_changed();
 | 
			
		||||
                }
 | 
			
		||||
                *self.value = new_value;
 | 
			
		||||
            }
 | 
			
		||||
            stale = true;
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,20 +1,22 @@
 | 
			
		|||
use std::sync::Arc;
 | 
			
		||||
 | 
			
		||||
use egui::{
 | 
			
		||||
    Align, Button, CentralPanel, Checkbox, Context, Label, Layout, ScrollArea, TextEdit, Ui,
 | 
			
		||||
    ViewportBuilder, ViewportId,
 | 
			
		||||
    Align, Button, CentralPanel, Checkbox, Color32, Context, Direction, Label, Layout, ScrollArea,
 | 
			
		||||
    TextEdit, Ui, ViewportBuilder, ViewportId,
 | 
			
		||||
};
 | 
			
		||||
use egui_extras::{Column, Size, StripBuilder, TableBuilder};
 | 
			
		||||
 | 
			
		||||
use crate::{
 | 
			
		||||
    emulator::SimId,
 | 
			
		||||
    memory::{MemoryClient, MemoryValue, MemoryView},
 | 
			
		||||
    memory::{MemoryClient, MemoryRef, MemoryValue, MemoryView},
 | 
			
		||||
    window::{
 | 
			
		||||
        utils::{NumberEdit, UiExt},
 | 
			
		||||
        AppWindow,
 | 
			
		||||
    },
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
use super::utils;
 | 
			
		||||
 | 
			
		||||
pub struct RegisterWindow {
 | 
			
		||||
    sim_id: SimId,
 | 
			
		||||
    memory: Arc<MemoryClient>,
 | 
			
		||||
| 
						 | 
				
			
			@ -26,7 +28,7 @@ impl RegisterWindow {
 | 
			
		|||
        Self {
 | 
			
		||||
            sim_id,
 | 
			
		||||
            memory: memory.clone(),
 | 
			
		||||
            registers: memory.watch(sim_id, 0x0005f800, 0x70),
 | 
			
		||||
            registers: memory.watch(sim_id, 0x0005f800, 0x72),
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -36,21 +38,21 @@ impl RegisterWindow {
 | 
			
		|||
        let mut intenb = InterruptReg::parse(raw_intenb);
 | 
			
		||||
        let mut intpnd = InterruptReg::parse(raw_intpnd);
 | 
			
		||||
        ui.section("Interrupt", |ui| {
 | 
			
		||||
            ui.vertical(|ui| {
 | 
			
		||||
            let width = ui.available_width();
 | 
			
		||||
            ui.with_layout(Layout::top_down_justified(Align::Center), |ui| {
 | 
			
		||||
                TableBuilder::new(ui)
 | 
			
		||||
                    .id_salt("raw_values")
 | 
			
		||||
                    .column(Column::auto())
 | 
			
		||||
                    .column(Column::remainder())
 | 
			
		||||
                    .columns(Column::exact(width * 0.5), 2)
 | 
			
		||||
                    .cell_layout(Layout::left_to_right(Align::Max))
 | 
			
		||||
                    .body(|mut body| {
 | 
			
		||||
                        body.row(row_height, |mut row| {
 | 
			
		||||
                            row.col(|ui| {
 | 
			
		||||
                                ui.label("INTENB");
 | 
			
		||||
                                ui.add_sized(ui.available_size(), Label::new("INTENB"));
 | 
			
		||||
                            });
 | 
			
		||||
                            row.col(|ui| {
 | 
			
		||||
                                let mut text = format!("{raw_intenb:04x}");
 | 
			
		||||
                                ui.add_enabled(
 | 
			
		||||
                                    false,
 | 
			
		||||
                                ui.add_sized(
 | 
			
		||||
                                    ui.available_size(),
 | 
			
		||||
                                    TextEdit::singleline(&mut text).horizontal_align(Align::Max),
 | 
			
		||||
                                );
 | 
			
		||||
                            });
 | 
			
		||||
| 
						 | 
				
			
			@ -71,17 +73,17 @@ impl RegisterWindow {
 | 
			
		|||
                ui.add_space(8.0);
 | 
			
		||||
                TableBuilder::new(ui)
 | 
			
		||||
                    .id_salt("flags")
 | 
			
		||||
                    .column(Column::auto())
 | 
			
		||||
                    .columns(Column::remainder(), 2)
 | 
			
		||||
                    .column(Column::exact(width * 0.5))
 | 
			
		||||
                    .columns(Column::exact(width * 0.25), 2)
 | 
			
		||||
                    .cell_layout(Layout::left_to_right(Align::Center).with_main_align(Align::RIGHT))
 | 
			
		||||
                    .body(|mut body| {
 | 
			
		||||
                        body.row(row_height, |mut row| {
 | 
			
		||||
                            row.col(|_ui| {});
 | 
			
		||||
                            row.col(|ui| {
 | 
			
		||||
                                ui.add_sized([ui.available_width(), 0.0], Label::new("ENB"));
 | 
			
		||||
                                ui.add_sized(ui.available_size(), Label::new("ENB"));
 | 
			
		||||
                            });
 | 
			
		||||
                            row.col(|ui| {
 | 
			
		||||
                                ui.add_sized([ui.available_width(), 0.0], Label::new("PND"));
 | 
			
		||||
                                ui.add_sized(ui.available_size(), Label::new("PND"));
 | 
			
		||||
                            });
 | 
			
		||||
                        });
 | 
			
		||||
                        let mut add_row = |label: &str, enb: &mut bool, pnd: &mut bool| {
 | 
			
		||||
| 
						 | 
				
			
			@ -112,7 +114,7 @@ impl RegisterWindow {
 | 
			
		|||
                        add_row("LFBEND", &mut intenb.lfbend, &mut intpnd.lfbend);
 | 
			
		||||
                        add_row("SCANERR", &mut intenb.scanerr, &mut intpnd.scanerr);
 | 
			
		||||
                    });
 | 
			
		||||
                ui.add_space(ui.available_height());
 | 
			
		||||
                ui.allocate_space(ui.available_size());
 | 
			
		||||
            });
 | 
			
		||||
        });
 | 
			
		||||
        if intpnd.update(&mut raw_intpnd) {
 | 
			
		||||
| 
						 | 
				
			
			@ -128,9 +130,10 @@ impl RegisterWindow {
 | 
			
		|||
        let mut raw_dpstts = self.read_address(0x0005f820);
 | 
			
		||||
        let mut dpstts = DisplayReg::parse(raw_dpstts);
 | 
			
		||||
        ui.section("Display", |ui| {
 | 
			
		||||
            let width = ui.available_width();
 | 
			
		||||
            TableBuilder::new(ui)
 | 
			
		||||
                .column(Column::auto())
 | 
			
		||||
                .column(Column::remainder())
 | 
			
		||||
                .column(Column::exact(width * 0.5))
 | 
			
		||||
                .column(Column::exact(width * 0.5))
 | 
			
		||||
                .cell_layout(Layout::left_to_right(Align::Max))
 | 
			
		||||
                .body(|mut body| {
 | 
			
		||||
                    body.row(row_height, |mut row| {
 | 
			
		||||
| 
						 | 
				
			
			@ -197,7 +200,7 @@ impl RegisterWindow {
 | 
			
		|||
                        });
 | 
			
		||||
                    });
 | 
			
		||||
                });
 | 
			
		||||
            ui.vertical(|ui| ui.add_space((ui.available_height() - row_height).max(0.0)));
 | 
			
		||||
            ui.allocate_space(ui.available_size());
 | 
			
		||||
        });
 | 
			
		||||
        if dpstts.update(&mut raw_dpstts) {
 | 
			
		||||
            self.memory.write(self.sim_id, 0x0005f822, &raw_dpstts);
 | 
			
		||||
| 
						 | 
				
			
			@ -209,9 +212,10 @@ impl RegisterWindow {
 | 
			
		|||
        let [mut raw_xpstts, raw_xpctrl] = self.read_address(0x0005f840);
 | 
			
		||||
        let mut xpstts = DrawingReg::parse(raw_xpstts);
 | 
			
		||||
        ui.section("Drawing", |ui| {
 | 
			
		||||
            let width = ui.available_width();
 | 
			
		||||
            TableBuilder::new(ui)
 | 
			
		||||
                .column(Column::auto())
 | 
			
		||||
                .column(Column::remainder())
 | 
			
		||||
                .column(Column::exact(width * 0.5))
 | 
			
		||||
                .column(Column::exact(width * 0.5))
 | 
			
		||||
                .cell_layout(Layout::left_to_right(Align::Max))
 | 
			
		||||
                .body(|mut body| {
 | 
			
		||||
                    body.row(row_height, |mut row| {
 | 
			
		||||
| 
						 | 
				
			
			@ -257,7 +261,9 @@ impl RegisterWindow {
 | 
			
		|||
                        row.col(|ui| {
 | 
			
		||||
                            ui.add_enabled(
 | 
			
		||||
                                false,
 | 
			
		||||
                                NumberEdit::new(&mut xpstts.sbcount).range(0..32),
 | 
			
		||||
                                NumberEdit::new(&mut xpstts.sbcount)
 | 
			
		||||
                                    .arrows(false)
 | 
			
		||||
                                    .range(0..32),
 | 
			
		||||
                            );
 | 
			
		||||
                        });
 | 
			
		||||
                    });
 | 
			
		||||
| 
						 | 
				
			
			@ -291,7 +297,7 @@ impl RegisterWindow {
 | 
			
		|||
                        });
 | 
			
		||||
                    });
 | 
			
		||||
                });
 | 
			
		||||
            ui.vertical(|ui| ui.add_space(ui.available_height()));
 | 
			
		||||
            ui.allocate_space(ui.available_size());
 | 
			
		||||
        });
 | 
			
		||||
        if xpstts.update(&mut raw_xpstts) {
 | 
			
		||||
            xpstts.update(&mut raw_xpstts);
 | 
			
		||||
| 
						 | 
				
			
			@ -299,10 +305,185 @@ impl RegisterWindow {
 | 
			
		|||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    fn read_address<T: MemoryValue>(&self, address: usize) -> T {
 | 
			
		||||
        let index = (address - 0x0005f800) / size_of::<T>();
 | 
			
		||||
        self.registers.borrow().read(index)
 | 
			
		||||
    fn show_colors(&mut self, ui: &mut Ui) {
 | 
			
		||||
        let row_height = ui.spacing().interact_size.y;
 | 
			
		||||
        let registers = self.registers.borrow();
 | 
			
		||||
        ui.section("Colors", |ui| {
 | 
			
		||||
            TableBuilder::new(ui)
 | 
			
		||||
                .column(Column::auto())
 | 
			
		||||
                .columns(Column::remainder(), 4)
 | 
			
		||||
                .cell_layout(Layout::left_to_right(Align::Max))
 | 
			
		||||
                .body(|mut body| {
 | 
			
		||||
                    body.row(row_height, |mut row| {
 | 
			
		||||
                        row.col(|_ui| {});
 | 
			
		||||
                        row.col(|_ui| {});
 | 
			
		||||
                        row.col(|ui| {
 | 
			
		||||
                            ui.with_layout(
 | 
			
		||||
                                Layout::centered_and_justified(Direction::LeftToRight),
 | 
			
		||||
                                |ui| ui.label("1"),
 | 
			
		||||
                            );
 | 
			
		||||
                        });
 | 
			
		||||
                        row.col(|ui| {
 | 
			
		||||
                            ui.with_layout(
 | 
			
		||||
                                Layout::centered_and_justified(Direction::LeftToRight),
 | 
			
		||||
                                |ui| ui.label("2"),
 | 
			
		||||
                            );
 | 
			
		||||
                        });
 | 
			
		||||
                        row.col(|ui| {
 | 
			
		||||
                            ui.with_layout(
 | 
			
		||||
                                Layout::centered_and_justified(Direction::LeftToRight),
 | 
			
		||||
                                |ui| ui.label("3"),
 | 
			
		||||
                            );
 | 
			
		||||
                        });
 | 
			
		||||
                    });
 | 
			
		||||
                    let mut brts: [u16; 3] = [
 | 
			
		||||
                        read_address(®isters, 0x0005f824),
 | 
			
		||||
                        read_address(®isters, 0x0005f826),
 | 
			
		||||
                        read_address(®isters, 0x0005f828),
 | 
			
		||||
                    ];
 | 
			
		||||
                    body.row(row_height, |mut row| {
 | 
			
		||||
                        let mut stale = false;
 | 
			
		||||
                        row.col(|ui| {
 | 
			
		||||
                            ui.label("BRT");
 | 
			
		||||
                        });
 | 
			
		||||
                        row.col(|_ui| {});
 | 
			
		||||
                        for brt in brts.iter_mut() {
 | 
			
		||||
                            row.col(|ui| {
 | 
			
		||||
                                if ui
 | 
			
		||||
                                    .add(NumberEdit::new(brt).range(0..256).arrows(false).hex(true))
 | 
			
		||||
                                    .changed()
 | 
			
		||||
                                {
 | 
			
		||||
                                    stale = true;
 | 
			
		||||
                                }
 | 
			
		||||
                            });
 | 
			
		||||
                        }
 | 
			
		||||
                        if stale {
 | 
			
		||||
                            self.memory.write(self.sim_id, 0x0005f824, &brts);
 | 
			
		||||
                        }
 | 
			
		||||
                    });
 | 
			
		||||
                    body.row(row_height, |mut row| {
 | 
			
		||||
                        row.col(|_ui| {});
 | 
			
		||||
                        for shade in utils::parse_brts(&brts, Color32::RED) {
 | 
			
		||||
                            row.col(|ui| {
 | 
			
		||||
                                ui.painter().rect_filled(
 | 
			
		||||
                                    ui.available_rect_before_wrap(),
 | 
			
		||||
                                    0.0,
 | 
			
		||||
                                    shade,
 | 
			
		||||
                                );
 | 
			
		||||
                            });
 | 
			
		||||
                        }
 | 
			
		||||
                    });
 | 
			
		||||
                    let mut palettes = read_address::<[u16; 8]>(®isters, 0x0005f860);
 | 
			
		||||
                    let mut add_row = |name: &str, address: u32, value: &mut u16| {
 | 
			
		||||
                        let mut c1 = (*value >> 2) & 0x03;
 | 
			
		||||
                        let mut c2 = (*value >> 4) & 0x03;
 | 
			
		||||
                        let mut c3 = (*value >> 6) & 0x03;
 | 
			
		||||
                        let mut stale = false;
 | 
			
		||||
                        body.row(row_height, |mut row| {
 | 
			
		||||
                            row.col(|ui| {
 | 
			
		||||
                                ui.label(name);
 | 
			
		||||
                            });
 | 
			
		||||
                            row.col(|ui| {
 | 
			
		||||
                                if ui
 | 
			
		||||
                                    .add(
 | 
			
		||||
                                        NumberEdit::new(value)
 | 
			
		||||
                                            .range(0..256)
 | 
			
		||||
                                            .arrows(false)
 | 
			
		||||
                                            .hex(true),
 | 
			
		||||
                                    )
 | 
			
		||||
                                    .changed()
 | 
			
		||||
                                {
 | 
			
		||||
                                    stale = true;
 | 
			
		||||
                                };
 | 
			
		||||
                            });
 | 
			
		||||
                            row.col(|ui| {
 | 
			
		||||
                                if ui
 | 
			
		||||
                                    .add(NumberEdit::new(&mut c1).range(0..4).arrows(false))
 | 
			
		||||
                                    .changed()
 | 
			
		||||
                                {
 | 
			
		||||
                                    *value = (*value & 0xfff3) | (c1 << 2);
 | 
			
		||||
                                    stale = true;
 | 
			
		||||
                                }
 | 
			
		||||
                            });
 | 
			
		||||
                            row.col(|ui| {
 | 
			
		||||
                                if ui
 | 
			
		||||
                                    .add(NumberEdit::new(&mut c2).range(0..4).arrows(false))
 | 
			
		||||
                                    .changed()
 | 
			
		||||
                                {
 | 
			
		||||
                                    *value = (*value & 0xffcf) | (c2 << 4);
 | 
			
		||||
                                    stale = true;
 | 
			
		||||
                                }
 | 
			
		||||
                            });
 | 
			
		||||
                            row.col(|ui| {
 | 
			
		||||
                                if ui
 | 
			
		||||
                                    .add(NumberEdit::new(&mut c3).range(0..4).arrows(false))
 | 
			
		||||
                                    .changed()
 | 
			
		||||
                                {
 | 
			
		||||
                                    *value = (*value & 0xff3f) | (c3 << 6);
 | 
			
		||||
                                    stale = true;
 | 
			
		||||
                                }
 | 
			
		||||
                            });
 | 
			
		||||
                        });
 | 
			
		||||
                        if stale {
 | 
			
		||||
                            self.memory.write(self.sim_id, address, value);
 | 
			
		||||
                        }
 | 
			
		||||
                    };
 | 
			
		||||
 | 
			
		||||
                    add_row("GPLT0", 0x0005f860, &mut palettes[0]);
 | 
			
		||||
                    add_row("GPLT1", 0x0005f862, &mut palettes[1]);
 | 
			
		||||
                    add_row("GPLT2", 0x0005f864, &mut palettes[2]);
 | 
			
		||||
                    add_row("GPLT3", 0x0005f866, &mut palettes[3]);
 | 
			
		||||
                    add_row("JPLT0", 0x0005f868, &mut palettes[4]);
 | 
			
		||||
                    add_row("JPLT1", 0x0005f86a, &mut palettes[5]);
 | 
			
		||||
                    add_row("JPLT2", 0x0005f86c, &mut palettes[6]);
 | 
			
		||||
                    add_row("JPLT3", 0x0005f86e, &mut palettes[7]);
 | 
			
		||||
 | 
			
		||||
                    body.row(row_height, |mut row| {
 | 
			
		||||
                        row.col(|ui| {
 | 
			
		||||
                            ui.label("BKCOL");
 | 
			
		||||
                        });
 | 
			
		||||
                        row.col(|ui| {
 | 
			
		||||
                            let mut bkcol: u16 = read_address(®isters, 0x0005f870);
 | 
			
		||||
                            if ui
 | 
			
		||||
                                .add(NumberEdit::new(&mut bkcol).range(0..4).arrows(false))
 | 
			
		||||
                                .changed()
 | 
			
		||||
                            {
 | 
			
		||||
                                self.memory.write(self.sim_id, 0x0005f870, &bkcol);
 | 
			
		||||
                            }
 | 
			
		||||
                        });
 | 
			
		||||
                        row.col(|_ui| {});
 | 
			
		||||
                        row.col(|ui| {
 | 
			
		||||
                            ui.label("REST");
 | 
			
		||||
                        });
 | 
			
		||||
                        row.col(|ui| {
 | 
			
		||||
                            let mut rest: u16 = read_address(®isters, 0x0005f82a);
 | 
			
		||||
                            if ui
 | 
			
		||||
                                .add(
 | 
			
		||||
                                    NumberEdit::new(&mut rest)
 | 
			
		||||
                                        .range(0..256)
 | 
			
		||||
                                        .arrows(false)
 | 
			
		||||
                                        .hex(true),
 | 
			
		||||
                                )
 | 
			
		||||
                                .changed()
 | 
			
		||||
                            {
 | 
			
		||||
                                self.memory.write(self.sim_id, 0x0005f82a, &rest);
 | 
			
		||||
                            }
 | 
			
		||||
                        });
 | 
			
		||||
                    });
 | 
			
		||||
                });
 | 
			
		||||
 | 
			
		||||
            ui.allocate_space(ui.available_size_before_wrap());
 | 
			
		||||
        });
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    fn read_address<T: MemoryValue>(&self, address: usize) -> T {
 | 
			
		||||
        read_address(&self.registers.borrow(), address)
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
fn read_address<T: MemoryValue>(registers: &MemoryRef, address: usize) -> T {
 | 
			
		||||
    let index = (address - 0x0005f800) / size_of::<T>();
 | 
			
		||||
    registers.read(index)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl AppWindow for RegisterWindow {
 | 
			
		||||
| 
						 | 
				
			
			@ -317,15 +498,19 @@ impl AppWindow for RegisterWindow {
 | 
			
		|||
    fn initial_viewport(&self) -> ViewportBuilder {
 | 
			
		||||
        ViewportBuilder::default()
 | 
			
		||||
            .with_title(format!("Registers ({})", self.sim_id))
 | 
			
		||||
            .with_inner_size((640.0, 480.0))
 | 
			
		||||
            .with_inner_size((800.0, 480.0))
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    fn show(&mut self, ctx: &Context) {
 | 
			
		||||
        CentralPanel::default().show(ctx, |ui| {
 | 
			
		||||
            ScrollArea::vertical().show(ui, |ui| {
 | 
			
		||||
                ui.horizontal_top(|ui| {
 | 
			
		||||
                    let width = ui.available_width() - (ui.spacing().item_spacing.x * 6.0);
 | 
			
		||||
                    StripBuilder::new(ui)
 | 
			
		||||
                        .sizes(Size::remainder(), 4)
 | 
			
		||||
                        .size(Size::exact(width * 0.2))
 | 
			
		||||
                        .size(Size::exact(width * 0.2))
 | 
			
		||||
                        .size(Size::exact(width * 0.3))
 | 
			
		||||
                        .size(Size::exact(width * 0.2))
 | 
			
		||||
                        .horizontal(|mut strip| {
 | 
			
		||||
                            strip.cell(|ui| {
 | 
			
		||||
                                self.show_interrupts(ui);
 | 
			
		||||
| 
						 | 
				
			
			@ -340,6 +525,9 @@ impl AppWindow for RegisterWindow {
 | 
			
		|||
                                    });
 | 
			
		||||
                                });
 | 
			
		||||
                            });
 | 
			
		||||
                            strip.cell(|ui| {
 | 
			
		||||
                                self.show_colors(ui);
 | 
			
		||||
                            });
 | 
			
		||||
                        });
 | 
			
		||||
                });
 | 
			
		||||
            });
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -28,6 +28,15 @@ pub const fn parse_shades(brts: &[u8; 8]) -> [u8; 4] {
 | 
			
		|||
    ]
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
pub fn parse_brts(brts: &[u16; 3], color: Color32) -> [Color32; 4] {
 | 
			
		||||
    [
 | 
			
		||||
        Color32::BLACK,
 | 
			
		||||
        shade(brts[0] as u8, color),
 | 
			
		||||
        shade(brts[1] as u8, color),
 | 
			
		||||
        shade((brts[0] + brts[1] + brts[2]) as u8, color),
 | 
			
		||||
    ]
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
pub fn palette_colors(palette: u8, brts: &[u8; 8], color: Color32) -> [Color32; 4] {
 | 
			
		||||
    let colors = parse_shades(brts).map(|s| shade(s, color));
 | 
			
		||||
    parse_palette(palette).map(|p| colors[p as usize])
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
		Reference in New Issue