Compare commits
13 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
05c96eaa28 | ||
|
|
9a9f49f467 | ||
|
|
c552ae98b4 | ||
|
|
df7493fd33 | ||
|
|
5de571fb03 | ||
|
|
62df7badf3 | ||
|
|
597e219257 | ||
|
|
3f8a9079ee | ||
|
|
5981767543 | ||
|
|
36146d970a | ||
|
|
464ba4f334 | ||
|
|
36a5eb2110 | ||
|
|
55840210c7 |
11
.travis.yml
11
.travis.yml
@@ -5,18 +5,17 @@ rust:
|
||||
- beta
|
||||
- nightly
|
||||
|
||||
env:
|
||||
- NO_RUSTUP=1
|
||||
|
||||
cache: cargo
|
||||
|
||||
matrix:
|
||||
fast_finish: true
|
||||
allow_failures:
|
||||
- rust: nightly
|
||||
- rust: beta
|
||||
|
||||
before_script:
|
||||
- ./scripts/travis/before_script.sh
|
||||
- rustup component add rustfmt-preview
|
||||
|
||||
script:
|
||||
- ./scripts/travis/script.sh
|
||||
- if [ "$TRAVIS_RUST_VERSION" == "stable" ]; then make fmt; fi
|
||||
- make build
|
||||
- make test
|
||||
|
||||
@@ -2,6 +2,13 @@
|
||||
|
||||
## To be released
|
||||
|
||||
## v0.2.3 - 2018-06-09
|
||||
|
||||
### Added
|
||||
|
||||
* Add `start_corner` option for `List`
|
||||
* Add more text aligment options for `Paragraph`
|
||||
|
||||
## v0.2.2 - 2018-05-06
|
||||
|
||||
### Added
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "tui"
|
||||
version = "0.2.2"
|
||||
version = "0.2.3"
|
||||
authors = ["Florian Dehau <work@fdehau.com>"]
|
||||
description = """
|
||||
A library to build rich terminal user interfaces or dashboards
|
||||
@@ -19,6 +19,7 @@ default = ["termion"]
|
||||
[dependencies]
|
||||
bitflags = "1.0.1"
|
||||
cassowary = "0.3.0"
|
||||
itertools = "0.7.8"
|
||||
log = "0.4.1"
|
||||
unicode-segmentation = "1.2.0"
|
||||
unicode-width = "0.1.4"
|
||||
|
||||
20
Makefile
20
Makefile
@@ -27,26 +27,6 @@ help: ## Print all the available commands
|
||||
awk 'BEGIN {FS = ":.*?## "}; {printf "\033[36m%-20s\033[0m %s\n", $$1, $$2}'
|
||||
|
||||
|
||||
# ================================ Tools ======================================
|
||||
|
||||
|
||||
install-tools: install-rustfmt install-clippy ## Install tools dependencies
|
||||
|
||||
INSTALL_RUSTFMT = ./scripts/tools/install.sh --name=rustfmt-nightly
|
||||
ifndef CI
|
||||
INSTALL_RUSTFMT += --channel=nightly
|
||||
endif
|
||||
install-rustfmt: ## Intall rustfmt
|
||||
$(INSTALL_RUSTFMT)
|
||||
|
||||
INSTALL_CLIPPY = ./scripts/tools/install.sh --name=clippy
|
||||
ifndef CI
|
||||
INSTALL_CLIPPY += --channel=nightly
|
||||
endif
|
||||
install-clippy: ## Intall rustfmt
|
||||
$(INSTALL_CLIPPY)
|
||||
|
||||
|
||||
# =============================== Build =======================================
|
||||
|
||||
check: ## Validate the project code
|
||||
|
||||
17
README.md
17
README.md
@@ -32,6 +32,10 @@ you may rely on the previously cited libraries to achieve such features.
|
||||
|
||||
### [Documentation](https://docs.rs/tui)
|
||||
|
||||
### Demo
|
||||
|
||||
The [source code](examples/demo.rs) of the demo gif.
|
||||
|
||||
### Widgets
|
||||
|
||||
The library comes with the following list of widgets:
|
||||
@@ -50,14 +54,15 @@ The library comes with the following list of widgets:
|
||||
Click on each item to see the source of the example. Run the examples with with
|
||||
cargo (e.g. to run the demo `cargo run --example demo`), and quit by pressing `q`.
|
||||
|
||||
### Demo
|
||||
### Third-party widgets
|
||||
|
||||
The [source code](examples/demo.rs) of the demo gif.
|
||||
* [tui-logger](https://github.com/gin66/tui-logger)
|
||||
|
||||
### Alternatives
|
||||
|
||||
You might want to checkout [Cursive](https://github.com/gyscos/Cursive) for an
|
||||
alternative solution to build text user interfaces in Rust.
|
||||
|
||||
## License
|
||||
|
||||
[MIT](LICENSE)
|
||||
|
||||
## Author
|
||||
|
||||
Florian Dehau
|
||||
|
||||
@@ -2,18 +2,18 @@ extern crate termion;
|
||||
extern crate tui;
|
||||
|
||||
use std::io;
|
||||
use std::sync::mpsc;
|
||||
use std::thread;
|
||||
use std::time;
|
||||
use std::sync::mpsc;
|
||||
|
||||
use termion::event;
|
||||
use termion::input::TermRead;
|
||||
|
||||
use tui::Terminal;
|
||||
use tui::backend::MouseBackend;
|
||||
use tui::widgets::{BarChart, Block, Borders, Widget};
|
||||
use tui::layout::{Direction, Group, Rect, Size};
|
||||
use tui::style::{Color, Modifier, Style};
|
||||
use tui::widgets::{BarChart, Block, Borders, Widget};
|
||||
use tui::Terminal;
|
||||
|
||||
struct App<'a> {
|
||||
size: Rect,
|
||||
|
||||
@@ -5,11 +5,11 @@ use std::io;
|
||||
use termion::event;
|
||||
use termion::input::TermRead;
|
||||
|
||||
use tui::Terminal;
|
||||
use tui::backend::MouseBackend;
|
||||
use tui::widgets::{Block, Borders, Widget};
|
||||
use tui::layout::{Direction, Group, Rect, Size};
|
||||
use tui::style::{Color, Modifier, Style};
|
||||
use tui::widgets::{Block, Borders, Widget};
|
||||
use tui::Terminal;
|
||||
|
||||
fn main() {
|
||||
let mut terminal = Terminal::new(MouseBackend::new().unwrap()).unwrap();
|
||||
|
||||
@@ -2,19 +2,19 @@ extern crate termion;
|
||||
extern crate tui;
|
||||
|
||||
use std::io;
|
||||
use std::sync::mpsc;
|
||||
use std::thread;
|
||||
use std::time;
|
||||
use std::sync::mpsc;
|
||||
|
||||
use termion::event;
|
||||
use termion::input::TermRead;
|
||||
|
||||
use tui::Terminal;
|
||||
use tui::backend::MouseBackend;
|
||||
use tui::widgets::{Block, Borders, Widget};
|
||||
use tui::widgets::canvas::{Canvas, Line, Map, MapResolution};
|
||||
use tui::layout::{Direction, Group, Rect, Size};
|
||||
use tui::style::Color;
|
||||
use tui::widgets::canvas::{Canvas, Line, Map, MapResolution};
|
||||
use tui::widgets::{Block, Borders, Widget};
|
||||
use tui::Terminal;
|
||||
|
||||
struct App {
|
||||
size: Rect,
|
||||
|
||||
@@ -5,18 +5,18 @@ mod util;
|
||||
use util::*;
|
||||
|
||||
use std::io;
|
||||
use std::sync::mpsc;
|
||||
use std::thread;
|
||||
use std::time;
|
||||
use std::sync::mpsc;
|
||||
|
||||
use termion::event;
|
||||
use termion::input::TermRead;
|
||||
|
||||
use tui::Terminal;
|
||||
use tui::backend::MouseBackend;
|
||||
use tui::widgets::{Axis, Block, Borders, Chart, Dataset, Marker, Widget};
|
||||
use tui::layout::Rect;
|
||||
use tui::style::{Color, Modifier, Style};
|
||||
use tui::widgets::{Axis, Block, Borders, Chart, Dataset, Marker, Widget};
|
||||
use tui::Terminal;
|
||||
|
||||
struct App {
|
||||
size: Rect,
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
extern crate tui;
|
||||
|
||||
use tui::Terminal;
|
||||
use tui::backend::MouseBackend;
|
||||
use tui::widgets::Widget;
|
||||
use tui::buffer::Buffer;
|
||||
use tui::layout::Rect;
|
||||
use tui::style::Style;
|
||||
use tui::widgets::Widget;
|
||||
use tui::Terminal;
|
||||
|
||||
struct Label<'a> {
|
||||
text: &'a str,
|
||||
|
||||
@@ -7,20 +7,20 @@ extern crate tui;
|
||||
mod util;
|
||||
|
||||
use std::io;
|
||||
use std::sync::mpsc;
|
||||
use std::thread;
|
||||
use std::time;
|
||||
use std::sync::mpsc;
|
||||
|
||||
use termion::event;
|
||||
use termion::input::TermRead;
|
||||
|
||||
use tui::Terminal;
|
||||
use tui::backend::MouseBackend;
|
||||
use tui::widgets::{Axis, BarChart, Block, Borders, Chart, Dataset, Gauge, Item, List, Marker,
|
||||
Paragraph, Row, SelectableList, Sparkline, Table, Tabs, Widget};
|
||||
use tui::widgets::canvas::{Canvas, Line, Map, MapResolution};
|
||||
use tui::layout::{Direction, Group, Rect, Size};
|
||||
use tui::style::{Color, Modifier, Style};
|
||||
use tui::widgets::canvas::{Canvas, Line, Map, MapResolution};
|
||||
use tui::widgets::{Axis, BarChart, Block, Borders, Chart, Dataset, Gauge, Item, List, Marker,
|
||||
Paragraph, Row, SelectableList, Sparkline, Table, Tabs, Widget};
|
||||
use tui::Terminal;
|
||||
|
||||
use util::*;
|
||||
|
||||
|
||||
@@ -2,18 +2,18 @@ extern crate termion;
|
||||
extern crate tui;
|
||||
|
||||
use std::io;
|
||||
use std::sync::mpsc;
|
||||
use std::thread;
|
||||
use std::time;
|
||||
use std::sync::mpsc;
|
||||
|
||||
use termion::event;
|
||||
use termion::input::TermRead;
|
||||
|
||||
use tui::Terminal;
|
||||
use tui::backend::MouseBackend;
|
||||
use tui::widgets::{Block, Borders, Gauge, Widget};
|
||||
use tui::layout::{Direction, Group, Rect, Size};
|
||||
use tui::style::{Color, Modifier, Style};
|
||||
use tui::widgets::{Block, Borders, Gauge, Widget};
|
||||
use tui::Terminal;
|
||||
|
||||
struct App {
|
||||
size: Rect,
|
||||
|
||||
@@ -4,16 +4,16 @@ extern crate termion;
|
||||
extern crate tui;
|
||||
|
||||
use std::io;
|
||||
use std::thread;
|
||||
use std::sync::mpsc;
|
||||
use std::thread;
|
||||
|
||||
use termion::event;
|
||||
use termion::input::TermRead;
|
||||
|
||||
use tui::Terminal;
|
||||
use tui::backend::MouseBackend;
|
||||
use tui::widgets::{Block, Borders, Widget};
|
||||
use tui::layout::{Direction, Group, Rect, Size};
|
||||
use tui::widgets::{Block, Borders, Widget};
|
||||
use tui::Terminal;
|
||||
|
||||
struct App {
|
||||
size: Rect,
|
||||
|
||||
@@ -2,18 +2,18 @@ extern crate termion;
|
||||
extern crate tui;
|
||||
|
||||
use std::io;
|
||||
use std::sync::mpsc;
|
||||
use std::thread;
|
||||
use std::time;
|
||||
use std::sync::mpsc;
|
||||
|
||||
use termion::event;
|
||||
use termion::input::TermRead;
|
||||
|
||||
use tui::Terminal;
|
||||
use tui::backend::MouseBackend;
|
||||
use tui::widgets::{Block, Borders, Item, List, SelectableList, Widget};
|
||||
use tui::layout::{Direction, Group, Rect, Size};
|
||||
use tui::layout::{Corner, Direction, Group, Rect, Size};
|
||||
use tui::style::{Color, Modifier, Style};
|
||||
use tui::widgets::{Block, Borders, Item, List, SelectableList, Widget};
|
||||
use tui::Terminal;
|
||||
|
||||
struct App<'a> {
|
||||
size: Rect,
|
||||
@@ -183,6 +183,7 @@ fn draw(t: &mut Terminal<MouseBackend>, app: &App) {
|
||||
});
|
||||
List::new(events)
|
||||
.block(Block::default().borders(Borders::ALL).title("List"))
|
||||
.start_corner(Corner::BottomLeft)
|
||||
.render(t, &chunks[1]);
|
||||
}
|
||||
});
|
||||
|
||||
@@ -5,11 +5,11 @@ use std::io;
|
||||
use termion::event;
|
||||
use termion::input::TermRead;
|
||||
|
||||
use tui::Terminal;
|
||||
use tui::backend::MouseBackend;
|
||||
use tui::widgets::{Block, Paragraph, Widget};
|
||||
use tui::layout::{Direction, Group, Rect, Size};
|
||||
use tui::style::{Color, Style};
|
||||
use tui::style::{Alignment, Color, Style};
|
||||
use tui::widgets::{Block, Paragraph, Widget};
|
||||
use tui::Terminal;
|
||||
|
||||
fn main() {
|
||||
let mut terminal = Terminal::new(MouseBackend::new().unwrap()).unwrap();
|
||||
@@ -44,13 +44,46 @@ fn draw(t: &mut Terminal<MouseBackend>, size: &Rect) {
|
||||
Group::default()
|
||||
.direction(Direction::Vertical)
|
||||
.margin(5)
|
||||
.sizes(&[Size::Percent(100)])
|
||||
.sizes(&[Size::Percent(30), Size::Percent(30), Size::Percent(30)])
|
||||
.render(t, size, |t, chunks| {
|
||||
Group::default()
|
||||
.direction(Direction::Horizontal)
|
||||
.sizes(&[Size::Percent(100)])
|
||||
.render(t, &chunks[0], |t, chunks| {
|
||||
Paragraph::default()
|
||||
.alignment(Alignment::Left)
|
||||
.text(
|
||||
"This is a line\n{fg=red This is a line}\n{bg=red This is a \
|
||||
line}\n{mod=italic This is a line}\n{mod=bold This is a \
|
||||
line}\n{mod=crossed_out This is a line}\n{mod=invert This is a \
|
||||
line}\n{mod=underline This is a \
|
||||
line}\n{bg=green;fg=yellow;mod=italic This is a line}\n",
|
||||
)
|
||||
.render(t, &chunks[0]);
|
||||
});
|
||||
Group::default()
|
||||
.direction(Direction::Horizontal)
|
||||
.sizes(&[Size::Percent(100)])
|
||||
.render(t, &chunks[1], |t, chunks| {
|
||||
Paragraph::default()
|
||||
.alignment(Alignment::Center)
|
||||
.wrap(true)
|
||||
.text(
|
||||
"This is a line\n{fg=red This is a line}\n{bg=red This is a \
|
||||
line}\n{mod=italic This is a line}\n{mod=bold This is a \
|
||||
line}\n{mod=crossed_out This is a line}\n{mod=invert This is a \
|
||||
line}\n{mod=underline This is a \
|
||||
line}\n{bg=green;fg=yellow;mod=italic This is a line}\n",
|
||||
)
|
||||
.render(t, &chunks[0]);
|
||||
});
|
||||
Group::default()
|
||||
.direction(Direction::Horizontal)
|
||||
.sizes(&[Size::Percent(100)])
|
||||
.render(t, &chunks[2], |t, chunks| {
|
||||
Paragraph::default()
|
||||
.alignment(Alignment::Right)
|
||||
.wrap(true)
|
||||
.text(
|
||||
"This is a line\n{fg=red This is a line}\n{bg=red This is a \
|
||||
line}\n{mod=italic This is a line}\n{mod=bold This is a \
|
||||
|
||||
@@ -1,14 +1,14 @@
|
||||
extern crate rustbox;
|
||||
extern crate tui;
|
||||
|
||||
use std::error::Error;
|
||||
use rustbox::Key;
|
||||
use std::error::Error;
|
||||
|
||||
use tui::Terminal;
|
||||
use tui::backend::RustboxBackend;
|
||||
use tui::widgets::{Block, Borders, Paragraph, Widget};
|
||||
use tui::layout::{Direction, Group, Size};
|
||||
use tui::style::{Color, Modifier, Style};
|
||||
use tui::widgets::{Block, Borders, Paragraph, Widget};
|
||||
use tui::Terminal;
|
||||
|
||||
fn main() {
|
||||
let mut terminal = Terminal::new(RustboxBackend::new().unwrap()).unwrap();
|
||||
|
||||
@@ -5,18 +5,18 @@ mod util;
|
||||
use util::*;
|
||||
|
||||
use std::io;
|
||||
use std::sync::mpsc;
|
||||
use std::thread;
|
||||
use std::time;
|
||||
use std::sync::mpsc;
|
||||
|
||||
use termion::event;
|
||||
use termion::input::TermRead;
|
||||
|
||||
use tui::Terminal;
|
||||
use tui::backend::MouseBackend;
|
||||
use tui::widgets::{Block, Borders, Sparkline, Widget};
|
||||
use tui::layout::{Direction, Group, Rect, Size};
|
||||
use tui::style::{Color, Style};
|
||||
use tui::widgets::{Block, Borders, Sparkline, Widget};
|
||||
use tui::Terminal;
|
||||
|
||||
struct App {
|
||||
size: Rect,
|
||||
|
||||
@@ -6,11 +6,11 @@ use std::io;
|
||||
use termion::event;
|
||||
use termion::input::TermRead;
|
||||
|
||||
use tui::Terminal;
|
||||
use tui::backend::MouseBackend;
|
||||
use tui::widgets::{Block, Borders, Row, Table, Widget};
|
||||
use tui::layout::{Direction, Group, Rect, Size};
|
||||
use tui::style::{Color, Modifier, Style};
|
||||
use tui::widgets::{Block, Borders, Row, Table, Widget};
|
||||
use tui::Terminal;
|
||||
|
||||
struct App<'a> {
|
||||
size: Rect,
|
||||
|
||||
@@ -8,11 +8,11 @@ use std::io;
|
||||
use termion::event;
|
||||
use termion::input::TermRead;
|
||||
|
||||
use tui::Terminal;
|
||||
use tui::backend::MouseBackend;
|
||||
use tui::widgets::{Block, Borders, Tabs, Widget};
|
||||
use tui::layout::{Direction, Group, Rect, Size};
|
||||
use tui::style::{Color, Style};
|
||||
use tui::widgets::{Block, Borders, Tabs, Widget};
|
||||
use tui::Terminal;
|
||||
|
||||
struct App<'a> {
|
||||
size: Rect,
|
||||
|
||||
@@ -13,17 +13,17 @@ extern crate termion;
|
||||
extern crate tui;
|
||||
|
||||
use std::io;
|
||||
use std::thread;
|
||||
use std::sync::mpsc;
|
||||
use std::thread;
|
||||
|
||||
use termion::event;
|
||||
use termion::input::TermRead;
|
||||
|
||||
use tui::Terminal;
|
||||
use tui::backend::MouseBackend;
|
||||
use tui::widgets::{Block, Borders, Item, List, Paragraph, Widget};
|
||||
use tui::layout::{Direction, Group, Rect, Size};
|
||||
use tui::style::{Color, Style};
|
||||
use tui::widgets::{Block, Borders, Item, List, Paragraph, Widget};
|
||||
use tui::Terminal;
|
||||
|
||||
struct App {
|
||||
size: Rect,
|
||||
|
||||
@@ -1,65 +0,0 @@
|
||||
#!/bin/bash
|
||||
|
||||
set -e
|
||||
|
||||
USAGE="$0 --name=STRING [--channel=STRING]"
|
||||
|
||||
# Default values
|
||||
CARGO="cargo"
|
||||
NAME=""
|
||||
CHANNEL=""
|
||||
|
||||
# Parse args
|
||||
for i in "$@"; do
|
||||
case $i in
|
||||
--name=*)
|
||||
NAME="${i#*=}"
|
||||
shift
|
||||
;;
|
||||
--channel=*)
|
||||
CHANNEL="${i#*=}"
|
||||
shift
|
||||
;;
|
||||
*)
|
||||
echo "$USAGE"
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
done
|
||||
|
||||
current_version() {
|
||||
local crate="$1"
|
||||
$CARGO install --list | \
|
||||
grep "$crate" | \
|
||||
head -n 1 | \
|
||||
cut -d ' ' -f 2 | \
|
||||
sed 's/v\(.*\):/\1/g'
|
||||
}
|
||||
|
||||
upstream_version() {
|
||||
local crate="$1"
|
||||
$CARGO search "$crate" | \
|
||||
grep "$crate" | \
|
||||
head -n 1 | \
|
||||
cut -d' ' -f 3 | \
|
||||
sed 's/"//g'
|
||||
}
|
||||
|
||||
if [ "$NAME" == "" ]; then
|
||||
echo "$USAGE"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [ "$CHANNEL" != "" ]; then
|
||||
CARGO+=" +$CHANNEL"
|
||||
fi
|
||||
|
||||
CURRENT_VERSION=$(current_version "$NAME")
|
||||
UPSTREAM_VERSION=$(upstream_version "$NAME")
|
||||
|
||||
if [[ "$CURRENT_VERSION" != "$UPSTREAM_VERSION" ]]; then
|
||||
echo "WARN: Latest version of $NAME not installed: $CURRENT_VERSION -> $UPSTREAM_VERSION"
|
||||
$CARGO install --force "$NAME"
|
||||
else
|
||||
echo "INFO: Latest version of $NAME already installed ($CURRENT_VERSION)"
|
||||
fi
|
||||
@@ -1,9 +0,0 @@
|
||||
#!/bin/bash
|
||||
|
||||
set -eu
|
||||
|
||||
export PATH="$PATH:$HOME/.cargo/bin"
|
||||
if [[ "$TRAVIS_RUST_VERSION" == "nightly" ]]; then
|
||||
export LD_LIBRARY_PATH="$(rustc +nightly --print sysroot)/lib:${LD_LIBRARY_PATH:-""}"
|
||||
make install-tools
|
||||
fi
|
||||
@@ -1,9 +0,0 @@
|
||||
#!/bin/bash
|
||||
|
||||
set -eu
|
||||
|
||||
make build
|
||||
make test
|
||||
if [[ "$TRAVIS_RUST_VERSION" == "nightly" ]]; then
|
||||
make lint
|
||||
fi
|
||||
@@ -11,7 +11,7 @@ pub use self::rustbox::RustboxBackend;
|
||||
#[cfg(feature = "termion")]
|
||||
mod termion;
|
||||
#[cfg(feature = "termion")]
|
||||
pub use self::termion::{MouseBackend, RawBackend, TermionBackend, AlternateScreenBackend};
|
||||
pub use self::termion::{AlternateScreenBackend, MouseBackend, RawBackend, TermionBackend};
|
||||
|
||||
pub trait Backend {
|
||||
fn draw<'a, I>(&mut self, content: I) -> Result<(), io::Error>
|
||||
|
||||
@@ -85,6 +85,7 @@ impl Into<rustbox::Color> for Color {
|
||||
Color::Magenta | Color::LightMagenta => rustbox::Color::Magenta,
|
||||
Color::Cyan | Color::LightCyan => rustbox::Color::Cyan,
|
||||
Color::White => rustbox::Color::White,
|
||||
Color::Blue | Color::LightBlue => rustbox::Color::Blue,
|
||||
Color::Rgb(r, g, b) => rustbox::Color::Byte(rgb_to_byte(r, g, b)),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -157,33 +157,33 @@ where
|
||||
}
|
||||
|
||||
macro_rules! termion_fg {
|
||||
($color:ident) => (
|
||||
($color:ident) => {
|
||||
format!("{}", termion::color::Fg(termion::color::$color))
|
||||
);
|
||||
};
|
||||
}
|
||||
|
||||
macro_rules! termion_fg_rgb {
|
||||
($r:expr, $g:expr, $b:expr) => (
|
||||
($r:expr, $g:expr, $b:expr) => {
|
||||
format!("{}", termion::color::Fg(termion::color::Rgb($r, $g, $b)))
|
||||
);
|
||||
};
|
||||
}
|
||||
|
||||
macro_rules! termion_bg {
|
||||
($color:ident) => (
|
||||
($color:ident) => {
|
||||
format!("{}", termion::color::Bg(termion::color::$color))
|
||||
);
|
||||
};
|
||||
}
|
||||
|
||||
macro_rules! termion_bg_rgb {
|
||||
($r:expr, $g:expr, $b:expr) => (
|
||||
($r:expr, $g:expr, $b:expr) => {
|
||||
format!("{}", termion::color::Bg(termion::color::Rgb($r, $g, $b)))
|
||||
);
|
||||
};
|
||||
}
|
||||
|
||||
macro_rules! termion_modifier {
|
||||
($style:ident) => (
|
||||
($style:ident) => {
|
||||
format!("{}", termion::style::$style)
|
||||
);
|
||||
};
|
||||
}
|
||||
|
||||
impl Color {
|
||||
|
||||
@@ -1,14 +1,22 @@
|
||||
use std::cmp::{max, min};
|
||||
use std::collections::HashMap;
|
||||
|
||||
use cassowary::{Constraint, Expression, Solver, Variable};
|
||||
use cassowary::WeightedRelation::*;
|
||||
use cassowary::strength::{REQUIRED, WEAK};
|
||||
use cassowary::WeightedRelation::*;
|
||||
use cassowary::{Constraint, Expression, Solver, Variable};
|
||||
|
||||
use terminal::Terminal;
|
||||
use backend::Backend;
|
||||
use terminal::Terminal;
|
||||
|
||||
#[derive(Debug, Hash, Clone, Copy, PartialEq, Eq)]
|
||||
pub enum Corner {
|
||||
TopLeft,
|
||||
TopRight,
|
||||
BottomRight,
|
||||
BottomLeft,
|
||||
}
|
||||
|
||||
#[derive(Debug, Hash, Clone, PartialEq, Eq)]
|
||||
pub enum Direction {
|
||||
Horizontal,
|
||||
Vertical,
|
||||
|
||||
@@ -156,17 +156,18 @@
|
||||
#[macro_use]
|
||||
extern crate bitflags;
|
||||
extern crate cassowary;
|
||||
extern crate itertools;
|
||||
#[macro_use]
|
||||
extern crate log;
|
||||
extern crate unicode_segmentation;
|
||||
extern crate unicode_width;
|
||||
|
||||
pub mod buffer;
|
||||
pub mod symbols;
|
||||
pub mod backend;
|
||||
pub mod buffer;
|
||||
pub mod layout;
|
||||
pub mod style;
|
||||
pub mod symbols;
|
||||
pub mod terminal;
|
||||
pub mod widgets;
|
||||
pub mod style;
|
||||
pub mod layout;
|
||||
|
||||
pub use self::terminal::Terminal;
|
||||
|
||||
@@ -40,6 +40,13 @@ pub enum Modifier {
|
||||
Underline,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Copy, PartialEq)]
|
||||
pub enum Alignment {
|
||||
Left,
|
||||
Center,
|
||||
Right,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Copy, PartialEq)]
|
||||
pub struct Style {
|
||||
pub fg: Color,
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
use std::io;
|
||||
use std::collections::HashMap;
|
||||
use std::io;
|
||||
|
||||
use backend::Backend;
|
||||
use buffer::Buffer;
|
||||
|
||||
@@ -2,11 +2,11 @@ use std::cmp::{max, min};
|
||||
|
||||
use unicode_width::UnicodeWidthStr;
|
||||
|
||||
use widgets::{Block, Widget};
|
||||
use buffer::Buffer;
|
||||
use layout::Rect;
|
||||
use style::Style;
|
||||
use symbols::bar;
|
||||
use widgets::{Block, Widget};
|
||||
|
||||
/// Display multiple bars in a single widgets
|
||||
///
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
use buffer::Buffer;
|
||||
use layout::Rect;
|
||||
use style::Style;
|
||||
use widgets::{Borders, Widget};
|
||||
use symbols::line;
|
||||
use widgets::{Borders, Widget};
|
||||
|
||||
/// Base widget to be used with all upper level ones. It may be used to display a box border around
|
||||
/// the widget and/or add a title.
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
use widgets::canvas::Shape;
|
||||
use style::Color;
|
||||
use widgets::canvas::points::PointsIterator;
|
||||
use widgets::canvas::world::{WORLD_HIGH_RESOLUTION, WORLD_LOW_RESOLUTION};
|
||||
use style::Color;
|
||||
use widgets::canvas::Shape;
|
||||
|
||||
#[derive(Clone, Copy)]
|
||||
pub enum MapResolution {
|
||||
|
||||
@@ -1,16 +1,16 @@
|
||||
mod points;
|
||||
mod line;
|
||||
mod map;
|
||||
mod points;
|
||||
mod world;
|
||||
|
||||
pub use self::points::Points;
|
||||
pub use self::line::Line;
|
||||
pub use self::map::{Map, MapResolution};
|
||||
pub use self::points::Points;
|
||||
|
||||
use style::{Color, Style};
|
||||
use buffer::Buffer;
|
||||
use widgets::{Block, Widget};
|
||||
use layout::Rect;
|
||||
use style::{Color, Style};
|
||||
use widgets::{Block, Widget};
|
||||
|
||||
pub const DOTS: [[u16; 2]; 4] = [
|
||||
[0x0001, 0x0008],
|
||||
|
||||
@@ -2,12 +2,12 @@ use std::cmp::max;
|
||||
|
||||
use unicode_width::UnicodeWidthStr;
|
||||
|
||||
use widgets::{Block, Borders, Widget};
|
||||
use widgets::canvas::{Canvas, Points};
|
||||
use buffer::Buffer;
|
||||
use layout::Rect;
|
||||
use style::Style;
|
||||
use symbols;
|
||||
use widgets::canvas::{Canvas, Points};
|
||||
use widgets::{Block, Borders, Widget};
|
||||
|
||||
/// An X or Y axis for the chart widget
|
||||
pub struct Axis<'a, L>
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
use unicode_width::UnicodeWidthStr;
|
||||
|
||||
use widgets::{Block, Widget};
|
||||
use buffer::Buffer;
|
||||
use style::{Color, Style};
|
||||
use layout::Rect;
|
||||
use style::{Color, Style};
|
||||
use widgets::{Block, Widget};
|
||||
|
||||
/// A widget to display a task progress.
|
||||
///
|
||||
|
||||
@@ -1,13 +1,13 @@
|
||||
use std::iter;
|
||||
use std::fmt::Display;
|
||||
use std::iter;
|
||||
use std::iter::Iterator;
|
||||
|
||||
use unicode_width::UnicodeWidthStr;
|
||||
|
||||
use buffer::Buffer;
|
||||
use widgets::{Block, Widget};
|
||||
use layout::Rect;
|
||||
use layout::{Corner, Rect};
|
||||
use style::Style;
|
||||
use widgets::{Block, Widget};
|
||||
|
||||
pub enum Item<'i, D: 'i> {
|
||||
Data(D),
|
||||
@@ -21,6 +21,7 @@ where
|
||||
block: Option<Block<'b>>,
|
||||
items: L,
|
||||
style: Style,
|
||||
start_corner: Corner,
|
||||
}
|
||||
|
||||
impl<'b, 'i, L, D> Default for List<'b, 'i, L, D>
|
||||
@@ -32,6 +33,7 @@ where
|
||||
block: None,
|
||||
items: L::default(),
|
||||
style: Default::default(),
|
||||
start_corner: Corner::TopLeft,
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -45,6 +47,7 @@ where
|
||||
block: None,
|
||||
items: items,
|
||||
style: Default::default(),
|
||||
start_corner: Corner::TopLeft,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -65,6 +68,11 @@ where
|
||||
self.style = style;
|
||||
self
|
||||
}
|
||||
|
||||
pub fn start_corner(&'b mut self, corner: Corner) -> &mut List<'b, 'i, L, D> {
|
||||
self.start_corner = corner;
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
impl<'b, 'i, L, D> Widget for List<'b, 'i, L, D>
|
||||
@@ -92,24 +100,24 @@ where
|
||||
.enumerate()
|
||||
.take(list_area.height as usize)
|
||||
{
|
||||
let (x, y) = match self.start_corner {
|
||||
Corner::TopLeft => (list_area.left(), list_area.top() + i as u16),
|
||||
Corner::BottomLeft => (list_area.left(), list_area.bottom() - (i + 1) as u16),
|
||||
// Not supported
|
||||
_ => (list_area.left(), list_area.top() + i as u16),
|
||||
};
|
||||
match item {
|
||||
Item::Data(ref v) => {
|
||||
buf.set_stringn(
|
||||
list_area.left(),
|
||||
list_area.top() + i as u16,
|
||||
x,
|
||||
y,
|
||||
&format!("{}", v),
|
||||
list_area.width as usize,
|
||||
&Style::default(),
|
||||
);
|
||||
}
|
||||
Item::StyledData(ref v, s) => {
|
||||
buf.set_stringn(
|
||||
list_area.left(),
|
||||
list_area.top() + i as u16,
|
||||
&format!("{}", v),
|
||||
list_area.width as usize,
|
||||
s,
|
||||
);
|
||||
buf.set_stringn(x, y, &format!("{}", v), list_area.width as usize, s);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@@ -1,29 +1,29 @@
|
||||
mod block;
|
||||
mod paragraph;
|
||||
mod list;
|
||||
mod gauge;
|
||||
mod sparkline;
|
||||
mod chart;
|
||||
mod barchart;
|
||||
mod tabs;
|
||||
mod table;
|
||||
mod block;
|
||||
pub mod canvas;
|
||||
mod chart;
|
||||
mod gauge;
|
||||
mod list;
|
||||
mod paragraph;
|
||||
mod sparkline;
|
||||
mod table;
|
||||
mod tabs;
|
||||
|
||||
pub use self::block::Block;
|
||||
pub use self::paragraph::Paragraph;
|
||||
pub use self::list::{Item, List, SelectableList};
|
||||
pub use self::gauge::Gauge;
|
||||
pub use self::sparkline::Sparkline;
|
||||
pub use self::chart::{Axis, Chart, Dataset, Marker};
|
||||
pub use self::barchart::BarChart;
|
||||
pub use self::tabs::Tabs;
|
||||
pub use self::block::Block;
|
||||
pub use self::chart::{Axis, Chart, Dataset, Marker};
|
||||
pub use self::gauge::Gauge;
|
||||
pub use self::list::{Item, List, SelectableList};
|
||||
pub use self::paragraph::Paragraph;
|
||||
pub use self::sparkline::Sparkline;
|
||||
pub use self::table::{Row, Table};
|
||||
pub use self::tabs::Tabs;
|
||||
|
||||
use backend::Backend;
|
||||
use buffer::Buffer;
|
||||
use layout::Rect;
|
||||
use terminal::Terminal;
|
||||
use backend::Backend;
|
||||
use style::Color;
|
||||
use terminal::Terminal;
|
||||
|
||||
/// Bitflags that can be composed to set the visible borders essentially on the block widget.
|
||||
bitflags! {
|
||||
|
||||
@@ -1,10 +1,11 @@
|
||||
use itertools::{multipeek, MultiPeek};
|
||||
use unicode_segmentation::UnicodeSegmentation;
|
||||
use unicode_width::UnicodeWidthStr;
|
||||
|
||||
use widgets::{Block, Widget};
|
||||
use buffer::Buffer;
|
||||
use layout::Rect;
|
||||
use style::{Color, Modifier, Style};
|
||||
use style::{Alignment, Color, Modifier, Style};
|
||||
use widgets::{Block, Widget};
|
||||
|
||||
/// A widget to display some text. You can specify colors using commands embedded in
|
||||
/// the text such as "{[color] [text]}".
|
||||
@@ -36,6 +37,8 @@ pub struct Paragraph<'a> {
|
||||
raw: bool,
|
||||
/// Scroll
|
||||
scroll: u16,
|
||||
/// Aligenment of the text
|
||||
alignment: Alignment,
|
||||
}
|
||||
|
||||
impl<'a> Default for Paragraph<'a> {
|
||||
@@ -47,6 +50,7 @@ impl<'a> Default for Paragraph<'a> {
|
||||
raw: false,
|
||||
text: "",
|
||||
scroll: 0,
|
||||
alignment: Alignment::Left,
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -81,6 +85,11 @@ impl<'a> Paragraph<'a> {
|
||||
self.scroll = offset;
|
||||
self
|
||||
}
|
||||
|
||||
pub fn alignment(&mut self, alignment: Alignment) -> &mut Paragraph<'a> {
|
||||
self.alignment = alignment;
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
struct Parser<'a, T>
|
||||
@@ -236,8 +245,6 @@ impl<'a> Widget for Paragraph<'a> {
|
||||
|
||||
self.background(&text_area, buf, self.style.bg);
|
||||
|
||||
let mut x = 0;
|
||||
let mut y = 0;
|
||||
let graphemes = UnicodeSegmentation::graphemes(self.text, true);
|
||||
let styled: Box<Iterator<Item = (&str, Style)>> = if self.raw {
|
||||
Box::new(graphemes.map(|g| (g, self.style)))
|
||||
@@ -245,38 +252,83 @@ impl<'a> Widget for Paragraph<'a> {
|
||||
Box::new(Parser::new(graphemes, self.style))
|
||||
};
|
||||
|
||||
let mut styled = multipeek(styled);
|
||||
|
||||
fn get_cur_line_len<'a, I: Iterator<Item = (&'a str, Style)>>(
|
||||
styled: &mut MultiPeek<I>,
|
||||
) -> u16 {
|
||||
let mut line_len = 0;
|
||||
while match &styled.peek() {
|
||||
Some(&(x, _)) => x != "\n",
|
||||
None => false,
|
||||
} {
|
||||
line_len += 1;
|
||||
}
|
||||
line_len
|
||||
};
|
||||
|
||||
let mut x = match self.alignment {
|
||||
Alignment::Center => {
|
||||
(text_area.width / 2).saturating_sub(get_cur_line_len(&mut styled) / 2)
|
||||
}
|
||||
Alignment::Right => (text_area.width).saturating_sub(get_cur_line_len(&mut styled)),
|
||||
Alignment::Left => 0,
|
||||
};
|
||||
let mut y = 0;
|
||||
|
||||
let mut remove_leading_whitespaces = false;
|
||||
for (string, style) in styled {
|
||||
if string == "\n" {
|
||||
x = 0;
|
||||
y += 1;
|
||||
continue;
|
||||
}
|
||||
if x >= text_area.width {
|
||||
if self.wrapping {
|
||||
x = 0;
|
||||
loop {
|
||||
if let Some((string, style)) = styled.next() {
|
||||
if string == "\n" {
|
||||
x = match self.alignment {
|
||||
Alignment::Center => {
|
||||
(text_area.width / 2).saturating_sub(get_cur_line_len(&mut styled) / 2)
|
||||
}
|
||||
|
||||
Alignment::Right => {
|
||||
(text_area.width).saturating_sub(get_cur_line_len(&mut styled))
|
||||
}
|
||||
Alignment::Left => 0,
|
||||
};
|
||||
y += 1;
|
||||
remove_leading_whitespaces = true
|
||||
continue;
|
||||
}
|
||||
}
|
||||
if x >= text_area.width {
|
||||
if self.wrapping {
|
||||
x = match self.alignment {
|
||||
Alignment::Center => (text_area.width / 2)
|
||||
.saturating_sub(get_cur_line_len(&mut styled) / 2),
|
||||
|
||||
if remove_leading_whitespaces && string == " " {
|
||||
continue;
|
||||
}
|
||||
remove_leading_whitespaces = false;
|
||||
Alignment::Right => {
|
||||
(text_area.width).saturating_sub(get_cur_line_len(&mut styled) + 1)
|
||||
}
|
||||
Alignment::Left => 0,
|
||||
};
|
||||
y += 1;
|
||||
remove_leading_whitespaces = true
|
||||
}
|
||||
}
|
||||
|
||||
if y > text_area.height + self.scroll - 1 {
|
||||
if remove_leading_whitespaces && string == " " {
|
||||
continue;
|
||||
}
|
||||
remove_leading_whitespaces = false;
|
||||
|
||||
if y > text_area.height + self.scroll - 1 {
|
||||
break;
|
||||
}
|
||||
|
||||
if y < self.scroll {
|
||||
continue;
|
||||
}
|
||||
|
||||
buf.get_mut(text_area.left() + x, text_area.top() + y - self.scroll)
|
||||
.set_symbol(string)
|
||||
.set_style(style);
|
||||
x += string.width() as u16;
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
|
||||
if y < self.scroll {
|
||||
continue;
|
||||
}
|
||||
|
||||
buf.get_mut(text_area.left() + x, text_area.top() + y - self.scroll)
|
||||
.set_symbol(string)
|
||||
.set_style(style);
|
||||
x += string.width() as u16;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
use std::cmp::min;
|
||||
|
||||
use layout::Rect;
|
||||
use buffer::Buffer;
|
||||
use widgets::{Block, Widget};
|
||||
use layout::Rect;
|
||||
use style::Style;
|
||||
use symbols::bar;
|
||||
use widgets::{Block, Widget};
|
||||
|
||||
/// Widget to render a sparkline over one or more lines.
|
||||
///
|
||||
|
||||
@@ -2,9 +2,9 @@ use std::fmt::Display;
|
||||
use std::iter::Iterator;
|
||||
|
||||
use buffer::Buffer;
|
||||
use widgets::{Block, Widget};
|
||||
use layout::Rect;
|
||||
use style::Style;
|
||||
use widgets::{Block, Widget};
|
||||
|
||||
/// Holds data to be displayed in a Table widget
|
||||
pub enum Row<'i, D, I>
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
use unicode_width::UnicodeWidthStr;
|
||||
|
||||
use widgets::{Block, Widget};
|
||||
use buffer::Buffer;
|
||||
use layout::Rect;
|
||||
use style::Style;
|
||||
use symbols::line;
|
||||
use widgets::{Block, Widget};
|
||||
|
||||
/// A widget to display available tabs in a multiple panels context.
|
||||
///
|
||||
|
||||
Reference in New Issue
Block a user