From 7b4c40026a441f0cec93113106e44df3358303e8 Mon Sep 17 00:00:00 2001 From: Henrik Friedrichsen Date: Wed, 6 Mar 2019 00:46:47 +0100 Subject: [PATCH] extract SplitButton from TrackButton for future PlaylistButton --- src/ui/mod.rs | 1 + src/ui/queue.rs | 3 +- src/ui/splitbutton.rs | 105 ++++++++++++++++++++++++++++++++++++++++++ src/ui/trackbutton.rs | 104 ++--------------------------------------- 4 files changed, 113 insertions(+), 100 deletions(-) create mode 100644 src/ui/splitbutton.rs diff --git a/src/ui/mod.rs b/src/ui/mod.rs index 1044dcf..391ab03 100644 --- a/src/ui/mod.rs +++ b/src/ui/mod.rs @@ -3,4 +3,5 @@ pub mod playlist; pub mod queue; pub mod search; pub mod statusbar; +pub mod splitbutton; pub mod trackbutton; diff --git a/src/ui/queue.rs b/src/ui/queue.rs index 243ba67..f4d3889 100644 --- a/src/ui/queue.rs +++ b/src/ui/queue.rs @@ -11,6 +11,7 @@ use std::sync::Mutex; use queue::{Queue, QueueChange}; use spotify::Spotify; use track::Track; +use ui::splitbutton::SplitButton; use ui::trackbutton::TrackButton; pub struct QueueView { @@ -71,7 +72,7 @@ impl QueueView { } } - fn create_button(&self, track: &Track) -> TrackButton { + fn create_button(&self, track: &Track) -> SplitButton { let mut button = TrackButton::new(&track); // 'd' deletes the selected track { diff --git a/src/ui/splitbutton.rs b/src/ui/splitbutton.rs new file mode 100644 index 0000000..9f627bf --- /dev/null +++ b/src/ui/splitbutton.rs @@ -0,0 +1,105 @@ +use cursive::align::HAlign; +use cursive::direction::Direction; +use cursive::event::{Callback, Event, EventResult, EventTrigger}; +use cursive::theme::ColorStyle; +use cursive::traits::View; +use cursive::vec::Vec2; +use cursive::Cursive; +use cursive::Printer; +use unicode_width::UnicodeWidthStr; + +pub struct SplitButton { + callbacks: Vec<(EventTrigger, Callback)>, + + left: String, + right: String, + + enabled: bool, + last_size: Vec2, + invalidated: bool, +} + +impl SplitButton { + pub fn new(left: &str, right: &str) -> SplitButton { + SplitButton { + callbacks: Vec::new(), + left: left.to_owned(), + right: right.to_owned(), + enabled: true, + last_size: Vec2::zero(), + invalidated: true, + } + } + + pub fn add_callback(&mut self, trigger: E, cb: F) + where + E: Into, + F: 'static + Fn(&mut Cursive), + { + self.callbacks.push((trigger.into(), Callback::from_fn(cb))); + } +} + +// This is heavily based on Cursive's Button implementation with minor +// modifications to print the track's duration at the right screen border +impl View for SplitButton { + fn draw(&self, printer: &Printer<'_, '_>) { + if printer.size.x == 0 { + return; + } + + let style = if !(self.enabled && printer.enabled) { + ColorStyle::secondary() + } else if !printer.focused { + ColorStyle::primary() + } else { + ColorStyle::highlight() + }; + + // shorten titles that are too long and append ".." to indicate this + let mut left_shortened = self.left.clone(); + left_shortened.truncate(printer.size.x - self.right.width() - 1); + if left_shortened.width() < self.left.width() { + let offset = left_shortened.width() - 2; + left_shortened.replace_range(offset.., ".."); + } + + printer.with_color(style, |printer| { + printer.print((0, 0), &left_shortened); + }); + + // track duration goes to the end of the line + let offset = HAlign::Right.get_offset(self.right.width(), printer.size.x); + + printer.with_color(style, |printer| { + printer.print((offset, 0), &self.right); + }); + } + + fn on_event(&mut self, event: Event) -> EventResult { + for (trigger, callback) in self.callbacks.iter() { + if trigger.apply(&event) { + return EventResult::Consumed(Some(callback.clone())); + } + } + EventResult::Ignored + } + + fn layout(&mut self, size: Vec2) { + self.last_size = size; + self.invalidated = false; + } + + fn required_size(&mut self, constraint: Vec2) -> Vec2 { + // we always want the full width + Vec2::new(constraint.x, 1) + } + + fn take_focus(&mut self, _: Direction) -> bool { + self.enabled + } + + fn needs_relayout(&self) -> bool { + self.invalidated + } +} diff --git a/src/ui/trackbutton.rs b/src/ui/trackbutton.rs index 24fe61e..94476e2 100644 --- a/src/ui/trackbutton.rs +++ b/src/ui/trackbutton.rs @@ -1,105 +1,11 @@ -use cursive::align::HAlign; -use cursive::direction::Direction; -use cursive::event::{Callback, Event, EventResult, EventTrigger}; -use cursive::theme::ColorStyle; -use cursive::traits::View; -use cursive::vec::Vec2; -use cursive::Cursive; -use cursive::Printer; -use unicode_width::UnicodeWidthStr; - +use ui::splitbutton::SplitButton; use track::Track; -pub struct TrackButton { - callbacks: Vec<(EventTrigger, Callback)>, - - track: Track, - - enabled: bool, - last_size: Vec2, - invalidated: bool, -} +pub struct TrackButton {} impl TrackButton { - pub fn new(track: &Track) -> TrackButton { - TrackButton { - callbacks: Vec::new(), - track: track.clone(), - enabled: true, - last_size: Vec2::zero(), - invalidated: true, - } - } - - pub fn add_callback(&mut self, trigger: E, cb: F) - where - E: Into, - F: 'static + Fn(&mut Cursive), - { - self.callbacks.push((trigger.into(), Callback::from_fn(cb))); - } -} - -// This is heavily based on Cursive's Button implementation with minor -// modifications to print the track's duration at the right screen border -impl View for TrackButton { - fn draw(&self, printer: &Printer<'_, '_>) { - if printer.size.x == 0 { - return; - } - - let style = if !(self.enabled && printer.enabled) { - ColorStyle::secondary() - } else if !printer.focused { - ColorStyle::primary() - } else { - ColorStyle::highlight() - }; - - // shorten titles that are too long and append ".." to indicate this - let mut title_shortened = self.track.to_string(); - title_shortened.truncate(printer.size.x - self.track.duration_str().width() - 1); - if title_shortened.width() < self.track.to_string().width() { - let offset = title_shortened.width() - 2; - title_shortened.replace_range(offset.., ".."); - } - - printer.with_color(style, |printer| { - printer.print((0, 0), &title_shortened); - }); - - // track duration goes to the end of the line - let offset = HAlign::Right.get_offset(self.track.duration_str().width(), printer.size.x); - - printer.with_color(style, |printer| { - printer.print((offset, 0), &self.track.duration_str()); - }); - } - - fn on_event(&mut self, event: Event) -> EventResult { - for (trigger, callback) in self.callbacks.iter() { - if trigger.apply(&event) { - return EventResult::Consumed(Some(callback.clone())); - } - } - EventResult::Ignored - } - - fn layout(&mut self, size: Vec2) { - self.last_size = size; - self.invalidated = false; - } - - fn required_size(&mut self, constraint: Vec2) -> Vec2 { - // we always want the full width - Vec2::new(constraint.x, 1) - } - - fn take_focus(&mut self, _: Direction) -> bool { - self.enabled - } - - fn needs_relayout(&self) -> bool { - self.invalidated + pub fn new(track: &Track) -> SplitButton { + let button = SplitButton::new(&track.to_string(), &track.duration_str()); + button } }