use crate::SettingsUI;
use crate::search::SearchTag;
use crate::section::{SLIDER_WIDTH, collapsing_section};
use par_term_config::{PowerPreference, VsyncMode};
use std::collections::HashSet;
const SLIDER_HEIGHT: f32 = 18.0;
pub(crate) fn show_performance_section(
ui: &mut egui::Ui,
settings: &mut SettingsUI,
changes_this_frame: &mut bool,
collapsed: &mut HashSet<String>,
) {
collapsing_section(
ui,
"Performance",
"window_performance",
false,
collapsed,
|ui| {
ui.horizontal(|ui| {
ui.label("Max FPS:");
if ui
.add_sized(
[SLIDER_WIDTH, SLIDER_HEIGHT],
egui::Slider::new(&mut settings.config.rendering.max_fps, 1..=240)
.suffix(" fps"),
)
.search_tag(&["max_fps"])
.changed()
{
settings.has_changes = true;
*changes_this_frame = true;
}
crate::reset::reset_button(ui, settings, changes_this_frame, |c| {
&mut c.rendering.max_fps
});
});
ui.horizontal(|ui| {
ui.label("VSync Mode:");
let current = match settings.config.rendering.vsync_mode {
VsyncMode::Immediate => 0,
VsyncMode::Mailbox => 1,
VsyncMode::Fifo => 2,
};
let mut selected = current;
let format_mode = |mode: VsyncMode, name: &str| -> String {
if settings.is_vsync_mode_supported(mode) {
name.to_string()
} else {
format!("{} (not supported)", name)
}
};
egui::ComboBox::from_id_salt("window_vsync_mode")
.selected_text(match current {
0 => format_mode(VsyncMode::Immediate, "Immediate (No VSync)"),
1 => format_mode(VsyncMode::Mailbox, "Mailbox (Balanced)"),
2 => format_mode(VsyncMode::Fifo, "FIFO (VSync)"),
_ => "Unknown".to_string(),
})
.show_ui(ui, |ui| {
ui.selectable_value(
&mut selected,
0,
format_mode(VsyncMode::Immediate, "Immediate (No VSync)"),
);
ui.selectable_value(
&mut selected,
1,
format_mode(VsyncMode::Mailbox, "Mailbox (Balanced)"),
);
ui.selectable_value(
&mut selected,
2,
format_mode(VsyncMode::Fifo, "FIFO (VSync)"),
);
})
.response
.search_tag(&["vsync_mode"]);
if selected != current {
let new_mode = match selected {
0 => VsyncMode::Immediate,
1 => VsyncMode::Mailbox,
2 => VsyncMode::Fifo,
_ => VsyncMode::Immediate,
};
if settings.is_vsync_mode_supported(new_mode) {
settings.config.rendering.vsync_mode = new_mode;
settings.vsync_warning = None;
settings.has_changes = true;
*changes_this_frame = true;
} else {
settings.vsync_warning = Some(format!(
"{:?} is not supported on this display. Using FIFO instead.",
new_mode
));
settings.config.rendering.vsync_mode = VsyncMode::Fifo;
settings.has_changes = true;
*changes_this_frame = true;
}
}
});
if let Some(ref warning) = settings.vsync_warning {
ui.colored_label(egui::Color32::YELLOW, warning);
}
ui.horizontal(|ui| {
ui.label("GPU Power Preference:");
let current_pref = settings.config.rendering.power_preference;
egui::ComboBox::from_id_salt("gpu_power_preference")
.selected_text(current_pref.display_name())
.show_ui(ui, |ui| {
for pref in PowerPreference::all() {
if ui
.selectable_value(
&mut settings.config.rendering.power_preference,
*pref,
pref.display_name(),
)
.changed()
{
settings.has_changes = true;
*changes_this_frame = true;
}
}
})
.response
.search_tag(&["power_preference"]);
crate::deferred_badge(ui, crate::Deferred::Restart);
});
ui.add_space(8.0);
ui.label(egui::RichText::new("Power Saving").strong());
if ui
.checkbox(
&mut settings.config.power.pause_shaders_on_blur,
"Pause shader animations when unfocused",
)
.search_tag(&["pause_shaders_on_blur"])
.on_hover_text(
"Reduces GPU usage by pausing animated shaders when the window is not in focus",
)
.changed()
{
settings.has_changes = true;
*changes_this_frame = true;
}
if ui
.checkbox(
&mut settings.config.power.pause_refresh_on_blur,
"Reduce refresh rate when unfocused",
).search_tag(&["pause_refresh_on_blur"])
.on_hover_text(
"Reduces CPU/GPU usage by lowering the frame rate when the window is not in focus",
)
.changed()
{
settings.has_changes = true;
*changes_this_frame = true;
}
ui.horizontal(|ui| {
ui.label("Unfocused FPS:");
if ui
.add_enabled(
settings.config.power.pause_refresh_on_blur,
egui::Slider::new(&mut settings.config.power.unfocused_fps, 1..=30)
.suffix(" fps"),
)
.search_tag(&["unfocused_fps"])
.on_hover_text(
"Target frame rate when window is unfocused (lower = more power savings)",
)
.changed()
{
settings.has_changes = true;
*changes_this_frame = true;
}
crate::reset::reset_button(ui, settings, changes_this_frame, |c| {
&mut c.power.unfocused_fps
});
});
ui.horizontal(|ui| {
ui.label("Inactive Tab FPS:");
if ui
.add_sized(
[SLIDER_WIDTH, SLIDER_HEIGHT],
egui::Slider::new(&mut settings.config.power.inactive_tab_fps, 1..=30)
.suffix(" fps"),
)
.search_tag(&["inactive_tab_fps"])
.on_hover_text(
"Refresh rate for non-visible tabs. Lower values reduce CPU usage\n\
from mutex polling when many tabs are open.\n\
Only needs to be high enough to detect activity, bells, and shell exit.",
)
.changed()
{
settings.has_changes = true;
*changes_this_frame = true;
}
crate::reset::reset_button(ui, settings, changes_this_frame, |c| {
&mut c.power.inactive_tab_fps
});
});
ui.add_space(8.0);
ui.label(egui::RichText::new("Flicker Reduction").strong());
if ui
.checkbox(
&mut settings.config.rendering.reduce_flicker,
"Reduce flicker during fast updates",
)
.search_tag(&["reduce_flicker"])
.on_hover_text(
"Delays screen redraws while the cursor is hidden (DECTCEM off).\n\
Many terminal programs hide the cursor during bulk updates.\n\
This batches updates to reduce visual flicker.",
)
.changed()
{
settings.has_changes = true;
*changes_this_frame = true;
}
ui.horizontal(|ui| {
ui.label("Maximum delay:");
if ui
.add_enabled(
settings.config.rendering.reduce_flicker,
egui::Slider::new(
&mut settings.config.rendering.reduce_flicker_delay_ms,
1..=100,
)
.suffix(" ms"),
)
.search_tag(&["reduce_flicker_delay_ms"])
.on_hover_text(
"Maximum time to wait for cursor to become visible.\n\
Lower = more responsive, Higher = smoother for slow programs.\n\
Default: 16ms (~1 frame at 60fps)",
)
.changed()
{
settings.has_changes = true;
*changes_this_frame = true;
}
crate::reset::reset_button(ui, settings, changes_this_frame, |c| {
&mut c.rendering.reduce_flicker_delay_ms
});
});
ui.add_space(10.0);
ui.label(egui::RichText::new("Throughput Mode").strong());
let throughput_label = crate::live_binding::with_binding(
&settings.config,
"Maximize throughput",
"toggle_throughput_mode",
);
if ui
.checkbox(
&mut settings.config.rendering.maximize_throughput,
throughput_label,
)
.search_tag(&["maximize_throughput"])
.on_hover_text(
"Batches screen updates during bulk terminal output.\n\
Reduces CPU overhead when processing large outputs.\n\
Trade-off: display updates are delayed by the interval below.",
)
.changed()
{
settings.has_changes = true;
*changes_this_frame = true;
}
ui.horizontal(|ui| {
ui.label("Render interval:");
if ui
.add_enabled(
settings.config.rendering.maximize_throughput,
egui::Slider::new(
&mut settings.config.rendering.throughput_render_interval_ms,
50..=500,
)
.suffix(" ms"),
)
.search_tag(&["throughput_render_interval_ms"])
.on_hover_text(
"How often to update the display in throughput mode.\n\
Lower = more responsive, Higher = better throughput.\n\
Default: 100ms (~10 updates/sec)",
)
.changed()
{
settings.has_changes = true;
*changes_this_frame = true;
}
crate::reset::reset_button(ui, settings, changes_this_frame, |c| {
&mut c.rendering.throughput_render_interval_ms
});
});
},
);
}