Skip to content

Commit a36b4f9

Browse files
committed
Tag history
Adds a menu with tags similar to the page history in a browser. And just like the browser, you can also go forward/backward using the respective mouse buttons, for those that have it
1 parent 1e7f050 commit a36b4f9

File tree

3 files changed

+134
-10
lines changed

3 files changed

+134
-10
lines changed

src/gui/mod.rs

Lines changed: 31 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -9,10 +9,12 @@ mod tag;
99
mod texture;
1010
mod texturelist;
1111

12+
use std::cell::RefCell;
13+
use std::rc::Rc;
1214
use std::sync::Arc;
1315

1416
use destiny_pkg::{PackageVersion, TagHash};
15-
use eframe::egui::{TextEdit, Widget};
17+
use eframe::egui::{PointerButton, TextEdit, Widget};
1618
use eframe::egui_wgpu::RenderState;
1719
use eframe::{
1820
egui::{self},
@@ -22,6 +24,7 @@ use eframe::{
2224
use egui_notify::Toasts;
2325
use poll_promise::Promise;
2426

27+
use crate::gui::tag::TagHistory;
2528
use crate::scanner::fnv1;
2629
use crate::text::RawStringHashCache;
2730
use crate::{
@@ -51,6 +54,7 @@ pub enum Panel {
5154
pub struct QuickTagApp {
5255
cache_load: Option<Promise<TagCache>>,
5356
cache: Arc<TagCache>,
57+
tag_history: Rc<RefCell<TagHistory>>,
5458
strings: Arc<StringCache>,
5559
raw_strings: Arc<RawStringHashCache>,
5660

@@ -100,6 +104,7 @@ impl QuickTagApp {
100104
cache_load: Some(Promise::spawn_thread("load_cache", move || {
101105
load_tag_cache(version)
102106
})),
107+
tag_history: Rc::new(RefCell::new(TagHistory::default())),
103108
cache: Default::default(),
104109
tag_view: None,
105110
tag_input: String::new(),
@@ -267,7 +272,7 @@ impl eframe::App for QuickTagApp {
267272
TagHash(u32::from_be(hash))
268273
};
269274

270-
self.open_tag(tag);
275+
self.open_tag(tag, true);
271276
}
272277

273278
ui.checkbox(&mut self.tag_split, "Split pkg/entry");
@@ -300,16 +305,32 @@ impl eframe::App for QuickTagApp {
300305
Panel::RawStrings => self.raw_strings_view.view(ctx, ui),
301306
};
302307

308+
if self.open_panel == Panel::Tag && action.is_none() {
309+
if ui.input(|i| i.pointer.button_pressed(PointerButton::Extra1)) {
310+
let t = self.tag_history.borrow_mut().back();
311+
if let Some(t) = t {
312+
self.open_tag(t, false);
313+
}
314+
}
315+
316+
if ui.input(|i| i.pointer.button_pressed(PointerButton::Extra2)) {
317+
let t = self.tag_history.borrow_mut().forward();
318+
if let Some(t) = t {
319+
self.open_tag(t, false);
320+
}
321+
}
322+
}
323+
303324
if let Some(action) = action {
304325
match action {
305-
ViewAction::OpenTag(t) => self.open_tag(t),
326+
ViewAction::OpenTag(t) => self.open_tag(t, true),
306327
}
307328
}
308329
});
309330
});
310331

311332
self.toasts.show(ctx);
312-
333+
313334
// Redraw the window while we're loading textures. This prevents loading textures from seeming "stuck"
314335
if self.texture_cache.is_loading_textures() {
315336
ctx.request_repaint();
@@ -318,9 +339,10 @@ impl eframe::App for QuickTagApp {
318339
}
319340

320341
impl QuickTagApp {
321-
fn open_tag(&mut self, tag: TagHash) {
342+
fn open_tag(&mut self, tag: TagHash, push_history: bool) {
322343
let new_view = TagView::create(
323344
self.cache.clone(),
345+
self.tag_history.clone(),
324346
self.strings.clone(),
325347
self.raw_strings.clone(),
326348
tag,
@@ -339,6 +361,10 @@ impl QuickTagApp {
339361
self.toasts
340362
.error(format!("Could not find tag '{}' ({tag})", self.tag_input));
341363
}
364+
365+
if push_history {
366+
self.tag_history.borrow_mut().push(tag);
367+
}
342368
}
343369
}
344370

src/gui/strings.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -109,7 +109,7 @@ impl View for StringsView {
109109
s.to_lowercase()
110110
};
111111

112-
if self.hide_devalpha_str && devstr_regex.is_match(&s) {
112+
if self.hide_devalpha_str && devstr_regex.is_match(s) {
113113
false
114114
} else if self.exact_match {
115115
match_a == match_b

src/gui/tag.rs

Lines changed: 102 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
use std::cell::RefCell;
12
use std::{
23
collections::HashSet,
34
fmt::Display,
@@ -10,10 +11,10 @@ use std::{
1011
use binrw::{binread, BinReaderExt, Endian};
1112
use destiny_pkg::{package::UEntryHeader, PackageVersion, TagHash, TagHash64};
1213
use eframe::egui::load::SizedTexture;
13-
use eframe::egui::{collapsing_header::CollapsingState, vec2, TextureId};
14+
use eframe::egui::{collapsing_header::CollapsingState, vec2, RichText, TextureId};
1415
use eframe::egui_wgpu::RenderState;
1516
use eframe::{
16-
egui::{self, CollapsingHeader, RichText},
17+
egui::{self, CollapsingHeader},
1718
epaint::Color32,
1819
wgpu,
1920
};
@@ -22,6 +23,7 @@ use log::error;
2223
use poll_promise::Promise;
2324
use rustc_hash::FxHashMap;
2425
use std::fmt::Write;
26+
use std::rc::Rc;
2527

2628
use crate::{gui::texture::Texture, scanner::read_raw_string_blob, text::RawStringHashCache};
2729
use crate::{
@@ -43,6 +45,7 @@ use super::{
4345

4446
pub struct TagView {
4547
cache: Arc<TagCache>,
48+
tag_history: Rc<RefCell<TagHistory>>,
4649
string_cache: Arc<StringCache>,
4750
raw_string_hash_cache: Arc<RawStringHashCache>,
4851

@@ -74,6 +77,7 @@ pub struct TagView {
7477
impl TagView {
7578
pub fn create(
7679
cache: Arc<TagCache>,
80+
tag_history: Rc<RefCell<TagHistory>>,
7781
string_cache: Arc<StringCache>,
7882
raw_string_hash_cache: Arc<RawStringHashCache>,
7983
tag: TagHash,
@@ -237,6 +241,7 @@ impl TagView {
237241

238242
scan,
239243
cache,
244+
tag_history,
240245
traversal_depth_limit: 16,
241246
tag_traversal: None,
242247
traversal_show_strings: false,
@@ -252,9 +257,13 @@ impl TagView {
252257
}
253258

254259
/// Replaces this view with another tag
255-
pub fn open_tag(&mut self, tag: TagHash) {
260+
pub fn open_tag(&mut self, tag: TagHash, push_history: bool) {
261+
if push_history {
262+
self.tag_history.borrow_mut().push(tag);
263+
}
256264
if let Some(mut tv) = Self::create(
257265
self.cache.clone(),
266+
self.tag_history.clone(),
258267
self.string_cache.clone(),
259268
self.raw_string_hash_cache.clone(),
260269
tag,
@@ -373,6 +382,49 @@ impl View for TagView {
373382
ui: &mut eframe::egui::Ui,
374383
) -> Option<ViewAction> {
375384
let mut open_new_tag = None;
385+
let mut push_history = true;
386+
387+
ui.horizontal(|ui| {
388+
let mut history = self.tag_history.borrow_mut();
389+
390+
ui.style_mut().spacing.button_padding = [4.0, 4.0].into();
391+
ui.add_enabled_ui(history.current > 0, |ui| {
392+
if ui.button(RichText::new("⬅").strong()).clicked() {
393+
open_new_tag = history.back();
394+
push_history = false;
395+
}
396+
});
397+
398+
ui.add_enabled_ui((history.current + 1) < history.tags.len(), |ui| {
399+
if ui.button(RichText::new("➡").strong()).clicked() {
400+
open_new_tag = history.forward();
401+
push_history = false;
402+
}
403+
});
404+
405+
egui::ComboBox::new("tag_history", "")
406+
.selected_text("History")
407+
.show_ui(ui, |ui| {
408+
let mut set_current = None;
409+
for (i, (tag, tag_label, tag_color)) in history.tags.iter().enumerate().rev() {
410+
if ui
411+
.selectable_label(
412+
i == history.current,
413+
RichText::new(tag_label).color(*tag_color),
414+
)
415+
.clicked()
416+
{
417+
open_new_tag = Some(*tag);
418+
push_history = false;
419+
set_current = Some(i);
420+
}
421+
}
422+
423+
if let Some(i) = set_current {
424+
history.current = i;
425+
}
426+
});
427+
});
376428

377429
ui.heading(format_tag_entry(self.tag, Some(&self.tag_entry)))
378430
.context_menu(|ui| tag_context(ui, self.tag, self.tag64));
@@ -812,7 +864,7 @@ impl View for TagView {
812864
ctx.request_repaint_after(Duration::from_secs(1));
813865

814866
if let Some(new_tag) = open_new_tag {
815-
self.open_tag(new_tag);
867+
self.open_tag(new_tag, push_history);
816868
}
817869

818870
None
@@ -1214,3 +1266,49 @@ pub fn strip_ansi_codes(input: &str) -> String {
12141266
let ansi_escape_pattern = regex::Regex::new(r"\x1B\[[0-9;]*[mK]").unwrap();
12151267
ansi_escape_pattern.replace_all(input, "").to_string()
12161268
}
1269+
1270+
#[derive(Default)]
1271+
pub struct TagHistory {
1272+
pub tags: Vec<(TagHash, String, Color32)>,
1273+
pub current: usize,
1274+
}
1275+
1276+
impl TagHistory {
1277+
pub fn push(&mut self, tag: TagHash) {
1278+
self.tags.truncate(self.current + 1);
1279+
1280+
if let Some(entry) = package_manager().get_entry(tag) {
1281+
let tagtype = TagType::from_type_subtype(entry.file_type, entry.file_subtype);
1282+
let color = tagtype.display_color();
1283+
let fancy_tag = format_tag_entry(tag, Some(&entry));
1284+
1285+
self.tags.push((tag, fancy_tag, color));
1286+
} else {
1287+
self.tags.push((
1288+
tag,
1289+
format!("{tag} (pkg entry not found)"),
1290+
Color32::LIGHT_RED,
1291+
));
1292+
}
1293+
1294+
self.current = self.tags.len().saturating_sub(1);
1295+
}
1296+
1297+
pub fn back(&mut self) -> Option<TagHash> {
1298+
if self.current > 0 {
1299+
self.current -= 1;
1300+
self.tags.get(self.current).map(|v| v.0)
1301+
} else {
1302+
None
1303+
}
1304+
}
1305+
1306+
pub fn forward(&mut self) -> Option<TagHash> {
1307+
if (self.current + 1) < self.tags.len() {
1308+
self.current += 1;
1309+
self.tags.get(self.current).map(|v| v.0)
1310+
} else {
1311+
None
1312+
}
1313+
}
1314+
}

0 commit comments

Comments
 (0)