<commit_before>use Printer;
use With;
use XY;
use align::*;
use direction::Direction;
use event::*;

use unicode_width::UnicodeWidthStr;

use utils::{LinesIterator, Row};
use vec::Vec2;
use view::{SizeCache, View, ScrollBase, ScrollStrategy};

/// A simple view showing a fixed text
pub struct TextView {
    content: String,
    rows: Vec<Row>,

    align: Align,

    // If `false`, disable scrolling.
    scrollable: bool,

    // ScrollBase make many scrolling-related things easier
    scrollbase: ScrollBase,
    scroll_strategy: ScrollStrategy,
    last_size: Option<XY<SizeCache>>,
    width: Option<usize>,
}

// If the last character is a newline, strip it.
fn strip_last_newline(content: &mut String) {
    if content.ends_with('\n') {
        content.pop().unwrap();
    }
}

impl TextView {
    /// Creates a new TextView with the given content.
    pub fn new<S: Into<String>>(content: S) -> Self {
        let mut content = content.into();
        strip_last_newline(&mut content);
        TextView {
            content: content,
            rows: Vec::new(),
            scrollable: true,
            scrollbase: ScrollBase::new(),
            scroll_strategy: ScrollStrategy::KeepRow,
            align: Align::top_left(),
            last_size: None,
            width: None,
        }
    }

    /// Enable or disable the view's scrolling capabilities.
    ///
    /// When disabled, the view will never attempt to scroll
    /// (and will always ask for the full height).
    pub fn set_scrollable(&mut self, scrollable: bool) {
        self.scrollable = scrollable;
    }

    /// Enable or disable the view's scrolling capabilities.
    ///
    /// When disabled, the view will never attempt to scroll
    /// (and will always ask for the full height).
    ///
    /// Chainable variant.
    pub fn scrollable(self, scrollable: bool) -> Self {
        self.with(|s| s.set_scrollable(scrollable))
    }

    /// Sets the horizontal alignment for this view.
    pub fn h_align(mut self, h: HAlign) -> Self {
        self.align.h = h;

        self
    }

    /// Sets the vertical alignment for this view.
    pub fn v_align(mut self, v: VAlign) -> Self {
        self.align.v = v;

        self
    }

    /// Sets the alignment for this view.
    pub fn align(mut self, a: Align) -> Self {
        self.align = a;

        self
    }

    /// Center the text horizontally and vertically inside the view.
    pub fn center(mut self) -> Self {
        self.align = Align::center();
        self
    }

    /// Replace the text in this view.
    pub fn set_content<S: Into<String>>(&mut self, content: S) {
        let mut content = content.into();
        strip_last_newline(&mut content);
        self.content = content;
        self.invalidate();
    }

    /// Returns the current text in this view.
    pub fn get_content(&self) -> &str {
        &self.content
    }

    fn is_cache_valid(&self, size: Vec2) -> bool {
        match self.last_size {
            None => false,
            Some(ref last) => last.x.accept(size.x) && last.y.accept(size.y),
        }
    }

    /// Defines the way scrolling is adjusted on content or size change.
    ///
    /// The scroll strategy defines how the scrolling position is adjusted
    /// when the size of the view or the content change.
    ///
    /// It is reset to `ScrollStrategy::KeepRow` whenever the user scrolls
    /// manually.
    pub fn set_scroll_strategy(&mut self, strategy: ScrollStrategy) {
        self.scroll_strategy = strategy;
        self.adjust_scroll();
    }

    /// Defines the way scrolling is adjusted on content or size change.
    ///
    /// Chainable variant.
    pub fn scroll_strategy(self, strategy: ScrollStrategy) -> Self {
        self.with(|s| s.set_scroll_strategy(strategy))
    }

    fn adjust_scroll(&mut self) {
        match self.scroll_strategy {
            ScrollStrategy::StickToTop => self.scrollbase.scroll_top(),
            ScrollStrategy::StickToBottom => self.scrollbase.scroll_bottom(),
            ScrollStrategy::KeepRow => (),
        };
    }

    fn compute_rows(&mut self, size: Vec2) {
        if !self.is_cache_valid(size) {
            self.last_size = None;
            // Recompute

            if size.x == 0 {
                // Nothing we can do at this poing.
                return;
            }

            self.rows = LinesIterator::new(&self.content, size.x).collect();
            let mut scrollbar = 0;
            if self.scrollable && self.rows.len() > size.y {
                scrollbar = 2;
                if size.x < scrollbar {
                    // Again, this is a lost cause.
                    return;
                }

                // If we're too high, include a scrollbar
                self.rows = LinesIterator::new(&self.content,
                                               size.x - scrollbar)
                    .collect();
                if self.rows.is_empty() && !self.content.is_empty() {
                    return;
                }
            }

            // Desired width, including the scrollbar.
            self.width = self.rows
                .iter()
                .map(|row| row.width)
                .max()
                .map(|w| w + scrollbar);

            // Our resulting size.
            // We can't go lower, width-wise.

            let mut my_size = Vec2::new(self.width.unwrap_or(0),
                                        self.rows.len());

            if self.scrollable && my_size.y > size.y {
                my_size.y = size.y;
            }

            // println_stderr!("my: {:?} | si: {:?}", my_size, size);
            self.last_size = Some(SizeCache::build(my_size, size));
            self.scrollbase.set_heights(size.y, self.rows.len());
            self.adjust_scroll();
        }
    }

    // Invalidates the cache, so next call will recompute everything.
    fn invalidate(&mut self) {
        self.last_size = None;
    }
}

impl View for TextView {
    fn draw(&self, printer: &Printer) {

        let h = self.rows.len();
        let offset = self.align.v.get_offset(h, printer.size.y);
        let printer =
            &printer.sub_printer(Vec2::new(0, offset), printer.size, true);

        self.scrollbase.draw(printer, |printer, i| {
            let row = &self.rows[i];
            let text = &self.content[row.start..row.end];
            let l = text.width();
            let x = self.align.h.get_offset(l, printer.size.x);
            printer.print((x, 0), text);
        });
    }

    fn on_event(&mut self, event: Event) -> EventResult {
        if !self.scrollbase.scrollable() {
            return EventResult::Ignored;
        }

        match event {
            Event::Key(Key::Home) => self.scrollbase.scroll_top(),
            Event::Key(Key::End) => self.scrollbase.scroll_bottom(),
            Event::Key(Key::Up) if self.scrollbase.can_scroll_up() => {
                self.scrollbase.scroll_up(1)
            }
            Event::Key(Key::Down) if self.scrollbase
                .can_scroll_down() => self.scrollbase.scroll_down(1),
            Event::Key(Key::PageDown) => self.scrollbase.scroll_down(10),
            Event::Key(Key::PageUp) => self.scrollbase.scroll_up(10),
            _ => return EventResult::Ignored,
        }

        // We just scrolled manually, so reset the scroll strategy.
        self.scroll_strategy = ScrollStrategy::KeepRow;
        EventResult::Consumed(None)
    }

    fn needs_relayout(&self) -> bool {
        self.last_size.is_none()
    }

    fn get_min_size(&mut self, size: Vec2) -> Vec2 {
        self.compute_rows(size);

        // This is what we'd like
        let mut ideal = Vec2::new(self.width.unwrap_or(0), self.rows.len());

        if self.scrollable && ideal.y > size.y {
            ideal.y = size.y;
        }

        ideal
    }

    fn take_focus(&mut self, _: Direction) -> bool {
        self.scrollbase.scrollable()
    }

    fn layout(&mut self, size: Vec2) {
        // Compute the text rows.
        self.compute_rows(size);
        self.scrollbase.set_heights(size.y, self.rows.len());
    }
}
<commit_msg>Add comments<commit_after>use Printer;
use With;
use XY;
use align::*;
use direction::Direction;
use event::*;

use unicode_width::UnicodeWidthStr;

use utils::{LinesIterator, Row};
use vec::Vec2;
use view::{SizeCache, View, ScrollBase, ScrollStrategy};

/// A simple view showing a fixed text
pub struct TextView {
    content: String,
    rows: Vec<Row>,

    align: Align,

    // If `false`, disable scrolling.
    scrollable: bool,

    // ScrollBase make many scrolling-related things easier
    scrollbase: ScrollBase,
    scroll_strategy: ScrollStrategy,
    last_size: Option<XY<SizeCache>>,
    width: Option<usize>,
}

// If the last character is a newline, strip it.
fn strip_last_newline(content: &mut String) {
    if content.ends_with('\n') {
        content.pop().unwrap();
    }
}

impl TextView {
    /// Creates a new TextView with the given content.
    pub fn new<S: Into<String>>(content: S) -> Self {
        let mut content = content.into();
        strip_last_newline(&mut content);
        TextView {
            content: content,
            rows: Vec::new(),
            scrollable: true,
            scrollbase: ScrollBase::new(),
            scroll_strategy: ScrollStrategy::KeepRow,
            align: Align::top_left(),
            last_size: None,
            width: None,
        }
    }

    /// Enable or disable the view's scrolling capabilities.
    ///
    /// When disabled, the view will never attempt to scroll
    /// (and will always ask for the full height).
    pub fn set_scrollable(&mut self, scrollable: bool) {
        self.scrollable = scrollable;
    }

    /// Enable or disable the view's scrolling capabilities.
    ///
    /// When disabled, the view will never attempt to scroll
    /// (and will always ask for the full height).
    ///
    /// Chainable variant.
    pub fn scrollable(self, scrollable: bool) -> Self {
        self.with(|s| s.set_scrollable(scrollable))
    }

    /// Sets the horizontal alignment for this view.
    pub fn h_align(mut self, h: HAlign) -> Self {
        self.align.h = h;

        self
    }

    /// Sets the vertical alignment for this view.
    pub fn v_align(mut self, v: VAlign) -> Self {
        self.align.v = v;

        self
    }

    /// Sets the alignment for this view.
    pub fn align(mut self, a: Align) -> Self {
        self.align = a;

        self
    }

    /// Center the text horizontally and vertically inside the view.
    pub fn center(mut self) -> Self {
        self.align = Align::center();
        self
    }

    /// Replace the text in this view.
    pub fn set_content<S: Into<String>>(&mut self, content: S) {
        let mut content = content.into();
        strip_last_newline(&mut content);
        self.content = content;
        self.invalidate();
    }

    /// Returns the current text in this view.
    pub fn get_content(&self) -> &str {
        &self.content
    }

    fn is_cache_valid(&self, size: Vec2) -> bool {
        match self.last_size {
            None => false,
            Some(ref last) => last.x.accept(size.x) && last.y.accept(size.y),
        }
    }

    /// Defines the way scrolling is adjusted on content or size change.
    ///
    /// The scroll strategy defines how the scrolling position is adjusted
    /// when the size of the view or the content change.
    ///
    /// It is reset to `ScrollStrategy::KeepRow` whenever the user scrolls
    /// manually.
    pub fn set_scroll_strategy(&mut self, strategy: ScrollStrategy) {
        self.scroll_strategy = strategy;
        self.adjust_scroll();
    }

    /// Defines the way scrolling is adjusted on content or size change.
    ///
    /// Chainable variant.
    pub fn scroll_strategy(self, strategy: ScrollStrategy) -> Self {
        self.with(|s| s.set_scroll_strategy(strategy))
    }

    // Apply the scrolling strategy to the current scroll position.
    //
    // Called when computing rows and when applying a new strategy.
    fn adjust_scroll(&mut self) {
        match self.scroll_strategy {
            ScrollStrategy::StickToTop => self.scrollbase.scroll_top(),
            ScrollStrategy::StickToBottom => self.scrollbase.scroll_bottom(),
            ScrollStrategy::KeepRow => (),
        };
    }

    fn compute_rows(&mut self, size: Vec2) {
        if self.is_cache_valid(size) {
            return;
        }

        // Completely bust the cache
        // Just in case we fail, we don't want to leave a bad cache.
        self.last_size = None;

        if size.x == 0 {
            // Nothing we can do at this point.
            return;
        }

        // First attempt: naively hope that we won't need a scrollbar_width
        // (This means we try to use the entire available width for text).
        self.rows = LinesIterator::new(&self.content, size.x).collect();

        // Width taken by the scrollbar. Without a scrollbar, it's 0.
        let mut scrollbar_width = 0;

        if self.scrollable && self.rows.len() > size.y {
            // We take 1 column for the bar itself + 1 spacing column
            scrollbar_width = 2;

            if size.x < scrollbar_width {
                // Again, this is a lost cause.
                return;
            }

            // If we're too high, include a scrollbar_width
            let available = size.x - scrollbar_width;
            self.rows = LinesIterator::new(&self.content, available).collect();

            if self.rows.is_empty() && !self.content.is_empty() {
                // We have some content, we we didn't find any row for it?
                // This probably means we couldn't even make a single row
                // (for instance we only have 1 column and we have a wide character).
                return;
            }
        }

        // Desired width, including the scrollbar_width.
        self.width = self.rows
            .iter()
            .map(|row| row.width)
            .max()
            .map(|w| w + scrollbar_width);

        // The entire "virtual" size (includes all rows)
        let mut my_size = Vec2::new(self.width.unwrap_or(0), self.rows.len());

        // If we're scrolling, cap the the available size.
        if self.scrollable && my_size.y > size.y {
            my_size.y = size.y;
        }

        // Build a fresh cache.
        self.last_size = Some(SizeCache::build(my_size, size));

        // Adjust scrolling, in case we're sticking to the bottom for instance.
        self.scrollbase.set_heights(size.y, self.rows.len());
        self.adjust_scroll();
    }

    // Invalidates the cache, so next call will recompute everything.
    fn invalidate(&mut self) {
        self.last_size = None;
    }
}

impl View for TextView {
    fn draw(&self, printer: &Printer) {

        let h = self.rows.len();
        let offset = self.align.v.get_offset(h, printer.size.y);
        let printer =
            &printer.sub_printer(Vec2::new(0, offset), printer.size, true);

        self.scrollbase.draw(printer, |printer, i| {
            let row = &self.rows[i];
            let text = &self.content[row.start..row.end];
            let l = text.width();
            let x = self.align.h.get_offset(l, printer.size.x);
            printer.print((x, 0), text);
        });
    }

    fn on_event(&mut self, event: Event) -> EventResult {
        if !self.scrollbase.scrollable() {
            return EventResult::Ignored;
        }

        match event {
            Event::Key(Key::Home) => self.scrollbase.scroll_top(),
            Event::Key(Key::End) => self.scrollbase.scroll_bottom(),
            Event::Key(Key::Up) if self.scrollbase.can_scroll_up() => {
                self.scrollbase.scroll_up(1)
            }
            Event::Key(Key::Down) if self.scrollbase
                .can_scroll_down() => self.scrollbase.scroll_down(1),
            Event::Key(Key::PageDown) => self.scrollbase.scroll_down(10),
            Event::Key(Key::PageUp) => self.scrollbase.scroll_up(10),
            _ => return EventResult::Ignored,
        }

        // We just scrolled manually, so reset the scroll strategy.
        self.scroll_strategy = ScrollStrategy::KeepRow;
        EventResult::Consumed(None)
    }

    fn needs_relayout(&self) -> bool {
        self.last_size.is_none()
    }

    fn get_min_size(&mut self, size: Vec2) -> Vec2 {
        self.compute_rows(size);

        // This is what we'd like
        let mut ideal = Vec2::new(self.width.unwrap_or(0), self.rows.len());

        if self.scrollable && ideal.y > size.y {
            ideal.y = size.y;
        }

        ideal
    }

    fn take_focus(&mut self, _: Direction) -> bool {
        self.scrollbase.scrollable()
    }

    fn layout(&mut self, size: Vec2) {
        // Compute the text rows.
        self.compute_rows(size);
        self.scrollbase.set_heights(size.y, self.rows.len());
    }
}
<|endoftext|>


<commit_before>use std::ops::Deref;
use std::sync::Arc;
use std::sync::{Mutex, MutexGuard};

use owning_ref::{ArcRef, OwningHandle};
use unicode_width::UnicodeWidthStr;

use crate::align::*;
use crate::theme::Effect;
use crate::utils::lines::spans::{LinesIterator, Row};
use crate::utils::markup::StyledString;
use crate::view::{SizeCache, View};
use crate::{Printer, Vec2, With, XY};

/// Provides access to the content of a [`TextView`].
///
/// Cloning this object will still point to the same content.
///
/// [`TextView`]: struct.TextView.html
///
/// # Examples
///
/// ```rust
/// # use cursive::views::{TextView, TextContent};
/// let mut content = TextContent::new("content");
/// let view = TextView::new_with_content(content.clone());
///
/// // Later, possibly in a different thread
/// content.set_content("new content");
/// assert!(content.get_content().source().contains("new"));
/// ```
#[derive(Clone)]
pub struct TextContent {
    content: Arc<Mutex<TextContentInner>>,
}

impl TextContent {
    /// Creates a new text content around the given value.
    ///
    /// Parses the given value.
    pub fn new<S>(content: S) -> Self
    where
        S: Into<StyledString>,
    {
        let content = content.into();

        TextContent {
            content: Arc::new(Mutex::new(TextContentInner {
                content,
                size_cache: None,
            })),
        }
    }
}

/// A reference to the text content.
///
/// This can be deref'ed into a [`StyledString`].
///
/// [`StyledString`]: ../utils/markup/type.StyledString.html
///
/// This keeps the content locked. Do not store this!
pub struct TextContentRef {
    handle: OwningHandle<
        ArcRef<Mutex<TextContentInner>>,
        MutexGuard<'static, TextContentInner>,
    >,
}

impl Deref for TextContentRef {
    type Target = StyledString;

    fn deref(&self) -> &StyledString {
        &self.handle.content
    }
}

impl TextContent {
    /// Replaces the content with the given value.
    pub fn set_content<S>(&mut self, content: S)
    where
        S: Into<StyledString>,
    {
        self.with_content(|c| *c = content.into());
    }

    /// Append `content` to the end of a `TextView`.
    pub fn append<S>(&mut self, content: S)
    where
        S: Into<StyledString>,
    {
        self.with_content(|c| c.append(content))
    }

    /// Returns a reference to the content.
    ///
    /// This locks the data while the returned value is alive,
    /// so don't keep it too long.
    pub fn get_content(&self) -> TextContentRef {
        TextContentInner::get_content(&self.content)
    }

    fn with_content<F, O>(&mut self, f: F) -> O
    where
        F: FnOnce(&mut StyledString) -> O,
    {
        let mut lock = self.content.lock().unwrap();

        let out = f(&mut lock.content);

        lock.size_cache = None;

        out
    }
}

/// Internel representation of the content for a `TextView`.
///
/// This is mostly just a `StyledString`.
///
/// Can be shared (through a `Arc<Mutex>`).
struct TextContentInner {
    // content: String,
    content: StyledString,

    // We keep the cache here so it can be busted when we change the content.
    size_cache: Option<XY<SizeCache>>,
}

impl TextContentInner {
    /// From a shareable content (Arc + Mutex), return a
    fn get_content(content: &Arc<Mutex<TextContentInner>>) -> TextContentRef {
        let arc_ref: ArcRef<Mutex<TextContentInner>> =
            ArcRef::new(Arc::clone(content));

        TextContentRef {
            handle: OwningHandle::new_with_fn(arc_ref, |mutex| unsafe {
                (*mutex).lock().unwrap()
            }),
        }
    }

    fn is_cache_valid(&self, size: Vec2) -> bool {
        match self.size_cache {
            None => false,
            Some(ref last) => last.x.accept(size.x) && last.y.accept(size.y),
        }
    }
}

/// A simple view showing a fixed text.
///
/// # Examples
///
/// ```rust
/// # use cursive::Cursive;
/// # use cursive::views::TextView;
/// let mut siv = Cursive::dummy();
///
/// siv.add_layer(TextView::new("Hello world!"));
/// ```
pub struct TextView {
    // content: String,
    content: Arc<Mutex<TextContentInner>>,
    rows: Vec<Row>,

    align: Align,
    effect: Effect,

    // True if we can wrap long lines.
    wrap: bool,

    // ScrollBase make many scrolling-related things easier
    last_size: Vec2,
    width: Option<usize>,
}

impl TextView {
    /// Creates a new TextView with the given content.
    pub fn new<S>(content: S) -> Self
    where
        S: Into<StyledString>,
    {
        Self::new_with_content(TextContent::new(content))
    }

    /// Creates a new TextView using the given `Arc<Mutex<String>>`.
    ///
    /// If you kept a clone of the given content, you'll be able to update it
    /// remotely.
    ///
    /// # Examples
    ///
    /// ```rust
    /// # use cursive::views::{TextView, TextContent};
    /// let mut content = TextContent::new("content");
    /// let view = TextView::new_with_content(content.clone());
    ///
    /// // Later, possibly in a different thread
    /// content.set_content("new content");
    /// assert!(content.get_content().source().contains("new"));
    /// ```
    pub fn new_with_content(content: TextContent) -> Self {
        TextView {
            content: content.content,
            effect: Effect::Simple,
            rows: Vec::new(),
            wrap: true,
            align: Align::top_left(),
            last_size: Vec2::zero(),
            width: None,
        }
    }

    /// Creates a new empty `TextView`.
    pub fn empty() -> Self {
        TextView::new("")
    }

    /// Sets the effect for the entire content.
    pub fn set_effect(&mut self, effect: Effect) {
        self.effect = effect;
    }

    /// Sets the effect for the entire content.
    ///
    /// Chainable variant.
    pub fn effect(self, effect: Effect) -> Self {
        self.with(|s| s.set_effect(effect))
    }

    /// Disables content wrap for this view.
    ///
    /// This may be useful if you want horizontal scrolling.
    pub fn no_wrap(self) -> Self {
        self.with(|s| s.set_content_wrap(false))
    }

    /// Controls content wrap for this view.
    ///
    /// If `true` (the default), text will wrap long lines when needed.
    pub fn set_content_wrap(&mut self, wrap: bool) {
        self.wrap = wrap;
    }

    /// Sets the horizontal alignment for this view.
    pub fn h_align(mut self, h: HAlign) -> Self {
        self.align.h = h;

        self
    }

    /// Sets the vertical alignment for this view.
    pub fn v_align(mut self, v: VAlign) -> Self {
        self.align.v = v;

        self
    }

    /// Sets the alignment for this view.
    pub fn align(mut self, a: Align) -> Self {
        self.align = a;

        self
    }

    /// Center the text horizontally and vertically inside the view.
    pub fn center(mut self) -> Self {
        self.align = Align::center();
        self
    }

    /// Replace the text in this view.
    ///
    /// Chainable variant.
    pub fn content<S>(self, content: S) -> Self
    where
        S: Into<StyledString>,
    {
        self.with(|s| s.set_content(content))
    }

    /// Replace the text in this view.
    pub fn set_content<S>(&mut self, content: S)
    where
        S: Into<StyledString>,
    {
        self.content.lock().unwrap().content = content.into();
        self.invalidate();
    }

    /// Append `content` to the end of a `TextView`.
    pub fn append<S>(&mut self, content: S)
    where
        S: Into<StyledString>,
    {
        self.content.lock().unwrap().content.append(content.into());
        self.invalidate();
    }

    /// Returns the current text in this view.
    pub fn get_content(&self) -> TextContentRef {
        TextContentInner::get_content(&self.content)
    }

    /// Returns a shared reference to the content, allowing content mutation.
    pub fn get_shared_content(&mut self) -> TextContent {
        // We take &mut here without really needing it,
        // because it sort of "makes sense".

        TextContent {
            content: Arc::clone(&self.content),
        }
    }

    // This must be non-destructive, as it may be called
    // multiple times during layout.
    fn compute_rows(&mut self, size: Vec2) {
        let size = if self.wrap { size } else { Vec2::max_value() };

        let mut content = self.content.lock().unwrap();
        if content.is_cache_valid(size) {
            return;
        }

        // Completely bust the cache
        // Just in case we fail, we don't want to leave a bad cache.
        content.size_cache = None;

        if size.x == 0 {
            // Nothing we can do at this point.
            return;
        }

        self.rows = LinesIterator::new(&content.content, size.x).collect();

        // Desired width
        self.width = self.rows.iter().map(|row| row.width).max();
    }

    // Invalidates the cache, so next call will recompute everything.
    fn invalidate(&mut self) {
        let mut content = self.content.lock().unwrap();
        content.size_cache = None;
    }
}

impl View for TextView {
    fn draw(&self, printer: &Printer<'_, '_>) {
        let h = self.rows.len();
        // If the content is smaller than the view, align it somewhere.
        let offset = self.align.v.get_offset(h, printer.size.y);
        let printer = &printer.offset((0, offset));

        let content = self.content.lock().unwrap();

        printer.with_effect(self.effect, |printer| {
            for (y, row) in self.rows.iter().enumerate() {
                let l = row.width;
                let mut x = self.align.h.get_offset(l, printer.size.x);

                for span in row.resolve(&content.content) {
                    printer.with_style(*span.attr, |printer| {
                        printer.print((x, y), span.content);
                        x += span.content.width();
                    });
                }
            }
        });
    }

    fn needs_relayout(&self) -> bool {
        let content = self.content.lock().unwrap();
        content.size_cache.is_none()
    }

    fn required_size(&mut self, size: Vec2) -> Vec2 {
        self.compute_rows(size);

        Vec2::new(self.width.unwrap_or(0), self.rows.len())
    }

    fn layout(&mut self, size: Vec2) {
        // Compute the text rows.
        self.last_size = size;
        self.compute_rows(size);

        // The entire "virtual" size (includes all rows)
        let my_size = Vec2::new(self.width.unwrap_or(0), self.rows.len());

        // Build a fresh cache.
        let mut content = self.content.lock().unwrap();
        content.size_cache = Some(SizeCache::build(my_size, size));
    }
}
<commit_msg>Fix a typo in text-view.rs (`content` -> `view`)<commit_after>use std::ops::Deref;
use std::sync::Arc;
use std::sync::{Mutex, MutexGuard};

use owning_ref::{ArcRef, OwningHandle};
use unicode_width::UnicodeWidthStr;

use crate::align::*;
use crate::theme::Effect;
use crate::utils::lines::spans::{LinesIterator, Row};
use crate::utils::markup::StyledString;
use crate::view::{SizeCache, View};
use crate::{Printer, Vec2, With, XY};

/// Provides access to the content of a [`TextView`].
///
/// Cloning this object will still point to the same content.
///
/// [`TextView`]: struct.TextView.html
///
/// # Examples
///
/// ```rust
/// # use cursive::views::{TextView, TextContent};
/// let mut content = TextContent::new("content");
/// let view = TextView::new_with_content(content.clone());
///
/// // Later, possibly in a different thread
/// content.set_content("new content");
/// assert!(view.get_content().source().contains("new"));
/// ```
#[derive(Clone)]
pub struct TextContent {
    content: Arc<Mutex<TextContentInner>>,
}

impl TextContent {
    /// Creates a new text content around the given value.
    ///
    /// Parses the given value.
    pub fn new<S>(content: S) -> Self
    where
        S: Into<StyledString>,
    {
        let content = content.into();

        TextContent {
            content: Arc::new(Mutex::new(TextContentInner {
                content,
                size_cache: None,
            })),
        }
    }
}

/// A reference to the text content.
///
/// This can be deref'ed into a [`StyledString`].
///
/// [`StyledString`]: ../utils/markup/type.StyledString.html
///
/// This keeps the content locked. Do not store this!
pub struct TextContentRef {
    handle: OwningHandle<
        ArcRef<Mutex<TextContentInner>>,
        MutexGuard<'static, TextContentInner>,
    >,
}

impl Deref for TextContentRef {
    type Target = StyledString;

    fn deref(&self) -> &StyledString {
        &self.handle.content
    }
}

impl TextContent {
    /// Replaces the content with the given value.
    pub fn set_content<S>(&mut self, content: S)
    where
        S: Into<StyledString>,
    {
        self.with_content(|c| *c = content.into());
    }

    /// Append `content` to the end of a `TextView`.
    pub fn append<S>(&mut self, content: S)
    where
        S: Into<StyledString>,
    {
        self.with_content(|c| c.append(content))
    }

    /// Returns a reference to the content.
    ///
    /// This locks the data while the returned value is alive,
    /// so don't keep it too long.
    pub fn get_content(&self) -> TextContentRef {
        TextContentInner::get_content(&self.content)
    }

    fn with_content<F, O>(&mut self, f: F) -> O
    where
        F: FnOnce(&mut StyledString) -> O,
    {
        let mut lock = self.content.lock().unwrap();

        let out = f(&mut lock.content);

        lock.size_cache = None;

        out
    }
}

/// Internel representation of the content for a `TextView`.
///
/// This is mostly just a `StyledString`.
///
/// Can be shared (through a `Arc<Mutex>`).
struct TextContentInner {
    // content: String,
    content: StyledString,

    // We keep the cache here so it can be busted when we change the content.
    size_cache: Option<XY<SizeCache>>,
}

impl TextContentInner {
    /// From a shareable content (Arc + Mutex), return a
    fn get_content(content: &Arc<Mutex<TextContentInner>>) -> TextContentRef {
        let arc_ref: ArcRef<Mutex<TextContentInner>> =
            ArcRef::new(Arc::clone(content));

        TextContentRef {
            handle: OwningHandle::new_with_fn(arc_ref, |mutex| unsafe {
                (*mutex).lock().unwrap()
            }),
        }
    }

    fn is_cache_valid(&self, size: Vec2) -> bool {
        match self.size_cache {
            None => false,
            Some(ref last) => last.x.accept(size.x) && last.y.accept(size.y),
        }
    }
}

/// A simple view showing a fixed text.
///
/// # Examples
///
/// ```rust
/// # use cursive::Cursive;
/// # use cursive::views::TextView;
/// let mut siv = Cursive::dummy();
///
/// siv.add_layer(TextView::new("Hello world!"));
/// ```
pub struct TextView {
    // content: String,
    content: Arc<Mutex<TextContentInner>>,
    rows: Vec<Row>,

    align: Align,
    effect: Effect,

    // True if we can wrap long lines.
    wrap: bool,

    // ScrollBase make many scrolling-related things easier
    last_size: Vec2,
    width: Option<usize>,
}

impl TextView {
    /// Creates a new TextView with the given content.
    pub fn new<S>(content: S) -> Self
    where
        S: Into<StyledString>,
    {
        Self::new_with_content(TextContent::new(content))
    }

    /// Creates a new TextView using the given `Arc<Mutex<String>>`.
    ///
    /// If you kept a clone of the given content, you'll be able to update it
    /// remotely.
    ///
    /// # Examples
    ///
    /// ```rust
    /// # use cursive::views::{TextView, TextContent};
    /// let mut content = TextContent::new("content");
    /// let view = TextView::new_with_content(content.clone());
    ///
    /// // Later, possibly in a different thread
    /// content.set_content("new content");
    /// assert!(view.get_content().source().contains("new"));
    /// ```
    pub fn new_with_content(content: TextContent) -> Self {
        TextView {
            content: content.content,
            effect: Effect::Simple,
            rows: Vec::new(),
            wrap: true,
            align: Align::top_left(),
            last_size: Vec2::zero(),
            width: None,
        }
    }

    /// Creates a new empty `TextView`.
    pub fn empty() -> Self {
        TextView::new("")
    }

    /// Sets the effect for the entire content.
    pub fn set_effect(&mut self, effect: Effect) {
        self.effect = effect;
    }

    /// Sets the effect for the entire content.
    ///
    /// Chainable variant.
    pub fn effect(self, effect: Effect) -> Self {
        self.with(|s| s.set_effect(effect))
    }

    /// Disables content wrap for this view.
    ///
    /// This may be useful if you want horizontal scrolling.
    pub fn no_wrap(self) -> Self {
        self.with(|s| s.set_content_wrap(false))
    }

    /// Controls content wrap for this view.
    ///
    /// If `true` (the default), text will wrap long lines when needed.
    pub fn set_content_wrap(&mut self, wrap: bool) {
        self.wrap = wrap;
    }

    /// Sets the horizontal alignment for this view.
    pub fn h_align(mut self, h: HAlign) -> Self {
        self.align.h = h;

        self
    }

    /// Sets the vertical alignment for this view.
    pub fn v_align(mut self, v: VAlign) -> Self {
        self.align.v = v;

        self
    }

    /// Sets the alignment for this view.
    pub fn align(mut self, a: Align) -> Self {
        self.align = a;

        self
    }

    /// Center the text horizontally and vertically inside the view.
    pub fn center(mut self) -> Self {
        self.align = Align::center();
        self
    }

    /// Replace the text in this view.
    ///
    /// Chainable variant.
    pub fn content<S>(self, content: S) -> Self
    where
        S: Into<StyledString>,
    {
        self.with(|s| s.set_content(content))
    }

    /// Replace the text in this view.
    pub fn set_content<S>(&mut self, content: S)
    where
        S: Into<StyledString>,
    {
        self.content.lock().unwrap().content = content.into();
        self.invalidate();
    }

    /// Append `content` to the end of a `TextView`.
    pub fn append<S>(&mut self, content: S)
    where
        S: Into<StyledString>,
    {
        self.content.lock().unwrap().content.append(content.into());
        self.invalidate();
    }

    /// Returns the current text in this view.
    pub fn get_content(&self) -> TextContentRef {
        TextContentInner::get_content(&self.content)
    }

    /// Returns a shared reference to the content, allowing content mutation.
    pub fn get_shared_content(&mut self) -> TextContent {
        // We take &mut here without really needing it,
        // because it sort of "makes sense".

        TextContent {
            content: Arc::clone(&self.content),
        }
    }

    // This must be non-destructive, as it may be called
    // multiple times during layout.
    fn compute_rows(&mut self, size: Vec2) {
        let size = if self.wrap { size } else { Vec2::max_value() };

        let mut content = self.content.lock().unwrap();
        if content.is_cache_valid(size) {
            return;
        }

        // Completely bust the cache
        // Just in case we fail, we don't want to leave a bad cache.
        content.size_cache = None;

        if size.x == 0 {
            // Nothing we can do at this point.
            return;
        }

        self.rows = LinesIterator::new(&content.content, size.x).collect();

        // Desired width
        self.width = self.rows.iter().map(|row| row.width).max();
    }

    // Invalidates the cache, so next call will recompute everything.
    fn invalidate(&mut self) {
        let mut content = self.content.lock().unwrap();
        content.size_cache = None;
    }
}

impl View for TextView {
    fn draw(&self, printer: &Printer<'_, '_>) {
        let h = self.rows.len();
        // If the content is smaller than the view, align it somewhere.
        let offset = self.align.v.get_offset(h, printer.size.y);
        let printer = &printer.offset((0, offset));

        let content = self.content.lock().unwrap();

        printer.with_effect(self.effect, |printer| {
            for (y, row) in self.rows.iter().enumerate() {
                let l = row.width;
                let mut x = self.align.h.get_offset(l, printer.size.x);

                for span in row.resolve(&content.content) {
                    printer.with_style(*span.attr, |printer| {
                        printer.print((x, y), span.content);
                        x += span.content.width();
                    });
                }
            }
        });
    }

    fn needs_relayout(&self) -> bool {
        let content = self.content.lock().unwrap();
        content.size_cache.is_none()
    }

    fn required_size(&mut self, size: Vec2) -> Vec2 {
        self.compute_rows(size);

        Vec2::new(self.width.unwrap_or(0), self.rows.len())
    }

    fn layout(&mut self, size: Vec2) {
        // Compute the text rows.
        self.last_size = size;
        self.compute_rows(size);

        // The entire "virtual" size (includes all rows)
        let my_size = Vec2::new(self.width.unwrap_or(0), self.rows.len());

        // Build a fresh cache.
        let mut content = self.content.lock().unwrap();
        content.size_cache = Some(SizeCache::build(my_size, size));
    }
}
<|endoftext|>


<commit_before>use stm32f0x2::{TIM2, TIM3, GPIOA, GPIOB, GPIOC, RCC};

use cortex_m;

static mut FREQ: u32 = 0;
static mut DUTY: f64 = 0.0;
const FREQUENCY: u32 = 48_000_000;

// PWM channels : Pins available
pub enum Pin {
    PA0,
    PB3,
    PB4,
    PB5,
    PB10,
    PB11,
    PC6,
    PC7,
    PC8,
    PC9,
}

pub struct Pwm {
    pin: Pin,
}

impl Pwm {
    pub fn init(pin: Pin) -> Pwm {
        cortex_m::interrupt::free(|cs| {
            let rcc = RCC.borrow(cs);
            let tim2 = TIM2.borrow(cs);
            let tim3 = TIM3.borrow(cs);

            let gpioa = GPIOA.borrow(cs);
            let gpiob = GPIOB.borrow(cs);
            let gpioc = GPIOC.borrow(cs);

            // GPIOA, GPIOB and GPIOC Clock Activated
            rcc.ahbenr
                .modify(|_, w| w.iopaen().enabled().iopben().enabled().iopcen().enabled());
            // TIMER Clock Activated
            rcc.apb1enr.modify(|_, w| w.tim2en().enabled());
            rcc.apb1enr.modify(|_, w| w.tim3en().enabled());

            match pin {
                Pin::PA0 => {
                    gpioa.moder.modify(|_, w| w.moder0().alternate());
                    gpioa.afrl.modify(|_, w| w.afrl0().af2());
                    gpioa.otyper.modify(|_, w| w.ot0().push_pull());
                    tim2.ccmr1_output
                        .modify(|_, w| w.oc1m().pwmmode1().oc1pe().enabled());
                    tim2.ccer.modify(|_, w| w.cc1p().clear_bit());
                    tim2.ccer.modify(|_, w| w.cc1e().active());
                }
                Pin::PB3 => {
                    gpiob.moder.modify(|_, w| w.moder3().alternate());
                    gpiob.afrl.modify(|_, w| w.afrl3().af2());
                    gpiob.otyper.modify(|_, w| w.ot3().push_pull());
                    tim2.ccmr1_output
                        .modify(|_, w| w.oc2m().pwmmode1().oc2pe().enabled());
                    tim2.ccer.modify(|_, w| w.cc2p().clear_bit());
                    tim2.ccer.modify(|_, w| w.cc2e().active());
                }
                Pin::PB10 => {
                    gpiob.moder.modify(|_, w| w.moder10().alternate());
                    gpiob.afrh.modify(|_, w| w.afrh10().af2());
                    gpiob.otyper.modify(|_, w| w.ot10().push_pull());
                    tim2.ccmr2_output
                        .modify(|_, w| w.oc3m().pwmmode1().oc3pe().enabled());
                    tim2.ccer.modify(|_, w| w.cc3p().clear_bit());
                    tim2.ccer.modify(|_, w| w.cc3e().active());
                }
                Pin::PB11 => {
                    gpiob.moder.modify(|_, w| w.moder11().alternate());
                    gpiob.afrh.modify(|_, w| w.afrh11().af2());
                    gpiob.otyper.modify(|_, w| w.ot11().push_pull());
                    tim2.ccmr2_output
                        .modify(|_, w| w.oc4m().pwmmode1().oc4pe().enabled());
                    tim2.ccer.modify(|_, w| w.cc4p().clear_bit());
                    tim2.ccer.modify(|_, w| w.cc4e().active());
                }
                Pin::PB4 => {
                    gpiob.moder.modify(|_, w| w.moder4().alternate());
                    gpiob.afrl.modify(|_, w| w.afrl4().af1());
                    gpiob.otyper.modify(|_, w| w.ot4().push_pull());
                    tim3.ccmr1_output
                        .modify(|_, w| w.oc1m().pwmmode1().oc1pe().enabled());
                    tim3.ccer.modify(|_, w| w.cc1p().clear_bit());
                    tim3.ccer.modify(|_, w| w.cc1e().active());
                }
                Pin::PB5 => {
                    gpiob.moder.modify(|_, w| w.moder5().alternate());
                    gpiob.afrl.modify(|_, w| w.afrl5().af1());
                    gpiob.otyper.modify(|_, w| w.ot5().push_pull());
                    tim3.ccmr1_output
                        .modify(|_, w| w.oc2m().pwmmode1().oc2pe().enabled());
                    tim3.ccer.modify(|_, w| w.cc2p().clear_bit());
                    tim3.ccer.modify(|_, w| w.cc2e().active());
                }
                Pin::PC6 => {
                    gpioc.moder.modify(|_, w| w.moder6().alternate());
                    gpioc.afrl.modify(|_, w| w.afrl6().af0());
                    gpioc.otyper.modify(|_, w| w.ot6().push_pull());
                    tim3.ccmr1_output
                        .modify(|_, w| w.oc1m().pwmmode1().oc1pe().enabled());
                    tim3.ccer.modify(|_, w| w.cc1p().clear_bit());
                    tim3.ccer.modify(|_, w| w.cc1e().active());
                }
                Pin::PC7 => {
                    gpioc.moder.modify(|_, w| w.moder7().alternate());
                    gpioc.afrl.modify(|_, w| w.afrl7().af0());
                    gpioc.otyper.modify(|_, w| w.ot7().push_pull());
                    tim3.ccmr1_output
                        .modify(|_, w| w.oc2m().pwmmode1().oc2pe().enabled());
                    tim3.ccer.modify(|_, w| w.cc2p().clear_bit());
                    tim3.ccer.modify(|_, w| w.cc2e().active());
                }
                Pin::PC8 => {
                    gpioc.moder.modify(|_, w| w.moder8().alternate());
                    gpioc.afrh.modify(|_, w| w.afrh8().af0());
                    gpioc.otyper.modify(|_, w| w.ot8().push_pull());
                    tim3.ccmr2_output
                        .modify(|_, w| w.oc3m().pwmmode1().oc3pe().enabled());
                    tim3.ccer.modify(|_, w| w.cc3p().clear_bit());
                    tim3.ccer.modify(|_, w| w.cc3e().active());
                }
                Pin::PC9 => {
                    gpioc.moder.modify(|_, w| w.moder9().alternate());
                    gpioc.afrh.modify(|_, w| w.afrh9().af0());
                    gpioc.otyper.modify(|_, w| w.ot9().push_pull());
                    tim3.ccmr2_output
                        .modify(|_, w| w.oc4m().pwmmode1().oc4pe().enabled());
                    tim3.ccer.modify(|_, w| w.cc4p().clear_bit());
                    tim3.ccer.modify(|_, w| w.cc4e().active());
                }
            }

            tim2.cr1.write(|w| {
                w.cms()
                    .center_align_mode1()
                    .dir()
                    .up()
                    .opm()
                    .continuous()
                    .cen()
                    .enabled()
            });
            tim2.egr.write(|w| w.ug().set_bit());

            tim3.cr1.write(|w| {
                w.cms()
                    .center_align_mode1()
                    .dir()
                    .up()
                    .opm()
                    .continuous()
                    .cen()
                    .enabled()
            });
            tim3.egr.write(|w| w.ug().set_bit());
        });
        Pwm { pin }
    }

    // Be careful, after you have set frequency, it will be necessary to set all duty cycles of others PWMs
    pub fn set_frequency(&self, frequency: u32) {
        cortex_m::interrupt::free(|cs| {
            let tim2 = TIM2.borrow(cs);
            let tim3 = TIM3.borrow(cs);

            // Set Prescaler Register - 16 bits
            const PRE_SCALER: u16 = ((FREQUENCY / (1_000_000 * 2)) - 1) as u16;
            tim2.psc.write(|w| w.psc().bits(PRE_SCALER));
            tim3.psc.write(|w| w.psc().bits(PRE_SCALER)); // Counter clock Frequency = (fCK_PSC / (PSC[15:0] + 1)

            // Set Auto-Reload register - 16 bits
            let arr = 1000000 / frequency; //1000000
            tim3.arr.write(|w| w.arr_h().bits((arr >> 16) as u16));
            tim3.arr.write(|w| w.arr_l().bits(arr as u16));
            tim2.arr.write(|w| w.arr_h().bits((arr >> 16) as u16));
            tim2.arr.write(|w| w.arr_l().bits(arr as u16));

            unsafe {
                FREQ = frequency;
            }
            unsafe {
                self.set_duty(DUTY);
            }
        });
    }

    pub fn enable(&self) {
        cortex_m::interrupt::free(|cs| {
            let tim2 = TIM2.borrow(cs);
            let tim3 = TIM3.borrow(cs);
            match self.pin {
                Pin::PA0 => tim2.ccer.modify(|_, w| w.cc1e().set_bit()),
                Pin::PB3 => tim2.ccer.modify(|_, w| w.cc2e().set_bit()),
                Pin::PB10 => tim2.ccer.modify(|_, w| w.cc3e().set_bit()),
                Pin::PB11 => tim2.ccer.modify(|_, w| w.cc4e().set_bit()),
                Pin::PB4 => tim3.ccer.modify(|_, w| w.cc1e().set_bit()),
                Pin::PB5 => tim3.ccer.modify(|_, w| w.cc2e().set_bit()),
                Pin::PC6 => tim3.ccer.modify(|_, w| w.cc1e().set_bit()),
                Pin::PC7 => tim3.ccer.modify(|_, w| w.cc2e().set_bit()),
                Pin::PC8 => tim3.ccer.modify(|_, w| w.cc3e().set_bit()),
                Pin::PC9 => tim3.ccer.modify(|_, w| w.cc4e().set_bit()),
            }
        });
    }

    pub fn set_duty(&self, duty: f64) {
        cortex_m::interrupt::free(|cs| {
            let tim2 = TIM2.borrow(cs);
            let tim3 = TIM3.borrow(cs);
            unsafe {
                let ccr_value = (((1000000.0 / FREQ as f64) / 100.0) * duty) as u32;
                DUTY = duty;
                match self.pin {
                    Pin::PA0 => tim2.ccr1.write(|w| {
                        w.ccr1_l()
                            .bits((ccr_value) as u16)
                            .ccr1_h()
                            .bits((ccr_value >> 16) as u16)
                    }),
                    Pin::PB3 => tim2.ccr2.write(|w| {
                        w.ccr2_l()
                            .bits((ccr_value) as u16)
                            .ccr2_h()
                            .bits((ccr_value >> 16) as u16)
                    }),
                    Pin::PB10 => tim2.ccr3.write(|w| {
                        w.ccr3_l()
                            .bits((ccr_value) as u16)
                            .ccr3_h()
                            .bits((ccr_value >> 16) as u16)
                    }),
                    Pin::PB11 => tim2.ccr4.write(|w| {
                        w.ccr4_l()
                            .bits((ccr_value) as u16)
                            .ccr4_h()
                            .bits((ccr_value >> 16) as u16)
                    }),

                    Pin::PB4 => tim3.ccr1.write(|w| {
                        w.ccr1_l()
                            .bits((ccr_value) as u16)
                            .ccr1_h()
                            .bits((ccr_value >> 16) as u16)
                    }),
                    Pin::PB5 => tim3.ccr2.write(|w| {
                        w.ccr2_l()
                            .bits((ccr_value) as u16)
                            .ccr2_h()
                            .bits((ccr_value >> 16) as u16)
                    }),
                    Pin::PC6 => tim3.ccr1.write(|w| {
                        w.ccr1_l()
                            .bits((ccr_value) as u16)
                            .ccr1_h()
                            .bits((ccr_value >> 16) as u16)
                    }),
                    Pin::PC7 => tim3.ccr2.write(|w| {
                        w.ccr2_l()
                            .bits((ccr_value) as u16)
                            .ccr2_h()
                            .bits((ccr_value >> 16) as u16)
                    }),
                    Pin::PC8 => tim3.ccr3.write(|w| {
                        w.ccr3_l()
                            .bits((ccr_value) as u16)
                            .ccr3_h()
                            .bits((ccr_value >> 16) as u16)
                    }),
                    Pin::PC9 => tim3.ccr4.write(|w| {
                        w.ccr4_l()
                            .bits((ccr_value) as u16)
                            .ccr4_h()
                            .bits((ccr_value >> 16) as u16)
                    }),
                }
            }
        });
    }
}
<commit_msg>Bugfix in pwm, make sure we reset the timer counter.<commit_after>use stm32f0x2::{TIM2, TIM3, GPIOA, GPIOB, GPIOC, RCC};

use cortex_m;

static mut FREQ: u32 = 0;
static mut DUTY: f64 = 0.0;
const FREQUENCY: u32 = 48_000_000;

// PWM channels : Pins available
pub enum Pin {
    PA0,
    PB3,
    PB4,
    PB5,
    PB10,
    PB11,
    PC6,
    PC7,
    PC8,
    PC9,
}

pub struct Pwm {
    pin: Pin,
}

impl Pwm {
    pub fn init(pin: Pin) -> Pwm {
        cortex_m::interrupt::free(|cs| {
            let rcc = RCC.borrow(cs);
            let tim2 = TIM2.borrow(cs);
            let tim3 = TIM3.borrow(cs);

            let gpioa = GPIOA.borrow(cs);
            let gpiob = GPIOB.borrow(cs);
            let gpioc = GPIOC.borrow(cs);

            // GPIOA, GPIOB and GPIOC Clock Activated
            rcc.ahbenr
                .modify(|_, w| w.iopaen().enabled().iopben().enabled().iopcen().enabled());
            // TIMER Clock Activated
            rcc.apb1enr.modify(|_, w| w.tim2en().enabled());
            rcc.apb1enr.modify(|_, w| w.tim3en().enabled());

            match pin {
                Pin::PA0 => {
                    gpioa.moder.modify(|_, w| w.moder0().alternate());
                    gpioa.afrl.modify(|_, w| w.afrl0().af2());
                    gpioa.otyper.modify(|_, w| w.ot0().push_pull());
                    tim2.ccmr1_output
                        .modify(|_, w| w.oc1m().pwmmode1().oc1pe().enabled());
                    tim2.ccer.modify(|_, w| w.cc1p().clear_bit());
                    tim2.ccer.modify(|_, w| w.cc1e().active());
                }
                Pin::PB3 => {
                    gpiob.moder.modify(|_, w| w.moder3().alternate());
                    gpiob.afrl.modify(|_, w| w.afrl3().af2());
                    gpiob.otyper.modify(|_, w| w.ot3().push_pull());
                    tim2.ccmr1_output
                        .modify(|_, w| w.oc2m().pwmmode1().oc2pe().enabled());
                    tim2.ccer.modify(|_, w| w.cc2p().clear_bit());
                    tim2.ccer.modify(|_, w| w.cc2e().active());
                }
                Pin::PB10 => {
                    gpiob.moder.modify(|_, w| w.moder10().alternate());
                    gpiob.afrh.modify(|_, w| w.afrh10().af2());
                    gpiob.otyper.modify(|_, w| w.ot10().push_pull());
                    tim2.ccmr2_output
                        .modify(|_, w| w.oc3m().pwmmode1().oc3pe().enabled());
                    tim2.ccer.modify(|_, w| w.cc3p().clear_bit());
                    tim2.ccer.modify(|_, w| w.cc3e().active());
                }
                Pin::PB11 => {
                    gpiob.moder.modify(|_, w| w.moder11().alternate());
                    gpiob.afrh.modify(|_, w| w.afrh11().af2());
                    gpiob.otyper.modify(|_, w| w.ot11().push_pull());
                    tim2.ccmr2_output
                        .modify(|_, w| w.oc4m().pwmmode1().oc4pe().enabled());
                    tim2.ccer.modify(|_, w| w.cc4p().clear_bit());
                    tim2.ccer.modify(|_, w| w.cc4e().active());
                }
                Pin::PB4 => {
                    gpiob.moder.modify(|_, w| w.moder4().alternate());
                    gpiob.afrl.modify(|_, w| w.afrl4().af1());
                    gpiob.otyper.modify(|_, w| w.ot4().push_pull());
                    tim3.ccmr1_output
                        .modify(|_, w| w.oc1m().pwmmode1().oc1pe().enabled());
                    tim3.ccer.modify(|_, w| w.cc1p().clear_bit());
                    tim3.ccer.modify(|_, w| w.cc1e().active());
                }
                Pin::PB5 => {
                    gpiob.moder.modify(|_, w| w.moder5().alternate());
                    gpiob.afrl.modify(|_, w| w.afrl5().af1());
                    gpiob.otyper.modify(|_, w| w.ot5().push_pull());
                    tim3.ccmr1_output
                        .modify(|_, w| w.oc2m().pwmmode1().oc2pe().enabled());
                    tim3.ccer.modify(|_, w| w.cc2p().clear_bit());
                    tim3.ccer.modify(|_, w| w.cc2e().active());
                }
                Pin::PC6 => {
                    gpioc.moder.modify(|_, w| w.moder6().alternate());
                    gpioc.afrl.modify(|_, w| w.afrl6().af0());
                    gpioc.otyper.modify(|_, w| w.ot6().push_pull());
                    tim3.ccmr1_output
                        .modify(|_, w| w.oc1m().pwmmode1().oc1pe().enabled());
                    tim3.ccer.modify(|_, w| w.cc1p().clear_bit());
                    tim3.ccer.modify(|_, w| w.cc1e().active());
                }
                Pin::PC7 => {
                    gpioc.moder.modify(|_, w| w.moder7().alternate());
                    gpioc.afrl.modify(|_, w| w.afrl7().af0());
                    gpioc.otyper.modify(|_, w| w.ot7().push_pull());
                    tim3.ccmr1_output
                        .modify(|_, w| w.oc2m().pwmmode1().oc2pe().enabled());
                    tim3.ccer.modify(|_, w| w.cc2p().clear_bit());
                    tim3.ccer.modify(|_, w| w.cc2e().active());
                }
                Pin::PC8 => {
                    gpioc.moder.modify(|_, w| w.moder8().alternate());
                    gpioc.afrh.modify(|_, w| w.afrh8().af0());
                    gpioc.otyper.modify(|_, w| w.ot8().push_pull());
                    tim3.ccmr2_output
                        .modify(|_, w| w.oc3m().pwmmode1().oc3pe().enabled());
                    tim3.ccer.modify(|_, w| w.cc3p().clear_bit());
                    tim3.ccer.modify(|_, w| w.cc3e().active());
                }
                Pin::PC9 => {
                    gpioc.moder.modify(|_, w| w.moder9().alternate());
                    gpioc.afrh.modify(|_, w| w.afrh9().af0());
                    gpioc.otyper.modify(|_, w| w.ot9().push_pull());
                    tim3.ccmr2_output
                        .modify(|_, w| w.oc4m().pwmmode1().oc4pe().enabled());
                    tim3.ccer.modify(|_, w| w.cc4p().clear_bit());
                    tim3.ccer.modify(|_, w| w.cc4e().active());
                }
            }

            tim2.cr1.write(|w| {
                w.cms()
                    .center_align_mode1()
                    .dir()
                    .up()
                    .opm()
                    .continuous()
                    .cen()
                    .enabled()
            });
            tim2.egr.write(|w| w.ug().set_bit());

            tim3.cr1.write(|w| {
                w.cms()
                    .center_align_mode1()
                    .dir()
                    .up()
                    .opm()
                    .continuous()
                    .cen()
                    .enabled()
            });
            tim3.egr.write(|w| w.ug().set_bit());
        });
        Pwm { pin }
    }

    // Be careful, after you have set frequency, it will be necessary to set all duty cycles of others PWMs
    pub fn set_frequency(&self, frequency: u32) {
        cortex_m::interrupt::free(|cs| {
            let tim2 = TIM2.borrow(cs);
            let tim3 = TIM3.borrow(cs);

            // Set Prescaler Register - 16 bits
            const PRE_SCALER: u16 = ((FREQUENCY / (1_000_000 * 2)) - 1) as u16;
            tim2.psc.write(|w| w.psc().bits(PRE_SCALER));
            tim3.psc.write(|w| w.psc().bits(PRE_SCALER)); // Counter clock Frequency = (fCK_PSC / (PSC[15:0] + 1)

            // Set Auto-Reload register - 16 bits
            let arr = 1000000 / frequency; //1000000
            tim3.arr.write(|w| w.arr_h().bits((arr >> 16) as u16));
            tim3.arr.write(|w| w.arr_l().bits(arr as u16));
            tim2.arr.write(|w| w.arr_h().bits((arr >> 16) as u16));
            tim2.arr.write(|w| w.arr_l().bits(arr as u16));

            unsafe {
                FREQ = frequency;
            }
            unsafe {
                self.set_duty(DUTY);
            }

            // Reset counter
            tim2.cnt.write(|w| w.cnt_h().bits(0));
            tim2.cnt.write(|w| w.cnt_l().bits(0));
            tim3.cnt.write(|w| w.cnt_h().bits(0));
            tim3.cnt.write(|w| w.cnt_l().bits(0));
        });
    }

    pub fn enable(&self) {
        cortex_m::interrupt::free(|cs| {
            let tim2 = TIM2.borrow(cs);
            let tim3 = TIM3.borrow(cs);
            match self.pin {
                Pin::PA0 => tim2.ccer.modify(|_, w| w.cc1e().set_bit()),
                Pin::PB3 => tim2.ccer.modify(|_, w| w.cc2e().set_bit()),
                Pin::PB10 => tim2.ccer.modify(|_, w| w.cc3e().set_bit()),
                Pin::PB11 => tim2.ccer.modify(|_, w| w.cc4e().set_bit()),
                Pin::PB4 => tim3.ccer.modify(|_, w| w.cc1e().set_bit()),
                Pin::PB5 => tim3.ccer.modify(|_, w| w.cc2e().set_bit()),
                Pin::PC6 => tim3.ccer.modify(|_, w| w.cc1e().set_bit()),
                Pin::PC7 => tim3.ccer.modify(|_, w| w.cc2e().set_bit()),
                Pin::PC8 => tim3.ccer.modify(|_, w| w.cc3e().set_bit()),
                Pin::PC9 => tim3.ccer.modify(|_, w| w.cc4e().set_bit()),
            }
        });
    }

    pub fn set_duty(&self, duty: f64) {
        cortex_m::interrupt::free(|cs| {
            let tim2 = TIM2.borrow(cs);
            let tim3 = TIM3.borrow(cs);
            unsafe {
                let ccr_value = (((1000000.0 / FREQ as f64) / 100.0) * duty) as u32;
                DUTY = duty;
                match self.pin {
                    Pin::PA0 => tim2.ccr1.write(|w| {
                        w.ccr1_l()
                            .bits((ccr_value) as u16)
                            .ccr1_h()
                            .bits((ccr_value >> 16) as u16)
                    }),
                    Pin::PB3 => tim2.ccr2.write(|w| {
                        w.ccr2_l()
                            .bits((ccr_value) as u16)
                            .ccr2_h()
                            .bits((ccr_value >> 16) as u16)
                    }),
                    Pin::PB10 => tim2.ccr3.write(|w| {
                        w.ccr3_l()
                            .bits((ccr_value) as u16)
                            .ccr3_h()
                            .bits((ccr_value >> 16) as u16)
                    }),
                    Pin::PB11 => tim2.ccr4.write(|w| {
                        w.ccr4_l()
                            .bits((ccr_value) as u16)
                            .ccr4_h()
                            .bits((ccr_value >> 16) as u16)
                    }),

                    Pin::PB4 => tim3.ccr1.write(|w| {
                        w.ccr1_l()
                            .bits((ccr_value) as u16)
                            .ccr1_h()
                            .bits((ccr_value >> 16) as u16)
                    }),
                    Pin::PB5 => tim3.ccr2.write(|w| {
                        w.ccr2_l()
                            .bits((ccr_value) as u16)
                            .ccr2_h()
                            .bits((ccr_value >> 16) as u16)
                    }),
                    Pin::PC6 => tim3.ccr1.write(|w| {
                        w.ccr1_l()
                            .bits((ccr_value) as u16)
                            .ccr1_h()
                            .bits((ccr_value >> 16) as u16)
                    }),
                    Pin::PC7 => tim3.ccr2.write(|w| {
                        w.ccr2_l()
                            .bits((ccr_value) as u16)
                            .ccr2_h()
                            .bits((ccr_value >> 16) as u16)
                    }),
                    Pin::PC8 => tim3.ccr3.write(|w| {
                        w.ccr3_l()
                            .bits((ccr_value) as u16)
                            .ccr3_h()
                            .bits((ccr_value >> 16) as u16)
                    }),
                    Pin::PC9 => tim3.ccr4.write(|w| {
                        w.ccr4_l()
                            .bits((ccr_value) as u16)
                            .ccr4_h()
                            .bits((ccr_value >> 16) as u16)
                    }),
                }
            }
        });
    }
}
<|endoftext|>


<commit_before>use rustwlc::WlcOutput;
use petgraph::graph::NodeIndex;
use uuid::Uuid;
use super::super::{LayoutTree, TreeError};
use super::super::core::container::{Container, ContainerType, Layout, Handle};
use ::debug_enabled;

// TODO This module needs to be updated like the other modules...
// Need to add some errors for this (such as when trying to move a non-container/view,
// or when trying to grab a workspace whos name already exists)
//
// Also the code is generally pretty crap, cause it's pretty old (mid-2016)

impl LayoutTree {
    /// Gets a workspace by name or creates it
    fn get_or_make_workspace(&mut self, name: &str) -> NodeIndex {
        let active_index = self.tree.follow_path_until(self.tree.root_ix(),
                                                      ContainerType::Output)
            .expect("get_or_make_wksp: Couldn't get output");
        let workspace_ix = self.tree.workspace_ix_by_name(name).unwrap_or_else(|| {
            let root_ix = self.init_workspace(name.to_string(), active_index);
            self.tree.parent_of(root_ix)
                .expect("Workspace was not properly initialized with a root container")
        });
        self.validate();
        workspace_ix
    }

    /// Initializes a workspace and gets the index of the root container
    pub fn init_workspace(&mut self, name: String, output_ix: NodeIndex)
                      -> NodeIndex {
        let geometry = self.tree.get(output_ix)
            .expect("init_workspace: invalid output").get_geometry()
            .expect("init_workspace: no geometry for output");
        let worksp = Container::new_workspace(name.to_string(), geometry);
        let output_handle = match self.tree[output_ix].get_handle() {
            Ok(Handle::Output(output)) => output,
            Err(err) => panic!("Could not get handle from output: {:#?}", err),
            _ => unreachable!()
        };

        trace!("Adding workspace {:?}", worksp);
        let worksp_ix = self.tree.add_child(output_ix, worksp, false);
        let container = Container::new_container(geometry, output_handle, None);
        let container_ix = self.tree.add_child(worksp_ix, container, false);
        self.tree.set_ancestor_paths_active(container_ix);
        self.validate();
        container_ix
    }

    /// Switch to the specified workspace
    pub fn switch_to_workspace(&mut self, name: &str) {
        let maybe_active_ix = self.active_container
            .or_else(|| {
                let new_active = self.tree.follow_path(self.tree.root_ix());
                match self.tree[new_active].get_type() {
                    ContainerType::View | ContainerType::Container => {
                        Some(new_active)
                    },
                    // else try and get the root container
                    _ => self.tree.descendant_of_type(new_active, ContainerType::Container).ok()
                }
            });
        if maybe_active_ix.is_none() {
            warn!("{:#?}", self);
            warn!("No active container, cannot switch");
            return;
        }
        let active_ix = maybe_active_ix.unwrap();
        // Get the old (current) workspace
        let old_worksp_ix: NodeIndex;
        if let Ok(index) = self.tree.ancestor_of_type(active_ix, ContainerType::Workspace) {
            old_worksp_ix = index;
            trace!("Switching to workspace {}", name);
        } else {
            match self.tree[active_ix].get_type() {
                ContainerType::Workspace => {
                    old_worksp_ix = active_ix;
                    trace!("Switching to workspace {}", name);
                },
                _ => {
                    warn!("Could not find old workspace, could not set invisible");
                    return;
                }
            }
        }
        // Get the new workspace, or create one if it doesn't work
        let mut workspace_ix = self.get_or_make_workspace(name);
        if old_worksp_ix == workspace_ix {
            return;
        }
        {
            // Update the border colors
            let container = &mut self.tree[active_ix];
            container.clear_border_color()
                .expect("Could not clear old active border color");
            container.draw_borders().expect("Could not draw borders");
        }
        let old_worksp_parent_ix = self.tree.parent_of(old_worksp_ix)
            .expect("Old workspace had no parent");
        let new_worksp_parent_ix = self.tree.parent_of(workspace_ix)
            .expect("New workspace had no parent");
        // Only set the old one to be invisible if new and old share output.
        if new_worksp_parent_ix == old_worksp_parent_ix {
            // Set the old one to invisible
            self.set_container_visibility(old_worksp_ix, false);
        } else {
            // Set all views on the target output to be invisible,
            // to clear the old workspace visibilty out.
            self.set_container_visibility(new_worksp_parent_ix, false);
        }
        // Set the new one to visible
        self.container_visibilty_wrapper(workspace_ix, true);
        // Focus on the new output
        match self.tree[new_worksp_parent_ix] {
            Container::Output { handle, .. } => {
                WlcOutput::focus(Some(handle))
            },
            _ => unreachable!()
        }
        // Delete the old workspace if it has no views on it
        self.active_container = None;
        if self.tree.descendant_of_type(old_worksp_ix, ContainerType::View).is_err() {
            let siblings = self.tree.children_of(old_worksp_parent_ix);
            // Only remove if it's **NOT** the only workspace on the output.
            // AND if the new workspace is on the same output.
            if siblings.len() > 1 && old_worksp_parent_ix == new_worksp_parent_ix {
                trace!("Removing workspace: {:?}", self.tree[old_worksp_ix].get_name()
                    .expect("Workspace had no name"));
                if let Err(err) = self.remove_workspace(old_worksp_ix) {
                    warn!("Tried to remove empty workspace {:#?}, error: {:?}",
                        old_worksp_ix, err);
                    debug!("{:#?}", self);
                    panic!("Could not remove old workspace");
                }
            }
        }
        workspace_ix = self.tree.workspace_ix_by_name(name)
            .expect("Workspace we just made was deleted!");
        let active_ix = self.tree.follow_path(workspace_ix);
        match self.tree[active_ix].get_type() {
            ContainerType::View  => {
                match self.tree[active_ix] {
                    Container::View { id, ..} => {
                        self.focus_on(id).unwrap_or_else(|_| {
                            warn!("Could not focus on {:?}", id);
                        });
                    },
                    _ => unreachable!()
                }
                self.set_active_node(active_ix)
                    .expect("Could not set new active node");
                self.tree.set_ancestor_paths_active(active_ix);
                self.layout(workspace_ix);
                self.validate();
                self.validate_path();
                return;
            },
            _ => {
                self.active_container = self.tree
                    .descendant_of_type(active_ix, ContainerType::View)
                    .or_else(|_| self.tree.descendant_of_type(active_ix,
                                                              ContainerType::Container)).ok();
                match self.tree[self.active_container.expect("Workspace had NO children!")] {
                    Container::View { floating, .. } => {
                        if !floating {
                            self.tree.set_ancestor_paths_active(self.active_container.unwrap());
                        } else {
                            let root_c_ix = *self.tree.children_of(workspace_ix).get(0)
                            .expect("The workspace we are switching to had no root container");
                            self.tree.set_ancestor_paths_active(root_c_ix);
                        }
                    },
                    Container::Container { .. } => {
                        self.tree.set_ancestor_paths_active(self.active_container.unwrap());
                    }
                    _ => unreachable!()
                };
            }
        }
        trace!("Focusing on next container");
        self.focus_on_next_container(workspace_ix);
        self.layout(workspace_ix);
        self.validate();
        self.validate_path();
    }

    /// Moves the active container to a new workspace.
    pub fn send_active_to_workspace(&mut self, name: &str) {
        if let Some(active_ix) = self.active_container {
            let id = self.tree[active_ix].get_id();
            self.send_to_workspace(id, name);
        }
    }
    /// Moves a container to a new workspace
    pub fn send_to_workspace(&mut self, id: Uuid, name: &str) {
        let node_ix = self.tree.lookup_id(id);
        // Ensure focus
        if let Some(active_ix) = node_ix.or(self.active_container) {
            let curr_work_ix = self.active_ix_of(ContainerType::Workspace)
                .expect("send_active: Not currently in a workspace!");
            if active_ix == self.tree.children_of(curr_work_ix)[0] {
                warn!("Tried to move the root container of a workspace, aborting move");
                return;
            }
            let next_work_ix = self.get_or_make_workspace(name);

            // Check if the workspaces are the same
            if next_work_ix == curr_work_ix {
                trace!("Attempted to move a view to the same workspace {}!", name);
                return;
            }
            self.set_container_visibility(curr_work_ix, false);
            let new_output_ix = self.tree.parent_of(next_work_ix)
                .expect("Target workspace had no parent");
            match self.tree[new_output_ix] {
                Container::Output { handle: output_handle, .. } => {
                    fn set_output_recurse(this: &mut LayoutTree,
                                          node_ix: NodeIndex,
                                          output_handle: WlcOutput) {
                        match this.tree[node_ix] {
                            Container::View { handle, .. } => {
                                handle.set_output(output_handle);
                            },
                            Container::Container { .. } => {
                                for child_ix in this.tree.children_of(node_ix) {
                                    set_output_recurse(this, child_ix, output_handle)
                                }
                            },
                            _ => unreachable!()
                        }
                    }
                    set_output_recurse(self, active_ix, output_handle);
                },
                _ => unreachable!()
            }

            // Save the parent of this view for focusing
            let maybe_active_parent = self.tree.parent_of(active_ix);

            // Get the root container of the next workspace
            let next_work_children = self.tree.children_of(next_work_ix);
            if cfg!(debug_assertions) || !debug_enabled() {
                assert!(next_work_children.len() == 1,
                        "Next workspace has multiple roots!");
            }
            let next_work_root_ix = next_work_children[0];

            // Move the container
            debug!("Moving container {:?} to workspace {}",
                self.get_active_container(), name);
            self.tree.move_node(active_ix, next_work_root_ix);

            // If it's a fullscreen app, then update the fullscreen lists
            self.transfer_fullscreen(curr_work_ix, next_work_ix, id);

            // Update the active container
            if let Ok(parent_ix) = maybe_active_parent {
                self.tree.set_ancestor_paths_active(parent_ix);
                let ctype = self.tree.node_type(parent_ix).unwrap_or(ContainerType::Root);
                if ctype == ContainerType::Container {
                    self.focus_on_next_container(parent_ix);
                } else {
                    trace!("Send to container invalidated a NodeIndex: {:?} to {:?}",
                    parent_ix, ctype);
                }
                if self.tree.can_remove_empty_parent(parent_ix) {
                    if let Err(err) = self.remove_view_or_container(parent_ix) {
                        error!("{:#?}\nCould not remove {:#?} from tree {:#?}", err, parent_ix, self);
                        panic!("Could not remove empty parent!");
                    }
                }
            }
            else {
                self.focus_on_next_container(curr_work_ix);
            }
            self.container_visibilty_wrapper(curr_work_ix, true);
            if !self.tree[active_ix].floating() {
                self.normalize_container(active_ix).ok();
            }
        }
        let root_ix = self.tree.root_ix();
        self.layout(root_ix);
        self.validate();
        self.validate_path();
    }

    /// Transfers a fullscreen app from this workspace to another.
    fn transfer_fullscreen(&mut self, cur_work_ix: NodeIndex, next_work_ix: NodeIndex,
                           fullscreen_id: Uuid) {
        if let Some(fullscreen_ids) = self.tree[cur_work_ix].fullscreen_c() {
            if !fullscreen_ids.iter().any(|id| *id == fullscreen_id) {
                return;
            }
        } else {
            return;
        }
        self.tree[cur_work_ix].update_fullscreen_c(fullscreen_id, false)
            .expect("cur_work_ix was not a workspace");
        self.tree[next_work_ix].update_fullscreen_c(fullscreen_id, true)
            .expect("next_work_ix was not a workspace");
    }

    /// Wrapper around `set_container_visibility`, so that tabbed/stacked
    /// is handled correctly (i.e, it's visibilty checks are skipped).
    fn container_visibilty_wrapper(&mut self, node_ix: NodeIndex, val: bool) {
        let mut set = false;
        match self.tree[node_ix] {
            Container::Container { layout, .. } => {
                match layout {
                    Layout::Tabbed | Layout::Stacked => {
                        if val {
                            set = true;
                        }
                    },
                    _ => {}
                }
            },
            _ => {}
        }
        if !set {
            self.tree[node_ix].set_visibility(val);
            for child in self.tree.children_of(node_ix) {
                self.container_visibilty_wrapper(child, val)
            }
        } else {
            self.tree.next_active_node(node_ix)
                .map(|node| self.container_visibilty_wrapper(node, val));
        }
    }

    /// Gets the current workspace we are focused on
    ///
    /// If a workspace is not found, this is considered a hard error and
    /// it will panic.
    #[allow(dead_code)]
    pub fn current_workspace(&self) -> Result<&str, TreeError> {
        let active_ix = self.active_container
            .ok_or(TreeError::NoActiveContainer)?;
        let workspace_ix = self.tree.ancestor_of_type(active_ix,
                                                      ContainerType::Workspace)?;
        Ok(self.tree[workspace_ix].get_name()
           .expect("workspace_ix didn't point to a workspace!"))
    }
}

#[cfg(test)]
mod tests {
    use ::layout::core::tree::tests::basic_tree;

    #[test]
    pub fn switch_empty_workspaces() {
        let mut tree = basic_tree();
        tree.switch_to_workspace("5");
        tree.switch_to_workspace("4");
        tree.switch_to_workspace("5");
        tree.switch_to_workspace("4");
        tree.switch_to_workspace("2");
    }
}
<commit_msg>Fixed bug where fullscreen could crash when changing workspaces<commit_after>use rustwlc::WlcOutput;
use petgraph::graph::NodeIndex;
use uuid::Uuid;
use super::super::{LayoutTree, TreeError, FocusError};
use super::super::core::container::{Container, ContainerType, Layout, Handle};
use ::debug_enabled;

// TODO This module needs to be updated like the other modules...
// Need to add some errors for this (such as when trying to move a non-container/view,
// or when trying to grab a workspace whos name already exists)
//
// Also the code is generally pretty crap, cause it's pretty old (mid-2016)

impl LayoutTree {
    /// Gets a workspace by name or creates it
    fn get_or_make_workspace(&mut self, name: &str) -> NodeIndex {
        let active_index = self.tree.follow_path_until(self.tree.root_ix(),
                                                      ContainerType::Output)
            .expect("get_or_make_wksp: Couldn't get output");
        let workspace_ix = self.tree.workspace_ix_by_name(name).unwrap_or_else(|| {
            let root_ix = self.init_workspace(name.to_string(), active_index);
            self.tree.parent_of(root_ix)
                .expect("Workspace was not properly initialized with a root container")
        });
        self.validate();
        workspace_ix
    }

    /// Initializes a workspace and gets the index of the root container
    pub fn init_workspace(&mut self, name: String, output_ix: NodeIndex)
                      -> NodeIndex {
        let geometry = self.tree.get(output_ix)
            .expect("init_workspace: invalid output").get_geometry()
            .expect("init_workspace: no geometry for output");
        let worksp = Container::new_workspace(name.to_string(), geometry);
        let output_handle = match self.tree[output_ix].get_handle() {
            Ok(Handle::Output(output)) => output,
            Err(err) => panic!("Could not get handle from output: {:#?}", err),
            _ => unreachable!()
        };

        trace!("Adding workspace {:?}", worksp);
        let worksp_ix = self.tree.add_child(output_ix, worksp, false);
        let container = Container::new_container(geometry, output_handle, None);
        let container_ix = self.tree.add_child(worksp_ix, container, false);
        self.tree.set_ancestor_paths_active(container_ix);
        self.validate();
        container_ix
    }

    /// Switch to the specified workspace
    pub fn switch_to_workspace(&mut self, name: &str) {
        let maybe_active_ix = self.active_container
            .or_else(|| {
                let new_active = self.tree.follow_path(self.tree.root_ix());
                match self.tree[new_active].get_type() {
                    ContainerType::View | ContainerType::Container => {
                        Some(new_active)
                    },
                    // else try and get the root container
                    _ => self.tree.descendant_of_type(new_active, ContainerType::Container).ok()
                }
            });
        if maybe_active_ix.is_none() {
            warn!("{:#?}", self);
            warn!("No active container, cannot switch");
            return;
        }
        let active_ix = maybe_active_ix.unwrap();
        // Get the old (current) workspace
        let old_worksp_ix: NodeIndex;
        if let Ok(index) = self.tree.ancestor_of_type(active_ix, ContainerType::Workspace) {
            old_worksp_ix = index;
            trace!("Switching to workspace {}", name);
        } else {
            match self.tree[active_ix].get_type() {
                ContainerType::Workspace => {
                    old_worksp_ix = active_ix;
                    trace!("Switching to workspace {}", name);
                },
                _ => {
                    warn!("Could not find old workspace, could not set invisible");
                    return;
                }
            }
        }
        // Get the new workspace, or create one if it doesn't work
        let mut workspace_ix = self.get_or_make_workspace(name);
        if old_worksp_ix == workspace_ix {
            return;
        }
        {
            // Update the border colors
            let container = &mut self.tree[active_ix];
            container.clear_border_color()
                .expect("Could not clear old active border color");
            container.draw_borders().expect("Could not draw borders");
        }
        let old_worksp_parent_ix = self.tree.parent_of(old_worksp_ix)
            .expect("Old workspace had no parent");
        let new_worksp_parent_ix = self.tree.parent_of(workspace_ix)
            .expect("New workspace had no parent");
        // Only set the old one to be invisible if new and old share output.
        if new_worksp_parent_ix == old_worksp_parent_ix {
            // Set the old one to invisible
            self.set_container_visibility(old_worksp_ix, false);
        } else {
            // Set all views on the target output to be invisible,
            // to clear the old workspace visibilty out.
            self.set_container_visibility(new_worksp_parent_ix, false);
        }
        // Set the new one to visible
        self.container_visibilty_wrapper(workspace_ix, true);
        // Focus on the new output
        match self.tree[new_worksp_parent_ix] {
            Container::Output { handle, .. } => {
                WlcOutput::focus(Some(handle))
            },
            _ => unreachable!()
        }
        // Delete the old workspace if it has no views on it
        self.active_container = None;
        if self.tree.descendant_of_type(old_worksp_ix, ContainerType::View).is_err() {
            let siblings = self.tree.children_of(old_worksp_parent_ix);
            // Only remove if it's **NOT** the only workspace on the output.
            // AND if the new workspace is on the same output.
            if siblings.len() > 1 && old_worksp_parent_ix == new_worksp_parent_ix {
                trace!("Removing workspace: {:?}", self.tree[old_worksp_ix].get_name()
                    .expect("Workspace had no name"));
                if let Err(err) = self.remove_workspace(old_worksp_ix) {
                    warn!("Tried to remove empty workspace {:#?}, error: {:?}",
                        old_worksp_ix, err);
                    debug!("{:#?}", self);
                    panic!("Could not remove old workspace");
                }
            }
        }
        workspace_ix = self.tree.workspace_ix_by_name(name)
            .expect("Workspace we just made was deleted!");
        let active_ix = self.tree.follow_path(workspace_ix);
        match self.tree[active_ix].get_type() {
            ContainerType::View  => {
                match self.tree[active_ix] {
                    Container::View { id, ..} => {
                        self.focus_on(id).unwrap_or_else(|_| {
                            warn!("Could not focus on {:?}", id);
                        });
                    },
                    _ => unreachable!()
                }
                // TODO Propogate this when this is refactored
                match self.set_active_node(active_ix) {
                    Ok(_) |
                    Err(TreeError::Focus(
                        FocusError::BlockedByFullscreen(_,_))) => {
                            Ok(())
                    },
                    err => err
                }.expect("Could not set new active node");
                self.tree.set_ancestor_paths_active(active_ix);
                self.layout(workspace_ix);
                self.validate();
                self.validate_path();
                return;
            },
            _ => {
                self.active_container = self.tree
                    .descendant_of_type(active_ix, ContainerType::View)
                    .or_else(|_| self.tree.descendant_of_type(active_ix,
                                                              ContainerType::Container)).ok();
                match self.tree[self.active_container.expect("Workspace had NO children!")] {
                    Container::View { floating, .. } => {
                        if !floating {
                            self.tree.set_ancestor_paths_active(self.active_container.unwrap());
                        } else {
                            let root_c_ix = *self.tree.children_of(workspace_ix).get(0)
                            .expect("The workspace we are switching to had no root container");
                            self.tree.set_ancestor_paths_active(root_c_ix);
                        }
                    },
                    Container::Container { .. } => {
                        self.tree.set_ancestor_paths_active(self.active_container.unwrap());
                    }
                    _ => unreachable!()
                };
            }
        }
        trace!("Focusing on next container");
        self.focus_on_next_container(workspace_ix);
        self.layout(workspace_ix);
        self.validate();
        self.validate_path();
    }

    /// Moves the active container to a new workspace.
    pub fn send_active_to_workspace(&mut self, name: &str) {
        if let Some(active_ix) = self.active_container {
            let id = self.tree[active_ix].get_id();
            self.send_to_workspace(id, name);
        }
    }
    /// Moves a container to a new workspace
    pub fn send_to_workspace(&mut self, id: Uuid, name: &str) {
        let node_ix = self.tree.lookup_id(id);
        // Ensure focus
        if let Some(active_ix) = node_ix.or(self.active_container) {
            let curr_work_ix = self.active_ix_of(ContainerType::Workspace)
                .expect("send_active: Not currently in a workspace!");
            if active_ix == self.tree.children_of(curr_work_ix)[0] {
                warn!("Tried to move the root container of a workspace, aborting move");
                return;
            }
            let next_work_ix = self.get_or_make_workspace(name);

            // Check if the workspaces are the same
            if next_work_ix == curr_work_ix {
                trace!("Attempted to move a view to the same workspace {}!", name);
                return;
            }
            self.set_container_visibility(curr_work_ix, false);
            let new_output_ix = self.tree.parent_of(next_work_ix)
                .expect("Target workspace had no parent");
            match self.tree[new_output_ix] {
                Container::Output { handle: output_handle, .. } => {
                    fn set_output_recurse(this: &mut LayoutTree,
                                          node_ix: NodeIndex,
                                          output_handle: WlcOutput) {
                        match this.tree[node_ix] {
                            Container::View { handle, .. } => {
                                handle.set_output(output_handle);
                            },
                            Container::Container { .. } => {
                                for child_ix in this.tree.children_of(node_ix) {
                                    set_output_recurse(this, child_ix, output_handle)
                                }
                            },
                            _ => unreachable!()
                        }
                    }
                    set_output_recurse(self, active_ix, output_handle);
                },
                _ => unreachable!()
            }

            // Save the parent of this view for focusing
            let maybe_active_parent = self.tree.parent_of(active_ix);

            // Get the root container of the next workspace
            let next_work_children = self.tree.children_of(next_work_ix);
            if cfg!(debug_assertions) || !debug_enabled() {
                assert!(next_work_children.len() == 1,
                        "Next workspace has multiple roots!");
            }
            let next_work_root_ix = next_work_children[0];

            // Move the container
            debug!("Moving container {:?} to workspace {}",
                self.get_active_container(), name);
            self.tree.move_node(active_ix, next_work_root_ix);

            // If it's a fullscreen app, then update the fullscreen lists
            self.transfer_fullscreen(curr_work_ix, next_work_ix, id);

            // Update the active container
            if let Ok(parent_ix) = maybe_active_parent {
                self.tree.set_ancestor_paths_active(parent_ix);
                let ctype = self.tree.node_type(parent_ix).unwrap_or(ContainerType::Root);
                if ctype == ContainerType::Container {
                    self.focus_on_next_container(parent_ix);
                } else {
                    trace!("Send to container invalidated a NodeIndex: {:?} to {:?}",
                    parent_ix, ctype);
                }
                if self.tree.can_remove_empty_parent(parent_ix) {
                    if let Err(err) = self.remove_view_or_container(parent_ix) {
                        error!("{:#?}\nCould not remove {:#?} from tree {:#?}", err, parent_ix, self);
                        panic!("Could not remove empty parent!");
                    }
                }
            }
            else {
                self.focus_on_next_container(curr_work_ix);
            }
            self.container_visibilty_wrapper(curr_work_ix, true);
            if !self.tree[active_ix].floating() {
                self.normalize_container(active_ix).ok();
            }
        }
        let root_ix = self.tree.root_ix();
        self.layout(root_ix);
        self.validate();
        self.validate_path();
    }

    /// Transfers a fullscreen app from this workspace to another.
    fn transfer_fullscreen(&mut self, cur_work_ix: NodeIndex, next_work_ix: NodeIndex,
                           fullscreen_id: Uuid) {
        if let Some(fullscreen_ids) = self.tree[cur_work_ix].fullscreen_c() {
            if !fullscreen_ids.iter().any(|id| *id == fullscreen_id) {
                return;
            }
        } else {
            return;
        }
        self.tree[cur_work_ix].update_fullscreen_c(fullscreen_id, false)
            .expect("cur_work_ix was not a workspace");
        self.tree[next_work_ix].update_fullscreen_c(fullscreen_id, true)
            .expect("next_work_ix was not a workspace");
    }

    /// Wrapper around `set_container_visibility`, so that tabbed/stacked
    /// is handled correctly (i.e, it's visibilty checks are skipped).
    fn container_visibilty_wrapper(&mut self, node_ix: NodeIndex, val: bool) {
        let mut set = false;
        match self.tree[node_ix] {
            Container::Container { layout, .. } => {
                match layout {
                    Layout::Tabbed | Layout::Stacked => {
                        if val {
                            set = true;
                        }
                    },
                    _ => {}
                }
            },
            _ => {}
        }
        if !set {
            self.tree[node_ix].set_visibility(val);
            for child in self.tree.children_of(node_ix) {
                self.container_visibilty_wrapper(child, val)
            }
        } else {
            self.tree.next_active_node(node_ix)
                .map(|node| self.container_visibilty_wrapper(node, val));
        }
    }

    /// Gets the current workspace we are focused on
    ///
    /// If a workspace is not found, this is considered a hard error and
    /// it will panic.
    #[allow(dead_code)]
    pub fn current_workspace(&self) -> Result<&str, TreeError> {
        let active_ix = self.active_container
            .ok_or(TreeError::NoActiveContainer)?;
        let workspace_ix = self.tree.ancestor_of_type(active_ix,
                                                      ContainerType::Workspace)?;
        Ok(self.tree[workspace_ix].get_name()
           .expect("workspace_ix didn't point to a workspace!"))
    }
}

#[cfg(test)]
mod tests {
    use ::layout::core::tree::tests::basic_tree;

    #[test]
    pub fn switch_empty_workspaces() {
        let mut tree = basic_tree();
        tree.switch_to_workspace("5");
        tree.switch_to_workspace("4");
        tree.switch_to_workspace("5");
        tree.switch_to_workspace("4");
        tree.switch_to_workspace("2");
    }
}
<|endoftext|>