Skip to content

Commit 084f57d

Browse files
committed
Copy paste
1 parent fa3eb22 commit 084f57d

File tree

1 file changed

+109
-9
lines changed

1 file changed

+109
-9
lines changed

src/app.rs

Lines changed: 109 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ use std::hash::Hash;
44

55
use egui::{
66
Align, Button, Color32, CornerRadius, Image, Layout, Pos2, Rect, Sense, Stroke, StrokeKind, Ui,
7-
Widget as _, vec2,
7+
Vec2, Widget as _, vec2,
88
};
99
use slotmap::{Key as _, SecondaryMap, SlotMap};
1010

@@ -15,19 +15,26 @@ pub const WIRE_HIT_DISTANCE: f32 = 10.0;
1515

1616
pub const COLOR_PIN_DETACH_HINT: Color32 = Color32::RED;
1717
pub const COLOR_PIN_POWERED_OUTLINE: Color32 = Color32::BLUE;
18-
pub const COLOR_WIRE_POWERED: Color32 = Color32::BLUE;
19-
pub const COLOR_WIRE_IDLE: Color32 = Color32::DARK_BLUE;
20-
pub const COLOR_WIRE_HOVER: Color32 = Color32::GREEN;
18+
pub const COLOR_WIRE_POWERED: Color32 = Color32::GREEN;
19+
pub const COLOR_WIRE_IDLE: Color32 = Color32::LIGHT_BLUE;
20+
pub const COLOR_WIRE_HOVER: Color32 = Color32::GRAY;
2121
pub const COLOR_HOVER_OUTLINE: Color32 = Color32::GRAY;
2222
pub const COLOR_ENDPOINT_HOVER: Color32 = Color32::LIGHT_YELLOW;
2323
pub const COLOR_POTENTIAL_CONN_HIGHLIGHT: Color32 = Color32::LIGHT_YELLOW;
24-
pub const COLOR_SELECTION_HIGHLIGHT: Color32 = Color32::LIGHT_YELLOW;
25-
pub const COLOR_SELECTION_BOX: Color32 = Color32::YELLOW;
24+
pub const COLOR_SELECTION_HIGHLIGHT: Color32 = Color32::GRAY;
25+
pub const COLOR_SELECTION_BOX: Color32 = Color32::LIGHT_BLUE;
2626

2727
slotmap::new_key_type! {
2828
pub struct InstanceId;
2929
}
3030

31+
#[derive(serde::Deserialize, serde::Serialize, Copy, Debug, Clone)]
32+
pub enum InstancePosOffset {
33+
Gate(GateKind, Vec2),
34+
Power(Vec2),
35+
Wire(Vec2, Vec2),
36+
}
37+
3138
#[derive(serde::Deserialize, serde::Serialize, Copy, Debug, Clone)]
3239
pub enum InstanceKind {
3340
Gate(GateKind),
@@ -164,7 +171,7 @@ pub struct DB {
164171
}
165172

166173
impl DB {
167-
pub fn new_gate(&mut self, g: Gate) {
174+
pub fn new_gate(&mut self, g: Gate) -> InstanceId {
168175
let k = self.instances.insert(());
169176
self.gates.insert(k, g);
170177
let kind = self
@@ -173,18 +180,21 @@ impl DB {
173180
.expect("gate must exist right after insertion")
174181
.kind;
175182
self.types.insert(k, InstanceKind::Gate(kind));
183+
k
176184
}
177185

178-
pub fn new_power(&mut self, p: Power) {
186+
pub fn new_power(&mut self, p: Power) -> InstanceId {
179187
let k = self.instances.insert(());
180188
self.powers.insert(k, p);
181189
self.types.insert(k, InstanceKind::Power);
190+
k
182191
}
183192

184-
pub fn new_wire(&mut self, w: Wire) {
193+
pub fn new_wire(&mut self, w: Wire) -> InstanceId {
185194
let k = self.instances.insert(());
186195
self.wires.insert(k, w);
187196
self.types.insert(k, InstanceKind::Wire);
197+
k
188198
}
189199

190200
pub fn ty(&self, id: InstanceId) -> InstanceKind {
@@ -280,6 +290,8 @@ pub struct App {
280290
pub show_debug: bool,
281291
// selection set and move preview
282292
pub selected: std::collections::HashSet<InstanceId>,
293+
//Copied. Items with their offset compared to a middle point in the rectangle
294+
pub clipboard: Vec<InstancePosOffset>,
283295
}
284296

285297
impl Default for App {
@@ -301,6 +313,7 @@ impl Default for App {
301313
current_dirty: true,
302314
show_debug: true,
303315
selected: Default::default(),
316+
clipboard: Default::default(),
304317
}
305318
}
306319
}
@@ -394,6 +407,8 @@ impl App {
394407
writeln!(out, "hovered: {:?}", self.hovered).ok();
395408
writeln!(out, "drag: {:?}", self.drag).ok();
396409
writeln!(out, "potential_conns: {}", self.potential_connections.len()).ok();
410+
writeln!(out, "clipboard: {:?}", self.clipboard).ok();
411+
writeln!(out, "selected: {:?}", self.selected).ok();
397412

398413
writeln!(out, "\nGates:").ok();
399414
for (id, g) in &self.db.gates {
@@ -587,6 +602,7 @@ impl App {
587602
}
588603
}
589604

605+
#[expect(clippy::too_many_lines)]
590606
fn draw_canvas(&mut self, ui: &mut Ui) {
591607
let (resp, _painter) = ui.allocate_painter(ui.available_size(), Sense::hover());
592608
let canvas_rect = resp.rect;
@@ -596,12 +612,96 @@ impl App {
596612
let right_clicked = ui.input(|i| i.pointer.secondary_clicked());
597613
let mouse_pos = ui.ctx().pointer_interact_pos();
598614

615+
let mut copy_event_detected = false;
616+
let mut paste_event_detected = false;
617+
ui.ctx().input(|i| {
618+
for event in &i.events {
619+
if matches!(event, egui::Event::Copy) {
620+
log::info!("Copy detected");
621+
copy_event_detected = true;
622+
}
623+
if let egui::Event::Paste(_) = event {
624+
paste_event_detected = true;
625+
}
626+
}
627+
});
628+
599629
let d_pressed = ui.input(|i| i.key_pressed(egui::Key::D));
600630

601631
if d_pressed && let Some(id) = self.hovered.take() {
602632
self.delete_instance(id);
603633
}
604634

635+
if copy_event_detected && !self.selected.is_empty() {
636+
let mut points = vec![];
637+
for &selected in &self.selected {
638+
match self.db.ty(selected) {
639+
InstanceKind::Gate(_) => {
640+
let g = self.db.get_gate(selected);
641+
points.push(g.pos);
642+
}
643+
InstanceKind::Power => {
644+
let p = self.db.get_power(selected);
645+
points.push(p.pos);
646+
}
647+
InstanceKind::Wire => {
648+
let w = self.db.get_wire(selected);
649+
points.push(w.start);
650+
points.push(w.end);
651+
}
652+
}
653+
}
654+
let rect = Rect::from_points(&points);
655+
let center = rect.center();
656+
657+
let mut object_pos = vec![];
658+
659+
for &selected in &self.selected {
660+
let ty = self.db.ty(selected);
661+
match ty {
662+
InstanceKind::Gate(kind) => {
663+
let g = self.db.get_gate(selected);
664+
object_pos.push(InstancePosOffset::Gate(kind, center - g.pos));
665+
}
666+
InstanceKind::Power => {
667+
let p = self.db.get_power(selected);
668+
object_pos.push(InstancePosOffset::Power(center - p.pos));
669+
}
670+
InstanceKind::Wire => {
671+
let w = self.db.get_wire(selected);
672+
object_pos.push(InstancePosOffset::Wire(center - w.start, center - w.end));
673+
}
674+
}
675+
}
676+
677+
self.clipboard = object_pos
678+
}
679+
680+
if paste_event_detected
681+
&& !self.clipboard.is_empty()
682+
&& let Some(mouse) = mouse_pos
683+
{
684+
for to_paste in self.clipboard.clone() {
685+
let id = match to_paste {
686+
InstancePosOffset::Gate(gate_kind, offset) => self.db.new_gate(Gate {
687+
kind: gate_kind,
688+
pos: mouse - offset,
689+
}),
690+
InstancePosOffset::Power(offset) => self.db.new_power(Power {
691+
pos: mouse - offset,
692+
on: false,
693+
}),
694+
InstancePosOffset::Wire(s, e) => self.db.new_wire(Wire {
695+
start: mouse - s,
696+
end: mouse - e,
697+
}),
698+
};
699+
self.potential_connections = self.compute_potential_connections_for_instance(id);
700+
self.finalize_connections_for_instance(id, &canvas_rect);
701+
}
702+
self.selected.clear();
703+
}
704+
605705
if let Some(mouse) = mouse_pos {
606706
self.handle_dragging(ui, mouse, &canvas_rect);
607707
self.hovered = self.interacted_instance(mouse);

0 commit comments

Comments
 (0)