mirror of https://codeberg.org/topola/topola.git
egui: implement zooming to fit
This commit is contained in:
parent
89717f2b6e
commit
0239a49c73
|
|
@ -177,12 +177,16 @@ impl eframe::App for App {
|
|||
self.history_channel.0.clone(),
|
||||
self.arc_mutex_maybe_invoker.clone(),
|
||||
&mut self.maybe_execute,
|
||||
&mut self.viewport,
|
||||
&mut self.maybe_overlay,
|
||||
&self.maybe_design,
|
||||
);
|
||||
|
||||
self.update_state(ctx.input(|i| i.stable_dt));
|
||||
|
||||
self.bottom
|
||||
.update(ctx, &self.translator, &self.viewport, &self.maybe_execute);
|
||||
|
||||
if let Some(ref mut layers) = self.maybe_layers {
|
||||
if let Some(invoker) = self.arc_mutex_maybe_invoker.lock().unwrap().as_ref() {
|
||||
layers.update(ctx, invoker.autorouter().board());
|
||||
|
|
@ -198,14 +202,6 @@ impl eframe::App for App {
|
|||
&self.maybe_layers,
|
||||
);
|
||||
|
||||
self.bottom.update(
|
||||
ctx,
|
||||
&self.translator,
|
||||
&self.viewport,
|
||||
&viewport_rect,
|
||||
&self.maybe_execute,
|
||||
);
|
||||
|
||||
if ctx.input(|i| i.key_pressed(egui::Key::Escape)) {
|
||||
ctx.send_viewport_cmd(egui::ViewportCommand::Close);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -14,13 +14,11 @@ impl Bottom {
|
|||
ctx: &egui::Context,
|
||||
tr: &Translator,
|
||||
viewport: &Viewport,
|
||||
viewport_rect: &egui::Rect,
|
||||
maybe_execute: &Option<ExecuteWithStatus>,
|
||||
) {
|
||||
egui::TopBottomPanel::bottom("bottom_panel").show(ctx, |ui| {
|
||||
let latest_pos = viewport.transform.inverse()
|
||||
* ctx.input(|i| i.pointer.latest_pos().unwrap_or_default())
|
||||
- viewport_rect.size() / 2.0;
|
||||
* ctx.input(|i| i.pointer.latest_pos().unwrap_or_default());
|
||||
|
||||
let mut message = String::from("");
|
||||
|
||||
|
|
|
|||
|
|
@ -19,6 +19,7 @@ use crate::{
|
|||
file_sender::FileSender,
|
||||
overlay::Overlay,
|
||||
translator::Translator,
|
||||
viewport::Viewport,
|
||||
};
|
||||
|
||||
pub struct Top {
|
||||
|
|
@ -56,6 +57,7 @@ impl Top {
|
|||
history_sender: Sender<String>,
|
||||
arc_mutex_maybe_invoker: Arc<Mutex<Option<Invoker<SpecctraMesadata>>>>,
|
||||
maybe_execute: &mut Option<ExecuteWithStatus>,
|
||||
viewport: &mut Viewport,
|
||||
maybe_overlay: &mut Option<Overlay>,
|
||||
maybe_design: &Option<SpecctraDesign>,
|
||||
) -> Result<(), InvokerError> {
|
||||
|
|
@ -145,10 +147,18 @@ impl Top {
|
|||
redo.button(ctx, ui);
|
||||
|
||||
ui.separator();
|
||||
|
||||
remove_bands.button(ctx, ui);
|
||||
});
|
||||
|
||||
ui.menu_button(tr.text("menu-view"), |ui| {
|
||||
ui.toggle_value(
|
||||
&mut viewport.scheduled_zoom_to_fit,
|
||||
tr.text("zoom-to-fit"),
|
||||
);
|
||||
|
||||
ui.separator();
|
||||
|
||||
ui.checkbox(&mut self.show_ratsnest, tr.text("show-ratsnest"));
|
||||
ui.checkbox(&mut self.show_navmesh, tr.text("show-navmesh"));
|
||||
ui.checkbox(&mut self.show_bboxes, tr.text("show-bboxes"));
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@ use petgraph::{
|
|||
data::DataMap,
|
||||
visit::{EdgeRef, IntoEdgeReferences},
|
||||
};
|
||||
use rstar::AABB;
|
||||
use rstar::{Envelope, AABB};
|
||||
use topola::{
|
||||
autorouter::invoker::{
|
||||
Command, ExecuteWithStatus, GetGhosts, GetMaybeNavmesh, GetMaybeTrace, GetObstacles,
|
||||
|
|
@ -24,13 +24,14 @@ use crate::{app::execute, layers::Layers, overlay::Overlay, painter::Painter, to
|
|||
|
||||
pub struct Viewport {
|
||||
pub transform: egui::emath::TSTransform,
|
||||
pub scheduled_zoom_to_fit: bool,
|
||||
}
|
||||
|
||||
impl Viewport {
|
||||
pub fn new() -> Self {
|
||||
Self {
|
||||
//from_rect: egui::Rect::from_x_y_ranges(0.0..=1000000.0, 0.0..=500000.0),
|
||||
transform: egui::emath::TSTransform::new([0.0, 0.0].into(), 0.01),
|
||||
scheduled_zoom_to_fit: false,
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -42,6 +43,31 @@ impl Viewport {
|
|||
maybe_execute: &mut Option<ExecuteWithStatus>,
|
||||
maybe_overlay: &mut Option<Overlay>,
|
||||
maybe_layers: &Option<Layers>,
|
||||
) -> egui::Rect {
|
||||
let viewport_rect = self.paint(
|
||||
ctx,
|
||||
top,
|
||||
maybe_invoker,
|
||||
maybe_execute,
|
||||
maybe_overlay,
|
||||
maybe_layers,
|
||||
);
|
||||
|
||||
if self.scheduled_zoom_to_fit {
|
||||
self.zoom_to_fit(maybe_invoker, &viewport_rect);
|
||||
}
|
||||
|
||||
viewport_rect
|
||||
}
|
||||
|
||||
pub fn paint(
|
||||
&mut self,
|
||||
ctx: &egui::Context,
|
||||
top: &Top,
|
||||
maybe_invoker: &mut Option<Invoker<SpecctraMesadata>>,
|
||||
maybe_execute: &mut Option<ExecuteWithStatus>,
|
||||
maybe_overlay: &mut Option<Overlay>,
|
||||
maybe_layers: &Option<Layers>,
|
||||
) -> egui::Rect {
|
||||
egui::CentralPanel::default().show(ctx, |ui| {
|
||||
egui::Frame::canvas(ui.style()).show(ui, |ui| {
|
||||
|
|
@ -250,4 +276,43 @@ impl Viewport {
|
|||
})
|
||||
}).inner.inner
|
||||
}
|
||||
|
||||
fn zoom_to_fit(
|
||||
&mut self,
|
||||
maybe_invoker: &mut Option<Invoker<SpecctraMesadata>>,
|
||||
viewport_rect: &egui::Rect,
|
||||
) {
|
||||
if self.scheduled_zoom_to_fit {
|
||||
if let Some(invoker) = maybe_invoker {
|
||||
let root_bbox = invoker
|
||||
.autorouter()
|
||||
.board()
|
||||
.layout()
|
||||
.drawing()
|
||||
.rtree()
|
||||
.root()
|
||||
.envelope();
|
||||
|
||||
let root_bbox_width = root_bbox.upper()[0] - root_bbox.lower()[0];
|
||||
let root_bbox_height = root_bbox.upper()[1] - root_bbox.lower()[1];
|
||||
|
||||
if root_bbox_width / root_bbox_height
|
||||
>= (viewport_rect.width() as f64) / (viewport_rect.height() as f64)
|
||||
{
|
||||
self.transform.scaling = viewport_rect.width() / root_bbox_width as f32;
|
||||
} else {
|
||||
self.transform.scaling = viewport_rect.height() / root_bbox_height as f32;
|
||||
}
|
||||
|
||||
self.transform.translation = egui::Vec2::new(
|
||||
viewport_rect.center()[0] as f32,
|
||||
viewport_rect.center()[1] as f32,
|
||||
) - (self.transform.scaling
|
||||
* egui::Pos2::new(root_bbox.center()[0] as f32, -root_bbox.center()[1] as f32))
|
||||
.to_vec2();
|
||||
}
|
||||
}
|
||||
|
||||
self.scheduled_zoom_to_fit = false;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue