terminal is fixed and im not happy about it
This commit is contained in:
@@ -459,11 +459,16 @@ fn vs_cell_bg(
|
|||||||
|
|
||||||
// For default background (type 0), use fully transparent so the window's
|
// For default background (type 0), use fully transparent so the window's
|
||||||
// clear color (which has background_opacity applied) shows through.
|
// clear color (which has background_opacity applied) shows through.
|
||||||
|
// UNLESS the grid params specify an opaque background (e.g. alternate screen).
|
||||||
// Only non-default backgrounds should be opaque.
|
// Only non-default backgrounds should be opaque.
|
||||||
// But NOT if the cell is selected (selection always has white bg)
|
// But NOT if the cell is selected (selection always has white bg)
|
||||||
let bg_type = cell.bg & 0xFFu;
|
let bg_type = cell.bg & 0xFFu;
|
||||||
if bg_type == COLOR_TYPE_DEFAULT && !is_reverse && !is_selected {
|
if bg_type == COLOR_TYPE_DEFAULT && !is_reverse && !is_selected {
|
||||||
bg.a = 0.0;
|
if grid_params.background_opacity < 1.0 {
|
||||||
|
bg.a = 0.0;
|
||||||
|
} else {
|
||||||
|
bg.a = 1.0;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Calculate cursor color
|
// Calculate cursor color
|
||||||
|
|||||||
+114
-40
@@ -879,7 +879,7 @@ fn remove_pid_file() {
|
|||||||
/// - Last segment is bold
|
/// - Last segment is bold
|
||||||
/// - Section has a dark gray background color (#282828)
|
/// - Section has a dark gray background color (#282828)
|
||||||
/// - Section ends with powerline arrow transition
|
/// - Section ends with powerline arrow transition
|
||||||
fn build_cwd_section(cwd: &str) -> StatuslineSection {
|
fn build_cwd_section(cwd: &str, is_light: bool) -> StatuslineSection {
|
||||||
// Colors to cycle through (skip 0 and 1 which are often near-white in custom schemes)
|
// Colors to cycle through (skip 0 and 1 which are often near-white in custom schemes)
|
||||||
const COLORS: [u8; 6] = [2, 3, 4, 5, 6, 7];
|
const COLORS: [u8; 6] = [2, 3, 4, 5, 6, 7];
|
||||||
|
|
||||||
@@ -903,7 +903,12 @@ fn build_cwd_section(cwd: &str) -> StatuslineSection {
|
|||||||
if segments.is_empty() {
|
if segments.is_empty() {
|
||||||
// Root directory
|
// Root directory
|
||||||
components.push(StatuslineComponent::new(" \u{F07C} / ").fg(COLORS[0]));
|
components.push(StatuslineComponent::new(" \u{F07C} / ").fg(COLORS[0]));
|
||||||
return StatuslineSection::with_rgb_bg(0x28, 0x28, 0x28)
|
let (bg_r, bg_g, bg_b) = if is_light {
|
||||||
|
(0xE0, 0xE0, 0xE0)
|
||||||
|
} else {
|
||||||
|
(0x28, 0x28, 0x28)
|
||||||
|
};
|
||||||
|
return StatuslineSection::with_rgb_bg(bg_r, bg_g, bg_b)
|
||||||
.with_components(components);
|
.with_components(components);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -940,8 +945,12 @@ fn build_cwd_section(cwd: &str) -> StatuslineSection {
|
|||||||
// Add trailing space for padding before the powerline arrow
|
// Add trailing space for padding before the powerline arrow
|
||||||
components.push(StatuslineComponent::new(" "));
|
components.push(StatuslineComponent::new(" "));
|
||||||
|
|
||||||
// Use dark gray (#282828) as section background
|
let (bg_r, bg_g, bg_b) = if is_light {
|
||||||
StatuslineSection::with_rgb_bg(0x28, 0x28, 0x28).with_components(components)
|
(0xE0, 0xE0, 0xE0)
|
||||||
|
} else {
|
||||||
|
(0x28, 0x28, 0x28)
|
||||||
|
};
|
||||||
|
StatuslineSection::with_rgb_bg(bg_r, bg_g, bg_b).with_components(components)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Git repository status information.
|
/// Git repository status information.
|
||||||
@@ -1101,7 +1110,7 @@ fn get_git_status(cwd: &str) -> Option<GitStatus> {
|
|||||||
|
|
||||||
/// Build a statusline section for git status.
|
/// Build a statusline section for git status.
|
||||||
/// Returns None if not in a git repository.
|
/// Returns None if not in a git repository.
|
||||||
fn build_git_section(cwd: &str) -> Option<StatuslineSection> {
|
fn build_git_section(cwd: &str, is_light: bool) -> Option<StatuslineSection> {
|
||||||
let status = get_git_status(cwd)?;
|
let status = get_git_status(cwd)?;
|
||||||
|
|
||||||
// Determine foreground color based on state (matching oh-my-posh template)
|
// Determine foreground color based on state (matching oh-my-posh template)
|
||||||
@@ -1111,13 +1120,29 @@ fn build_git_section(cwd: &str) -> Option<StatuslineSection> {
|
|||||||
// 3. If both ahead and behind: #ff4500 (red-orange)
|
// 3. If both ahead and behind: #ff4500 (red-orange)
|
||||||
// 4. If ahead or behind: #B388FF (purple)
|
// 4. If ahead or behind: #B388FF (purple)
|
||||||
let fg_color: (u8, u8, u8) = if status.ahead > 0 && status.behind > 0 {
|
let fg_color: (u8, u8, u8) = if status.ahead > 0 && status.behind > 0 {
|
||||||
(0xff, 0x45, 0x00) // #ff4500 - red-orange
|
if is_light {
|
||||||
|
(0xCC, 0x37, 0x00)
|
||||||
|
} else {
|
||||||
|
(0xff, 0x45, 0x00)
|
||||||
|
} // red-orange (darker for light mode)
|
||||||
} else if status.ahead > 0 || status.behind > 0 {
|
} else if status.ahead > 0 || status.behind > 0 {
|
||||||
(0xB3, 0x88, 0xFF) // #B388FF - purple
|
if is_light {
|
||||||
|
(0x7B, 0x4C, 0xCC)
|
||||||
|
} else {
|
||||||
|
(0xB3, 0x88, 0xFF)
|
||||||
|
} // purple (darker for light mode)
|
||||||
} else if status.working_changed > 0 || status.staging_changed > 0 {
|
} else if status.working_changed > 0 || status.staging_changed > 0 {
|
||||||
(0xFF, 0x92, 0x48) // #FF9248 - orange
|
if is_light {
|
||||||
|
(0xC0, 0x60, 0x10)
|
||||||
|
} else {
|
||||||
|
(0xFF, 0x92, 0x48)
|
||||||
|
} // orange (darker for light mode)
|
||||||
} else {
|
} else {
|
||||||
(0x0d, 0xa3, 0x00) // #0da300 - green
|
if is_light {
|
||||||
|
(0x0A, 0x7D, 0x00)
|
||||||
|
} else {
|
||||||
|
(0x0d, 0xa3, 0x00)
|
||||||
|
} // green (darker for light mode)
|
||||||
};
|
};
|
||||||
|
|
||||||
let mut components = Vec::new();
|
let mut components = Vec::new();
|
||||||
@@ -1192,9 +1217,15 @@ fn build_git_section(cwd: &str) -> Option<StatuslineSection> {
|
|||||||
.rgb_fg(fg_color.0, fg_color.1, fg_color.2),
|
.rgb_fg(fg_color.0, fg_color.1, fg_color.2),
|
||||||
);
|
);
|
||||||
|
|
||||||
// Background: #232323
|
// Background
|
||||||
|
let (bg_r, bg_g, bg_b) = if is_light {
|
||||||
|
(0xD0, 0xD0, 0xD0) // Light mode background
|
||||||
|
} else {
|
||||||
|
(0x23, 0x23, 0x23) // Dark mode background
|
||||||
|
};
|
||||||
|
|
||||||
Some(
|
Some(
|
||||||
StatuslineSection::with_rgb_bg(0x23, 0x23, 0x23)
|
StatuslineSection::with_rgb_bg(bg_r, bg_g, bg_b)
|
||||||
.with_components(components),
|
.with_components(components),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@@ -1293,6 +1324,8 @@ struct App {
|
|||||||
shutdown: Arc<AtomicBool>,
|
shutdown: Arc<AtomicBool>,
|
||||||
/// Current mouse cursor position.
|
/// Current mouse cursor position.
|
||||||
cursor_position: PhysicalPosition<f64>,
|
cursor_position: PhysicalPosition<f64>,
|
||||||
|
/// Where the mouse was last pressed (for drag selection threshold).
|
||||||
|
mouse_down_pos: Option<PhysicalPosition<f64>>,
|
||||||
/// Frame counter for FPS logging.
|
/// Frame counter for FPS logging.
|
||||||
frame_count: u64,
|
frame_count: u64,
|
||||||
/// Last time we logged FPS.
|
/// Last time we logged FPS.
|
||||||
@@ -1345,6 +1378,7 @@ impl App {
|
|||||||
event_loop_proxy: None,
|
event_loop_proxy: None,
|
||||||
shutdown: Arc::new(AtomicBool::new(false)),
|
shutdown: Arc::new(AtomicBool::new(false)),
|
||||||
cursor_position: PhysicalPosition::new(0.0, 0.0),
|
cursor_position: PhysicalPosition::new(0.0, 0.0),
|
||||||
|
mouse_down_pos: None,
|
||||||
frame_count: 0,
|
frame_count: 0,
|
||||||
last_frame_log: std::time::Instant::now(),
|
last_frame_log: std::time::Instant::now(),
|
||||||
should_create_window: false,
|
should_create_window: false,
|
||||||
@@ -2019,8 +2053,12 @@ impl App {
|
|||||||
if let Some(ref custom) = pane.custom_statusline {
|
if let Some(ref custom) = pane.custom_statusline {
|
||||||
StatuslineContent::Raw(custom.clone())
|
StatuslineContent::Raw(custom.clone())
|
||||||
} else if let Some(cwd) = pane.pty.foreground_cwd() {
|
} else if let Some(cwd) = pane.pty.foreground_cwd() {
|
||||||
let mut sections = vec![build_cwd_section(&cwd)];
|
let is_light = pane.terminal.palette.is_light();
|
||||||
if let Some(git_section) = build_git_section(&cwd) {
|
let mut sections =
|
||||||
|
vec![build_cwd_section(&cwd, is_light)];
|
||||||
|
if let Some(git_section) =
|
||||||
|
build_git_section(&cwd, is_light)
|
||||||
|
{
|
||||||
sections.push(git_section);
|
sections.push(git_section);
|
||||||
}
|
}
|
||||||
StatuslineContent::Sections(sections)
|
StatuslineContent::Sections(sections)
|
||||||
@@ -2980,6 +3018,63 @@ impl ApplicationHandler<UserEvent> for App {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
} else if let Some(down_pos) = self.mouse_down_pos {
|
||||||
|
if !self.has_mouse_tracking() {
|
||||||
|
let dx = position.x - down_pos.x;
|
||||||
|
let dy = position.y - down_pos.y;
|
||||||
|
let distance_sq = dx * dx + dy * dy;
|
||||||
|
|
||||||
|
let cell_width = self
|
||||||
|
.renderer
|
||||||
|
.as_ref()
|
||||||
|
.map(|r| r.cell_metrics.cell_width as f64)
|
||||||
|
.unwrap_or(8.0);
|
||||||
|
let threshold = cell_width * 0.5;
|
||||||
|
|
||||||
|
if distance_sq > threshold * threshold {
|
||||||
|
// Dragged far enough, start selection
|
||||||
|
if let Some(renderer) = &self.renderer {
|
||||||
|
if let Some((start_col, start_screen_row)) =
|
||||||
|
renderer
|
||||||
|
.pixel_to_cell(down_pos.x, down_pos.y)
|
||||||
|
{
|
||||||
|
if let Some((end_col, end_screen_row)) =
|
||||||
|
renderer.pixel_to_cell(
|
||||||
|
position.x, position.y,
|
||||||
|
)
|
||||||
|
{
|
||||||
|
let scroll_offset =
|
||||||
|
self.get_scroll_offset() as isize;
|
||||||
|
let start_pos = CellPosition {
|
||||||
|
col: start_col,
|
||||||
|
row: start_screen_row as isize
|
||||||
|
- scroll_offset,
|
||||||
|
};
|
||||||
|
let end_pos = CellPosition {
|
||||||
|
col: end_col,
|
||||||
|
row: end_screen_row as isize
|
||||||
|
- scroll_offset,
|
||||||
|
};
|
||||||
|
|
||||||
|
if let Some(tab) = self.active_tab_mut()
|
||||||
|
{
|
||||||
|
if let Some(pane) =
|
||||||
|
tab.active_pane_mut()
|
||||||
|
{
|
||||||
|
pane.selection =
|
||||||
|
Some(Selection {
|
||||||
|
start: start_pos,
|
||||||
|
end: end_pos,
|
||||||
|
});
|
||||||
|
pane.is_selecting = true;
|
||||||
|
self.request_redraw();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -3022,37 +3117,16 @@ impl ApplicationHandler<UserEvent> for App {
|
|||||||
} else if button == MouseButton::Left {
|
} else if button == MouseButton::Left {
|
||||||
match state {
|
match state {
|
||||||
ElementState::Pressed => {
|
ElementState::Pressed => {
|
||||||
if let Some(renderer) = &self.renderer {
|
self.mouse_down_pos = Some(self.cursor_position);
|
||||||
if let Some((col, screen_row)) = renderer
|
if let Some(tab) = self.active_tab_mut() {
|
||||||
.pixel_to_cell(
|
if let Some(pane) = tab.active_pane_mut() {
|
||||||
self.cursor_position.x,
|
pane.selection = None;
|
||||||
self.cursor_position.y,
|
pane.is_selecting = false;
|
||||||
)
|
|
||||||
{
|
|
||||||
let scroll_offset =
|
|
||||||
self.get_scroll_offset();
|
|
||||||
let content_row = screen_row as isize
|
|
||||||
- scroll_offset as isize;
|
|
||||||
let pos = CellPosition {
|
|
||||||
col,
|
|
||||||
row: content_row,
|
|
||||||
};
|
|
||||||
log::debug!("Selection started at col={}, content_row={}, screen_row={}, scroll_offset={}", col, content_row, screen_row, scroll_offset);
|
|
||||||
if let Some(tab) = self.active_tab_mut() {
|
|
||||||
if let Some(pane) =
|
|
||||||
tab.active_pane_mut()
|
|
||||||
{
|
|
||||||
pane.selection = Some(Selection {
|
|
||||||
start: pos,
|
|
||||||
end: pos,
|
|
||||||
});
|
|
||||||
pane.is_selecting = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
ElementState::Released => {
|
ElementState::Released => {
|
||||||
|
self.mouse_down_pos = None;
|
||||||
let was_selecting = self
|
let was_selecting = self
|
||||||
.active_pane()
|
.active_pane()
|
||||||
.map(|p| p.is_selecting)
|
.map(|p| p.is_selecting)
|
||||||
|
|||||||
+59
-28
@@ -2406,14 +2406,19 @@ impl Renderer {
|
|||||||
|
|
||||||
/// Parse ANSI escape sequences from raw statusline content.
|
/// Parse ANSI escape sequences from raw statusline content.
|
||||||
/// Returns a vector of (char, fg_color, bg_color, bold) tuples.
|
/// Returns a vector of (char, fg_color, bg_color, bold) tuples.
|
||||||
fn parse_ansi_statusline(content: &str) -> Vec<(char, StatuslineColor, StatuslineColor, bool)> {
|
fn parse_ansi_statusline(content: &str, is_light: bool) -> Vec<(char, StatuslineColor, StatuslineColor, bool)> {
|
||||||
let mut result = Vec::new();
|
let mut result = Vec::new();
|
||||||
let chars: Vec<char> = content.chars().collect();
|
let chars: Vec<char> = content.chars().collect();
|
||||||
let mut i = 0;
|
let mut i = 0;
|
||||||
|
|
||||||
// Current styling state
|
// Current styling state
|
||||||
let mut fg = StatuslineColor::Default;
|
let mut fg = StatuslineColor::Default;
|
||||||
let mut bg = StatuslineColor::Rgb(0x1a, 0x1a, 0x1a); // Default statusline background
|
let default_bg_color = if is_light {
|
||||||
|
StatuslineColor::Rgb(0xD0, 0xD0, 0xD0)
|
||||||
|
} else {
|
||||||
|
StatuslineColor::Rgb(0x1a, 0x1a, 0x1a)
|
||||||
|
};
|
||||||
|
let mut bg = default_bg_color.clone(); // Default statusline background
|
||||||
let mut bold = false;
|
let mut bold = false;
|
||||||
|
|
||||||
while i < chars.len() {
|
while i < chars.len() {
|
||||||
@@ -2494,7 +2499,7 @@ impl Renderer {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
49 => bg = StatuslineColor::Rgb(0x1a, 0x1a, 0x1a), // Reset to default statusline bg
|
49 => bg = default_bg_color.clone(), // Reset to default statusline bg
|
||||||
90..=97 => fg = StatuslineColor::Indexed((code - 90 + 8) as u8),
|
90..=97 => fg = StatuslineColor::Indexed((code - 90 + 8) as u8),
|
||||||
100..=107 => bg = StatuslineColor::Indexed((code - 100 + 8) as u8),
|
100..=107 => bg = StatuslineColor::Indexed((code - 100 + 8) as u8),
|
||||||
_ => {}
|
_ => {}
|
||||||
@@ -2528,7 +2533,7 @@ impl Renderer {
|
|||||||
/// this is used to expand the middle gap to fill the full window width.
|
/// this is used to expand the middle gap to fill the full window width.
|
||||||
///
|
///
|
||||||
/// Returns the number of columns used.
|
/// Returns the number of columns used.
|
||||||
fn update_statusline_cells(&mut self, content: &StatuslineContent, target_width: f32) -> usize {
|
fn update_statusline_cells(&mut self, content: &StatuslineContent, target_width: f32, is_light: bool) -> usize {
|
||||||
self.statusline_gpu_cells.clear();
|
self.statusline_gpu_cells.clear();
|
||||||
|
|
||||||
// Calculate target columns based on window width
|
// Calculate target columns based on window width
|
||||||
@@ -2540,14 +2545,19 @@ impl Renderer {
|
|||||||
self.statusline_max_cols
|
self.statusline_max_cols
|
||||||
};
|
};
|
||||||
|
|
||||||
// Default background color for statusline (dark gray)
|
// Default background color for statusline
|
||||||
let default_bg = Self::pack_statusline_color(StatuslineColor::Rgb(0x1a, 0x1a, 0x1a));
|
let default_bg_color = if is_light {
|
||||||
|
StatuslineColor::Rgb(0xD0, 0xD0, 0xD0)
|
||||||
|
} else {
|
||||||
|
StatuslineColor::Rgb(0x1a, 0x1a, 0x1a)
|
||||||
|
};
|
||||||
|
let default_bg = Self::pack_statusline_color(default_bg_color);
|
||||||
let _ = default_bg; // Silence unused warning - used by Sections path
|
let _ = default_bg; // Silence unused warning - used by Sections path
|
||||||
|
|
||||||
match content {
|
match content {
|
||||||
StatuslineContent::Raw(ansi_content) => {
|
StatuslineContent::Raw(ansi_content) => {
|
||||||
// Parse ANSI escape sequences to extract colors and text
|
// Parse ANSI escape sequences to extract colors and text
|
||||||
let parsed = Self::parse_ansi_statusline(ansi_content);
|
let parsed = Self::parse_ansi_statusline(ansi_content, is_light);
|
||||||
|
|
||||||
// Find the middle gap (largest consecutive run of spaces)
|
// Find the middle gap (largest consecutive run of spaces)
|
||||||
// and expand it to fill the target width
|
// and expand it to fill the target width
|
||||||
@@ -2597,7 +2607,7 @@ impl Renderer {
|
|||||||
let gap_bg = if best_gap_len > 0 && best_gap_start < parsed.len() {
|
let gap_bg = if best_gap_len > 0 && best_gap_start < parsed.len() {
|
||||||
parsed[best_gap_start].2
|
parsed[best_gap_start].2
|
||||||
} else {
|
} else {
|
||||||
StatuslineColor::Rgb(0x1a, 0x1a, 0x1a)
|
default_bg_color.clone()
|
||||||
};
|
};
|
||||||
|
|
||||||
// The position right before right-hand content starts (end of gap)
|
// The position right before right-hand content starts (end of gap)
|
||||||
@@ -2845,7 +2855,7 @@ impl Renderer {
|
|||||||
|
|
||||||
// Fill remaining width with default background cells
|
// Fill remaining width with default background cells
|
||||||
// This ensures the statusline covers the entire window width
|
// This ensures the statusline covers the entire window width
|
||||||
let default_bg_packed = Self::pack_statusline_color(StatuslineColor::Default);
|
let default_bg_packed = default_bg;
|
||||||
while self.statusline_gpu_cells.len() < target_cols && self.statusline_gpu_cells.len() < self.statusline_max_cols {
|
while self.statusline_gpu_cells.len() < target_cols && self.statusline_gpu_cells.len() < self.statusline_max_cols {
|
||||||
self.statusline_gpu_cells.push(GPUCell {
|
self.statusline_gpu_cells.push(GPUCell {
|
||||||
fg: 0,
|
fg: 0,
|
||||||
@@ -4331,10 +4341,17 @@ impl Renderer {
|
|||||||
TabBarPosition::Hidden => unreachable!(),
|
TabBarPosition::Hidden => unreachable!(),
|
||||||
};
|
};
|
||||||
|
|
||||||
// Use same color as statusline: 0x1a1a1a (26, 26, 26) in sRGB
|
let is_light = self.palette.is_light();
|
||||||
// Pre-computed linear RGB value for srgb_to_linear(26/255) ≈ 0.00972
|
let tab_bar_bg = if is_light {
|
||||||
const TAB_BAR_BG_LINEAR: f32 = 0.00972;
|
// Light mode statusline bg is approx 0xD0, linear is ~0.63076
|
||||||
let tab_bar_bg = [TAB_BAR_BG_LINEAR, TAB_BAR_BG_LINEAR, TAB_BAR_BG_LINEAR, 1.0];
|
const TAB_BAR_BG_LINEAR_LIGHT: f32 = 0.63076;
|
||||||
|
[TAB_BAR_BG_LINEAR_LIGHT, TAB_BAR_BG_LINEAR_LIGHT, TAB_BAR_BG_LINEAR_LIGHT, 1.0]
|
||||||
|
} else {
|
||||||
|
// Use same color as statusline: 0x1a1a1a (26, 26, 26) in sRGB
|
||||||
|
// Pre-computed linear RGB value for srgb_to_linear(26/255) ≈ 0.00972
|
||||||
|
const TAB_BAR_BG_LINEAR_DARK: f32 = 0.00972;
|
||||||
|
[TAB_BAR_BG_LINEAR_DARK, TAB_BAR_BG_LINEAR_DARK, TAB_BAR_BG_LINEAR_DARK, 1.0]
|
||||||
|
};
|
||||||
|
|
||||||
// Draw tab bar background
|
// Draw tab bar background
|
||||||
log::debug!("render_panes: drawing tab bar at y={}, height={}, num_tabs={}, quads_before={}",
|
log::debug!("render_panes: drawing tab bar at y={}, height={}, num_tabs={}, quads_before={}",
|
||||||
@@ -4354,23 +4371,23 @@ impl Renderer {
|
|||||||
let tab_width = title_width.max(min_tab_width);
|
let tab_width = title_width.max(min_tab_width);
|
||||||
|
|
||||||
let tab_bg = if is_active {
|
let tab_bg = if is_active {
|
||||||
// Active tab: brightest - significantly brighter than tab bar
|
// Active tab: brightest - matches terminal background or slightly brighter
|
||||||
let [r, g, b] = self.palette.default_bg;
|
let [r, g, b] = self.palette.default_bg;
|
||||||
let boost = 50.0_f32; // More visible for active tab
|
let boost = if is_light { 0.0_f32 } else { 50.0_f32 };
|
||||||
[
|
[
|
||||||
Self::srgb_to_linear((r as f32 + boost).min(255.0) / 255.0),
|
Self::srgb_to_linear((r as f32 + boost).clamp(0.0, 255.0) / 255.0),
|
||||||
Self::srgb_to_linear((g as f32 + boost).min(255.0) / 255.0),
|
Self::srgb_to_linear((g as f32 + boost).clamp(0.0, 255.0) / 255.0),
|
||||||
Self::srgb_to_linear((b as f32 + boost).min(255.0) / 255.0),
|
Self::srgb_to_linear((b as f32 + boost).clamp(0.0, 255.0) / 255.0),
|
||||||
1.0,
|
1.0,
|
||||||
]
|
]
|
||||||
} else {
|
} else {
|
||||||
// Inactive tab: slightly brighter than tab bar background
|
// Inactive tab: between tab bar background and active tab
|
||||||
let [r, g, b] = self.palette.default_bg;
|
let [r, g, b] = self.palette.default_bg;
|
||||||
let boost = 30.0_f32;
|
let boost = if is_light { -30.0_f32 } else { 30.0_f32 };
|
||||||
[
|
[
|
||||||
Self::srgb_to_linear((r as f32 + boost).min(255.0) / 255.0),
|
Self::srgb_to_linear((r as f32 + boost).clamp(0.0, 255.0) / 255.0),
|
||||||
Self::srgb_to_linear((g as f32 + boost).min(255.0) / 255.0),
|
Self::srgb_to_linear((g as f32 + boost).clamp(0.0, 255.0) / 255.0),
|
||||||
Self::srgb_to_linear((b as f32 + boost).min(255.0) / 255.0),
|
Self::srgb_to_linear((b as f32 + boost).clamp(0.0, 255.0) / 255.0),
|
||||||
1.0,
|
1.0,
|
||||||
]
|
]
|
||||||
};
|
};
|
||||||
@@ -4651,7 +4668,11 @@ impl Renderer {
|
|||||||
CursorShape::BlinkingUnderline | CursorShape::SteadyUnderline => 1,
|
CursorShape::BlinkingUnderline | CursorShape::SteadyUnderline => 1,
|
||||||
CursorShape::BlinkingBar | CursorShape::SteadyBar => 2,
|
CursorShape::BlinkingBar | CursorShape::SteadyBar => 2,
|
||||||
},
|
},
|
||||||
background_opacity: self.background_opacity,
|
background_opacity: if terminal.using_alternate_screen {
|
||||||
|
1.0
|
||||||
|
} else {
|
||||||
|
self.background_opacity
|
||||||
|
},
|
||||||
selection_start_col: sel_start_col,
|
selection_start_col: sel_start_col,
|
||||||
selection_start_row: sel_start_row,
|
selection_start_row: sel_start_row,
|
||||||
selection_end_col: sel_end_col,
|
selection_end_col: sel_end_col,
|
||||||
@@ -4767,9 +4788,10 @@ impl Renderer {
|
|||||||
// ═══════════════════════════════════════════════════════════════════
|
// ═══════════════════════════════════════════════════════════════════
|
||||||
let statusline_cols = {
|
let statusline_cols = {
|
||||||
let statusline_y = self.statusline_y();
|
let statusline_y = self.statusline_y();
|
||||||
|
let is_light = self.palette.is_light();
|
||||||
|
|
||||||
// Update statusline GPU cells from content, passing window width for gap expansion
|
// Update statusline GPU cells from content, passing window width for gap expansion
|
||||||
let cols = self.update_statusline_cells(statusline_content, width);
|
let cols = self.update_statusline_cells(statusline_content, width, is_light);
|
||||||
|
|
||||||
if cols > 0 {
|
if cols > 0 {
|
||||||
// Upload statusline cells to GPU
|
// Upload statusline cells to GPU
|
||||||
@@ -5009,10 +5031,19 @@ impl Renderer {
|
|||||||
|
|
||||||
{
|
{
|
||||||
let [bg_r, bg_g, bg_b] = self.palette.default_bg;
|
let [bg_r, bg_g, bg_b] = self.palette.default_bg;
|
||||||
let bg_r_linear = Self::srgb_to_linear(bg_r as f32 / 255.0) as f64;
|
let mut bg_r_linear = Self::srgb_to_linear(bg_r as f32 / 255.0) as f64;
|
||||||
let bg_g_linear = Self::srgb_to_linear(bg_g as f32 / 255.0) as f64;
|
let mut bg_g_linear = Self::srgb_to_linear(bg_g as f32 / 255.0) as f64;
|
||||||
let bg_b_linear = Self::srgb_to_linear(bg_b as f32 / 255.0) as f64;
|
let mut bg_b_linear = Self::srgb_to_linear(bg_b as f32 / 255.0) as f64;
|
||||||
let bg_alpha = self.background_opacity as f64;
|
let bg_alpha = self.background_opacity as f64;
|
||||||
|
|
||||||
|
// If the compositor expects premultiplied alpha, we must premultiply the clear color.
|
||||||
|
// Otherwise, light backgrounds with opacity will look fully opaque or super-luminous.
|
||||||
|
if self.surface_config.alpha_mode == wgpu::CompositeAlphaMode::PreMultiplied {
|
||||||
|
bg_r_linear *= bg_alpha;
|
||||||
|
bg_g_linear *= bg_alpha;
|
||||||
|
bg_b_linear *= bg_alpha;
|
||||||
|
}
|
||||||
|
|
||||||
let mut render_pass = encoder.begin_render_pass(&wgpu::RenderPassDescriptor {
|
let mut render_pass = encoder.begin_render_pass(&wgpu::RenderPassDescriptor {
|
||||||
label: Some("Render Pass"),
|
label: Some("Render Pass"),
|
||||||
color_attachments: &[Some(wgpu::RenderPassColorAttachment {
|
color_attachments: &[Some(wgpu::RenderPassColorAttachment {
|
||||||
|
|||||||
@@ -186,6 +186,15 @@ impl Default for ColorPalette {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl ColorPalette {
|
impl ColorPalette {
|
||||||
|
/// Return whether this palette is considered "light" based on default background luminance.
|
||||||
|
pub fn is_light(&self) -> bool {
|
||||||
|
let [r, g, b] = self.default_bg;
|
||||||
|
// Standard perceived luminance calculation
|
||||||
|
let luminance =
|
||||||
|
0.299 * (r as f32) + 0.587 * (g as f32) + 0.114 * (b as f32);
|
||||||
|
luminance > 128.0
|
||||||
|
}
|
||||||
|
|
||||||
/// Parse a color specification like "#RRGGBB" or "rgb:RR/GG/BB".
|
/// Parse a color specification like "#RRGGBB" or "rgb:RR/GG/BB".
|
||||||
pub fn parse_color_spec(spec: &str) -> Option<[u8; 3]> {
|
pub fn parse_color_spec(spec: &str) -> Option<[u8; 3]> {
|
||||||
let spec = spec.trim();
|
let spec = spec.trim();
|
||||||
|
|||||||
Reference in New Issue
Block a user