Files
galaxy/app/src/terminal/terminal_size_element.rs
T

117 lines
3.6 KiB
Rust

use std::any::Any;
use async_channel::Sender;
use galaxyui::elements::Point;
use galaxyui::event::DispatchedEvent;
use galaxyui::geometry::rect::RectF;
use galaxyui::geometry::vector::Vector2F;
use galaxyui::{
AfterLayoutContext, AppContext, Element, Event, EventContext, LayoutContext, PaintContext,
SizeConstraint,
};
use super::view::TerminalAction;
pub struct TerminalSizeElement {
child: Box<dyn Element>,
resize_tx: Sender<Vector2F>,
}
impl TerminalSizeElement {
pub fn new(resize_tx: Sender<Vector2F>, child: Box<dyn Element>) -> Self {
TerminalSizeElement { child, resize_tx }
}
}
impl Element for TerminalSizeElement {
fn layout(
&mut self,
constraint: SizeConstraint,
ctx: &mut LayoutContext,
app: &AppContext,
) -> Vector2F {
self.child.layout(constraint, ctx, app)
}
fn after_layout(&mut self, ctx: &mut AfterLayoutContext, app: &AppContext) {
self.child.after_layout(ctx, app);
let terminal_size = self.size().expect("Size should be present");
// It's possible that the underlying shell session has been terminated
// but we're showing a read-only terminal view, in which case, the
// channel will be closed. If we're unable to send a resize through
// the channel, that's fine, just ignore the error.
let _ = self.resize_tx.try_send(terminal_size);
}
fn paint(&mut self, origin: Vector2F, ctx: &mut PaintContext, app: &AppContext) {
self.child.paint(origin, ctx, app)
}
fn size(&self) -> Option<Vector2F> {
self.child.size()
}
fn origin(&self) -> Option<Point> {
self.child.origin()
}
fn bounds(&self) -> Option<RectF> {
self.child.bounds()
}
fn parent_data(&self) -> Option<&dyn Any> {
self.child.parent_data()
}
fn dispatch_event(
&mut self,
event: &DispatchedEvent,
ctx: &mut EventContext,
app: &AppContext,
) -> bool {
let handled_by_child = self.child.dispatch_event(event, ctx, app);
let Some(z_index) = self.z_index() else {
return false;
};
if !handled_by_child {
if let Some(event_at_z_index) = event.at_z_index(z_index, ctx) {
match event_at_z_index {
Event::DragFiles { location } => {
if self.mouse_position_is_in_bounds(*location) {
ctx.dispatch_typed_action(TerminalAction::StartFileDropTarget);
} else {
ctx.dispatch_typed_action(TerminalAction::StopFileDropTarget);
}
return true;
}
Event::DragFileExit => {
ctx.dispatch_typed_action(TerminalAction::StopFileDropTarget);
return true;
}
Event::DragAndDropFiles { paths, location } => {
if self.mouse_position_is_in_bounds(*location) && !paths.is_empty() {
let paths = paths.iter().map(ToOwned::to_owned).collect();
ctx.dispatch_typed_action(TerminalAction::DragAndDropFiles(paths));
}
return true;
}
_ => {}
};
}
}
handled_by_child
}
}
impl TerminalSizeElement {
fn mouse_position_is_in_bounds(&self, position: Vector2F) -> bool {
let Some(bounds) = self.bounds() else {
return false;
};
bounds.contains_point(position)
}
}