use crate::core::types::Rect;
use crate::docking::panels::DockPanel;
use crate::layout::{LayoutManager, LayoutNodeId, PanelNode, StyleManager};
use crate::render::RenderContext;
use crate::ui::widgets::composite::panel::input::register_layout_manager_panel;
use crate::ui::widgets::composite::panel::settings::PanelSettings;
use crate::ui::widgets::composite::panel::state::PanelState;
use crate::ui::widgets::composite::panel::style::DefaultPanelStyle;
use crate::ui::widgets::composite::panel::theme::{DefaultPanelTheme, PanelTheme};
use crate::ui::widgets::composite::panel::types::{
ColumnDef, HeaderAction, PanelHeader, PanelRenderKind, PanelView,
};
struct StyledPanelTheme {
bg: String,
border: String,
header_bg: String,
header_text: String,
fallback: DefaultPanelTheme,
}
impl StyledPanelTheme {
fn from_styles(s: &StyleManager) -> Self {
Self {
bg: s.color_or_owned("surface_0", "#0d1117"),
border: s.color_or_owned("border", "#30363d"),
header_bg: s.color_or_owned("surface", "#161b22"),
header_text: s.color_or_owned("fg_2", "#8091a5"),
fallback: DefaultPanelTheme,
}
}
}
impl PanelTheme for StyledPanelTheme {
fn bg(&self) -> &str { &self.bg }
fn border(&self) -> &str { &self.border }
fn header_bg(&self) -> &str { &self.header_bg }
fn header_text(&self) -> &str { &self.header_text }
fn column_header_bg(&self) -> &str { &self.header_bg }
fn column_header_text(&self) -> &str { self.fallback.column_header_text() }
fn row_bg_normal(&self) -> &str { &self.bg }
fn row_bg_hover(&self) -> &str { self.fallback.row_bg_hover() }
fn row_bg_selected(&self) -> &str { self.fallback.row_bg_selected() }
fn footer_bg(&self) -> &str { &self.header_bg }
fn footer_text(&self) -> &str { self.fallback.footer_text() }
fn divider(&self) -> &str { &self.border }
fn action_icon_normal(&self) -> &str { self.fallback.action_icon_normal() }
fn action_icon_hover(&self) -> &str { self.fallback.action_icon_hover() }
fn sort_arrow_color(&self) -> &str { self.fallback.sort_arrow_color() }
}
fn panel_settings_from_styles(s: &StyleManager) -> PanelSettings {
PanelSettings {
theme: Box::new(StyledPanelTheme::from_styles(s)),
style: Box::<DefaultPanelStyle>::default(),
}
}
pub struct PanelBuilder<'a> {
slot_id: &'a str,
widget_id: &'a str,
parent: LayoutNodeId,
state: Option<&'a mut PanelState>,
header_title: Option<&'a str>,
header_actions:&'a [HeaderAction<'a>],
columns: &'a [ColumnDef<'a>],
show_scrollbar: bool,
content_height: f64,
settings: Option<PanelSettings>,
kind: PanelRenderKind,
}
pub fn panel<'a>(slot_id: &'a str, widget_id: &'a str) -> PanelBuilder<'a> {
PanelBuilder::new(slot_id, widget_id)
}
impl<'a> PanelBuilder<'a> {
pub fn new(slot_id: &'a str, widget_id: &'a str) -> Self {
Self {
slot_id,
widget_id,
parent: LayoutNodeId::ROOT,
state: None,
header_title: None,
header_actions: &[],
columns: &[],
show_scrollbar: false,
content_height: 0.0,
settings: None,
kind: PanelRenderKind::Plain,
}
}
pub fn parent(mut self, p: LayoutNodeId) -> Self { self.parent = p; self }
pub fn state(mut self, s: &'a mut PanelState) -> Self { self.state = Some(s); self }
pub fn header_title(mut self, t: &'a str) -> Self { self.header_title = Some(t); self }
pub fn header_actions(mut self, a: &'a [HeaderAction<'a>]) -> Self {
self.header_actions = a; self
}
pub fn columns(mut self, cs: &'a [ColumnDef<'a>]) -> Self { self.columns = cs; self }
pub fn show_scrollbar(mut self, on: bool) -> Self { self.show_scrollbar = on; self }
pub fn content_height(mut self, h: f64) -> Self { self.content_height = h; self }
pub fn settings(mut self, s: PanelSettings) -> Self { self.settings = Some(s); self }
pub fn kind(mut self, k: PanelRenderKind) -> Self { self.kind = k; self }
pub fn build<P: DockPanel>(
self,
layout: &mut LayoutManager<P>,
render: &mut dyn RenderContext,
) -> Option<PanelNode> {
let state = self.state.expect("PanelBuilder: .state(...) is required");
let mut view = PanelView {
header: self.header_title.map(|title| PanelHeader {
title,
actions: self.header_actions,
}),
columns: self.columns,
show_scrollbar: self.show_scrollbar,
content_height: self.content_height,
};
let settings = self.settings.unwrap_or_else(|| panel_settings_from_styles(layout.styles()));
register_layout_manager_panel(
layout,
render,
self.parent,
self.slot_id,
self.widget_id,
state,
&mut view,
&settings,
&self.kind,
)
}
}
#[allow(dead_code)]
const _: Option<Rect> = None;