mirror of
https://github.com/alexpasmantier/television.git
synced 2025-06-06 11:35:25 +00:00
feat(orientation): add orientation for television #489
This commit is contained in:
parent
be8008e97d
commit
85fe9bb388
@ -50,6 +50,8 @@ show_help_bar = false
|
||||
show_preview_panel = true
|
||||
# Where to place the input bar in the UI (top or bottom)
|
||||
input_bar_position = "top"
|
||||
# What orientation should tv be (landscape or portrait)
|
||||
orientation = "landscape"
|
||||
# DEPRECATED: title is now always displayed at the top as part of the border
|
||||
# Where to place the preview title in the UI (top or bottom)
|
||||
# preview_title_position = "top"
|
||||
|
@ -1,6 +1,8 @@
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
use crate::screen::layout::{InputPosition, PreviewTitlePosition};
|
||||
use crate::screen::layout::{
|
||||
InputPosition, Orientation, PreviewTitlePosition,
|
||||
};
|
||||
|
||||
use super::themes::DEFAULT_THEME;
|
||||
|
||||
@ -17,6 +19,7 @@ pub struct UiConfig {
|
||||
pub show_preview_panel: bool,
|
||||
#[serde(default)]
|
||||
pub input_bar_position: InputPosition,
|
||||
pub orientation: Orientation,
|
||||
pub preview_title_position: Option<PreviewTitlePosition>,
|
||||
pub theme: String,
|
||||
pub custom_header: Option<String>,
|
||||
@ -31,6 +34,7 @@ impl Default for UiConfig {
|
||||
show_help_bar: false,
|
||||
show_preview_panel: true,
|
||||
input_bar_position: InputPosition::Top,
|
||||
orientation: Orientation::Landscape,
|
||||
preview_title_position: None,
|
||||
theme: String::from(DEFAULT_THEME),
|
||||
custom_header: None,
|
||||
|
@ -241,12 +241,13 @@ pub fn draw(ctx: &Ctx, f: &mut Frame<'_>, area: Rect) -> Result<Layout> {
|
||||
&ctx.tv_state.spinner,
|
||||
&ctx.colorscheme,
|
||||
&ctx.config.ui.custom_header,
|
||||
&ctx.config.ui.input_bar_position,
|
||||
)?;
|
||||
|
||||
if layout.preview_window.is_some() {
|
||||
if let Some(preview_rect) = layout.preview_window {
|
||||
draw_preview_content_block(
|
||||
f,
|
||||
layout.preview_window.unwrap(),
|
||||
preview_rect,
|
||||
&ctx.tv_state.preview_state,
|
||||
ctx.config.ui.use_nerd_font_icons,
|
||||
&ctx.colorscheme,
|
||||
|
@ -6,12 +6,16 @@ use ratatui::{
|
||||
},
|
||||
style::{Style, Stylize},
|
||||
text::{Line, Span},
|
||||
widgets::{Block, BorderType, Borders, ListState, Paragraph},
|
||||
widgets::{
|
||||
block::Position, Block, BorderType, Borders, ListState, Paragraph,
|
||||
},
|
||||
Frame,
|
||||
};
|
||||
|
||||
use crate::screen::{colors::Colorscheme, spinner::Spinner};
|
||||
|
||||
use super::layout::InputPosition;
|
||||
|
||||
#[allow(clippy::too_many_arguments)]
|
||||
pub fn draw_input_box(
|
||||
f: &mut Frame,
|
||||
@ -25,13 +29,18 @@ pub fn draw_input_box(
|
||||
spinner: &Spinner,
|
||||
colorscheme: &Colorscheme,
|
||||
custom_header: &Option<String>,
|
||||
input_bar_position: &InputPosition,
|
||||
) -> Result<()> {
|
||||
let header = custom_header.as_deref().unwrap_or(channel_name);
|
||||
let input_block = Block::default()
|
||||
.borders(Borders::ALL)
|
||||
.border_type(BorderType::Rounded)
|
||||
.border_style(Style::default().fg(colorscheme.general.border_fg))
|
||||
.title_top(
|
||||
.title_position(match input_bar_position {
|
||||
InputPosition::Top => Position::Top,
|
||||
InputPosition::Bottom => Position::Bottom,
|
||||
})
|
||||
.title(
|
||||
Line::from(String::from(" ") + header + " ")
|
||||
.style(Style::default().fg(colorscheme.mode.channel).bold())
|
||||
.centered(),
|
||||
|
@ -66,6 +66,17 @@ impl Display for InputPosition {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(
|
||||
Debug, Clone, Copy, Deserialize, Serialize, Default, PartialEq, Hash,
|
||||
)]
|
||||
pub enum Orientation {
|
||||
#[serde(rename = "landscape")]
|
||||
#[default]
|
||||
Landscape,
|
||||
#[serde(rename = "portrait")]
|
||||
Portrait,
|
||||
}
|
||||
|
||||
#[derive(
|
||||
Debug, Clone, Copy, Deserialize, Serialize, Default, PartialEq, Hash,
|
||||
)]
|
||||
@ -168,26 +179,57 @@ impl Layout {
|
||||
help_bar_layout = None;
|
||||
}
|
||||
|
||||
// split the main block into 1, 2, or 3 vertical chunks
|
||||
// (results + preview + remote)
|
||||
let mut constraints = vec![Constraint::Fill(1)];
|
||||
if show_preview {
|
||||
constraints.push(Constraint::Fill(1));
|
||||
}
|
||||
if show_remote {
|
||||
// in order to fit with the help bar logo
|
||||
constraints.push(Constraint::Length(24));
|
||||
}
|
||||
let vt_chunks = layout::Layout::default()
|
||||
let remote_constraints = if show_remote {
|
||||
vec![Constraint::Fill(1), Constraint::Length(24)]
|
||||
} else {
|
||||
vec![Constraint::Fill(1)]
|
||||
};
|
||||
let remote_chunks = layout::Layout::default()
|
||||
.direction(Direction::Horizontal)
|
||||
.constraints(constraints)
|
||||
.constraints(remote_constraints)
|
||||
.split(main_rect);
|
||||
|
||||
// left block: results + input field
|
||||
let remote_control = if show_remote {
|
||||
Some(remote_chunks[1])
|
||||
} else {
|
||||
None
|
||||
};
|
||||
|
||||
// split the main block into 1 or 2 chunks
|
||||
// (results + preview)
|
||||
let constraints = if show_preview {
|
||||
vec![Constraint::Fill(1), Constraint::Fill(1)]
|
||||
} else {
|
||||
vec![Constraint::Fill(1)]
|
||||
};
|
||||
|
||||
let main_chunks = layout::Layout::default()
|
||||
.direction(match ui_config.orientation {
|
||||
Orientation::Portrait => Direction::Vertical,
|
||||
Orientation::Landscape => Direction::Horizontal,
|
||||
})
|
||||
.constraints(constraints)
|
||||
.split(remote_chunks[0]);
|
||||
|
||||
// result block: results + input field
|
||||
let results_constraints =
|
||||
vec![Constraint::Min(3), Constraint::Length(3)];
|
||||
|
||||
let left_chunks = layout::Layout::default()
|
||||
let (result_window, preview_window) = if show_preview {
|
||||
match (ui_config.orientation, ui_config.input_bar_position) {
|
||||
(Orientation::Landscape, _)
|
||||
| (Orientation::Portrait, InputPosition::Top) => {
|
||||
(main_chunks[0], Some(main_chunks[1]))
|
||||
}
|
||||
(Orientation::Portrait, InputPosition::Bottom) => {
|
||||
(main_chunks[1], Some(main_chunks[0]))
|
||||
}
|
||||
}
|
||||
} else {
|
||||
(main_chunks[0], None)
|
||||
};
|
||||
|
||||
let result_chunks = layout::Layout::default()
|
||||
.direction(Direction::Vertical)
|
||||
.constraints(match ui_config.input_bar_position {
|
||||
InputPosition::Top => {
|
||||
@ -195,25 +237,10 @@ impl Layout {
|
||||
}
|
||||
InputPosition::Bottom => results_constraints,
|
||||
})
|
||||
.split(vt_chunks[0]);
|
||||
.split(result_window);
|
||||
let (input, results) = match ui_config.input_bar_position {
|
||||
InputPosition::Bottom => (left_chunks[1], left_chunks[0]),
|
||||
InputPosition::Top => (left_chunks[0], left_chunks[1]),
|
||||
};
|
||||
|
||||
// right block: preview title + preview
|
||||
let mut remote_idx = 1;
|
||||
let preview_window = if show_preview {
|
||||
remote_idx += 1;
|
||||
Some(vt_chunks[1])
|
||||
} else {
|
||||
None
|
||||
};
|
||||
|
||||
let remote_control = if show_remote {
|
||||
Some(vt_chunks[remote_idx])
|
||||
} else {
|
||||
None
|
||||
InputPosition::Bottom => (result_chunks[1], result_chunks[0]),
|
||||
InputPosition::Top => (result_chunks[0], result_chunks[1]),
|
||||
};
|
||||
|
||||
Self::new(
|
||||
|
Loading…
x
Reference in New Issue
Block a user