egui: move viewport to its own file

This commit is contained in:
Mikolaj Wielgus 2024-06-13 13:27:18 +02:00
parent ce1a070a70
commit 6d66558a72
3 changed files with 266 additions and 215 deletions

View File

@ -40,7 +40,7 @@ use topola::{
},
};
use crate::{layers::Layers, overlay::Overlay, painter::Painter, top::Top};
use crate::{layers::Layers, overlay::Overlay, painter::Painter, top::Top, viewport::Viewport};
#[derive(Debug, Default)]
pub struct SharedData {
@ -69,7 +69,7 @@ pub struct App {
text_channel: (Sender<String>, Receiver<String>),
#[serde(skip)]
from_rect: egui::emath::Rect,
viewport: Viewport,
#[serde(skip)]
top: Top,
@ -85,7 +85,7 @@ impl Default for App {
invoker: None,
shared_data: Default::default(),
text_channel: channel(),
from_rect: egui::Rect::from_x_y_ranges(0.0..=1000000.0, 0.0..=500000.0),
viewport: Viewport::new(),
top: Top::new(),
layers: None,
}
@ -189,7 +189,7 @@ impl eframe::App for App {
self.shared_data.clone(),
self.text_channel.0.clone(),
&self.invoker,
&self.overlay,
&mut self.overlay,
);
if let Some(ref mut layers) = self.layers {
@ -198,217 +198,13 @@ impl eframe::App for App {
}
}
egui::CentralPanel::default().show(ctx, |ui| {
egui::Frame::canvas(ui.style()).show(ui, |ui| {
ui.ctx().request_repaint();
let desired_size = ui.available_width() * egui::vec2(1.0, 0.5);
let (_id, viewport_rect) = ui.allocate_space(desired_size);
let old_transform =
egui::emath::RectTransform::from_to(self.from_rect, viewport_rect);
let latest_pos = old_transform
.inverse()
.transform_pos(ctx.input(|i| i.pointer.latest_pos().unwrap_or_default()));
let old_scale = old_transform.scale().x;
self.from_rect = self.from_rect / ctx.input(|i| i.zoom_delta());
let new_scale = egui::emath::RectTransform::from_to(self.from_rect, viewport_rect)
.scale()
.x;
self.from_rect = self.from_rect.translate(
ctx.input(|i| latest_pos.to_vec2() * (new_scale - old_scale) / new_scale),
);
self.from_rect = self
.from_rect
.translate(ctx.input(|i| -i.raw_scroll_delta / new_scale));
let transform = egui::emath::RectTransform::from_to(self.from_rect, viewport_rect);
let mut painter = Painter::new(ui, transform);
if let Some(invoker_arc_mutex) = &self.invoker {
if ctx.input(|i| i.pointer.any_click()) {
if self.top.is_placing_via {
let invoker_arc_mutex = invoker_arc_mutex.clone();
execute(async move {
let mut invoker = invoker_arc_mutex.lock().unwrap();
invoker.execute(
Command::PlaceVia(ViaWeight {
from_layer: 0,
to_layer: 0,
circle: Circle {
pos: point! {x: latest_pos.x as f64, y: -latest_pos.y as f64},
r: 10000.0,
},
maybe_net: Some(1234),
}),
&mut EmptyRouterObserver,
);
});
} else if let Some(overlay) = &mut self.overlay {
let invoker = invoker_arc_mutex.lock().unwrap();
overlay.click(
invoker.autorouter().board(),
point! {x: latest_pos.x as f64, y: -latest_pos.y as f64},
);
}
}
if let (invoker, shared_data, Some(overlay)) = (
&invoker_arc_mutex.lock().unwrap(),
self.shared_data.lock().unwrap(),
self.viewport.update(
ctx,
&self.top,
self.shared_data.clone(),
&self.invoker,
&mut self.overlay,
) {
let board = invoker.autorouter().board();
for primitive in board.layout().drawing().layer_primitive_nodes(1) {
let shape = primitive.primitive(board.layout().drawing()).shape();
let color = if shared_data.highlighteds.contains(&primitive)
|| overlay
.selection()
.contains_node(board, GenericNode::Primitive(primitive))
{
egui::Color32::from_rgb(100, 100, 255)
} else {
egui::Color32::from_rgb(52, 52, 200)
};
painter.paint_primitive(&shape, color);
}
for zone in board.layout().layer_zone_nodes(1) {
let color = if overlay
.selection()
.contains_node(board, GenericNode::Compound(zone.into()))
{
egui::Color32::from_rgb(100, 100, 255)
} else {
egui::Color32::from_rgb(52, 52, 200)
};
painter.paint_polygon(&board.layout().zone(zone).shape().polygon, color)
}
for primitive in board.layout().drawing().layer_primitive_nodes(0) {
let shape = primitive.primitive(board.layout().drawing()).shape();
let color = if shared_data.highlighteds.contains(&primitive)
|| overlay
.selection()
.contains_node(board, GenericNode::Primitive(primitive))
{
egui::Color32::from_rgb(255, 100, 100)
} else {
egui::Color32::from_rgb(200, 52, 52)
};
painter.paint_primitive(&shape, color);
}
for zone in board.layout().layer_zone_nodes(0) {
let color = if overlay
.selection()
.contains_node(board, GenericNode::Compound(zone.into()))
{
egui::Color32::from_rgb(255, 100, 100)
} else {
egui::Color32::from_rgb(200, 52, 52)
};
painter.paint_polygon(&board.layout().zone(zone).shape().polygon, color)
}
if self.top.show_ratsnest {
for edge in overlay.ratsnest().graph().edge_references() {
let from = overlay
.ratsnest()
.graph()
.node_weight(edge.source())
.unwrap()
.pos;
let to = overlay
.ratsnest()
.graph()
.node_weight(edge.target())
.unwrap()
.pos;
painter.paint_edge(
from,
to,
egui::Stroke::new(1.0, egui::Color32::from_rgb(90, 90, 200)),
);
}
}
if let Some(navmesh) = &shared_data.navmesh {
for edge in navmesh.edge_references() {
let from = edge
.source()
.primitive(board.layout().drawing())
.shape()
.center();
let to = edge
.target()
.primitive(board.layout().drawing())
.shape()
.center();
let stroke = 'blk: {
if let (Some(source_pos), Some(target_pos)) = (
shared_data
.path
.iter()
.position(|node| *node == edge.source()),
shared_data
.path
.iter()
.position(|node| *node == edge.target()),
) {
if target_pos == source_pos + 1
|| source_pos == target_pos + 1
{
break 'blk egui::Stroke::new(
5.0,
egui::Color32::from_rgb(250, 250, 0),
);
}
}
egui::Stroke::new(1.0, egui::Color32::from_rgb(125, 125, 125))
};
painter.paint_edge(from, to, stroke);
}
}
for ghost in shared_data.ghosts.iter() {
painter.paint_primitive(&ghost, egui::Color32::from_rgb(75, 75, 150));
}
if let (Some(from), Some(to)) = (shared_data.from, shared_data.to) {
painter.paint_dot(
Circle {
pos: board.layout().drawing().primitive(from).shape().center(),
r: 20.0,
},
egui::Color32::from_rgb(255, 255, 100),
);
painter.paint_dot(
Circle {
pos: board.layout().drawing().primitive(to).shape().center(),
r: 20.0,
},
egui::Color32::from_rgb(255, 255, 100),
);
}
//unreachable!();
}
}
})
});
if ctx.input(|i| i.key_pressed(egui::Key::Escape)) {
ctx.send_viewport_cmd(egui::ViewportCommand::Close);

View File

@ -5,6 +5,7 @@ mod layers;
mod overlay;
mod painter;
mod top;
mod viewport;
use app::App;
// Build to native.

View File

@ -0,0 +1,254 @@
use std::sync::{Arc, Mutex};
use geo::point;
use petgraph::visit::{EdgeRef, IntoEdgeReferences};
use topola::{
autorouter::invoker::{Command, Invoker},
board::mesadata::MesadataTrait,
drawing::{graph::MakePrimitive, primitive::MakePrimitiveShape},
dsn::mesadata::DsnMesadata,
geometry::{shape::ShapeTrait, GenericNode},
layout::{via::ViaWeight, zone::MakePolyShape},
math::Circle,
router::EmptyRouterObserver,
};
use crate::{
app::{execute, SharedData},
overlay::Overlay,
painter::Painter,
top::Top,
};
pub struct Viewport {
from_rect: egui::emath::Rect,
}
impl Viewport {
pub fn new() -> Self {
Self {
from_rect: egui::Rect::from_x_y_ranges(0.0..=1000000.0, 0.0..=500000.0),
}
}
pub fn update(
&mut self,
ctx: &egui::Context,
top: &Top,
shared_data: Arc<Mutex<SharedData>>,
maybe_invoker: &Option<Arc<Mutex<Invoker<DsnMesadata>>>>,
maybe_overlay: &mut Option<Overlay>,
) {
egui::CentralPanel::default().show(ctx, |ui| {
egui::Frame::canvas(ui.style()).show(ui, |ui| {
ui.ctx().request_repaint();
let desired_size = ui.available_width() * egui::vec2(1.0, 0.5);
let (_id, viewport_rect) = ui.allocate_space(desired_size);
let old_transform =
egui::emath::RectTransform::from_to(self.from_rect, viewport_rect);
let latest_pos = old_transform
.inverse()
.transform_pos(ctx.input(|i| i.pointer.latest_pos().unwrap_or_default()));
let old_scale = old_transform.scale().x;
self.from_rect = self.from_rect / ctx.input(|i| i.zoom_delta());
let new_scale = egui::emath::RectTransform::from_to(self.from_rect, viewport_rect)
.scale()
.x;
self.from_rect = self.from_rect.translate(
ctx.input(|i| latest_pos.to_vec2() * (new_scale - old_scale) / new_scale),
);
self.from_rect = self
.from_rect
.translate(ctx.input(|i| -i.raw_scroll_delta / new_scale));
let transform = egui::emath::RectTransform::from_to(self.from_rect, viewport_rect);
let mut painter = Painter::new(ui, transform);
if let Some(invoker_arc_mutex) = maybe_invoker {
if ctx.input(|i| i.pointer.any_click()) {
if top.is_placing_via {
let invoker_arc_mutex = invoker_arc_mutex.clone();
execute(async move {
let mut invoker = invoker_arc_mutex.lock().unwrap();
invoker.execute(
Command::PlaceVia(ViaWeight {
from_layer: 0,
to_layer: 0,
circle: Circle {
pos: point! {x: latest_pos.x as f64, y: -latest_pos.y as f64},
r: 10000.0,
},
maybe_net: Some(1234),
}),
&mut EmptyRouterObserver,
);
});
} else if let Some(overlay) = maybe_overlay {
let invoker = invoker_arc_mutex.lock().unwrap();
overlay.click(
invoker.autorouter().board(),
point! {x: latest_pos.x as f64, y: -latest_pos.y as f64},
);
}
}
if let (invoker, shared_data, Some(overlay)) = (
&invoker_arc_mutex.lock().unwrap(),
shared_data.lock().unwrap(),
maybe_overlay,
) {
let board = invoker.autorouter().board();
for primitive in board.layout().drawing().layer_primitive_nodes(1) {
let shape = primitive.primitive(board.layout().drawing()).shape();
let color = if shared_data.highlighteds.contains(&primitive)
|| overlay
.selection()
.contains_node(board, GenericNode::Primitive(primitive))
{
egui::Color32::from_rgb(100, 100, 255)
} else {
egui::Color32::from_rgb(52, 52, 200)
};
painter.paint_primitive(&shape, color);
}
for zone in board.layout().layer_zone_nodes(1) {
let color = if overlay
.selection()
.contains_node(board, GenericNode::Compound(zone.into()))
{
egui::Color32::from_rgb(100, 100, 255)
} else {
egui::Color32::from_rgb(52, 52, 200)
};
painter.paint_polygon(&board.layout().zone(zone).shape().polygon, color)
}
for primitive in board.layout().drawing().layer_primitive_nodes(0) {
let shape = primitive.primitive(board.layout().drawing()).shape();
let color = if shared_data.highlighteds.contains(&primitive)
|| overlay
.selection()
.contains_node(board, GenericNode::Primitive(primitive))
{
egui::Color32::from_rgb(255, 100, 100)
} else {
egui::Color32::from_rgb(200, 52, 52)
};
painter.paint_primitive(&shape, color);
}
for zone in board.layout().layer_zone_nodes(0) {
let color = if overlay
.selection()
.contains_node(board, GenericNode::Compound(zone.into()))
{
egui::Color32::from_rgb(255, 100, 100)
} else {
egui::Color32::from_rgb(200, 52, 52)
};
painter.paint_polygon(&board.layout().zone(zone).shape().polygon, color)
}
if top.show_ratsnest {
for edge in overlay.ratsnest().graph().edge_references() {
let from = overlay
.ratsnest()
.graph()
.node_weight(edge.source())
.unwrap()
.pos;
let to = overlay
.ratsnest()
.graph()
.node_weight(edge.target())
.unwrap()
.pos;
painter.paint_edge(
from,
to,
egui::Stroke::new(1.0, egui::Color32::from_rgb(90, 90, 200)),
);
}
}
if let Some(navmesh) = &shared_data.navmesh {
for edge in navmesh.edge_references() {
let from = edge
.source()
.primitive(board.layout().drawing())
.shape()
.center();
let to = edge
.target()
.primitive(board.layout().drawing())
.shape()
.center();
let stroke = 'blk: {
if let (Some(source_pos), Some(target_pos)) = (
shared_data
.path
.iter()
.position(|node| *node == edge.source()),
shared_data
.path
.iter()
.position(|node| *node == edge.target()),
) {
if target_pos == source_pos + 1
|| source_pos == target_pos + 1
{
break 'blk egui::Stroke::new(
5.0,
egui::Color32::from_rgb(250, 250, 0),
);
}
}
egui::Stroke::new(1.0, egui::Color32::from_rgb(125, 125, 125))
};
painter.paint_edge(from, to, stroke);
}
}
for ghost in shared_data.ghosts.iter() {
painter.paint_primitive(&ghost, egui::Color32::from_rgb(75, 75, 150));
}
if let (Some(from), Some(to)) = (shared_data.from, shared_data.to) {
painter.paint_dot(
Circle {
pos: board.layout().drawing().primitive(from).shape().center(),
r: 20.0,
},
egui::Color32::from_rgb(255, 255, 100),
);
painter.paint_dot(
Circle {
pos: board.layout().drawing().primitive(to).shape().center(),
r: 20.0,
},
egui::Color32::from_rgb(255, 255, 100),
);
}
//unreachable!();
}
}
})
});
}
}