mirror of
https://github.com/encounter/objdiff.git
synced 2025-10-05 09:29:51 +00:00
149 lines
5.4 KiB
Rust
149 lines
5.4 KiB
Rust
use std::default::Default;
|
|
|
|
use egui::{Label, Sense, Widget, text::LayoutJob};
|
|
use objdiff_core::{
|
|
diff::{
|
|
DataDiffKind, DataDiffRow,
|
|
data::BYTES_PER_ROW,
|
|
display::{data_row_context, data_row_hover},
|
|
},
|
|
obj::Object,
|
|
};
|
|
|
|
use super::diff::{context_menu_items_ui, hover_items_ui};
|
|
use crate::views::{appearance::Appearance, write_text};
|
|
|
|
fn data_row_hover_ui(
|
|
ui: &mut egui::Ui,
|
|
obj: &Object,
|
|
diff_row: &DataDiffRow,
|
|
appearance: &Appearance,
|
|
) {
|
|
ui.scope(|ui| {
|
|
ui.style_mut().override_text_style = Some(egui::TextStyle::Monospace);
|
|
ui.style_mut().wrap_mode = Some(egui::TextWrapMode::Extend);
|
|
hover_items_ui(ui, data_row_hover(obj, diff_row), appearance);
|
|
});
|
|
}
|
|
|
|
fn data_row_context_menu(
|
|
ui: &mut egui::Ui,
|
|
obj: &Object,
|
|
diff_row: &DataDiffRow,
|
|
column: usize,
|
|
appearance: &Appearance,
|
|
) {
|
|
ui.scope(|ui| {
|
|
ui.style_mut().override_text_style = Some(egui::TextStyle::Monospace);
|
|
ui.style_mut().wrap_mode = Some(egui::TextWrapMode::Extend);
|
|
context_menu_items_ui(ui, data_row_context(obj, diff_row), column, appearance);
|
|
});
|
|
}
|
|
|
|
fn get_color_for_diff_kind(diff_kind: DataDiffKind, appearance: &Appearance) -> egui::Color32 {
|
|
match diff_kind {
|
|
DataDiffKind::None => appearance.text_color,
|
|
DataDiffKind::Replace => appearance.replace_color,
|
|
DataDiffKind::Delete => appearance.delete_color,
|
|
DataDiffKind::Insert => appearance.insert_color,
|
|
}
|
|
}
|
|
|
|
pub(crate) fn data_row_ui(
|
|
ui: &mut egui::Ui,
|
|
obj: Option<&Object>,
|
|
base_address: u64,
|
|
row_address: u64,
|
|
diff_row: &DataDiffRow,
|
|
appearance: &Appearance,
|
|
column: usize,
|
|
) {
|
|
if diff_row.segments.iter().any(|dd| dd.kind != DataDiffKind::None)
|
|
|| diff_row.relocations.iter().any(|rd| rd.kind != DataDiffKind::None)
|
|
{
|
|
ui.painter().rect_filled(ui.available_rect_before_wrap(), 0.0, ui.visuals().faint_bg_color);
|
|
}
|
|
let mut job = LayoutJob::default();
|
|
write_text(
|
|
format!("{row_address:08x}: ").as_str(),
|
|
appearance.text_color,
|
|
&mut job,
|
|
appearance.code_font.clone(),
|
|
);
|
|
// The offset shown on the side of the GUI, shifted by insertions/deletions.
|
|
let mut cur_addr = 0usize;
|
|
// The offset into the actual bytes of the section on this side, ignoring differences.
|
|
let mut cur_addr_actual = base_address + row_address;
|
|
for diff in diff_row.segments.iter() {
|
|
let base_color = get_color_for_diff_kind(diff.kind, appearance);
|
|
if diff.data.is_empty() {
|
|
let mut str = " ".repeat(diff.size);
|
|
let n1 = cur_addr / 8;
|
|
let n2 = (diff.size + cur_addr) / 8;
|
|
str.push_str(" ".repeat(n2 - n1).as_str());
|
|
write_text(str.as_str(), base_color, &mut job, appearance.code_font.clone());
|
|
cur_addr += diff.size;
|
|
} else {
|
|
for byte in &diff.data {
|
|
let mut byte_text = format!("{byte:02x} ");
|
|
let mut byte_color = base_color;
|
|
if let Some(reloc_diff) = diff_row
|
|
.relocations
|
|
.iter()
|
|
.find(|reloc_diff| reloc_diff.range.contains(&cur_addr_actual))
|
|
{
|
|
if *byte == 0 {
|
|
// Display 00 data bytes with a relocation as ?? instead.
|
|
byte_text = "?? ".to_string();
|
|
}
|
|
if reloc_diff.kind != DataDiffKind::None {
|
|
byte_color = get_color_for_diff_kind(reloc_diff.kind, appearance);
|
|
}
|
|
}
|
|
write_text(byte_text.as_str(), byte_color, &mut job, appearance.code_font.clone());
|
|
cur_addr += 1;
|
|
cur_addr_actual += 1;
|
|
if cur_addr.is_multiple_of(8) {
|
|
write_text(" ", base_color, &mut job, appearance.code_font.clone());
|
|
}
|
|
}
|
|
}
|
|
}
|
|
if cur_addr < BYTES_PER_ROW {
|
|
let n = BYTES_PER_ROW - cur_addr;
|
|
let mut str = " ".to_string();
|
|
str.push_str(" ".repeat(n).as_str());
|
|
str.push_str(" ".repeat(n / 8).as_str());
|
|
write_text(str.as_str(), appearance.text_color, &mut job, appearance.code_font.clone());
|
|
}
|
|
write_text(" ", appearance.text_color, &mut job, appearance.code_font.clone());
|
|
for diff in diff_row.segments.iter() {
|
|
let base_color = get_color_for_diff_kind(diff.kind, appearance);
|
|
if diff.data.is_empty() {
|
|
write_text(
|
|
" ".repeat(diff.size).as_str(),
|
|
base_color,
|
|
&mut job,
|
|
appearance.code_font.clone(),
|
|
);
|
|
} else {
|
|
let mut text = String::new();
|
|
for byte in &diff.data {
|
|
let c = char::from(*byte);
|
|
if c.is_ascii() && !c.is_ascii_control() {
|
|
text.push(c);
|
|
} else {
|
|
text.push('.');
|
|
}
|
|
}
|
|
write_text(text.as_str(), base_color, &mut job, appearance.code_font.clone());
|
|
}
|
|
}
|
|
|
|
let response = Label::new(job).sense(Sense::click()).ui(ui);
|
|
if let Some(obj) = obj {
|
|
response.context_menu(|ui| data_row_context_menu(ui, obj, diff_row, column, appearance));
|
|
response.on_hover_ui_at_pointer(|ui| data_row_hover_ui(ui, obj, diff_row, appearance));
|
|
}
|
|
}
|