diff options
Diffstat (limited to 'src/cue_view.rs')
| -rw-r--r-- | src/cue_view.rs | 81 |
1 files changed, 55 insertions, 26 deletions
diff --git a/src/cue_view.rs b/src/cue_view.rs index fbf2520..05c45c4 100644 --- a/src/cue_view.rs +++ b/src/cue_view.rs @@ -8,18 +8,25 @@ use relm4::prelude::*; use relm4::{ComponentParts, SimpleComponent}; use unicode_segmentation::UnicodeSegmentation; +use crate::subtitles::state::CueAddress; +use crate::translation::TRANSLATIONS; use crate::util::Tracker; -pub struct CueView { - text: Tracker<Option<String>>, +pub struct ActiveCueViewState { + addr: CueAddress, + text: String, // byte ranges for the words in `text` word_ranges: Vec<Range<usize>>, } +pub struct CueView { + state: Tracker<Option<ActiveCueViewState>>, +} + #[derive(Debug)] pub enum CueViewMsg { // messages from the app - SetText(Option<String>), + SetCue(Option<CueAddress>), // messages from UI MouseMotion, } @@ -42,7 +49,7 @@ impl SimpleComponent for CueView { gtk::Label { add_controller: event_controller.clone(), set_use_markup: true, - set_visible: false, + set_sensitive: false, set_justify: gtk::Justification::Center, add_css_class: "cue-view", }, @@ -71,8 +78,7 @@ impl SimpleComponent for CueView { sender: relm4::ComponentSender<Self>, ) -> relm4::ComponentParts<Self> { let model = Self { - text: Tracker::new(None), - word_ranges: Vec::new(), + state: Tracker::new(None), }; let widgets = view_output!(); @@ -81,19 +87,26 @@ impl SimpleComponent for CueView { } fn update(&mut self, message: Self::Input, _sender: relm4::ComponentSender<Self>) { - match message { - CueViewMsg::SetText(text) => { - self.text.set(text); + self.state.reset(); - if let Some(text) = self.text.get() { - self.word_ranges = UnicodeSegmentation::unicode_word_indices(text.as_str()) + match message { + CueViewMsg::SetCue(addr) => { + if let Some(addr) = addr { + let text = addr.resolve_text(); + let word_ranges = UnicodeSegmentation::unicode_word_indices(text.as_str()) .map(|(offset, slice)| Range { start: offset, end: offset + slice.len(), }) .collect(); + + self.state.set(Some(ActiveCueViewState { + addr, + text, + word_ranges, + })) } else { - self.word_ranges = Vec::new(); + self.state.set(None); } } CueViewMsg::MouseMotion => { @@ -103,11 +116,16 @@ impl SimpleComponent for CueView { } fn post_view() { - if self.text.is_dirty() { - if let Some(text) = self.text.get() { + if self.state.is_dirty() { + if let Some(ActiveCueViewState { + addr: _, + text, + word_ranges, + }) = self.state.get() + { let mut markup = String::new(); - let mut it = self.word_ranges.iter().enumerate().peekable(); + let mut it = word_ranges.iter().enumerate().peekable(); if let Some((_, first_word_range)) = it.peek() { markup.push_str( glib::markup_escape_text(&text[..first_word_range.start]).as_str(), @@ -127,24 +145,35 @@ impl SimpleComponent for CueView { markup.push_str(glib::markup_escape_text(&text[next_gap_range]).as_str()); } - widgets.label.set_markup(markup.as_str()); - widgets.label.set_visible(true); + widgets.label.set_markup(&markup); + widgets.label.set_sensitive(true); } else { - widgets.label.set_visible(false); + // insensitive = invisible by css + widgets.label.set_sensitive(false); } } - if let Some(word_ix_str) = widgets.label.current_uri() { - let range = self - .word_ranges - .get(usize::from_str(word_ix_str.as_str()).unwrap()) - .unwrap(); - widgets - .popover_label - .set_text(&self.text.get().as_ref().unwrap()[range.clone()]); + if let ( + Some(ActiveCueViewState { + addr: CueAddress(stream_ix, cue_ix), + text: _, + word_ranges, + }), + Some(word_ix_str), + ) = (self.state.get(), widgets.label.current_uri()) + { + let word_ix = usize::from_str(word_ix_str.as_str()).unwrap(); + + { + // TODO get translation + widgets.popover_label.set_text(word_ix_str.as_str()); + } + + let range = word_ranges.get(word_ix).unwrap(); widgets .popover .set_pointing_to(Some(&Self::get_rect_of_byte_range(&widgets.label, &range))); + widgets.popover.popup(); } else { widgets.popover.popdown(); |