use elicitation::elicit_tool;
use rmcp::ErrorData;
use rmcp::model::{CallToolResult, Content};
use schemars::JsonSchema;
use serde::Deserialize;
use tracing::instrument;
use crate::serde_types::{
ColorJson, ContainerJson, CornerRadiusJson, MarginJson, StrokeJson, Vec2Json,
};
fn container_result(container: &ContainerJson) -> CallToolResult {
match serde_json::to_string(container) {
Ok(s) => CallToolResult::success(vec![Content::text(s)]),
Err(e) => CallToolResult::error(vec![Content::text(format!("serialize error: {e}"))]),
}
}
#[derive(Debug, Deserialize, JsonSchema)]
pub struct EmptyContainerParams {}
#[derive(Debug, Deserialize, JsonSchema)]
pub struct WindowParams {
pub title: String,
pub default_pos: Option<Vec2Json>,
pub default_size: Option<Vec2Json>,
#[serde(default = "default_true")]
pub resizable: bool,
#[serde(default = "default_true")]
pub collapsible: bool,
#[serde(default)]
pub scroll: bool,
#[serde(default = "default_true")]
pub title_bar: bool,
}
fn default_true() -> bool {
true
}
#[elicit_tool(
plugin = "egui_containers",
name = "container_window",
description = "Create a floating window. Returns ContainerJson::Window."
)]
#[instrument(skip_all)]
async fn container_window(p: WindowParams) -> Result<CallToolResult, ErrorData> {
let c = ContainerJson::Window {
title: p.title,
default_pos: p.default_pos,
default_size: p.default_size,
resizable: p.resizable,
collapsible: p.collapsible,
scroll: p.scroll,
title_bar: p.title_bar,
};
Ok(container_result(&c))
}
#[derive(Debug, Deserialize, JsonSchema)]
pub struct LeftPanelParams {
pub id: String,
pub default_width: Option<f32>,
#[serde(default = "default_true")]
pub resizable: bool,
pub min_width: Option<f32>,
pub max_width: Option<f32>,
}
#[elicit_tool(
plugin = "egui_containers",
name = "container_left_panel",
description = "Create a left side panel. Returns ContainerJson::LeftPanel."
)]
#[instrument(skip_all)]
async fn container_left_panel(p: LeftPanelParams) -> Result<CallToolResult, ErrorData> {
let c = ContainerJson::LeftPanel {
id: p.id,
default_width: p.default_width,
resizable: p.resizable,
min_width: p.min_width,
max_width: p.max_width,
};
Ok(container_result(&c))
}
#[derive(Debug, Deserialize, JsonSchema)]
pub struct RightPanelParams {
pub id: String,
pub default_width: Option<f32>,
#[serde(default = "default_true")]
pub resizable: bool,
}
#[elicit_tool(
plugin = "egui_containers",
name = "container_right_panel",
description = "Create a right side panel. Returns ContainerJson::RightPanel."
)]
#[instrument(skip_all)]
async fn container_right_panel(p: RightPanelParams) -> Result<CallToolResult, ErrorData> {
let c = ContainerJson::RightPanel {
id: p.id,
default_width: p.default_width,
resizable: p.resizable,
};
Ok(container_result(&c))
}
#[derive(Debug, Deserialize, JsonSchema)]
pub struct TopPanelParams {
pub id: String,
pub default_height: Option<f32>,
#[serde(default)]
pub resizable: bool,
}
#[elicit_tool(
plugin = "egui_containers",
name = "container_top_panel",
description = "Create a top panel. Returns ContainerJson::TopPanel."
)]
#[instrument(skip_all)]
async fn container_top_panel(p: TopPanelParams) -> Result<CallToolResult, ErrorData> {
let c = ContainerJson::TopPanel {
id: p.id,
default_height: p.default_height,
resizable: p.resizable,
};
Ok(container_result(&c))
}
#[derive(Debug, Deserialize, JsonSchema)]
pub struct BottomPanelParams {
pub id: String,
pub default_height: Option<f32>,
#[serde(default)]
pub resizable: bool,
}
#[elicit_tool(
plugin = "egui_containers",
name = "container_bottom_panel",
description = "Create a bottom panel. Returns ContainerJson::BottomPanel."
)]
#[instrument(skip_all)]
async fn container_bottom_panel(p: BottomPanelParams) -> Result<CallToolResult, ErrorData> {
let c = ContainerJson::BottomPanel {
id: p.id,
default_height: p.default_height,
resizable: p.resizable,
};
Ok(container_result(&c))
}
#[elicit_tool(
plugin = "egui_containers",
name = "container_central_panel",
description = "Create a central panel that fills remaining space. Returns ContainerJson::CentralPanel."
)]
#[instrument(skip_all)]
async fn container_central_panel(p: EmptyContainerParams) -> Result<CallToolResult, ErrorData> {
let _ = p;
Ok(container_result(&ContainerJson::CentralPanel))
}
#[derive(Debug, Deserialize, JsonSchema)]
pub struct ScrollAreaParams {
#[serde(default = "default_true")]
pub vertical: bool,
#[serde(default)]
pub horizontal: bool,
pub max_height: Option<f32>,
pub max_width: Option<f32>,
#[serde(default)]
pub auto_shrink: bool,
#[serde(default)]
pub always_show_scroll: bool,
}
#[elicit_tool(
plugin = "egui_containers",
name = "container_scroll_area",
description = "Create a scrollable region. Returns ContainerJson::ScrollArea."
)]
#[instrument(skip_all)]
async fn container_scroll_area(p: ScrollAreaParams) -> Result<CallToolResult, ErrorData> {
let c = ContainerJson::ScrollArea {
vertical: p.vertical,
horizontal: p.horizontal,
max_height: p.max_height,
max_width: p.max_width,
auto_shrink: p.auto_shrink,
always_show_scroll: p.always_show_scroll,
};
Ok(container_result(&c))
}
#[derive(Debug, Deserialize, JsonSchema)]
pub struct CollapsingParams {
pub text: String,
#[serde(default)]
pub default_open: bool,
}
#[elicit_tool(
plugin = "egui_containers",
name = "container_collapsing",
description = "Create a collapsible section with header. Returns ContainerJson::CollapsingHeader."
)]
#[instrument(skip_all)]
async fn container_collapsing(p: CollapsingParams) -> Result<CallToolResult, ErrorData> {
let c = ContainerJson::CollapsingHeader {
text: p.text,
default_open: p.default_open,
};
Ok(container_result(&c))
}
#[elicit_tool(
plugin = "egui_containers",
name = "container_group",
description = "Create a visual grouping box around content. Returns ContainerJson::Group.",
emit = None
)]
#[instrument(skip_all)]
async fn container_group(p: EmptyContainerParams) -> Result<CallToolResult, ErrorData> {
let _ = p;
Ok(container_result(&ContainerJson::Group))
}
#[derive(Debug, Deserialize, JsonSchema)]
pub struct FrameParams {
pub fill: Option<ColorJson>,
pub stroke: Option<StrokeJson>,
pub corner_radius: Option<CornerRadiusJson>,
pub inner_margin: Option<MarginJson>,
pub outer_margin: Option<MarginJson>,
}
#[elicit_tool(
plugin = "egui_containers",
name = "container_frame",
description = "Create a framed region with fill, stroke, and margins. Returns ContainerJson::Frame."
)]
#[instrument(skip_all)]
async fn container_frame(p: FrameParams) -> Result<CallToolResult, ErrorData> {
let c = ContainerJson::Frame {
fill: p.fill,
stroke: p.stroke,
corner_radius: p.corner_radius,
inner_margin: p.inner_margin,
outer_margin: p.outer_margin,
};
Ok(container_result(&c))
}
#[elicit_tool(
plugin = "egui_containers",
name = "container_menu_bar",
description = "Create a menu bar. Returns ContainerJson::MenuBar.",
emit = None
)]
#[instrument(skip_all)]
async fn container_menu_bar(p: EmptyContainerParams) -> Result<CallToolResult, ErrorData> {
let _ = p;
Ok(container_result(&ContainerJson::MenuBar))
}
#[derive(Debug, Deserialize, JsonSchema)]
pub struct MenuParams {
pub title: String,
}
#[elicit_tool(
plugin = "egui_containers",
name = "container_menu",
description = "Create a menu within a menu bar. Returns ContainerJson::Menu."
)]
#[instrument(skip_all)]
async fn container_menu(p: MenuParams) -> Result<CallToolResult, ErrorData> {
let c = ContainerJson::Menu { title: p.title };
Ok(container_result(&c))
}
#[derive(Debug, Deserialize, JsonSchema)]
pub struct TooltipParams {
pub text: String,
}
#[elicit_tool(
plugin = "egui_containers",
name = "container_tooltip",
description = "Create a tooltip. Returns ContainerJson::Tooltip."
)]
#[instrument(skip_all)]
async fn container_tooltip(p: TooltipParams) -> Result<CallToolResult, ErrorData> {
let c = ContainerJson::Tooltip { text: p.text };
Ok(container_result(&c))
}
#[derive(Debug, Deserialize, JsonSchema)]
pub struct PopupParams {
pub id: String,
}
#[elicit_tool(
plugin = "egui_containers",
name = "container_popup",
description = "Create a popup area. Returns ContainerJson::Popup."
)]
#[instrument(skip_all)]
async fn container_popup(p: PopupParams) -> Result<CallToolResult, ErrorData> {
let c = ContainerJson::Popup { id: p.id };
Ok(container_result(&c))
}