diff options
author | Sam Tay <sam.chong.tay@gmail.com> | 2020-06-15 09:01:15 -0700 |
---|---|---|
committer | Sam Tay <sam.chong.tay@gmail.com> | 2020-06-15 12:04:38 -0700 |
commit | 2e3964d35141beb37e08a144c9440a687dfec8fb (patch) | |
tree | 915e4ddb79917f179c7aec04ed760a00741d171c | |
parent | 812cfc8c3e3b878ae11b4c79d468e718ad583689 (diff) |
Get resizing to work, finally
-rw-r--r-- | src/tui/app.rs | 6 | ||||
-rw-r--r-- | src/tui/views.rs | 158 |
2 files changed, 122 insertions, 42 deletions
diff --git a/src/tui/app.rs b/src/tui/app.rs index 35e3ef1..97249b0 100644 --- a/src/tui/app.rs +++ b/src/tui/app.rs @@ -1,3 +1,4 @@ +use cursive::event::{Callback, Event, EventResult}; use cursive::theme::{BaseColor, Color, Effect, Style}; use cursive::utils::markup::StyledString; use cursive::utils::span::SpannedString; @@ -9,8 +10,8 @@ use std::sync::Arc; use super::markdown; use super::views::{ - FullLayout, ListView, MdView, Name, NAME_ANSWER_LIST, NAME_ANSWER_VIEW, NAME_QUESTION_LIST, - NAME_QUESTION_VIEW, + FullLayout, ListView, MdView, Name, NAME_ANSWER_LIST, NAME_ANSWER_VIEW, NAME_FULL_LAYOUT, + NAME_QUESTION_LIST, NAME_QUESTION_VIEW, }; use crate::config; use crate::error::Result; @@ -85,7 +86,6 @@ pub fn run(qs: Vec<Question>) -> Result<()> { siv.add_layer(FullLayout::new( 1, - siv.screen_size(), question_list_view, question_view, answer_list_view, diff --git a/src/tui/views.rs b/src/tui/views.rs index 9571341..0d52623 100644 --- a/src/tui/views.rs +++ b/src/tui/views.rs @@ -1,13 +1,16 @@ -use cursive::event::{Callback, EventResult}; +use cursive::event::{Callback, Event, EventResult}; use cursive::traits::{Finder, Nameable, Resizable, Scrollable}; use cursive::utils::markup::StyledString; use cursive::view::{Margins, SizeConstraint, View, ViewWrapper}; use cursive::views::{ - LinearLayout, NamedView, OnEventView, PaddedView, Panel, ScrollView, SelectView, TextView, + LinearLayout, NamedView, OnEventView, PaddedView, Panel, ResizedView, ScrollView, SelectView, + TextView, }; use cursive::{Cursive, Vec2}; +use std::cell::RefCell; use std::fmt; use std::fmt::Display; +use std::rc::Rc; use super::markdown; use crate::error::Result; @@ -16,6 +19,7 @@ pub const NAME_QUESTION_LIST: &str = "question_list"; pub const NAME_ANSWER_LIST: &str = "answer_list"; pub const NAME_QUESTION_VIEW: &str = "question_view"; pub const NAME_ANSWER_VIEW: &str = "answer_view"; +pub const NAME_FULL_LAYOUT: &str = "full_layout"; // TODO might need resizable wrappers in types @@ -49,7 +53,8 @@ impl From<Name> for String { } // TODO maybe I should use cursive's ListView over SelectView ? -pub type ListView = ListViewT<Panel<ScrollView<OnEventView<NamedView<SelectView<u32>>>>>>; +pub type ListView = + ListViewT<ResizedView<Panel<ScrollView<OnEventView<NamedView<SelectView<u32>>>>>>>; pub struct ListViewT<T: View> { inner_name: String, @@ -92,6 +97,7 @@ impl ListView { let view = add_vim_bindings(view); let view = view.scrollable(); let view = Panel::new(view).title(format!("{}", name)); + let view = view.resized(SizeConstraint::Free, SizeConstraint::Free); let view = ListViewT { view, inner_name }; view.with_name(name) } @@ -118,9 +124,13 @@ impl ListView { { self.view.call_on_name(&self.inner_name, cb).expect("TODO") } + + pub fn resize(&mut self, width: SizeConstraint, height: SizeConstraint) { + self.view.set_constraints(width, height); + } } -pub type MdView = MdViewT<Panel<ScrollView<NamedView<TextView>>>>; +pub type MdView = MdViewT<ResizedView<Panel<ScrollView<NamedView<TextView>>>>>; pub struct MdViewT<T: View> { inner_name: String, @@ -137,6 +147,7 @@ impl MdView { let view = TextView::empty().with_name(&inner_name); let view = view.scrollable(); let view = Panel::new(view); + let view = view.resized(SizeConstraint::Free, SizeConstraint::Free); let view = MdViewT { view, inner_name }; view.with_name(name) } @@ -152,70 +163,139 @@ impl MdView { }) .expect("unwrap failed in MdView.set_content") } + + pub fn resize(&mut self, width: SizeConstraint, height: SizeConstraint) { + self.view.set_constraints(width, height); + } } pub type FullLayout = FullLayoutT<PaddedView<LinearLayout>>; pub struct FullLayoutT<T: View> { view: T, - lr_margin: usize, + invalidated: bool, +} + +struct FullLayoutSizing { + width: SizeConstraint, + list_height: SizeConstraint, + view_height: SizeConstraint, } // TODO set child widths based on parent impl ViewWrapper for FullLayoutT<PaddedView<LinearLayout>> { cursive::wrap_impl!(self.view: PaddedView<LinearLayout>); - fn wrap_layout(&mut self, size: Vec2) { - let margin = self.lr_margin; - let horiz_xy = size.map_x(|x| x / 2 - margin); - for ix in 0..2 { - self.view - .get_inner_mut() - .get_child_mut(ix) - .and_then(|pane| { - // Set top level horizontal constraints - pane.layout(horiz_xy); - // Then coerce the inner linear layouts - pane.downcast_mut() - }) - // And get their children - .and_then(|v: &mut LinearLayout| v.get_child_mut(0)) - // And set the inner vertical constraints - .map(|v| v.layout(horiz_xy.map_y(|y| (ix + 1) * y / 3))); + // TODO what the actual fuck is wrong with this lifetime? + // cursive does this shit all over the place... + // For now just issue a call_on_name like an asshat + fn wrap_on_event(&mut self, event: Event) -> EventResult { + if let Event::WindowResize = event { + println!("resize event thrown"); + self.invalidated = true; } + self.view.on_event(event) + } + + fn wrap_required_size(&mut self, req: Vec2) -> Vec2 { + req + } + + fn wrap_layout(&mut self, size: Vec2) { + self.resize(size); + self.invalidated = false; + self.view.layout(size); + } + + fn wrap_needs_relayout(&self) -> bool { + self.invalidated || self.view.needs_relayout() } } impl FullLayout { pub fn new( lr_margin: usize, - screen_size: Vec2, q_list: NamedView<ListView>, q_view: NamedView<MdView>, a_list: NamedView<ListView>, a_view: NamedView<MdView>, - ) -> Self { - let heuristic = 1; - let x = SizeConstraint::Fixed(screen_size.x / 2 - lr_margin - heuristic); - let y_list = SizeConstraint::AtMost(screen_size.y / 3); - let y_view = SizeConstraint::Full; //AtLeast(2 * screen_size.y / 3); + ) -> NamedView<Self> { let view = LinearLayout::horizontal() .child( // TODO decide whats better, horizontal sizing on the outside, // or keeping both sizings on the 4 internal views - LinearLayout::vertical() - .child(q_list.resized(x, y_list)) - .child(q_view.resized(x, y_view)) - .with_name("question-pane"), // TODO constants + LinearLayout::vertical().child(q_list).child(q_view), ) - .child( - LinearLayout::vertical() - .child(a_list.resized(x, y_list)) - .child(a_view.resized(x, y_view)) - .with_name("answer-pane"), - ); + .child(LinearLayout::vertical().child(a_list).child(a_view)); let view = PaddedView::new(Margins::lrtb(lr_margin, lr_margin, 0, 0), view); - FullLayoutT { view, lr_margin } + (FullLayoutT { + view, + invalidated: true, + }) + .with_name(NAME_FULL_LAYOUT) + } + + // public for now TODO remove + pub fn resize(&mut self, size: Vec2) { + let FullLayoutSizing { + width, + list_height, + view_height, + } = self.get_constraints(size); + self.view + .call_on_name(NAME_QUESTION_LIST, |v: &mut ListView| { + v.resize(width, list_height) + }) + .expect("TODO"); + self.view + .call_on_name(NAME_ANSWER_LIST, |v: &mut ListView| { + v.resize(width, list_height) + }) + .expect("TODO"); + self.view + .call_on_name(NAME_QUESTION_VIEW, |v: &mut MdView| { + v.resize(width, view_height) + }) + .expect("TODO"); + self.view + .call_on_name(NAME_ANSWER_VIEW, |v: &mut MdView| { + v.resize(width, view_height) + }) + .expect("TODO"); + //.and_then(View::downcast_mut) + //.map(View::downcast_mut) + //.map(|v: &mut LinearLayout| { + //println!("downcast successful!"); + //v.get_child_mut(0).and_then(View::downcast_mut).map( + //|v: &mut ResizedView<NamedView<ListView>>| { + //println!("LIST CONSTRAINTS SET"); + //v.set_constraints(width, list_height); + //}, + //); + //v.get_child_mut(1).and_then(View::downcast_mut).map( + //|v: &mut ResizedView<NamedView<ListView>>| { + //println!("VIEW CONSTRAINTS SET"); + //v.set_constraints(width, list_height); + //}, + //) + //}); + } + + fn get_constraints(&self, screen_size: Vec2) -> FullLayoutSizing { + let heuristic = 1; + let width = SizeConstraint::Fixed(screen_size.x / 2 - heuristic); + let list_height = SizeConstraint::AtMost(screen_size.y / 3); + let view_height = SizeConstraint::Full; //AtLeast(2 * screen_size.y / 3); + println!( + "list constraints: {} x {}", + screen_size.x / 2 - heuristic, + screen_size.y / 3 + ); + FullLayoutSizing { + width, + list_height, + view_height, + } } } |