Last active
April 5, 2023 13:12
-
-
Save sophacles/bd7722ffdaca99b7531054676c6c092b to your computer and use it in GitHub Desktop.
block splitting
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
[package] | |
name = "nested_blocks" | |
version = "0.1.0" | |
edition = "2021" | |
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html | |
[dependencies] | |
ratatui = "0.20.1" | |
crossterm = "0.23.2" |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
use crossterm::{ | |
event::{self, Event, KeyCode}, | |
execute, | |
terminal::{disable_raw_mode, enable_raw_mode, EnterAlternateScreen, LeaveAlternateScreen}, | |
}; | |
use ratatui::{ | |
backend::{Backend, CrosstermBackend}, | |
layout::{Constraint, Direction, Layout}, | |
style::{Color, Style}, | |
widgets::{Block, Borders}, | |
Frame, Terminal, | |
}; | |
fn main() { | |
// panic handler to always restore terminal | |
let original_hook = std::panic::take_hook(); | |
std::panic::set_hook(Box::new(move |panic| { | |
let _ = crossterm::terminal::disable_raw_mode(); | |
let _ = crossterm::execute!(std::io::stdout(), LeaveAlternateScreen); | |
original_hook(panic); | |
})); | |
enable_raw_mode().unwrap(); | |
let mut stdout = std::io::stdout(); | |
execute!(stdout, EnterAlternateScreen).unwrap(); | |
let backend = CrosstermBackend::new(stdout); | |
let mut terminal = Terminal::new(backend).unwrap(); | |
loop { | |
let _ = terminal.draw(|f| draw(f)); | |
if let Event::Key(key) = event::read().unwrap() { | |
#[allow(clippy::single_match)] | |
match key.code { | |
KeyCode::Char(_) => { | |
break; | |
} | |
_ => {} | |
}; | |
} | |
} | |
disable_raw_mode().unwrap(); | |
execute!(terminal.backend_mut(), LeaveAlternateScreen).unwrap(); | |
terminal.show_cursor().unwrap(); | |
} | |
fn draw<B: Backend>(frame: &mut Frame<B>) { | |
// start with the area of the terminal window (the frame) | |
let app_area = frame.size(); | |
// split vertically | |
// +--------------------------------+ | |
// | ignore 20% | | |
// +--------------------------------+ | |
// | keep this | | |
// | 60% | | |
// +--------------------------------+ | |
// | ignore 20% | | |
// +--------------------------------+ | |
// | |
// vmid_area is an area, just like the frame size | |
let vmid_area = Layout::default() | |
.direction(Direction::Vertical) | |
.margin(0) | |
.constraints( | |
[ | |
Constraint::Percentage(20), | |
Constraint::Percentage(60), | |
Constraint::Percentage(20), | |
] | |
.as_ref(), | |
) | |
.split(app_area)[1]; | |
// split horizontally in the kept area | |
// The overall splits look like this | |
// +--------------------------------+ | |
// | ignore 20% | | |
// +------+----------------+--------+ | |
// | ign | keep this | ign | | |
// | | 60% | | | |
// +------+----------------+--------+ | |
// | ignore 20% | | |
// +--------------------------------+ | |
let vh_mid_area = Layout::default() | |
.direction(Direction::Horizontal) | |
.margin(0) | |
.constraints( | |
[ | |
Constraint::Percentage(25), | |
Constraint::Percentage(50), | |
Constraint::Percentage(25), | |
] | |
.as_ref(), | |
) | |
.split(vmid_area)[1]; | |
// now create the outer Block. | |
let container = Block::default() | |
.borders(Borders::ALL) | |
.title("outer block") | |
.style(Style::default().bg(Color::Yellow)); | |
// get the area inside the container block. To calculate this, the area that the block | |
// will be rendered to is required as an argument. | |
let inside_container = container.inner(vh_mid_area); | |
// Split the inside area into 2 chunks, left and right. | |
let (left_inside, right_inside) = { | |
let chunks = Layout::default() | |
.direction(Direction::Horizontal) | |
.margin(0) | |
.constraints([Constraint::Percentage(50), Constraint::Percentage(50)].as_ref()) | |
.split(inside_container); | |
(chunks[0], chunks[1]) | |
}; | |
// create the left block with a red background | |
let block_left = Block::default().style(Style::default().bg(Color::Red)); | |
// create the right block with a blue background | |
let block_right = Block::default().style(Style::default().bg(Color::Blue)); | |
// draw everything. | |
frame.render_widget(container, vh_mid_area); | |
frame.render_widget(block_left, left_inside); | |
frame.render_widget(block_right, right_inside); | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment