use par_term_scripting::protocol::{OverlayScene, OverlayWidgetEvent, PluginOverlay};
#[derive(Debug, Clone, PartialEq)]
pub(crate) struct OverlayInteraction {
pub(crate) plugin_id: String,
pub(crate) widget_id: String,
pub(crate) event: OverlayWidgetEvent,
pub(crate) focus_request: bool,
}
pub(super) fn render_interactive_overlay(
ctx: &egui::Context,
plugin_id: &str,
overlay: &PluginOverlay,
rect: egui::Rect,
interactions: &mut Vec<OverlayInteraction>,
focused: bool,
) {
egui::Area::new(egui::Id::new(("plugin_overlay_interactive", plugin_id)))
.fixed_pos(rect.min)
.order(egui::Order::Middle)
.interactable(true)
.show(ctx, |ui| {
ui.set_min_size(rect.size());
ui.set_max_size(rect.size());
let frame = egui::Frame::NONE
.fill(egui::Color32::from_rgba_unmultiplied(
20,
20,
28,
(220.0 * overlay.opacity) as u8,
))
.inner_margin(egui::Margin::same(8))
.corner_radius(6.0)
.stroke(egui::Stroke::new(
if focused { 2.0 } else { 1.0 },
if focused {
egui::Color32::from_rgba_unmultiplied(
130,
160,
255,
(230.0 * overlay.opacity) as u8,
)
} else {
egui::Color32::from_rgba_unmultiplied(
120,
140,
190,
(200.0 * overlay.opacity) as u8,
)
},
));
frame.show(ui, |ui| {
render_widget_scene(ui, plugin_id, &overlay.content, interactions, focused);
})
});
let panel_clicked = ctx.input(|i| {
i.pointer.any_click() && rect.contains(i.pointer.interact_pos().unwrap_or_default())
});
if panel_clicked && !focused {
interactions.push(OverlayInteraction {
plugin_id: plugin_id.to_string(),
widget_id: String::new(),
event: OverlayWidgetEvent::Click {},
focus_request: true,
});
}
}
fn render_widget_scene(
ui: &mut egui::Ui,
plugin_id: &str,
scene: &OverlayScene,
interactions: &mut Vec<OverlayInteraction>,
focused: bool,
) {
match scene {
OverlayScene::Text { text } => {
ui.label(egui::RichText::new(text).monospace().size(13.0));
}
OverlayScene::Markdown { text } => {
ui.label(egui::RichText::new(text).size(13.0));
}
OverlayScene::Row { children } => {
ui.horizontal(|ui| {
for child in children {
render_widget_scene(ui, plugin_id, child, interactions, focused);
}
});
}
OverlayScene::Button { id, label } => {
if ui.button(egui::RichText::new(label).size(13.0)).clicked() {
interactions.push(OverlayInteraction {
plugin_id: plugin_id.to_string(),
widget_id: id.clone(),
event: OverlayWidgetEvent::Click {},
focus_request: true,
});
}
}
OverlayScene::TextInput {
id,
value,
placeholder,
} => {
let mut buffer = value.clone();
let response = ui.add(
egui::TextEdit::singleline(&mut buffer)
.hint_text(placeholder)
.desired_width(ui.available_width() - 12.0),
);
if focused && response.changed() {
interactions.push(OverlayInteraction {
plugin_id: plugin_id.to_string(),
widget_id: id.clone(),
event: OverlayWidgetEvent::TextChanged { value: buffer },
focus_request: false,
});
}
}
OverlayScene::List {
id,
items,
selected,
} => {
for (index, item) in items.iter().enumerate() {
let is_selected = *selected == Some(index);
if ui
.selectable_label(
is_selected,
egui::RichText::new(item).monospace().size(13.0),
)
.clicked()
{
interactions.push(OverlayInteraction {
plugin_id: plugin_id.to_string(),
widget_id: id.clone(),
event: OverlayWidgetEvent::Select { index },
focus_request: true,
});
}
}
}
}
}