124 lines
3.9 KiB
Rust
124 lines
3.9 KiB
Rust
use galaxyui_core::elements::{Border, CornerRadius, Empty, Radius};
|
|
use galaxyui_core::geometry::vector::vec2f;
|
|
use galaxyui_core::{AppContext, Element, SizeConstraint};
|
|
|
|
use super::{RenderContext, RenderableBlock};
|
|
use crate::editor::RunnableCommandModel;
|
|
use crate::extract_block;
|
|
use crate::render::BLOCK_FOOTER_HEIGHT;
|
|
use crate::render::model::viewport::ViewportItem;
|
|
use crate::render::model::{BlockItem, RenderState};
|
|
|
|
/// [`RenderableBlock`] implementation for runnable command blocks.
|
|
pub struct RenderableRunnableCommand {
|
|
viewport_item: ViewportItem,
|
|
footer: Box<dyn Element>,
|
|
border: Option<Border>,
|
|
}
|
|
|
|
impl RenderableRunnableCommand {
|
|
pub fn new(
|
|
viewport_item: ViewportItem,
|
|
model: Option<&dyn RunnableCommandModel>,
|
|
editor_is_focused: bool,
|
|
ctx: &AppContext,
|
|
) -> Self {
|
|
let border = model.as_ref().and_then(|model| model.border(ctx));
|
|
let footer = match model {
|
|
Some(model) => model.render_block_footer(editor_is_focused, ctx),
|
|
None => Empty::new().finish(),
|
|
};
|
|
|
|
Self {
|
|
viewport_item,
|
|
footer,
|
|
border,
|
|
}
|
|
}
|
|
}
|
|
|
|
impl RenderableBlock for RenderableRunnableCommand {
|
|
fn viewport_item(&self) -> &ViewportItem {
|
|
&self.viewport_item
|
|
}
|
|
|
|
fn layout(
|
|
&mut self,
|
|
_model: &RenderState,
|
|
ctx: &mut galaxyui_core::LayoutContext,
|
|
app: &AppContext,
|
|
) {
|
|
self.footer.layout(
|
|
SizeConstraint::strict(vec2f(
|
|
self.viewport_item.content_size.x(),
|
|
BLOCK_FOOTER_HEIGHT,
|
|
)),
|
|
ctx,
|
|
app,
|
|
);
|
|
}
|
|
|
|
fn paint(&mut self, model: &RenderState, ctx: &mut RenderContext, app: &AppContext) {
|
|
let content = model.content();
|
|
let code_block = extract_block!(self.viewport_item, content, (block, BlockItem::RunnableCodeBlock{paragraph_block, ..}) => block.code_block(paragraph_block));
|
|
|
|
let styles = model.styles();
|
|
let code_style = &styles.code_text;
|
|
|
|
let border = if ctx.focused {
|
|
self.border.unwrap_or(styles.code_border)
|
|
} else {
|
|
styles.code_border
|
|
};
|
|
|
|
let background_rect = self.viewport_item.visible_bounds(ctx);
|
|
|
|
ctx.paint
|
|
.scene
|
|
.draw_rect_without_hit_recording(background_rect)
|
|
.with_corner_radius(CornerRadius::with_all(Radius::Pixels(8.)))
|
|
.with_border(border)
|
|
.with_background(model.styles().code_background);
|
|
|
|
for paragraph in code_block.paragraphs() {
|
|
ctx.draw_paragraph(¶graph, code_style, model);
|
|
}
|
|
|
|
// Place the button at a higher z-index for event handling. See the comment on
|
|
// `RichTextElement::content_z_index` for context.
|
|
ctx.paint
|
|
.scene
|
|
.start_layer(galaxyui_core::ClipBounds::ActiveLayer);
|
|
|
|
// Position the block footer right below the content area, flush with its right-hand edge.
|
|
// This gives the footer some padding relative to the visible area with a background.
|
|
let content_rect = self.viewport_item.content_bounds(ctx);
|
|
let button_origin = content_rect.lower_right()
|
|
- vec2f(
|
|
self.footer.size().expect("Footer should be laid out").x(),
|
|
0.,
|
|
);
|
|
self.footer.paint(button_origin, ctx.paint, app);
|
|
|
|
ctx.paint.scene.stop_layer();
|
|
}
|
|
|
|
fn after_layout(
|
|
&mut self,
|
|
ctx: &mut galaxyui_core::AfterLayoutContext,
|
|
app: &galaxyui_core::AppContext,
|
|
) {
|
|
self.footer.after_layout(ctx, app);
|
|
}
|
|
|
|
fn dispatch_event(
|
|
&mut self,
|
|
_model: &crate::render::model::RenderState,
|
|
event: &galaxyui_core::event::DispatchedEvent,
|
|
ctx: &mut galaxyui_core::EventContext,
|
|
app: &AppContext,
|
|
) -> bool {
|
|
self.footer.dispatch_event(event, ctx, app)
|
|
}
|
|
}
|