Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions assets/not.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
133 changes: 59 additions & 74 deletions src/app.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,6 @@ use crate::{
config::CanvasConfig,
connection_manager::{Connection, ConnectionManager},
drag::Drag,
module::Module,
};

pub const PANEL_BUTTON_MAX_HEIGHT: f32 = 50.0;
Expand Down Expand Up @@ -325,6 +324,7 @@ impl App {
}

fn is_on(&self, pin: Pin) -> bool {
let pin = pin.is_passthrough(&self.db).unwrap_or(pin);
let Some(v) = self.simulator.current.get(&pin) else {
return false;
};
Expand Down Expand Up @@ -449,6 +449,7 @@ impl App {
self.draw_panel_button(ui, InstanceKind::Gate(GateKind::Nor));
self.draw_panel_button(ui, InstanceKind::Gate(GateKind::Xor));
self.draw_panel_button(ui, InstanceKind::Gate(GateKind::Xnor));
self.draw_panel_button(ui, InstanceKind::Gate(GateKind::Not));
self.draw_panel_button(ui, InstanceKind::Power);
self.draw_panel_button(ui, InstanceKind::Lamp);
self.draw_panel_button(ui, InstanceKind::Clock);
Expand Down Expand Up @@ -538,10 +539,7 @@ impl App {
InstanceKind::Wire => self.db.circuit.new_wire(Wire::new_at(pos)),
InstanceKind::Lamp => self.db.circuit.new_lamp(Lamp { pos }),
InstanceKind::Clock => self.db.circuit.new_clock(Clock { pos }),
InstanceKind::Module(c) => self.db.new_module_with_flattening(Module {
pos,
definition_index: c,
}),
InstanceKind::Module(c) => self.db.new_module(c, pos),
};
self.set_drag(Drag::Canvas(crate::drag::CanvasDrag::Single {
id,
Expand All @@ -556,7 +554,7 @@ impl App {
{
let mut ids = Vec::new();
for (id, m) in &self.circuit().modules {
if m.definition_index == i {
if m.definition_id == i {
ids.push(id);
}
}
Expand Down Expand Up @@ -730,7 +728,7 @@ impl App {
Self::draw_grid(ui, canvas_rect, self.viewport_offset);

let mouse_clicked_canvas = resp.clicked();
let mouse_dragging_canvas = resp.dragged();
let mouse_dragging_canvas = resp.dragged_by(egui::PointerButton::Primary);
let double_clicked = ui.input(|i| {
i.pointer
.button_double_clicked(egui::PointerButton::Primary)
Expand Down Expand Up @@ -953,7 +951,7 @@ impl App {
}
}

fn draw_instance_graphics_new(
fn draw_instance_graphics(
&mut self,
ui: &mut Ui,
graphics: assets::InstanceGraphics,
Expand Down Expand Up @@ -1028,15 +1026,15 @@ impl App {
let gate = self.db.circuit.get_gate(id);
(gate.pos, gate.kind)
};
self.draw_instance_graphics_new(ui, kind.graphics(), self.adjusted_pos(pos), id);
self.draw_instance_graphics(ui, kind.graphics(), self.adjusted_pos(pos), id);
}

fn draw_power(&mut self, ui: &mut Ui, id: InstanceId) {
let (pos, graphics) = {
let power = self.db.circuit.get_power(id);
(power.pos, power.graphics())
};
self.draw_instance_graphics_new(ui, graphics, self.adjusted_pos(pos), id);
self.draw_instance_graphics(ui, graphics, self.adjusted_pos(pos), id);
}

fn draw_lamp(&mut self, ui: &mut Ui, id: InstanceId) {
Expand All @@ -1062,7 +1060,7 @@ impl App {
}
}

self.draw_instance_graphics_new(ui, graphics, pos, id);
self.draw_instance_graphics(ui, graphics, pos, id);
}

fn draw_clock(&mut self, ui: &mut Ui, id: InstanceId) {
Expand All @@ -1071,24 +1069,25 @@ impl App {
(clock.pos, clock.graphics())
};
let pos = self.adjusted_pos(pos);
self.draw_instance_graphics_new(ui, graphics, pos, id);
self.draw_instance_graphics(ui, graphics, pos, id);
}

fn draw_module(&mut self, ui: &mut Ui, id: InstanceId) {
let (pos, definition_index) = {
let module = self.db.circuit.get_module(id);
(module.pos, module.definition_index)
(module.pos, module.definition_id)
};
let screen_center = pos - self.viewport_offset;

let (name, pins, pin_offsets) = {
let definition = self.db.circuit.get_module(id).definition(&self.db);
let name = definition.name.clone();
let pins = definition.get_unconnected_pins(&self.db, id);

let pins = self.db.circuit.get_module(id).pins();
let pin_offsets: Vec<Vec2> = pins
.iter()
.map(|pin| definition.calculate_pin_offset(&self.db, pin, &self.canvas_config))
.map(|pin| {
definition.calculate_pin_offset(&self.db, &pins, pin, &self.canvas_config)
})
.collect();

(name, pins, pin_offsets)
Expand Down Expand Up @@ -1128,7 +1127,7 @@ impl App {
}));
}

for (pin_index, (&pin, &pin_offset)) in pins.iter().zip(pin_offsets.iter()).enumerate() {
for (&pin, &pin_offset) in pins.iter().zip(pin_offsets.iter()) {
let pin_pos_world = pos + pin_offset;
let pin_screen_pos = self.adjusted_pos(pin_pos_world);

Expand All @@ -1140,7 +1139,7 @@ impl App {
ui.painter()
.circle_filled(pin_screen_pos, self.canvas_config.base_pin_size, pin_color);

let has_current = self.is_on(Pin::new(id, pin_index as u32, pin.kind));
let has_current = self.is_on(pin);

if has_current {
ui.painter().circle_stroke(
Expand All @@ -1155,15 +1154,12 @@ impl App {
Vec2::splat(self.canvas_config.base_pin_size + PIN_HOVER_THRESHOLD),
);
let pin_resp = ui.allocate_rect(pin_rect, Sense::drag());
let pin_obj = Pin::new(id, pin_index as u32, pin.kind);
if pin_resp.hovered() {
self.hovered = Some(Hover::Pin(pin_obj));
self.hovered = Some(Hover::Pin(pin));
}
if pin_resp.dragged() {
self.selected.clear();
self.set_drag(Drag::PinToWire {
source_pin: pin_obj,
});
self.set_drag(Drag::PinToWire { source_pin: pin });
}
}
}
Expand Down Expand Up @@ -1259,7 +1255,7 @@ impl App {
&& let Some(split_point) = self.wire_branching_action_point(mouse, id)
{
ui.painter().circle_filled(
split_point,
self.adjusted_pos(split_point),
PIN_HOVER_THRESHOLD,
COLOR_HOVER_PIN_TO_WIRE,
);
Expand All @@ -1273,7 +1269,7 @@ impl App {
&& let Some(split_point) = self.wire_branching_action_point(mouse, id)
{
ui.painter().circle_filled(
split_point,
self.adjusted_pos(split_point),
PIN_HOVER_THRESHOLD,
COLOR_HOVER_PIN_TO_WIRE,
);
Expand Down Expand Up @@ -1551,30 +1547,31 @@ impl App {

fn debug_string(&self, ui: &Ui) -> String {
let mut out = String::new();

// App state (compact)
writeln!(out, "======================================").ok();
writeln!(out, " APP STATE").ok();
writeln!(out, "======================================").ok();
let mouse_pos_world = self.mouse_pos_world(ui);
writeln!(out, "mouse: {mouse_pos_world:?}").ok();

writeln!(out, "hovered: {:?}", self.hovered).ok();
writeln!(out, "drag: {:?}", self.drag).ok();
writeln!(out, "viewport_offset: {:?}", self.viewport_offset).ok();
writeln!(out, "potential_conns: {}", self.potential_connections.len()).ok();
writeln!(out, "clipboard: {:?}", self.clipboard).ok();
writeln!(out, "selected: {:?}", self.selected).ok();
writeln!(out, "editing_label: {:?}", self.editing_label).ok();
writeln!(out, "label_edit_buffer: {}", self.label_edit_buffer).ok();
writeln!(out, "viewing_module: {:?}", self.viewing_module).ok();

// Simulation status
writeln!(out, "\n=== Simulation Status ===").ok();
writeln!(out, "needs update {}", self.current_dirty).ok();
writeln!(out).ok();
writeln!(out, "======================================").ok();
writeln!(out, " SIMULATION").ok();
writeln!(out, "======================================").ok();
match self.simulator.status {
SimulationStatus::Stable { iterations } => {
writeln!(out, "Status: STABLE (after {iterations} iterations)").ok();
writeln!(out, "Status: STABLE ({iterations} iters)").ok();
}
SimulationStatus::Unstable { max_reached } => {
if max_reached {
let iters = self.simulator.last_iterations;
writeln!(out, "Status: UNSTABLE (max iterations: {iters})").ok();
writeln!(out, "Status: UNSTABLE (max: {iters})").ok();
} else {
writeln!(out, "Status: UNSTABLE").ok();
}
Expand All @@ -1583,44 +1580,31 @@ impl App {
writeln!(out, "Status: RUNNING...").ok();
}
}
let iters = self.simulator.last_iterations;
writeln!(out, "Iterations: {iters}").ok();

// Clock controller state
writeln!(out, "\n--- Clock Controller ---").ok();
writeln!(out, "State: {:?}", self.clock_controller.state).ok();
writeln!(
out,
"Tick interval: {:.2}s",
self.clock_controller.tick_interval
"Clock: {:?}, interval: {:.2}s",
self.clock_controller.state, self.clock_controller.tick_interval
)
.ok();
writeln!(out, "Voltage: {}", self.clock_controller.voltage).ok();

if self.potential_connections.is_empty() {
writeln!(out, "\nPotential Connections: none").ok();
} else {
writeln!(out, "\nPotential Connections:").ok();
for c in &self.potential_connections {
writeln!(out, " {}", c.display(self.circuit())).ok();
}
}

writeln!(out, "\n{}", self.connection_manager.debug_info()).ok();

writeln!(out, "\n").ok();

out.write_str(&self.circuit().display(&self.db)).ok();
// Circuit instances (main content)
writeln!(out).ok();
out.write_str(&self.circuit().display(&self.db, Some(&self.simulator)))
.ok();

// Module definitions (at the bottom, summary only)
if !self.db.module_definitions.is_empty() {
writeln!(out, "\nModule Def:").ok();
let mut iter = self.db.module_definitions.iter();
if let Some((id, first)) = iter.next() {
writeln!(out, " {}", first.display_definition(&self.db, id)).ok();
}
for (id, m) in iter {
writeln!(out).ok();
writeln!(out, " {}", m.display_definition(&self.db, id)).ok();
writeln!(out).ok();
writeln!(out, "======================================").ok();
writeln!(
out,
" MODULE DEFINITIONS ({} total)",
self.db.module_definitions.len()
)
.ok();
writeln!(out, "======================================").ok();
for (id, m) in &self.db.module_definitions {
writeln!(out, "{}", m.display_definition(&self.db, id)).ok();
}
}

Expand Down Expand Up @@ -1691,7 +1675,7 @@ impl App {
}
InstanceKind::Module(_) => {
let cc = self.db.circuit.get_module(id);
object_pos.push(ClipBoardItem::Module(cc.definition_index, center - cc.pos));
object_pos.push(ClipBoardItem::Module(cc.definition_id, center - cc.pos));
}
}
}
Expand Down Expand Up @@ -1742,12 +1726,13 @@ impl App {
self.selected.insert(id);
}
ClipBoardItem::Module(def_index, offset) => {
let id = self.db.new_module_with_flattening(Module {
pos: mouse - offset,
definition_index: def_index,
});
self.connection_manager.mark_instance_dirty(id);
self.selected.insert(id);
// TODO: Modules
// let id = self.db.new_module_with_flattening(Module {
// pos: mouse - offset,
// definition_index: def_index,
// });
// self.connection_manager.mark_instance_dirty(id);
// self.selected.insert(id);
}
ClipBoardItem::Lamp(offset) => {
let id = self.db.circuit.new_lamp(Lamp {
Expand Down Expand Up @@ -1886,7 +1871,7 @@ impl App {
pos - self.viewport_offset
}

fn mouse_pos_world(&self, ui: &Ui) -> Option<Pos2> {
pub fn mouse_pos_world(&self, ui: &Ui) -> Option<Pos2> {
ui.ctx()
.pointer_interact_pos()
.map(|p| p + self.viewport_offset)
Expand Down
Loading
Loading